Loading drivers/usb/gadget/f_accessory.c +3 −0 Original line number Diff line number Diff line Loading @@ -802,6 +802,9 @@ static const struct file_operations acc_fops = { .read = acc_read, .write = acc_write, .unlocked_ioctl = acc_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = acc_ioctl, #endif .open = acc_open, .release = acc_release, }; Loading drivers/usb/gadget/f_mtp.c +156 −72 Original line number Diff line number Diff line Loading @@ -978,23 +978,17 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) return ret; } static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) static long mtp_send_receive_ioctl(struct file *fp, unsigned code, struct mtp_file_range *mfr) { struct mtp_dev *dev = fp->private_data; struct file *filp = NULL; struct work_struct *work; int ret = -EINVAL; if (mtp_lock(&dev->ioctl_excl)) return -EBUSY; switch (code) { case MTP_SEND_FILE: case MTP_RECEIVE_FILE: case MTP_SEND_FILE_WITH_HEADER: { struct mtp_file_range mfr; struct work_struct *work; spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) { /* report cancelation to userspace */ Loading @@ -1011,12 +1005,8 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) dev->state = STATE_BUSY; spin_unlock_irq(&dev->lock); if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { ret = -EFAULT; goto fail; } /* hold a reference to the file while we are working with it */ filp = fget(mfr.fd); filp = fget(mfr->fd); if (!filp) { ret = -EBADF; goto fail; Loading @@ -1024,15 +1014,15 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) /* write the parameters */ dev->xfer_file = filp; dev->xfer_file_offset = mfr.offset; dev->xfer_file_length = mfr.length; dev->xfer_file_offset = mfr->offset; dev->xfer_file_length = mfr->length; smp_wmb(); if (code == MTP_SEND_FILE_WITH_HEADER) { work = &dev->send_file_work; dev->xfer_send_header = 1; dev->xfer_command = mfr.command; dev->xfer_transaction_id = mfr.transaction_id; dev->xfer_command = mfr->command; dev->xfer_transaction_id = mfr->transaction_id; } else if (code == MTP_SEND_FILE) { work = &dev->send_file_work; dev->xfer_send_header = 0; Loading @@ -1052,11 +1042,40 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) /* read the result */ smp_rmb(); ret = dev->xfer_result; break; fail: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) ret = -ECANCELED; else if (dev->state != STATE_OFFLINE) dev->state = STATE_READY; spin_unlock_irq(&dev->lock); out: mtp_unlock(&dev->ioctl_excl); DBG(dev->cdev, "ioctl returning %d\n", ret); return ret; } case MTP_SEND_EVENT: static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) { struct mtp_dev *dev = fp->private_data; struct mtp_file_range mfr; struct mtp_event event; int ret = -EINVAL; switch (code) { case MTP_SEND_FILE: case MTP_RECEIVE_FILE: case MTP_SEND_FILE_WITH_HEADER: if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { ret = -EFAULT; goto fail; } ret = mtp_send_receive_ioctl(fp, code, &mfr); break; case MTP_SEND_EVENT: if (mtp_lock(&dev->ioctl_excl)) return -EBUSY; /* return here so we don't change dev->state below, * which would interfere with bulk transfer state. */ Loading @@ -1064,22 +1083,84 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) ret = -EFAULT; else ret = mtp_send_event(dev, &event); goto out; mtp_unlock(&dev->ioctl_excl); break; default: DBG(dev->cdev, "unknown ioctl code: %d\n", code); } fail: return ret; } fail: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) ret = -ECANCELED; else if (dev->state != STATE_OFFLINE) dev->state = STATE_READY; spin_unlock_irq(&dev->lock); out: /* * 32 bit userspace calling into 64 bit kernl. handle ioctl code * and userspace pointer */ #ifdef CONFIG_COMPAT static long compat_mtp_ioctl(struct file *fp, unsigned code, unsigned long value) { struct mtp_dev *dev = fp->private_data; struct mtp_file_range mfr; struct __compat_mtp_file_range cmfr; struct mtp_event event; struct __compat_mtp_event cevent; unsigned cmd; bool send_file = false; int ret = -EINVAL; switch (code) { case COMPAT_MTP_SEND_FILE: cmd = MTP_SEND_FILE; send_file = true; break; case COMPAT_MTP_RECEIVE_FILE: cmd = MTP_RECEIVE_FILE; send_file = true; break; case COMPAT_MTP_SEND_FILE_WITH_HEADER: cmd = MTP_SEND_FILE_WITH_HEADER; send_file = true; break; case COMPAT_MTP_SEND_EVENT: cmd = MTP_SEND_EVENT; break; default: DBG(dev->cdev, "unknown compat_ioctl code: %d\n", code); goto fail; } if (send_file) { if (copy_from_user(&cmfr, (void __user *)value, sizeof(cmfr))) { ret = -EFAULT; goto fail; } mfr.fd = cmfr.fd; mfr.offset = cmfr.offset; mfr.length = cmfr.length; mfr.command = cmfr.command; mfr.transaction_id = cmfr.transaction_id; ret = mtp_send_receive_ioctl(fp, cmd, &mfr); } else { if (mtp_lock(&dev->ioctl_excl)) return -EBUSY; /* return here so we don't change dev->state below, * which would interfere with bulk transfer state. */ if (copy_from_user(&cevent, (void __user *)value, sizeof(cevent))) { ret = -EFAULT; goto fail; } event.length = cevent.length; event.data = compat_ptr(cevent.data); ret = mtp_send_event(dev, &event); mtp_unlock(&dev->ioctl_excl); DBG(dev->cdev, "ioctl returning %d\n", ret); } fail: return ret; } #endif static int mtp_open(struct inode *ip, struct file *fp) { Loading Loading @@ -1109,6 +1190,9 @@ static const struct file_operations mtp_fops = { .read = mtp_read, .write = mtp_write, .unlocked_ioctl = mtp_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = compat_mtp_ioctl, #endif .open = mtp_open, .release = mtp_release, }; Loading include/linux/usb/f_mtp.h +30 −0 Original line number Diff line number Diff line Loading @@ -19,5 +19,35 @@ #define __LINUX_USB_F_MTP_H #include <uapi/linux/usb/f_mtp.h> #include <linux/ioctl.h> #ifdef CONFIG_COMPAT #include <linux/compat.h> #endif #ifdef __KERNEL__ #ifdef CONFIG_COMPAT struct __compat_mtp_file_range { compat_int_t fd; compat_loff_t offset; int64_t length; uint16_t command; uint32_t transaction_id; }; struct __compat_mtp_event { compat_size_t length; compat_caddr_t data; }; #define COMPAT_MTP_SEND_FILE _IOW('M', 0, \ struct __compat_mtp_file_range) #define COMPAT_MTP_RECEIVE_FILE _IOW('M', 1, \ struct __compat_mtp_file_range) #define COMPAT_MTP_SEND_EVENT _IOW('M', 3, \ struct __compat_mtp_event) #define COMPAT_MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, \ struct __compat_mtp_file_range) #endif #endif #endif /* __LINUX_USB_F_MTP_H */ Loading
drivers/usb/gadget/f_accessory.c +3 −0 Original line number Diff line number Diff line Loading @@ -802,6 +802,9 @@ static const struct file_operations acc_fops = { .read = acc_read, .write = acc_write, .unlocked_ioctl = acc_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = acc_ioctl, #endif .open = acc_open, .release = acc_release, }; Loading
drivers/usb/gadget/f_mtp.c +156 −72 Original line number Diff line number Diff line Loading @@ -978,23 +978,17 @@ static int mtp_send_event(struct mtp_dev *dev, struct mtp_event *event) return ret; } static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) static long mtp_send_receive_ioctl(struct file *fp, unsigned code, struct mtp_file_range *mfr) { struct mtp_dev *dev = fp->private_data; struct file *filp = NULL; struct work_struct *work; int ret = -EINVAL; if (mtp_lock(&dev->ioctl_excl)) return -EBUSY; switch (code) { case MTP_SEND_FILE: case MTP_RECEIVE_FILE: case MTP_SEND_FILE_WITH_HEADER: { struct mtp_file_range mfr; struct work_struct *work; spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) { /* report cancelation to userspace */ Loading @@ -1011,12 +1005,8 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) dev->state = STATE_BUSY; spin_unlock_irq(&dev->lock); if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { ret = -EFAULT; goto fail; } /* hold a reference to the file while we are working with it */ filp = fget(mfr.fd); filp = fget(mfr->fd); if (!filp) { ret = -EBADF; goto fail; Loading @@ -1024,15 +1014,15 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) /* write the parameters */ dev->xfer_file = filp; dev->xfer_file_offset = mfr.offset; dev->xfer_file_length = mfr.length; dev->xfer_file_offset = mfr->offset; dev->xfer_file_length = mfr->length; smp_wmb(); if (code == MTP_SEND_FILE_WITH_HEADER) { work = &dev->send_file_work; dev->xfer_send_header = 1; dev->xfer_command = mfr.command; dev->xfer_transaction_id = mfr.transaction_id; dev->xfer_command = mfr->command; dev->xfer_transaction_id = mfr->transaction_id; } else if (code == MTP_SEND_FILE) { work = &dev->send_file_work; dev->xfer_send_header = 0; Loading @@ -1052,11 +1042,40 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) /* read the result */ smp_rmb(); ret = dev->xfer_result; break; fail: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) ret = -ECANCELED; else if (dev->state != STATE_OFFLINE) dev->state = STATE_READY; spin_unlock_irq(&dev->lock); out: mtp_unlock(&dev->ioctl_excl); DBG(dev->cdev, "ioctl returning %d\n", ret); return ret; } case MTP_SEND_EVENT: static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) { struct mtp_dev *dev = fp->private_data; struct mtp_file_range mfr; struct mtp_event event; int ret = -EINVAL; switch (code) { case MTP_SEND_FILE: case MTP_RECEIVE_FILE: case MTP_SEND_FILE_WITH_HEADER: if (copy_from_user(&mfr, (void __user *)value, sizeof(mfr))) { ret = -EFAULT; goto fail; } ret = mtp_send_receive_ioctl(fp, code, &mfr); break; case MTP_SEND_EVENT: if (mtp_lock(&dev->ioctl_excl)) return -EBUSY; /* return here so we don't change dev->state below, * which would interfere with bulk transfer state. */ Loading @@ -1064,22 +1083,84 @@ static long mtp_ioctl(struct file *fp, unsigned code, unsigned long value) ret = -EFAULT; else ret = mtp_send_event(dev, &event); goto out; mtp_unlock(&dev->ioctl_excl); break; default: DBG(dev->cdev, "unknown ioctl code: %d\n", code); } fail: return ret; } fail: spin_lock_irq(&dev->lock); if (dev->state == STATE_CANCELED) ret = -ECANCELED; else if (dev->state != STATE_OFFLINE) dev->state = STATE_READY; spin_unlock_irq(&dev->lock); out: /* * 32 bit userspace calling into 64 bit kernl. handle ioctl code * and userspace pointer */ #ifdef CONFIG_COMPAT static long compat_mtp_ioctl(struct file *fp, unsigned code, unsigned long value) { struct mtp_dev *dev = fp->private_data; struct mtp_file_range mfr; struct __compat_mtp_file_range cmfr; struct mtp_event event; struct __compat_mtp_event cevent; unsigned cmd; bool send_file = false; int ret = -EINVAL; switch (code) { case COMPAT_MTP_SEND_FILE: cmd = MTP_SEND_FILE; send_file = true; break; case COMPAT_MTP_RECEIVE_FILE: cmd = MTP_RECEIVE_FILE; send_file = true; break; case COMPAT_MTP_SEND_FILE_WITH_HEADER: cmd = MTP_SEND_FILE_WITH_HEADER; send_file = true; break; case COMPAT_MTP_SEND_EVENT: cmd = MTP_SEND_EVENT; break; default: DBG(dev->cdev, "unknown compat_ioctl code: %d\n", code); goto fail; } if (send_file) { if (copy_from_user(&cmfr, (void __user *)value, sizeof(cmfr))) { ret = -EFAULT; goto fail; } mfr.fd = cmfr.fd; mfr.offset = cmfr.offset; mfr.length = cmfr.length; mfr.command = cmfr.command; mfr.transaction_id = cmfr.transaction_id; ret = mtp_send_receive_ioctl(fp, cmd, &mfr); } else { if (mtp_lock(&dev->ioctl_excl)) return -EBUSY; /* return here so we don't change dev->state below, * which would interfere with bulk transfer state. */ if (copy_from_user(&cevent, (void __user *)value, sizeof(cevent))) { ret = -EFAULT; goto fail; } event.length = cevent.length; event.data = compat_ptr(cevent.data); ret = mtp_send_event(dev, &event); mtp_unlock(&dev->ioctl_excl); DBG(dev->cdev, "ioctl returning %d\n", ret); } fail: return ret; } #endif static int mtp_open(struct inode *ip, struct file *fp) { Loading Loading @@ -1109,6 +1190,9 @@ static const struct file_operations mtp_fops = { .read = mtp_read, .write = mtp_write, .unlocked_ioctl = mtp_ioctl, #ifdef CONFIG_COMPAT .compat_ioctl = compat_mtp_ioctl, #endif .open = mtp_open, .release = mtp_release, }; Loading
include/linux/usb/f_mtp.h +30 −0 Original line number Diff line number Diff line Loading @@ -19,5 +19,35 @@ #define __LINUX_USB_F_MTP_H #include <uapi/linux/usb/f_mtp.h> #include <linux/ioctl.h> #ifdef CONFIG_COMPAT #include <linux/compat.h> #endif #ifdef __KERNEL__ #ifdef CONFIG_COMPAT struct __compat_mtp_file_range { compat_int_t fd; compat_loff_t offset; int64_t length; uint16_t command; uint32_t transaction_id; }; struct __compat_mtp_event { compat_size_t length; compat_caddr_t data; }; #define COMPAT_MTP_SEND_FILE _IOW('M', 0, \ struct __compat_mtp_file_range) #define COMPAT_MTP_RECEIVE_FILE _IOW('M', 1, \ struct __compat_mtp_file_range) #define COMPAT_MTP_SEND_EVENT _IOW('M', 3, \ struct __compat_mtp_event) #define COMPAT_MTP_SEND_FILE_WITH_HEADER _IOW('M', 4, \ struct __compat_mtp_file_range) #endif #endif #endif /* __LINUX_USB_F_MTP_H */