Commit d9cbf022 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid:
  Revert "HID: magicmouse: ignore 'ivalid report id' while switching modes"
  HID: hid-multitouch: fix broken eGalax
  HID: MAINTAINERS: Update USB HID/HIDBP DRIVERS pattern
  HID: hid-multitouch: add support for Chunghwa multi-touch panel
  HID: hiddev: fix use after free in hiddev_release
  HID: add quirk for HyperPen 10000U
  HID: hiddev: fix potential use-after-free
parents 08356193 c3a49245
...@@ -6463,7 +6463,7 @@ M: Jiri Kosina <jkosina@suse.cz> ...@@ -6463,7 +6463,7 @@ M: Jiri Kosina <jkosina@suse.cz>
L: linux-usb@vger.kernel.org L: linux-usb@vger.kernel.org
T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid.git
S: Maintained S: Maintained
F: Documentation/usb/hiddev.txt F: Documentation/hid/hiddev.txt
F: drivers/hid/usbhid/ F: drivers/hid/usbhid/
USB ISP116X DRIVER USB ISP116X DRIVER
......
...@@ -305,6 +305,7 @@ config HID_MULTITOUCH ...@@ -305,6 +305,7 @@ config HID_MULTITOUCH
- 3M PCT touch screens - 3M PCT touch screens
- ActionStar dual touch panels - ActionStar dual touch panels
- Cando dual touch panels - Cando dual touch panels
- Chunghwa panels
- CVTouch panels - CVTouch panels
- Cypress TrueTouch panels - Cypress TrueTouch panels
- Elo TouchSystems IntelliTouch Plus panels - Elo TouchSystems IntelliTouch Plus panels
......
...@@ -1359,6 +1359,7 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -1359,6 +1359,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) }, { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT, USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) }, { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, { HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) }, { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
......
...@@ -173,6 +173,9 @@ ...@@ -173,6 +173,9 @@
#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d #define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618 #define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
#define USB_VENDOR_ID_CHUNGHWAT 0x2247
#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001
#define USB_VENDOR_ID_CIDC 0x1677 #define USB_VENDOR_ID_CIDC 0x1677
#define USB_VENDOR_ID_CMEDIA 0x0d8c #define USB_VENDOR_ID_CMEDIA 0x0d8c
...@@ -622,6 +625,7 @@ ...@@ -622,6 +625,7 @@
#define USB_VENDOR_ID_UCLOGIC 0x5543 #define USB_VENDOR_ID_UCLOGIC 0x5543
#define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042
#define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001 #define USB_DEVICE_ID_UCLOGIC_TABLET_KNA5 0x6001
#define USB_DEVICE_ID_UCLOGIC_TABLET_TWA60 0x0064
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U 0x0003
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U 0x0004
#define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005 #define USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U 0x0005
......
...@@ -501,17 +501,9 @@ static int magicmouse_probe(struct hid_device *hdev, ...@@ -501,17 +501,9 @@ static int magicmouse_probe(struct hid_device *hdev,
} }
report->size = 6; report->size = 6;
/*
* The device reponds with 'invalid report id' when feature
* report switching it into multitouch mode is sent to it.
*
* This results in -EIO from the _raw low-level transport callback,
* but there seems to be no other way of switching the mode.
* Thus the super-ugly hacky success check below.
*/
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature), ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT); HID_FEATURE_REPORT);
if (ret != -EIO) { if (ret != sizeof(feature)) {
hid_err(hdev, "unable to request touch data (%d)\n", ret); hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw; goto err_stop_hw;
} }
......
...@@ -64,6 +64,7 @@ struct mt_device { ...@@ -64,6 +64,7 @@ struct mt_device {
struct mt_class *mtclass; /* our mt device class */ struct mt_class *mtclass; /* our mt device class */
unsigned last_field_index; /* last field index of the report */ unsigned last_field_index; /* last field index of the report */
unsigned last_slot_field; /* the last field of a slot */ unsigned last_slot_field; /* the last field of a slot */
int last_mt_collection; /* last known mt-related collection */
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */ __s8 inputmode; /* InputMode HID feature, -1 if non-existent */
__u8 num_received; /* how many contacts we received */ __u8 num_received; /* how many contacts we received */
__u8 num_expected; /* expected last contact index */ __u8 num_expected; /* expected last contact index */
...@@ -225,8 +226,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -225,8 +226,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_move); cls->sn_move);
/* touchscreen emulation */ /* touchscreen emulation */
set_abs(hi->input, ABS_X, field, cls->sn_move); set_abs(hi->input, ABS_X, field, cls->sn_move);
if (td->last_mt_collection == usage->collection_index) {
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
}
return 1; return 1;
case HID_GD_Y: case HID_GD_Y:
if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
...@@ -237,8 +240,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -237,8 +240,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_move); cls->sn_move);
/* touchscreen emulation */ /* touchscreen emulation */
set_abs(hi->input, ABS_Y, field, cls->sn_move); set_abs(hi->input, ABS_Y, field, cls->sn_move);
if (td->last_mt_collection == usage->collection_index) {
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
}
return 1; return 1;
} }
return 0; return 0;
...@@ -246,31 +251,40 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -246,31 +251,40 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER: case HID_UP_DIGITIZER:
switch (usage->hid) { switch (usage->hid) {
case HID_DG_INRANGE: case HID_DG_INRANGE:
if (td->last_mt_collection == usage->collection_index) {
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
}
return 1; return 1;
case HID_DG_CONFIDENCE: case HID_DG_CONFIDENCE:
if (td->last_mt_collection == usage->collection_index) {
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
}
return 1; return 1;
case HID_DG_TIPSWITCH: case HID_DG_TIPSWITCH:
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
if (td->last_mt_collection == usage->collection_index) {
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
}
return 1; return 1;
case HID_DG_CONTACTID: case HID_DG_CONTACTID:
input_mt_init_slots(hi->input, td->maxcontacts); input_mt_init_slots(hi->input, td->maxcontacts);
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
td->last_mt_collection = usage->collection_index;
return 1; return 1;
case HID_DG_WIDTH: case HID_DG_WIDTH:
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TOUCH_MAJOR); EV_ABS, ABS_MT_TOUCH_MAJOR);
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width); cls->sn_width);
if (td->last_mt_collection == usage->collection_index) {
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
}
return 1; return 1;
case HID_DG_HEIGHT: case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max, hid_map_usage(hi, usage, bit, max,
...@@ -279,8 +293,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -279,8 +293,10 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_height); cls->sn_height);
input_set_abs_params(hi->input, input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0); ABS_MT_ORIENTATION, 0, 1, 0, 0);
if (td->last_mt_collection == usage->collection_index) {
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
}
return 1; return 1;
case HID_DG_TIPPRESSURE: case HID_DG_TIPPRESSURE:
if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
...@@ -292,15 +308,19 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -292,15 +308,19 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* touchscreen emulation */ /* touchscreen emulation */
set_abs(hi->input, ABS_PRESSURE, field, set_abs(hi->input, ABS_PRESSURE, field,
cls->sn_pressure); cls->sn_pressure);
if (td->last_mt_collection == usage->collection_index) {
td->last_slot_field = usage->hid; td->last_slot_field = usage->hid;
td->last_field_index = field->index; td->last_field_index = field->index;
}
return 1; return 1;
case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTCOUNT:
if (td->last_mt_collection == usage->collection_index)
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_CONTACTMAX: case HID_DG_CONTACTMAX:
/* we don't set td->last_slot_field as contactcount and /* we don't set td->last_slot_field as contactcount and
* contact max are global to the report */ * contact max are global to the report */
if (td->last_mt_collection == usage->collection_index)
td->last_field_index = field->index; td->last_field_index = field->index;
return -1; return -1;
} }
...@@ -516,6 +536,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -516,6 +536,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
} }
td->mtclass = mtclass; td->mtclass = mtclass;
td->inputmode = -1; td->inputmode = -1;
td->last_mt_collection = -1;
hid_set_drvdata(hdev, td); hid_set_drvdata(hdev, td);
ret = hid_parse(hdev); ret = hid_parse(hdev);
...@@ -593,6 +614,11 @@ static const struct hid_device_id mt_devices[] = { ...@@ -593,6 +614,11 @@ static const struct hid_device_id mt_devices[] = {
HID_USB_DEVICE(USB_VENDOR_ID_CANDO, HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
/* Chunghwa Telecom touch panels */
{ .driver_data = MT_CLS_DEFAULT,
HID_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
/* CVTouch panels */ /* CVTouch panels */
{ .driver_data = MT_CLS_DEFAULT, { .driver_data = MT_CLS_DEFAULT,
HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, HID_USB_DEVICE(USB_VENDOR_ID_CVTOUCH,
......
...@@ -74,6 +74,7 @@ static const struct hid_blacklist { ...@@ -74,6 +74,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WALTOP, USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH, HID_QUIRK_MULTI_INPUT },
......
...@@ -248,12 +248,15 @@ static int hiddev_release(struct inode * inode, struct file * file) ...@@ -248,12 +248,15 @@ static int hiddev_release(struct inode * inode, struct file * file)
usbhid_close(list->hiddev->hid); usbhid_close(list->hiddev->hid);
usbhid_put_power(list->hiddev->hid); usbhid_put_power(list->hiddev->hid);
} else { } else {
mutex_unlock(&list->hiddev->existancelock);
kfree(list->hiddev); kfree(list->hiddev);
kfree(list);
return 0;
} }
} }
kfree(list);
mutex_unlock(&list->hiddev->existancelock); mutex_unlock(&list->hiddev->existancelock);
kfree(list);
return 0; return 0;
} }
...@@ -923,10 +926,11 @@ void hiddev_disconnect(struct hid_device *hid) ...@@ -923,10 +926,11 @@ void hiddev_disconnect(struct hid_device *hid)
usb_deregister_dev(usbhid->intf, &hiddev_class); usb_deregister_dev(usbhid->intf, &hiddev_class);
if (hiddev->open) { if (hiddev->open) {
mutex_unlock(&hiddev->existancelock);
usbhid_close(hiddev->hid); usbhid_close(hiddev->hid);
wake_up_interruptible(&hiddev->wait); wake_up_interruptible(&hiddev->wait);
} else { } else {
mutex_unlock(&hiddev->existancelock);
kfree(hiddev); kfree(hiddev);
} }
mutex_unlock(&hiddev->existancelock);
} }
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