Loading drivers/hid/hid-core.c +8 −15 Original line number 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); if (!buf) { report = hid_get_report(report_enum, data); if (!buf) 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 */ 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); for (i = 0; i < size; i++) { snprintf(buf, HID_DEBUG_BUFSIZE - 1, " %02x", data[i]); hid_debug_event(hid, buf); } hid_debug_event(hid, "\n"); kfree(buf); nomem: report = hid_get_report(report_enum, data); if (!report) return -1; if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { ret = hdrv->raw_event(hid, report, data, size); if (ret != 0) Loading drivers/hid/hid-magicmouse.c +4 −1 Original line number Diff line number Diff line Loading @@ -354,12 +354,15 @@ static int magicmouse_probe(struct hid_device *hdev, goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT); ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { dev_err(&hdev->dev, "magicmouse hw start failed\n"); goto err_free; } /* we are handling the input ourselves */ hidinput_disconnect(hdev); report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); if (!report) { dev_err(&hdev->dev, "unable to register touch report\n"); Loading drivers/hid/hidraw.c +26 −22 Original line number Diff line number Diff line Loading @@ -106,38 +106,48 @@ out: 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); /* FIXME: What stops hidraw_table going NULL */ struct hid_device *dev = hidraw_table[minor]->hid; struct hid_device *dev; __u8 *buf; int ret = 0; if (!dev->hid_output_raw_report) return -ENODEV; mutex_lock(&minors_lock); dev = hidraw_table[minor]->hid; if (!dev->hid_output_raw_report) { ret = -ENODEV; goto out; } if (count > HID_MAX_BUFFER_SIZE) { printk(KERN_WARNING "hidraw: pid %d passed too large report\n", task_pid_nr(current)); return -EINVAL; ret = -EINVAL; goto out; } if (count < 2) { printk(KERN_WARNING "hidraw: pid %d passed too short report\n", task_pid_nr(current)); return -EINVAL; ret = -EINVAL; goto out; } buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); if (!buf) return -ENOMEM; if (!buf) { ret = -ENOMEM; goto out; } if (copy_from_user(buf, buffer, count)) { ret = -EFAULT; goto out; goto out_free; } ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); out: out_free: kfree(buf); out: mutex_unlock(&minors_lock); return ret; } Loading Loading @@ -165,11 +175,8 @@ static int hidraw_open(struct inode *inode, struct file *file) goto out; } lock_kernel(); mutex_lock(&minors_lock); if (!hidraw_table[minor]) { printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", minor); kfree(list); err = -ENODEV; goto out_unlock; Loading Loading @@ -197,7 +204,6 @@ static int hidraw_open(struct inode *inode, struct file *file) out_unlock: mutex_unlock(&minors_lock); unlock_kernel(); out: return err; Loading @@ -209,11 +215,8 @@ static int hidraw_release(struct inode * inode, struct file * file) struct hidraw *dev; struct hidraw_list *list = file->private_data; if (!hidraw_table[minor]) { printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", minor); if (!hidraw_table[minor]) return -ENODEV; } list_del(&list->node); 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; unsigned int minor = iminor(inode); long ret = 0; /* FIXME: What stops hidraw_table going NULL */ struct hidraw *dev = hidraw_table[minor]; struct hidraw *dev; void __user *user_arg = (void __user*) arg; lock_kernel(); mutex_lock(&minors_lock); dev = hidraw_table[minor]; switch (cmd) { case HIDIOCGRDESCSIZE: 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; } unlock_kernel(); mutex_unlock(&minors_lock); return ret; } Loading drivers/hid/usbhid/hid-core.c +23 −1 Original line number 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); spin_unlock_irq(&usbhid->lock); if (hid->driver && hid->driver->suspend) { status = hid->driver->suspend(hid, message); if (status < 0) return status; } } else { usbhid_mark_busy(usbhid); spin_unlock_irq(&usbhid->lock); Loading @@ -1320,6 +1325,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) } } else { if (hid->driver && hid->driver->suspend) { status = hid->driver->suspend(hid, message); if (status < 0) return status; } spin_lock_irq(&usbhid->lock); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); Loading Loading @@ -1374,6 +1384,11 @@ static int hid_resume(struct usb_interface *intf) hid_io_error(hid); 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); 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 usbhid_device *usbhid = hid->driver_data; int status; 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 */ Loading drivers/hid/usbhid/hiddev.c +17 −2 Original line number Diff line number Diff line Loading @@ -267,6 +267,7 @@ static int hiddev_open(struct inode *inode, struct file *file) struct hiddev_list *list; int res, i; /* See comment in hiddev_connect() for BKL explanation */ lock_kernel(); 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->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(); retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { Loading Loading
drivers/hid/hid-core.c +8 −15 Original line number 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); if (!buf) { report = hid_get_report(report_enum, data); if (!buf) 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 */ 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); for (i = 0; i < size; i++) { snprintf(buf, HID_DEBUG_BUFSIZE - 1, " %02x", data[i]); hid_debug_event(hid, buf); } hid_debug_event(hid, "\n"); kfree(buf); nomem: report = hid_get_report(report_enum, data); if (!report) return -1; if (hdrv && hdrv->raw_event && hid_match_report(hid, report)) { ret = hdrv->raw_event(hid, report, data, size); if (ret != 0) Loading
drivers/hid/hid-magicmouse.c +4 −1 Original line number Diff line number Diff line Loading @@ -354,12 +354,15 @@ static int magicmouse_probe(struct hid_device *hdev, goto err_free; } ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_HIDINPUT); ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { dev_err(&hdev->dev, "magicmouse hw start failed\n"); goto err_free; } /* we are handling the input ourselves */ hidinput_disconnect(hdev); report = hid_register_report(hdev, HID_INPUT_REPORT, TOUCH_REPORT_ID); if (!report) { dev_err(&hdev->dev, "unable to register touch report\n"); Loading
drivers/hid/hidraw.c +26 −22 Original line number Diff line number Diff line Loading @@ -106,38 +106,48 @@ out: 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); /* FIXME: What stops hidraw_table going NULL */ struct hid_device *dev = hidraw_table[minor]->hid; struct hid_device *dev; __u8 *buf; int ret = 0; if (!dev->hid_output_raw_report) return -ENODEV; mutex_lock(&minors_lock); dev = hidraw_table[minor]->hid; if (!dev->hid_output_raw_report) { ret = -ENODEV; goto out; } if (count > HID_MAX_BUFFER_SIZE) { printk(KERN_WARNING "hidraw: pid %d passed too large report\n", task_pid_nr(current)); return -EINVAL; ret = -EINVAL; goto out; } if (count < 2) { printk(KERN_WARNING "hidraw: pid %d passed too short report\n", task_pid_nr(current)); return -EINVAL; ret = -EINVAL; goto out; } buf = kmalloc(count * sizeof(__u8), GFP_KERNEL); if (!buf) return -ENOMEM; if (!buf) { ret = -ENOMEM; goto out; } if (copy_from_user(buf, buffer, count)) { ret = -EFAULT; goto out; goto out_free; } ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT); out: out_free: kfree(buf); out: mutex_unlock(&minors_lock); return ret; } Loading Loading @@ -165,11 +175,8 @@ static int hidraw_open(struct inode *inode, struct file *file) goto out; } lock_kernel(); mutex_lock(&minors_lock); if (!hidraw_table[minor]) { printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", minor); kfree(list); err = -ENODEV; goto out_unlock; Loading Loading @@ -197,7 +204,6 @@ static int hidraw_open(struct inode *inode, struct file *file) out_unlock: mutex_unlock(&minors_lock); unlock_kernel(); out: return err; Loading @@ -209,11 +215,8 @@ static int hidraw_release(struct inode * inode, struct file * file) struct hidraw *dev; struct hidraw_list *list = file->private_data; if (!hidraw_table[minor]) { printk(KERN_EMERG "hidraw device with minor %d doesn't exist\n", minor); if (!hidraw_table[minor]) return -ENODEV; } list_del(&list->node); 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; unsigned int minor = iminor(inode); long ret = 0; /* FIXME: What stops hidraw_table going NULL */ struct hidraw *dev = hidraw_table[minor]; struct hidraw *dev; void __user *user_arg = (void __user*) arg; lock_kernel(); mutex_lock(&minors_lock); dev = hidraw_table[minor]; switch (cmd) { case HIDIOCGRDESCSIZE: 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; } unlock_kernel(); mutex_unlock(&minors_lock); return ret; } Loading
drivers/hid/usbhid/hid-core.c +23 −1 Original line number 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); spin_unlock_irq(&usbhid->lock); if (hid->driver && hid->driver->suspend) { status = hid->driver->suspend(hid, message); if (status < 0) return status; } } else { usbhid_mark_busy(usbhid); spin_unlock_irq(&usbhid->lock); Loading @@ -1320,6 +1325,11 @@ static int hid_suspend(struct usb_interface *intf, pm_message_t message) } } else { if (hid->driver && hid->driver->suspend) { status = hid->driver->suspend(hid, message); if (status < 0) return status; } spin_lock_irq(&usbhid->lock); set_bit(HID_REPORTED_IDLE, &usbhid->iofl); spin_unlock_irq(&usbhid->lock); Loading Loading @@ -1374,6 +1384,11 @@ static int hid_resume(struct usb_interface *intf) hid_io_error(hid); 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); 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 usbhid_device *usbhid = hid->driver_data; int status; 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 */ Loading
drivers/hid/usbhid/hiddev.c +17 −2 Original line number Diff line number Diff line Loading @@ -267,6 +267,7 @@ static int hiddev_open(struct inode *inode, struct file *file) struct hiddev_list *list; int res, i; /* See comment in hiddev_connect() for BKL explanation */ lock_kernel(); 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->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(); retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { Loading