Commit b9aa527a authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID fixes from Jiri Kosina:

 - regression fix / revert of a commit that intended to reduce probing
   delay by ~50ms, but introduced a race that causes quite a few devices
   not to enumerate, or get stuck on first IRQ

 - buffer overflow fix in hiddev, from Peilin Ye

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  Revert "HID: usbhid: do not sleep when opening device"
  HID: hiddev: Fix slab-out-of-bounds write in hiddev_ioctl_usage()
  HID: quirks: Always poll three more Lenovo PixArt mice
  HID: i2c-hid: Always sleep 60ms after I2C_HID_PWR_ON commands
  HID: macally: Constify macally_id_table
  HID: cougar: Constify cougar_id_table
parents 6a9dc5fd 5b0545dc
...@@ -321,7 +321,7 @@ static const struct kernel_param_ops cougar_g6_is_space_ops = { ...@@ -321,7 +321,7 @@ static const struct kernel_param_ops cougar_g6_is_space_ops = {
}; };
module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644); module_param_cb(g6_is_space, &cougar_g6_is_space_ops, &g6_is_space, 0644);
static struct hid_device_id cougar_id_table[] = { static const struct hid_device_id cougar_id_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) }, USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
......
...@@ -728,6 +728,9 @@ ...@@ -728,6 +728,9 @@
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067 #define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085 #define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d #define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019 0x6019
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E 0x602e
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093 0x6093
#define USB_VENDOR_ID_LG 0x1fd2 #define USB_VENDOR_ID_LG 0x1fd2
#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
......
...@@ -29,7 +29,7 @@ static __u8 *macally_report_fixup(struct hid_device *hdev, __u8 *rdesc, ...@@ -29,7 +29,7 @@ static __u8 *macally_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc; return rdesc;
} }
static struct hid_device_id macally_id_table[] = { static const struct hid_device_id macally_id_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR, { HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
USB_DEVICE_ID_MACALLY_IKEY_KEYBOARD) }, USB_DEVICE_ID_MACALLY_IKEY_KEYBOARD) },
{ } { }
......
...@@ -105,6 +105,9 @@ static const struct hid_device_id hid_quirks[] = { ...@@ -105,6 +105,9 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M406XE), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_PIXART_USB_OPTICAL_MOUSE_ID2), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6019), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_602E), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_6093), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS), HID_QUIRK_NOGET },
......
...@@ -420,6 +420,19 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state) ...@@ -420,6 +420,19 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
dev_err(&client->dev, "failed to change power setting.\n"); dev_err(&client->dev, "failed to change power setting.\n");
set_pwr_exit: set_pwr_exit:
/*
* The HID over I2C specification states that if a DEVICE needs time
* after the PWR_ON request, it should utilise CLOCK stretching.
* However, it has been observered that the Windows driver provides a
* 1ms sleep between the PWR_ON and RESET requests.
* According to Goodix Windows even waits 60 ms after (other?)
* PWR_ON requests. Testing has confirmed that several devices
* will not work properly without a delay after a PWR_ON request.
*/
if (!ret && power_state == I2C_HID_PWR_ON)
msleep(60);
return ret; return ret;
} }
...@@ -441,15 +454,6 @@ static int i2c_hid_hwreset(struct i2c_client *client) ...@@ -441,15 +454,6 @@ static int i2c_hid_hwreset(struct i2c_client *client)
if (ret) if (ret)
goto out_unlock; goto out_unlock;
/*
* The HID over I2C specification states that if a DEVICE needs time
* after the PWR_ON request, it should utilise CLOCK stretching.
* However, it has been observered that the Windows driver provides a
* 1ms sleep between the PWR_ON and RESET requests and that some devices
* rely on this.
*/
usleep_range(1000, 5000);
i2c_hid_dbg(ihid, "resetting...\n"); i2c_hid_dbg(ihid, "resetting...\n");
ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0); ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0);
......
...@@ -26,7 +26,6 @@ ...@@ -26,7 +26,6 @@
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/timekeeping.h>
#include <linux/usb.h> #include <linux/usb.h>
...@@ -96,18 +95,6 @@ static int hid_start_in(struct hid_device *hid) ...@@ -96,18 +95,6 @@ static int hid_start_in(struct hid_device *hid)
set_bit(HID_NO_BANDWIDTH, &usbhid->iofl); set_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
} else { } else {
clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl); clear_bit(HID_NO_BANDWIDTH, &usbhid->iofl);
if (test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
/*
* In case events are generated while nobody was
* listening, some are released when the device
* is re-opened. Wait 50 msec for the queue to
* empty before allowing events to go through
* hid.
*/
usbhid->input_start_time =
ktime_add_ms(ktime_get_coarse(), 50);
}
} }
} }
spin_unlock_irqrestore(&usbhid->lock, flags); spin_unlock_irqrestore(&usbhid->lock, flags);
...@@ -293,23 +280,20 @@ static void hid_irq_in(struct urb *urb) ...@@ -293,23 +280,20 @@ static void hid_irq_in(struct urb *urb)
if (!test_bit(HID_OPENED, &usbhid->iofl)) if (!test_bit(HID_OPENED, &usbhid->iofl))
break; break;
usbhid_mark_busy(usbhid); usbhid_mark_busy(usbhid);
if (test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) { if (!test_bit(HID_RESUME_RUNNING, &usbhid->iofl)) {
if (ktime_before(ktime_get_coarse(), hid_input_report(urb->context, HID_INPUT_REPORT,
usbhid->input_start_time)) urb->transfer_buffer,
break; urb->actual_length, 1);
clear_bit(HID_RESUME_RUNNING, &usbhid->iofl); /*
* autosuspend refused while keys are pressed
* because most keyboards don't wake up when
* a key is released
*/
if (hid_check_keys_pressed(hid))
set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
else
clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
} }
hid_input_report(urb->context, HID_INPUT_REPORT,
urb->transfer_buffer, urb->actual_length, 1);
/*
* autosuspend refused while keys are pressed
* because most keyboards don't wake up when
* a key is released
*/
if (hid_check_keys_pressed(hid))
set_bit(HID_KEYS_PRESSED, &usbhid->iofl);
else
clear_bit(HID_KEYS_PRESSED, &usbhid->iofl);
break; break;
case -EPIPE: /* stall */ case -EPIPE: /* stall */
usbhid_mark_busy(usbhid); usbhid_mark_busy(usbhid);
...@@ -736,6 +720,17 @@ static int usbhid_open(struct hid_device *hid) ...@@ -736,6 +720,17 @@ static int usbhid_open(struct hid_device *hid)
usb_autopm_put_interface(usbhid->intf); usb_autopm_put_interface(usbhid->intf);
/*
* In case events are generated while nobody was listening,
* some are released when the device is re-opened.
* Wait 50 msec for the queue to empty before allowing events
* to go through hid.
*/
if (res == 0)
msleep(50);
clear_bit(HID_RESUME_RUNNING, &usbhid->iofl);
Done: Done:
mutex_unlock(&usbhid->mutex); mutex_unlock(&usbhid->mutex);
return res; return res;
......
...@@ -519,12 +519,16 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd, ...@@ -519,12 +519,16 @@ static noinline int hiddev_ioctl_usage(struct hiddev *hiddev, unsigned int cmd,
switch (cmd) { switch (cmd) {
case HIDIOCGUSAGE: case HIDIOCGUSAGE:
if (uref->usage_index >= field->report_count)
goto inval;
uref->value = field->value[uref->usage_index]; uref->value = field->value[uref->usage_index];
if (copy_to_user(user_arg, uref, sizeof(*uref))) if (copy_to_user(user_arg, uref, sizeof(*uref)))
goto fault; goto fault;
goto goodreturn; goto goodreturn;
case HIDIOCSUSAGE: case HIDIOCSUSAGE:
if (uref->usage_index >= field->report_count)
goto inval;
field->value[uref->usage_index] = uref->value; field->value[uref->usage_index] = uref->value;
goto goodreturn; goto goodreturn;
......
...@@ -13,7 +13,6 @@ ...@@ -13,7 +13,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/ktime.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/timer.h> #include <linux/timer.h>
...@@ -84,7 +83,6 @@ struct usbhid_device { ...@@ -84,7 +83,6 @@ struct usbhid_device {
struct mutex mutex; /* start/stop/open/close */ struct mutex mutex; /* start/stop/open/close */
spinlock_t lock; /* fifo spinlock */ spinlock_t lock; /* fifo spinlock */
unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */
ktime_t input_start_time; /* When to start handling input */
struct timer_list io_retry; /* Retry timer */ struct timer_list io_retry; /* Retry timer */
unsigned long stop_retry; /* Time to give up, in jiffies */ unsigned long stop_retry; /* Time to give up, in jiffies */
unsigned int retry_delay; /* Delay length in ms */ unsigned int retry_delay; /* Delay length in ms */
......
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