Loading drivers/hid/hid-core.c +8 −15 Original line number Original line Diff line number Diff line Loading @@ -1081,35 +1081,28 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); if (!buf) { if (!buf) report = hid_get_report(report_enum, data); goto nomem; goto nomem; } snprintf(buf, HID_DEBUG_BUFSIZE - 1, "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); hid_debug_event(hid, buf); report = hid_get_report(report_enum, data); if (!report) { kfree(buf); return -1; } /* dump the report */ /* dump the report */ snprintf(buf, HID_DEBUG_BUFSIZE - 1, snprintf(buf, HID_DEBUG_BUFSIZE - 1, "report %d (size %u) = ", report->id, size); "\nreport (size %u) (%snumbered) = ", size, report_enum->numbered ? "" : "un"); hid_debug_event(hid, buf); hid_debug_event(hid, buf); for (i = 0; i < size; i++) { for (i = 0; i < size; i++) { snprintf(buf, HID_DEBUG_BUFSIZE - 1, snprintf(buf, HID_DEBUG_BUFSIZE - 1, " %02x", data[i]); " %02x", data[i]); hid_debug_event(hid, buf); hid_debug_event(hid, buf); } } hid_debug_event(hid, "\n"); hid_debug_event(hid, "\n"); kfree(buf); kfree(buf); nomem: nomem: report = hid_get_report(report_enum, data); if (!report) return -1; if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { ret = hdrv->raw_event(hid, report, data, size); ret = hdrv->raw_event(hid, report, data, size); if (ret != 0) if (ret != 0) Loading drivers/hid/hid-magicmouse.c +4 −1 Original line number Original line Diff line number Diff line Loading @@ -354,12 +354,15 @@ static int magicmouse_probe(struct hid_device *hdev, goto err_free; goto err_free; } } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT); ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { if (ret) { dev_err(&hdev->dev, "magicmouse hw start failed\n"); dev_err(&hdev->dev, "magicmouse hw start failed\n"); goto err_free; goto err_free; } } /* we are handling the input ourselves */ hidinput_disconnect(hdev); report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); if (!report) { if (!report) { dev_err(&hdev->dev, "unable to register touch report\n"); dev_err(&hdev->dev, "unable to register touch report\n"); Loading drivers/hid/hidraw.c +26 −22 Original line number Original line Diff line number Diff line Loading @@ -106,38 +106,48 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { { unsigned int minor = iminor(file->f_path.dentry->d_inode); unsigned int minor = iminor(file->f_path.dentry->d_inode); /* FIXME: What stops hidraw_table going NULL */ struct hid_device *dev; struct hid_device *dev = hidraw_table[minor]->hid; __u8 *buf; __u8 *buf; int ret = 0; int ret = 0; if (!dev->hid_output_raw_report) mutex_lock(&minors_lock); return -ENODEV; dev = hidraw_table[minor]->hid; if (!dev->hid_output_raw_report) { ret = -ENODEV; goto out; } if (count > HID_MAX_BUFFER_SIZE) { if (count > HID_MAX_BUFFER_SIZE) { printk(KERN_WARNING "hidraw: pid %d passed too large report\n", printk(KERN_WARNING "hidraw: pid %d passed too large report\n", task_pid_nr(current)); task_pid_nr(current)); return -EINVAL; ret = -EINVAL; goto out; } } if (count < 2) { if (count < 2) { printk(KERN_WARNING "hidraw: pid %d passed too short report\n", printk(KERN_WARNING "hidraw: pid %d passed too short report\n", task_pid_nr(current)); task_pid_nr(current)); return -EINVAL; ret = -EINVAL; goto out; } } buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); if (!buf) if (!buf) { return -ENOMEM; ret = -ENOMEM; goto out; } if (copy_from_user(buf, buffer, count)) { if (copy_from_user(buf, buffer, count)) { ret = -EFAULT; ret = -EFAULT; goto out; goto out_free; } } ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); out: out_free: kfree(buf); kfree(buf); out: mutex_unlock(&minors_lock); return ret; return ret; } } Loading Loading @@ -165,11 +175,8 @@ static int hidraw_open(struct inode *inode, struct file *file) goto out; goto out; } } lock_kernel(); mutex_lock(&minors_lock); mutex_lock(&minors_lock); if (!hidraw_table[minor]) { if (!hidraw_table[minor]) { printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", minor); kfree(list); kfree(list); err = -ENODEV; err = -ENODEV; goto out_unlock; goto out_unlock; Loading Loading @@ -197,7 +204,6 @@ static int hidraw_open(struct inode *inode, struct file *file) out_unlock: out_unlock: mutex_unlock(&minors_lock); mutex_unlock(&minors_lock); unlock_kernel(); out: out: return err; return err; Loading @@ -209,11 +215,8 @@ static int hidraw_release(struct inode * inode, struct file * file) struct hidraw *dev; struct hidraw *dev; struct hidraw_list *list = file->private_data; struct hidraw_list *list = file->private_data; if (!hidraw_table[minor]) { if (!hidraw_table[minor]) printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", minor); return -ENODEV; return -ENODEV; } list_del(&list->node); list_del(&list->node); dev = hidraw_table[minor]; dev = hidraw_table[minor]; Loading @@ -238,11 +241,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode; unsigned int minor = iminor(inode); unsigned int minor = iminor(inode); long ret = 0; long ret = 0; /* FIXME: What stops hidraw_table going NULL */ struct hidraw *dev; struct hidraw *dev = hidraw_table[minor]; void __user *user_arg = (void __user*) arg; void __user *user_arg = (void __user*) arg; lock_kernel(); mutex_lock(&minors_lock); dev = hidraw_table[minor]; switch (cmd) { switch (cmd) { case HIDIOCGRDESCSIZE: case HIDIOCGRDESCSIZE: if (put_user(dev->hid->rsize, (int __user *)arg)) if (put_user(dev->hid->rsize, (int __user *)arg)) Loading Loading @@ -315,7 +319,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, ret = -ENOTTY; ret = -ENOTTY; } } unlock_kernel(); mutex_unlock(&minors_lock); return ret; return ret; } } Loading drivers/hid/usbhid/hid-core.c +23 −1 Original line number Original line Diff line number Diff line Loading @@ -1313,6 +1313,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) { { set_bit(HID_REPORTED_IDLE, &usbhid->iofl); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); spin_unlock_irq(&usbhid->lock); if (hid->driver && hid->driver->suspend) { status = hid->driver->suspend(hid, message); if (status < 0) return status; } } else { } else { usbhid_mark_busy(usbhid); usbhid_mark_busy(usbhid); spin_unlock_irq(&usbhid->lock); spin_unlock_irq(&usbhid->lock); Loading @@ -1320,6 +1325,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) } } } else { } else { if (hid->driver && hid->driver->suspend) { status = hid->driver->suspend(hid, message); if (status < 0) return status; } spin_lock_irq(&usbhid->lock); spin_lock_irq(&usbhid->lock); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); spin_unlock_irq(&usbhid->lock); Loading Loading @@ -1374,6 +1384,11 @@ static int hid_resume(struct usb_interface *intf) hid_io_error(hid); hid_io_error(hid); usbhid_restart_queues(usbhid); usbhid_restart_queues(usbhid); if (status >= 0 && hid->driver && hid->driver->resume) { int ret = hid->driver->resume(hid); if (ret < 0) status = ret; } dev_dbg(&intf->dev, "resume status %d\n", status); dev_dbg(&intf->dev, "resume status %d\n", status); return 0; return 0; } } Loading @@ -1382,9 +1397,16 @@ static int hid_reset_resume(struct usb_interface *intf) { { struct hid_device *hid = usb_get_intfdata(intf); struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; struct usbhid_device *usbhid = hid->driver_data; int status; clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); return hid_post_reset(intf); status = hid_post_reset(intf); if (status >= 0 && hid->driver && hid->driver->reset_resume) { int ret = hid->driver->reset_resume(hid); if (ret < 0) status = ret; } return status; } } #endif /* CONFIG_PM */ #endif /* CONFIG_PM */ Loading drivers/hid/usbhid/hiddev.c +17 −2 Original line number Original line Diff line number Diff line Loading @@ -267,6 +267,7 @@ static int hiddev_open(struct inode *inode, struct file *file) struct hiddev_list *list; struct hiddev_list *list; int res, i; int res, i; /* See comment in hiddev_connect() for BKL explanation */ lock_kernel(); lock_kernel(); i = iminor(inode) - HIDDEV_MINOR_BASE; i = iminor(inode) - HIDDEV_MINOR_BASE; Loading Loading @@ -894,8 +895,22 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) hiddev->hid = hid; hiddev->hid = hid; hiddev->exist = 1; hiddev->exist = 1; /* when lock_kernel() usage is fixed in usb_open(), /* * we could also fix it here */ * BKL here is used to avoid race after usb_register_dev(). * Once the device node has been created, open() could happen on it. * The code below will then fail, as hiddev_table hasn't been * updated. * * The obvious fix -- introducing mutex to guard hiddev_table[] * doesn't work, as usb_open() and usb_register_dev() both take * minor_rwsem, thus we'll have ABBA deadlock. * * Before BKL pushdown, usb_open() had been acquiring it in right * order, so _open() was safe to use it to protect from this race. * Now the order is different, but AB-BA deadlock still doesn't occur * as BKL is dropped on schedule() (i.e. while sleeping on * minor_rwsem). Fugly. */ lock_kernel(); lock_kernel(); retval = usb_register_dev(usbhid->intf, &hiddev_class); retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { if (retval) { Loading Loading
drivers/hid/hid-core.c +8 −15 Original line number Original line Diff line number Diff line Loading @@ -1081,35 +1081,28 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC); if (!buf) { if (!buf) report = hid_get_report(report_enum, data); goto nomem; goto nomem; } snprintf(buf, HID_DEBUG_BUFSIZE - 1, "\nreport (size %u) (%snumbered)\n", size, report_enum->numbered ? "" : "un"); hid_debug_event(hid, buf); report = hid_get_report(report_enum, data); if (!report) { kfree(buf); return -1; } /* dump the report */ /* dump the report */ snprintf(buf, HID_DEBUG_BUFSIZE - 1, snprintf(buf, HID_DEBUG_BUFSIZE - 1, "report %d (size %u) = ", report->id, size); "\nreport (size %u) (%snumbered) = ", size, report_enum->numbered ? "" : "un"); hid_debug_event(hid, buf); hid_debug_event(hid, buf); for (i = 0; i < size; i++) { for (i = 0; i < size; i++) { snprintf(buf, HID_DEBUG_BUFSIZE - 1, snprintf(buf, HID_DEBUG_BUFSIZE - 1, " %02x", data[i]); " %02x", data[i]); hid_debug_event(hid, buf); hid_debug_event(hid, buf); } } hid_debug_event(hid, "\n"); hid_debug_event(hid, "\n"); kfree(buf); kfree(buf); nomem: nomem: report = hid_get_report(report_enum, data); if (!report) return -1; if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { ret = hdrv->raw_event(hid, report, data, size); ret = hdrv->raw_event(hid, report, data, size); if (ret != 0) if (ret != 0) Loading
drivers/hid/hid-magicmouse.c +4 −1 Original line number Original line Diff line number Diff line Loading @@ -354,12 +354,15 @@ static int magicmouse_probe(struct hid_device *hdev, goto err_free; goto err_free; } } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT); ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { if (ret) { dev_err(&hdev->dev, "magicmouse hw start failed\n"); dev_err(&hdev->dev, "magicmouse hw start failed\n"); goto err_free; goto err_free; } } /* we are handling the input ourselves */ hidinput_disconnect(hdev); report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); if (!report) { if (!report) { dev_err(&hdev->dev, "unable to register touch report\n"); dev_err(&hdev->dev, "unable to register touch report\n"); Loading
drivers/hid/hidraw.c +26 −22 Original line number Original line Diff line number Diff line Loading @@ -106,38 +106,48 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos) { { unsigned int minor = iminor(file->f_path.dentry->d_inode); unsigned int minor = iminor(file->f_path.dentry->d_inode); /* FIXME: What stops hidraw_table going NULL */ struct hid_device *dev; struct hid_device *dev = hidraw_table[minor]->hid; __u8 *buf; __u8 *buf; int ret = 0; int ret = 0; if (!dev->hid_output_raw_report) mutex_lock(&minors_lock); return -ENODEV; dev = hidraw_table[minor]->hid; if (!dev->hid_output_raw_report) { ret = -ENODEV; goto out; } if (count > HID_MAX_BUFFER_SIZE) { if (count > HID_MAX_BUFFER_SIZE) { printk(KERN_WARNING "hidraw: pid %d passed too large report\n", printk(KERN_WARNING "hidraw: pid %d passed too large report\n", task_pid_nr(current)); task_pid_nr(current)); return -EINVAL; ret = -EINVAL; goto out; } } if (count < 2) { if (count < 2) { printk(KERN_WARNING "hidraw: pid %d passed too short report\n", printk(KERN_WARNING "hidraw: pid %d passed too short report\n", task_pid_nr(current)); task_pid_nr(current)); return -EINVAL; ret = -EINVAL; goto out; } } buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); if (!buf) if (!buf) { return -ENOMEM; ret = -ENOMEM; goto out; } if (copy_from_user(buf, buffer, count)) { if (copy_from_user(buf, buffer, count)) { ret = -EFAULT; ret = -EFAULT; goto out; goto out_free; } } ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); out: out_free: kfree(buf); kfree(buf); out: mutex_unlock(&minors_lock); return ret; return ret; } } Loading Loading @@ -165,11 +175,8 @@ static int hidraw_open(struct inode *inode, struct file *file) goto out; goto out; } } lock_kernel(); mutex_lock(&minors_lock); mutex_lock(&minors_lock); if (!hidraw_table[minor]) { if (!hidraw_table[minor]) { printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", minor); kfree(list); kfree(list); err = -ENODEV; err = -ENODEV; goto out_unlock; goto out_unlock; Loading Loading @@ -197,7 +204,6 @@ static int hidraw_open(struct inode *inode, struct file *file) out_unlock: out_unlock: mutex_unlock(&minors_lock); mutex_unlock(&minors_lock); unlock_kernel(); out: out: return err; return err; Loading @@ -209,11 +215,8 @@ static int hidraw_release(struct inode * inode, struct file * file) struct hidraw *dev; struct hidraw *dev; struct hidraw_list *list = file->private_data; struct hidraw_list *list = file->private_data; if (!hidraw_table[minor]) { if (!hidraw_table[minor]) printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", minor); return -ENODEV; return -ENODEV; } list_del(&list->node); list_del(&list->node); dev = hidraw_table[minor]; dev = hidraw_table[minor]; Loading @@ -238,11 +241,12 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, struct inode *inode = file->f_path.dentry->d_inode; struct inode *inode = file->f_path.dentry->d_inode; unsigned int minor = iminor(inode); unsigned int minor = iminor(inode); long ret = 0; long ret = 0; /* FIXME: What stops hidraw_table going NULL */ struct hidraw *dev; struct hidraw *dev = hidraw_table[minor]; void __user *user_arg = (void __user*) arg; void __user *user_arg = (void __user*) arg; lock_kernel(); mutex_lock(&minors_lock); dev = hidraw_table[minor]; switch (cmd) { switch (cmd) { case HIDIOCGRDESCSIZE: case HIDIOCGRDESCSIZE: if (put_user(dev->hid->rsize, (int __user *)arg)) if (put_user(dev->hid->rsize, (int __user *)arg)) Loading Loading @@ -315,7 +319,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, ret = -ENOTTY; ret = -ENOTTY; } } unlock_kernel(); mutex_unlock(&minors_lock); return ret; return ret; } } Loading
drivers/hid/usbhid/hid-core.c +23 −1 Original line number Original line Diff line number Diff line Loading @@ -1313,6 +1313,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) { { set_bit(HID_REPORTED_IDLE, &usbhid->iofl); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); spin_unlock_irq(&usbhid->lock); if (hid->driver && hid->driver->suspend) { status = hid->driver->suspend(hid, message); if (status < 0) return status; } } else { } else { usbhid_mark_busy(usbhid); usbhid_mark_busy(usbhid); spin_unlock_irq(&usbhid->lock); spin_unlock_irq(&usbhid->lock); Loading @@ -1320,6 +1325,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) } } } else { } else { if (hid->driver && hid->driver->suspend) { status = hid->driver->suspend(hid, message); if (status < 0) return status; } spin_lock_irq(&usbhid->lock); spin_lock_irq(&usbhid->lock); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); spin_unlock_irq(&usbhid->lock); Loading Loading @@ -1374,6 +1384,11 @@ static int hid_resume(struct usb_interface *intf) hid_io_error(hid); hid_io_error(hid); usbhid_restart_queues(usbhid); usbhid_restart_queues(usbhid); if (status >= 0 && hid->driver && hid->driver->resume) { int ret = hid->driver->resume(hid); if (ret < 0) status = ret; } dev_dbg(&intf->dev, "resume status %d\n", status); dev_dbg(&intf->dev, "resume status %d\n", status); return 0; return 0; } } Loading @@ -1382,9 +1397,16 @@ static int hid_reset_resume(struct usb_interface *intf) { { struct hid_device *hid = usb_get_intfdata(intf); struct hid_device *hid = usb_get_intfdata(intf); struct usbhid_device *usbhid = hid->driver_data; struct usbhid_device *usbhid = hid->driver_data; int status; clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); clear_bit(HID_REPORTED_IDLE, &usbhid->iofl); return hid_post_reset(intf); status = hid_post_reset(intf); if (status >= 0 && hid->driver && hid->driver->reset_resume) { int ret = hid->driver->reset_resume(hid); if (ret < 0) status = ret; } return status; } } #endif /* CONFIG_PM */ #endif /* CONFIG_PM */ Loading
drivers/hid/usbhid/hiddev.c +17 −2 Original line number Original line Diff line number Diff line Loading @@ -267,6 +267,7 @@ static int hiddev_open(struct inode *inode, struct file *file) struct hiddev_list *list; struct hiddev_list *list; int res, i; int res, i; /* See comment in hiddev_connect() for BKL explanation */ lock_kernel(); lock_kernel(); i = iminor(inode) - HIDDEV_MINOR_BASE; i = iminor(inode) - HIDDEV_MINOR_BASE; Loading Loading @@ -894,8 +895,22 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) hiddev->hid = hid; hiddev->hid = hid; hiddev->exist = 1; hiddev->exist = 1; /* when lock_kernel() usage is fixed in usb_open(), /* * we could also fix it here */ * BKL here is used to avoid race after usb_register_dev(). * Once the device node has been created, open() could happen on it. * The code below will then fail, as hiddev_table hasn't been * updated. * * The obvious fix -- introducing mutex to guard hiddev_table[] * doesn't work, as usb_open() and usb_register_dev() both take * minor_rwsem, thus we'll have ABBA deadlock. * * Before BKL pushdown, usb_open() had been acquiring it in right * order, so _open() was safe to use it to protect from this race. * Now the order is different, but AB-BA deadlock still doesn't occur * as BKL is dropped on schedule() (i.e. while sleeping on * minor_rwsem). Fugly. */ lock_kernel(); lock_kernel(); retval = usb_register_dev(usbhid->intf, &hiddev_class); retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { if (retval) { Loading