Commit cf93039a authored by Anton Blanchard's avatar Anton Blanchard

ppc64: ioctl32 updates

add missing dev_put in dev_ifname32
fix usbdevfs (from sparc64)
add SG_IO (from sparc64)
add tun, vlan and random device ioctls
parent d5197a08
......@@ -44,6 +44,7 @@
#include <linux/ppp_defs.h>
#include <linux/if_ppp.h>
#include <linux/if_pppox.h>
#include <linux/if_tun.h>
#include <linux/mtio.h>
#include <linux/cdrom.h>
#include <linux/loop.h>
......@@ -102,20 +103,10 @@
#include <linux/usb.h>
#include <linux/usbdevice_fs.h>
#include <linux/nbd.h>
#include <linux/random.h>
#include <asm/ppc32.h>
#include <asm/ppcdebug.h>
/* Use this to get at 32-bit user passed pointers.
See sys_sparc32.c for description about these. */
#define A(__x) ((unsigned long)(__x))
#define AA(__x) \
({ unsigned long __ret; \
__asm__ ("clrldi %0, %0, 32" \
: "=r" (__ret) \
: "0" (__x)); \
__ret; \
})
/* Aiee. Someone does not find a difference between int and long */
#define EXT2_IOC32_GETFLAGS _IOR('f', 1, int)
#define EXT2_IOC32_SETFLAGS _IOW('f', 2, int)
......@@ -480,6 +471,7 @@ static int dev_ifname32(unsigned int fd, unsigned int cmd, unsigned long arg)
return -ENODEV;
strcpy(ifr32.ifr_name, dev->name);
dev_put(dev);
err = copy_to_user((struct ifreq32 *)arg, &ifr32, sizeof(struct ifreq32));
return (err ? -EFAULT : 0);
......@@ -1168,6 +1160,234 @@ out: if (karg) kfree(karg);
return err;
}
typedef struct sg_io_hdr32 {
s32 interface_id; /* [i] 'S' for SCSI generic (required) */
s32 dxfer_direction; /* [i] data transfer direction */
u8 cmd_len; /* [i] SCSI command length ( <= 16 bytes) */
u8 mx_sb_len; /* [i] max length to write to sbp */
u16 iovec_count; /* [i] 0 implies no scatter gather */
u32 dxfer_len; /* [i] byte count of data transfer */
u32 dxferp; /* [i], [*io] points to data transfer memory
or scatter gather list */
u32 cmdp; /* [i], [*i] points to command to perform */
u32 sbp; /* [i], [*o] points to sense_buffer memory */
u32 timeout; /* [i] MAX_UINT->no timeout (unit: millisec) */
u32 flags; /* [i] 0 -> default, see SG_FLAG... */
s32 pack_id; /* [i->o] unused internally (normally) */
u32 usr_ptr; /* [i->o] unused internally */
u8 status; /* [o] scsi status */
u8 masked_status; /* [o] shifted, masked scsi status */
u8 msg_status; /* [o] messaging level data (optional) */
u8 sb_len_wr; /* [o] byte count actually written to sbp */
u16 host_status; /* [o] errors from host adapter */
u16 driver_status; /* [o] errors from software driver */
s32 resid; /* [o] dxfer_len - actual_transferred */
u32 duration; /* [o] time taken by cmd (unit: millisec) */
u32 info; /* [o] auxiliary information */
} sg_io_hdr32_t; /* 64 bytes long (on sparc32) */
typedef struct sg_iovec32 {
u32 iov_base;
u32 iov_len;
} sg_iovec32_t;
static int alloc_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
{
sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
sg_iovec_t *kiov;
int i;
sgp->dxferp = kmalloc(sgp->iovec_count *
sizeof(sg_iovec_t), GFP_KERNEL);
if (!sgp->dxferp)
return -ENOMEM;
memset(sgp->dxferp, 0,
sgp->iovec_count * sizeof(sg_iovec_t));
kiov = (sg_iovec_t *) sgp->dxferp;
for (i = 0; i < sgp->iovec_count; i++) {
u32 iov_base32;
if (__get_user(iov_base32, &uiov->iov_base) ||
__get_user(kiov->iov_len, &uiov->iov_len))
return -EFAULT;
kiov->iov_base = kmalloc(kiov->iov_len, GFP_KERNEL);
if (!kiov->iov_base)
return -ENOMEM;
if (copy_from_user(kiov->iov_base,
(void *) A(iov_base32),
kiov->iov_len))
return -EFAULT;
uiov++;
kiov++;
}
return 0;
}
static int copy_back_sg_iovec(sg_io_hdr_t *sgp, u32 uptr32)
{
sg_iovec32_t *uiov = (sg_iovec32_t *) A(uptr32);
sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
int i;
for (i = 0; i < sgp->iovec_count; i++) {
u32 iov_base32;
if (__get_user(iov_base32, &uiov->iov_base))
return -EFAULT;
if (copy_to_user((void *) A(iov_base32),
kiov->iov_base,
kiov->iov_len))
return -EFAULT;
uiov++;
kiov++;
}
return 0;
}
static void free_sg_iovec(sg_io_hdr_t *sgp)
{
sg_iovec_t *kiov = (sg_iovec_t *) sgp->dxferp;
int i;
for (i = 0; i < sgp->iovec_count; i++) {
if (kiov->iov_base) {
kfree(kiov->iov_base);
kiov->iov_base = NULL;
}
kiov++;
}
kfree(sgp->dxferp);
sgp->dxferp = NULL;
}
static int sg_ioctl_trans(unsigned int fd, unsigned int cmd, unsigned long arg)
{
sg_io_hdr32_t *sg_io32;
sg_io_hdr_t sg_io64;
u32 dxferp32, cmdp32, sbp32;
mm_segment_t old_fs;
int err = 0;
sg_io32 = (sg_io_hdr32_t *)arg;
err = __get_user(sg_io64.interface_id, &sg_io32->interface_id);
err |= __get_user(sg_io64.dxfer_direction, &sg_io32->dxfer_direction);
err |= __get_user(sg_io64.cmd_len, &sg_io32->cmd_len);
err |= __get_user(sg_io64.mx_sb_len, &sg_io32->mx_sb_len);
err |= __get_user(sg_io64.iovec_count, &sg_io32->iovec_count);
err |= __get_user(sg_io64.dxfer_len, &sg_io32->dxfer_len);
err |= __get_user(sg_io64.timeout, &sg_io32->timeout);
err |= __get_user(sg_io64.flags, &sg_io32->flags);
err |= __get_user(sg_io64.pack_id, &sg_io32->pack_id);
sg_io64.dxferp = NULL;
sg_io64.cmdp = NULL;
sg_io64.sbp = NULL;
err |= __get_user(cmdp32, &sg_io32->cmdp);
sg_io64.cmdp = kmalloc(sg_io64.cmd_len, GFP_KERNEL);
if (!sg_io64.cmdp) {
err = -ENOMEM;
goto out;
}
if (copy_from_user(sg_io64.cmdp,
(void *) A(cmdp32),
sg_io64.cmd_len)) {
err = -EFAULT;
goto out;
}
err |= __get_user(sbp32, &sg_io32->sbp);
sg_io64.sbp = kmalloc(sg_io64.mx_sb_len, GFP_KERNEL);
if (!sg_io64.sbp) {
err = -ENOMEM;
goto out;
}
if (copy_from_user(sg_io64.sbp,
(void *) A(sbp32),
sg_io64.mx_sb_len)) {
err = -EFAULT;
goto out;
}
err |= __get_user(dxferp32, &sg_io32->dxferp);
if (sg_io64.iovec_count) {
int ret;
if ((ret = alloc_sg_iovec(&sg_io64, dxferp32))) {
err = ret;
goto out;
}
} else {
sg_io64.dxferp = kmalloc(sg_io64.dxfer_len, GFP_KERNEL);
if (!sg_io64.dxferp) {
err = -ENOMEM;
goto out;
}
if (copy_from_user(sg_io64.dxferp,
(void *) A(dxferp32),
sg_io64.dxfer_len)) {
err = -EFAULT;
goto out;
}
}
/* Unused internally, do not even bother to copy it over. */
sg_io64.usr_ptr = NULL;
if (err)
return -EFAULT;
old_fs = get_fs();
set_fs (KERNEL_DS);
err = sys_ioctl (fd, cmd, (unsigned long) &sg_io64);
set_fs (old_fs);
if (err < 0)
goto out;
err = __put_user(sg_io64.pack_id, &sg_io32->pack_id);
err |= __put_user(sg_io64.status, &sg_io32->status);
err |= __put_user(sg_io64.masked_status, &sg_io32->masked_status);
err |= __put_user(sg_io64.msg_status, &sg_io32->msg_status);
err |= __put_user(sg_io64.sb_len_wr, &sg_io32->sb_len_wr);
err |= __put_user(sg_io64.host_status, &sg_io32->host_status);
err |= __put_user(sg_io64.driver_status, &sg_io32->driver_status);
err |= __put_user(sg_io64.resid, &sg_io32->resid);
err |= __put_user(sg_io64.duration, &sg_io32->duration);
err |= __put_user(sg_io64.info, &sg_io32->info);
err |= copy_to_user((void *)A(sbp32), sg_io64.sbp, sg_io64.mx_sb_len);
if (sg_io64.dxferp) {
if (sg_io64.iovec_count)
err |= copy_back_sg_iovec(&sg_io64, dxferp32);
else
err |= copy_to_user((void *)A(dxferp32),
sg_io64.dxferp,
sg_io64.dxfer_len);
}
if (err)
err = -EFAULT;
out:
if (sg_io64.cmdp)
kfree(sg_io64.cmdp);
if (sg_io64.sbp)
kfree(sg_io64.sbp);
if (sg_io64.dxferp) {
if (sg_io64.iovec_count) {
free_sg_iovec(&sg_io64);
} else {
kfree(sg_io64.dxferp);
}
}
return err;
}
struct ppp_option_data32 {
__kernel_caddr_t32 ptr;
__u32 length;
......@@ -3058,13 +3278,12 @@ static int ioc_settimeout(unsigned int fd, unsigned int cmd, unsigned long arg)
return rw_long(fd, AUTOFS_IOC_SETTIMEOUT, arg);
}
#if 0
struct usbdevfs_ctrltransfer32 {
__u8 requesttype;
__u8 request;
__u16 value;
__u16 index;
__u16 length;
__u8 bRequestType;
__u8 bRequest;
__u16 wValue;
__u16 wIndex;
__u16 wLength;
__u32 timeout; /* in milliseconds */
__u32 data;
};
......@@ -3094,14 +3313,14 @@ static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long
/* In usbdevice_fs, it limits the control buffer to a page,
* for simplicity so do we.
*/
if (!uptr || kctrl.length > PAGE_SIZE)
if (!uptr || kctrl.wLength > PAGE_SIZE)
return -EINVAL;
kptr = (void *)__get_free_page(GFP_KERNEL);
if ((kctrl.requesttype & 0x80) == 0) {
if ((kctrl.bRequestType & 0x80) == 0) {
err = -EFAULT;
if (copy_from_user(kptr, uptr, kctrl.length))
if (copy_from_user(kptr, uptr, kctrl.wLength))
goto out;
}
......@@ -3113,8 +3332,8 @@ static int do_usbdevfs_control(unsigned int fd, unsigned int cmd, unsigned long
set_fs(old_fs);
if (err >= 0 &&
((kctrl.requesttype & 0x80) != 0)) {
if (copy_to_user(uptr, kptr, kctrl.length))
((kctrl.bRequestType & 0x80) != 0)) {
if (copy_to_user(uptr, kptr, kctrl.wLength))
err = -EFAULT;
}
......@@ -3449,7 +3668,6 @@ static int do_usbdevfs_discsignal(unsigned int fd, unsigned int cmd, unsigned lo
return err;
}
#endif
struct mtd_oob_buf32 {
u32 start;
......@@ -3507,119 +3725,6 @@ mtd_rw_oob(unsigned int fd, unsigned int cmd, unsigned long arg)
return ((0 == ret) ? 0 : -EFAULT);
}
struct sg_io_hdr_32
{
int interface_id;
int dxfer_direction;
unsigned char cmd_len;
unsigned char mx_sb_len;
unsigned short iovec_count;
unsigned int dxfer_len;
u32 dxferp;
u32 cmdp;
u32 sbp;
unsigned int timeout;
unsigned int flags;
int pack_id;
u32 usr_ptr;
unsigned char status;
unsigned char masked_status;
unsigned char msg_status;
unsigned char sb_len_wr;
unsigned short host_status;
unsigned short driver_status;
int resid;
unsigned int duration;
unsigned int info;
};
static int do_sg_io(unsigned int fd, unsigned int cmd, unsigned long arg)
{
struct sg_io_hdr *sg = kmalloc(sizeof(struct sg_io_hdr), GFP_KERNEL);
struct sg_io_hdr_32 *sg_32 = (struct sg_io_hdr_32 *)arg;
u32 dxferp_32;
u32 cmdp_32;
u32 sbp_32;
u32 usr_ptr_32;
int ret = -EFAULT;
int err;
mm_segment_t old_fs = get_fs();
if (!sg)
return -ENOMEM;
memset(sg, 0, sizeof(*sg));
err = copy_from_user(sg, sg_32, offsetof(struct sg_io_hdr, dxferp));
err |= __get_user(dxferp_32, &sg_32->dxferp);
err |= __get_user(cmdp_32, &sg_32->cmdp);
err |= __get_user(sbp_32, &sg_32->sbp);
if (err)
goto error;
sg->dxferp = (void *)A(dxferp_32);
sg->cmdp = (void *)A(cmdp_32);
sg->sbp = (void *)A(sbp_32);
err = __copy_from_user(&sg->timeout, &sg_32->timeout,
(long)&sg->usr_ptr - (long)&sg->timeout);
err |= __get_user(usr_ptr_32, &sg_32->usr_ptr);
if (err)
goto error;
sg->usr_ptr = (void *)A(usr_ptr_32);
err = __copy_from_user(&sg->status, &sg_32->status,
sizeof(struct sg_io_hdr) -
offsetof(struct sg_io_hdr, status));
if (err)
goto error;
set_fs(KERNEL_DS);
ret = sys_ioctl(fd, cmd, (unsigned long)sg);
set_fs(old_fs);
err = copy_to_user(sg_32, sg, offsetof(struct sg_io_hdr, dxferp));
dxferp_32 = (unsigned long)sg->dxferp;
cmdp_32 = (unsigned long)sg->cmdp;
sbp_32 = (unsigned long)sg->sbp;
err |= __put_user(dxferp_32, &sg_32->dxferp);
err |= __put_user(cmdp_32, &sg_32->cmdp);
err |= __put_user(sbp_32, &sg_32->sbp);
if (err) {
ret = -EFAULT;
goto error;
}
err = __copy_to_user(&sg_32->timeout, &sg->timeout,
(long)&sg->usr_ptr - (long)&sg->timeout);
usr_ptr_32 = (unsigned long)sg->usr_ptr;
err |= __put_user(usr_ptr_32, &sg_32->usr_ptr);
if (err) {
ret = -EFAULT;
goto error;
}
err = __copy_to_user(&sg_32->status, &sg->status,
sizeof(struct sg_io_hdr) -
offsetof(struct sg_io_hdr, status));
if (err)
ret = -EFAULT;
error:
kfree(sg);
return ret;
}
struct ioctl_trans {
unsigned long cmd;
unsigned long handler;
......@@ -3796,6 +3901,7 @@ COMPATIBLE_IOCTL(PIO_UNIMAPCLR),
/* Big S */
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_IDLUN),
COMPATIBLE_IOCTL(SCSI_IOCTL_PROBE_HOST),
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_PCI),
COMPATIBLE_IOCTL(SCSI_IOCTL_DOORLOCK),
COMPATIBLE_IOCTL(SCSI_IOCTL_DOORUNLOCK),
COMPATIBLE_IOCTL(SCSI_IOCTL_TEST_UNIT_READY),
......@@ -3803,6 +3909,12 @@ COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_ENABLE),
COMPATIBLE_IOCTL(SCSI_IOCTL_TAGGED_DISABLE),
COMPATIBLE_IOCTL(SCSI_IOCTL_GET_BUS_NUMBER),
COMPATIBLE_IOCTL(SCSI_IOCTL_SEND_COMMAND),
/* Big T */
COMPATIBLE_IOCTL(TUNSETNOCSUM),
COMPATIBLE_IOCTL(TUNSETDEBUG),
COMPATIBLE_IOCTL(TUNSETIFF),
COMPATIBLE_IOCTL(TUNSETPERSIST),
COMPATIBLE_IOCTL(TUNSETOWNER),
/* Big V */
COMPATIBLE_IOCTL(VT_SETMODE),
COMPATIBLE_IOCTL(VT_GETMODE),
......@@ -3879,6 +3991,11 @@ COMPATIBLE_IOCTL(SIOCGRARP),
COMPATIBLE_IOCTL(SIOCDRARP),
COMPATIBLE_IOCTL(SIOCADDDLCI),
COMPATIBLE_IOCTL(SIOCDELDLCI),
COMPATIBLE_IOCTL(SIOCGMIIPHY),
COMPATIBLE_IOCTL(SIOCGMIIREG),
COMPATIBLE_IOCTL(SIOCSMIIREG),
COMPATIBLE_IOCTL(SIOCGIFVLAN),
COMPATIBLE_IOCTL(SIOCSIFVLAN),
/* SG stuff */
COMPATIBLE_IOCTL(SG_SET_TIMEOUT),
COMPATIBLE_IOCTL(SG_GET_TIMEOUT),
......@@ -4208,6 +4325,13 @@ COMPATIBLE_IOCTL(WDIOC_GETBOOTSTATUS),
COMPATIBLE_IOCTL(WDIOC_GETTEMP),
COMPATIBLE_IOCTL(WDIOC_SETOPTIONS),
COMPATIBLE_IOCTL(WDIOC_KEEPALIVE),
/* Big R */
COMPATIBLE_IOCTL(RNDGETENTCNT),
COMPATIBLE_IOCTL(RNDADDTOENTCNT),
COMPATIBLE_IOCTL(RNDGETPOOL),
COMPATIBLE_IOCTL(RNDADDENTROPY),
COMPATIBLE_IOCTL(RNDZAPENTCNT),
COMPATIBLE_IOCTL(RNDCLEARPOOL),
/* Bluetooth ioctls */
COMPATIBLE_IOCTL(HCIDEVUP),
COMPATIBLE_IOCTL(HCIDEVDOWN),
......@@ -4252,13 +4376,6 @@ COMPATIBLE_IOCTL(NBD_CLEAR_QUE),
COMPATIBLE_IOCTL(NBD_PRINT_DEBUG),
COMPATIBLE_IOCTL(NBD_SET_SIZE_BLOCKS),
COMPATIBLE_IOCTL(NBD_DISCONNECT),
/* Remove *PRIVATE in 2.5 */
COMPATIBLE_IOCTL(SIOCDEVPRIVATE),
COMPATIBLE_IOCTL(SIOCDEVPRIVATE+1),
COMPATIBLE_IOCTL(SIOCDEVPRIVATE+2),
COMPATIBLE_IOCTL(SIOCGMIIPHY),
COMPATIBLE_IOCTL(SIOCGMIIREG),
COMPATIBLE_IOCTL(SIOCSMIIREG),
/* And these ioctls need translation */
HANDLE_IOCTL(MEMREADOOB32, mtd_rw_oob),
HANDLE_IOCTL(MEMWRITEOOB32, mtd_rw_oob),
......@@ -4326,6 +4443,7 @@ HANDLE_IOCTL(FDGETDRVSTAT32, fd_ioctl_trans),
HANDLE_IOCTL(FDPOLLDRVSTAT32, fd_ioctl_trans),
HANDLE_IOCTL(FDGETFDCSTAT32, fd_ioctl_trans),
HANDLE_IOCTL(FDWERRORGET32, fd_ioctl_trans),
HANDLE_IOCTL(SG_IO,sg_ioctl_trans),
HANDLE_IOCTL(PPPIOCGIDLE32, ppp_ioctl_trans),
HANDLE_IOCTL(PPPIOCSCOMPRESS32, ppp_ioctl_trans),
HANDLE_IOCTL(MTIOCGET32, mt_ioctl_trans),
......@@ -4418,15 +4536,12 @@ HANDLE_IOCTL(DRM32_IOCTL_MAP_BUFS, drm32_map_bufs),
HANDLE_IOCTL(DRM32_IOCTL_DMA, drm32_dma),
HANDLE_IOCTL(DRM32_IOCTL_RES_CTX, drm32_res_ctx),
#endif /* DRM */
#if 0
HANDLE_IOCTL(USBDEVFS_CONTROL32, do_usbdevfs_control),
HANDLE_IOCTL(USBDEVFS_BULK32, do_usbdevfs_bulk),
/*HANDLE_IOCTL(USBDEVFS_SUBMITURB32, do_usbdevfs_urb)*/
HANDLE_IOCTL(USBDEVFS_REAPURB32, do_usbdevfs_reapurb),
HANDLE_IOCTL(USBDEVFS_REAPURBNDELAY32, do_usbdevfs_reapurb),
HANDLE_IOCTL(USBDEVFS_DISCSIGNAL32, do_usbdevfs_discsignal),
#endif
HANDLE_IOCTL(SG_IO, do_sg_io),
};
unsigned long ioctl32_hash_table[1024];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment