Commit 77ede3a0 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID subsystem fixes from Jiri Kosina:

 - buffer management size fix for i2c-hid driver, from Adrian Salido

 - tool ID regression fixes for Wacom driver from Jason Gerecke

 - a few small assorted fixes and a few device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  Revert "HID: multitouch: Support ALPS PTP stick with pid 0x120A"
  HID: hidraw: fix power sequence when closing device
  HID: wacom: Always increment hdev refcount within wacom_get_hdev_data
  HID: wacom: generic: Clear ABS_MISC when tool leaves proximity
  HID: wacom: generic: Send MSC_SERIAL and ABS_MISC when leaving prox
  HID: i2c-hid: allocate hid buffers for real worst case
  HID: rmi: Make sure the HID device is opened on resume
  HID: multitouch: Support ALPS PTP stick with pid 0x120A
  HID: multitouch: support buttons and trackpoint on Lenovo X1 Tab Gen2
  HID: wacom: Correct coordinate system of touchring and pen twist
  HID: wacom: Properly report negative values from Intuos Pro 2 Bluetooth
  HID: multitouch: Fix system-control buttons not working
  HID: add multi-input quirk for IDC6680 touchscreen
  HID: wacom: leds: Don't try to control the EKR's read-only LEDs
  HID: wacom: bits shifted too much for 9th and 10th buttons
parents 9a431ef9 66dcdafe
...@@ -533,6 +533,7 @@ ...@@ -533,6 +533,7 @@
#define USB_VENDOR_ID_IDEACOM 0x1cb6 #define USB_VENDOR_ID_IDEACOM 0x1cb6
#define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650 #define USB_DEVICE_ID_IDEACOM_IDC6650 0x6650
#define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651 #define USB_DEVICE_ID_IDEACOM_IDC6651 0x6651
#define USB_DEVICE_ID_IDEACOM_IDC6680 0x6680
#define USB_VENDOR_ID_ILITEK 0x222a #define USB_VENDOR_ID_ILITEK 0x222a
#define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001 #define USB_DEVICE_ID_ILITEK_MULTITOUCH 0x0001
...@@ -660,6 +661,7 @@ ...@@ -660,6 +661,7 @@
#define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048 #define USB_DEVICE_ID_LENOVO_CBTKBD 0x6048
#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_X1_TAB 0x60a3
#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
......
...@@ -930,6 +930,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -930,6 +930,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
field->application != HID_DG_PEN && field->application != HID_DG_PEN &&
field->application != HID_DG_TOUCHPAD && field->application != HID_DG_TOUCHPAD &&
field->application != HID_GD_KEYBOARD && field->application != HID_GD_KEYBOARD &&
field->application != HID_GD_SYSTEM_CONTROL &&
field->application != HID_CP_CONSUMER_CONTROL && field->application != HID_CP_CONSUMER_CONTROL &&
field->application != HID_GD_WIRELESS_RADIO_CTLS && field->application != HID_GD_WIRELESS_RADIO_CTLS &&
!(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS && !(field->application == HID_VD_ASUS_CUSTOM_MEDIA_KEYS &&
...@@ -1419,6 +1420,12 @@ static const struct hid_device_id mt_devices[] = { ...@@ -1419,6 +1420,12 @@ static const struct hid_device_id mt_devices[] = {
USB_VENDOR_ID_ALPS_JP, USB_VENDOR_ID_ALPS_JP,
HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) }, HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
/* Lenovo X1 TAB Gen 2 */
{ .driver_data = MT_CLS_WIN_8_DUAL,
HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_LENOVO,
USB_DEVICE_ID_LENOVO_X1_TAB) },
/* Anton devices */ /* Anton devices */
{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS, { .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
MT_USB_DEVICE(USB_VENDOR_ID_ANTON, MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
......
...@@ -436,17 +436,24 @@ static int rmi_post_resume(struct hid_device *hdev) ...@@ -436,17 +436,24 @@ static int rmi_post_resume(struct hid_device *hdev)
if (!(data->device_flags & RMI_DEVICE)) if (!(data->device_flags & RMI_DEVICE))
return 0; return 0;
ret = rmi_reset_attn_mode(hdev); /* Make sure the HID device is ready to receive events */
ret = hid_hw_open(hdev);
if (ret) if (ret)
return ret; return ret;
ret = rmi_reset_attn_mode(hdev);
if (ret)
goto out;
ret = rmi_driver_resume(rmi_dev, false); ret = rmi_driver_resume(rmi_dev, false);
if (ret) { if (ret) {
hid_warn(hdev, "Failed to resume device: %d\n", ret); hid_warn(hdev, "Failed to resume device: %d\n", ret);
return ret; goto out;
} }
return 0; out:
hid_hw_close(hdev);
return ret;
} }
#endif /* CONFIG_PM */ #endif /* CONFIG_PM */
......
...@@ -337,8 +337,8 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit) ...@@ -337,8 +337,8 @@ static void drop_ref(struct hidraw *hidraw, int exists_bit)
kfree(hidraw); kfree(hidraw);
} else { } else {
/* close device for last reader */ /* close device for last reader */
hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
hid_hw_close(hidraw->hid); hid_hw_close(hidraw->hid);
hid_hw_power(hidraw->hid, PM_HINT_NORMAL);
} }
} }
} }
......
...@@ -543,7 +543,8 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size) ...@@ -543,7 +543,8 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size)
{ {
/* the worst case is computed from the set_report command with a /* the worst case is computed from the set_report command with a
* reportID > 15 and the maximum report length */ * reportID > 15 and the maximum report length */
int args_len = sizeof(__u8) + /* optional ReportID byte */ int args_len = sizeof(__u8) + /* ReportID */
sizeof(__u8) + /* optional ReportID byte */
sizeof(__u16) + /* data register */ sizeof(__u16) + /* data register */
sizeof(__u16) + /* size of the report */ sizeof(__u16) + /* size of the report */
report_size; /* report */ report_size; /* report */
......
...@@ -99,6 +99,7 @@ static const struct hid_blacklist { ...@@ -99,6 +99,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0A4A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C007, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_C077, HID_QUIRK_ALWAYS_POLL },
{ USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET }, { USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_KEYBOARD_G710_PLUS, HID_QUIRK_NOGET },
......
...@@ -668,9 +668,11 @@ static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev) ...@@ -668,9 +668,11 @@ static struct wacom_hdev_data *wacom_get_hdev_data(struct hid_device *hdev)
/* Try to find an already-probed interface from the same device */ /* Try to find an already-probed interface from the same device */
list_for_each_entry(data, &wacom_udev_list, list) { list_for_each_entry(data, &wacom_udev_list, list) {
if (compare_device_paths(hdev, data->dev, '/')) if (compare_device_paths(hdev, data->dev, '/')) {
kref_get(&data->kref);
return data; return data;
} }
}
/* Fallback to finding devices that appear to be "siblings" */ /* Fallback to finding devices that appear to be "siblings" */
list_for_each_entry(data, &wacom_udev_list, list) { list_for_each_entry(data, &wacom_udev_list, list) {
...@@ -766,6 +768,9 @@ static int wacom_led_control(struct wacom *wacom) ...@@ -766,6 +768,9 @@ static int wacom_led_control(struct wacom *wacom)
if (!wacom->led.groups) if (!wacom->led.groups)
return -ENOTSUPP; return -ENOTSUPP;
if (wacom->wacom_wac.features.type == REMOTE)
return -ENOTSUPP;
if (wacom->wacom_wac.pid) { /* wireless connected */ if (wacom->wacom_wac.pid) { /* wireless connected */
report_id = WAC_CMD_WL_LED_CONTROL; report_id = WAC_CMD_WL_LED_CONTROL;
buf_size = 13; buf_size = 13;
......
...@@ -567,8 +567,8 @@ static int wacom_intuos_pad(struct wacom_wac *wacom) ...@@ -567,8 +567,8 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
keys = data[9] & 0x07; keys = data[9] & 0x07;
} }
} else { } else {
buttons = ((data[6] & 0x10) << 10) | buttons = ((data[6] & 0x10) << 5) |
((data[5] & 0x10) << 9) | ((data[5] & 0x10) << 4) |
((data[6] & 0x0F) << 4) | ((data[6] & 0x0F) << 4) |
(data[5] & 0x0F); (data[5] & 0x0F);
} }
...@@ -1227,11 +1227,17 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom) ...@@ -1227,11 +1227,17 @@ static void wacom_intuos_pro2_bt_pen(struct wacom_wac *wacom)
continue; continue;
if (range) { if (range) {
/* Fix rotation alignment: userspace expects zero at left */
int16_t rotation = (int16_t)get_unaligned_le16(&frame[9]);
rotation += 1800/4;
if (rotation > 899)
rotation -= 1800;
input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1])); input_report_abs(pen_input, ABS_X, get_unaligned_le16(&frame[1]));
input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3])); input_report_abs(pen_input, ABS_Y, get_unaligned_le16(&frame[3]));
input_report_abs(pen_input, ABS_TILT_X, frame[7]); input_report_abs(pen_input, ABS_TILT_X, (char)frame[7]);
input_report_abs(pen_input, ABS_TILT_Y, frame[8]); input_report_abs(pen_input, ABS_TILT_Y, (char)frame[8]);
input_report_abs(pen_input, ABS_Z, get_unaligned_le16(&frame[9])); input_report_abs(pen_input, ABS_Z, rotation);
input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11])); input_report_abs(pen_input, ABS_WHEEL, get_unaligned_le16(&frame[11]));
} }
input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5])); input_report_abs(pen_input, ABS_PRESSURE, get_unaligned_le16(&frame[5]));
...@@ -1319,12 +1325,19 @@ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom) ...@@ -1319,12 +1325,19 @@ static void wacom_intuos_pro2_bt_pad(struct wacom_wac *wacom)
unsigned char *data = wacom->data; unsigned char *data = wacom->data;
int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01); int buttons = (data[282] << 1) | ((data[281] >> 6) & 0x01);
int ring = data[285]; int ring = data[285] & 0x7F;
int prox = buttons | (ring & 0x80); bool ringstatus = data[285] & 0x80;
bool prox = buttons || ringstatus;
/* Fix touchring data: userspace expects 0 at left and increasing clockwise */
ring = 71 - ring;
ring += 3*72/16;
if (ring > 71)
ring -= 72;
wacom_report_numbered_buttons(pad_input, 9, buttons); wacom_report_numbered_buttons(pad_input, 9, buttons);
input_report_abs(pad_input, ABS_WHEEL, (ring & 0x80) ? (ring & 0x7f) : 0); input_report_abs(pad_input, ABS_WHEEL, ringstatus ? ring : 0);
input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0); input_report_key(pad_input, wacom->tool[1], prox ? 1 : 0);
input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0); input_report_abs(pad_input, ABS_MISC, prox ? PAD_DEVICE_ID : 0);
...@@ -1616,6 +1629,20 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len) ...@@ -1616,6 +1629,20 @@ static int wacom_tpc_irq(struct wacom_wac *wacom, size_t len)
return 0; return 0;
} }
static int wacom_offset_rotation(struct input_dev *input, struct hid_usage *usage,
int value, int num, int denom)
{
struct input_absinfo *abs = &input->absinfo[usage->code];
int range = (abs->maximum - abs->minimum + 1);
value += num*range/denom;
if (value > abs->maximum)
value -= range;
else if (value < abs->minimum)
value += range;
return value;
}
int wacom_equivalent_usage(int usage) int wacom_equivalent_usage(int usage)
{ {
if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) { if ((usage & HID_USAGE_PAGE) == WACOM_HID_UP_WACOMDIGITIZER) {
...@@ -1898,6 +1925,7 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field ...@@ -1898,6 +1925,7 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
unsigned equivalent_usage = wacom_equivalent_usage(usage->hid); unsigned equivalent_usage = wacom_equivalent_usage(usage->hid);
int i; int i;
bool is_touch_on = value; bool is_touch_on = value;
bool do_report = false;
/* /*
* Avoid reporting this event and setting inrange_state if this usage * Avoid reporting this event and setting inrange_state if this usage
...@@ -1912,6 +1940,29 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field ...@@ -1912,6 +1940,29 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
} }
switch (equivalent_usage) { switch (equivalent_usage) {
case WACOM_HID_WD_TOUCHRING:
/*
* Userspace expects touchrings to increase in value with
* clockwise gestures and have their zero point at the
* tablet's left. HID events "should" be clockwise-
* increasing and zero at top, though the MobileStudio
* Pro and 2nd-gen Intuos Pro don't do this...
*/
if (hdev->vendor == 0x56a &&
(hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */
hdev->product == 0x357 || hdev->product == 0x358)) { /* Intuos Pro 2 */
value = (field->logical_maximum - value);
if (hdev->product == 0x357 || hdev->product == 0x358)
value = wacom_offset_rotation(input, usage, value, 3, 16);
else if (hdev->product == 0x34d || hdev->product == 0x34e)
value = wacom_offset_rotation(input, usage, value, 1, 2);
}
else {
value = wacom_offset_rotation(input, usage, value, 1, 4);
}
do_report = true;
break;
case WACOM_HID_WD_TOUCHRINGSTATUS: case WACOM_HID_WD_TOUCHRINGSTATUS:
if (!value) if (!value)
input_event(input, usage->type, usage->code, 0); input_event(input, usage->type, usage->code, 0);
...@@ -1945,10 +1996,14 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field ...@@ -1945,10 +1996,14 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
value, i); value, i);
/* fall through*/ /* fall through*/
default: default:
do_report = true;
break;
}
if (do_report) {
input_event(input, usage->type, usage->code, value); input_event(input, usage->type, usage->code, value);
if (value) if (value)
wacom_wac->hid_data.pad_input_event_flag = true; wacom_wac->hid_data.pad_input_event_flag = true;
break;
} }
} }
...@@ -2086,13 +2141,24 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field ...@@ -2086,13 +2141,24 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
wacom_wac->hid_data.tipswitch |= value; wacom_wac->hid_data.tipswitch |= value;
return; return;
case HID_DG_TOOLSERIALNUMBER: case HID_DG_TOOLSERIALNUMBER:
if (value) {
wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL); wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL);
wacom_wac->serial[0] |= (__u32)value; wacom_wac->serial[0] |= (__u32)value;
}
return; return;
case HID_DG_TWIST:
/*
* Userspace expects pen twist to have its zero point when
* the buttons/finger is on the tablet's left. HID values
* are zero when buttons are toward the top.
*/
value = wacom_offset_rotation(input, usage, value, 1, 4);
break;
case WACOM_HID_WD_SENSE: case WACOM_HID_WD_SENSE:
wacom_wac->hid_data.sense_state = value; wacom_wac->hid_data.sense_state = value;
return; return;
case WACOM_HID_WD_SERIALHI: case WACOM_HID_WD_SERIALHI:
if (value) {
wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF); wacom_wac->serial[0] = (wacom_wac->serial[0] & 0xFFFFFFFF);
wacom_wac->serial[0] |= ((__u64)value) << 32; wacom_wac->serial[0] |= ((__u64)value) << 32;
/* /*
...@@ -2103,6 +2169,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field ...@@ -2103,6 +2169,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field
if (value >> 20 == 1) { if (value >> 20 == 1) {
wacom_wac->id[0] |= value & 0xFFFFF; wacom_wac->id[0] |= value & 0xFFFFF;
} }
}
return; return;
case WACOM_HID_WD_TOOLTYPE: case WACOM_HID_WD_TOOLTYPE:
/* /*
...@@ -2205,7 +2272,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev, ...@@ -2205,7 +2272,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
input_report_key(input, wacom_wac->tool[0], prox); input_report_key(input, wacom_wac->tool[0], prox);
if (wacom_wac->serial[0]) { if (wacom_wac->serial[0]) {
input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]); input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]);
input_report_abs(input, ABS_MISC, id); input_report_abs(input, ABS_MISC, prox ? id : 0);
} }
wacom_wac->hid_data.tipswitch = false; wacom_wac->hid_data.tipswitch = false;
...@@ -2216,6 +2283,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev, ...@@ -2216,6 +2283,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev,
if (!prox) { if (!prox) {
wacom_wac->tool[0] = 0; wacom_wac->tool[0] = 0;
wacom_wac->id[0] = 0; wacom_wac->id[0] = 0;
wacom_wac->serial[0] = 0;
} }
} }
......
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