From 0fa9c61618fe996c153d186e4087a61ca4e7b2ed Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 28 Feb 2014 11:41:23 -0500 Subject: HID: multitouch: remove registered devices with default behavior The default multitouch protocol class in use since the kernel v3.9 is working quite well. Since its inclusion, the only devices we had to tweak were those who really need quirks (GeneralTouch, FocalTech and Wistron, the 3 of them are Win 7 certified ones). The flow of new unhandled devices has stopped, which is great and I think it's time to reduce the list of registered device. This commit removes only the registration in the kernel of devices that use the class MT_CLS_DEFAULT, or that can use it. By that, I mean that I checked all the recordings I have, and the produced input device and events are the same before and after applying the patch. This gives two benefits: - remove a bunch of lines of codes - prevent bad handling of existing registered devices which are using a different protocol while using the same VID/PID (I got the case of a Quanta 3008 recently). I also removed the associated classes (MT_CLS*). I kept their #define in case people use the new_id sysfs node with a non standard class (their should be really few people now, but we never now). This is why there are /* reserved .... */. Last, I add a comment on top of mt_devices[] definition to remember people (and myself) not to include devices for the beauty of it. To people still trying to add devices with the default class: """ Guys, try out your device under a kernel greater or equal to v3.9. If it works, you are all set. Adding your VID/PID to the kernel only brings us overload and you won't get anything from it _because_ even a backport of this shiny patch will _not_ make the device work under 3.0, 3.2, 3.4 or even 3.8. So if it works, it works. If it does not work, then yes, submit a patch or call for help. In any cases, if you want me to do regression tests, I'd be happy to get some traces of your device. But I won't patch the kernel if it works. """ Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index f134d73..3e81f4e 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -128,16 +128,16 @@ static void mt_post_parse(struct mt_device *td); #define MT_CLS_CONFIDENCE_MINUS_ONE 0x0005 #define MT_CLS_DUAL_INRANGE_CONTACTID 0x0006 #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 0x0007 -#define MT_CLS_DUAL_NSMU_CONTACTID 0x0008 +/* reserved 0x0008 */ #define MT_CLS_INRANGE_CONTACTNUMBER 0x0009 #define MT_CLS_NSMU 0x000a -#define MT_CLS_DUAL_CONTACT_NUMBER 0x0010 -#define MT_CLS_DUAL_CONTACT_ID 0x0011 +/* reserved 0x0010 */ +/* reserved 0x0011 */ #define MT_CLS_WIN_8 0x0012 /* vendor specific classes */ #define MT_CLS_3M 0x0101 -#define MT_CLS_CYPRESS 0x0102 +/* reserved 0x0102 */ #define MT_CLS_EGALAX 0x0103 #define MT_CLS_EGALAX_SERIAL 0x0104 #define MT_CLS_TOPSEED 0x0105 @@ -189,23 +189,9 @@ static struct mt_class mt_classes[] = { .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTNUMBER, .maxcontacts = 2 }, - { .name = MT_CLS_DUAL_NSMU_CONTACTID, - .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | - MT_QUIRK_SLOT_IS_CONTACTID, - .maxcontacts = 2 }, { .name = MT_CLS_INRANGE_CONTACTNUMBER, .quirks = MT_QUIRK_VALID_IS_INRANGE | MT_QUIRK_SLOT_IS_CONTACTNUMBER }, - { .name = MT_CLS_DUAL_CONTACT_NUMBER, - .quirks = MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_SLOT_IS_CONTACTNUMBER, - .maxcontacts = 2 }, - { .name = MT_CLS_DUAL_CONTACT_ID, - .quirks = MT_QUIRK_ALWAYS_VALID | - MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_SLOT_IS_CONTACTID, - .maxcontacts = 2 }, { .name = MT_CLS_WIN_8, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | @@ -223,10 +209,6 @@ static struct mt_class mt_classes[] = { .sn_height = 128, .maxcontacts = 60, }, - { .name = MT_CLS_CYPRESS, - .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | - MT_QUIRK_CYPRESS, - .maxcontacts = 10 }, { .name = MT_CLS_EGALAX, .quirks = MT_QUIRK_SLOT_IS_CONTACTID | MT_QUIRK_VALID_IS_INRANGE, @@ -1034,6 +1016,12 @@ static void mt_remove(struct hid_device *hdev) hid_hw_stop(hdev); } +/* + * This list contains only: + * - VID/PID of products not working with the default multitouch handling + * - 2 generic rules. + * So there is no point in adding here any device with MT_CLS_DEFAULT. + */ static const struct hid_device_id mt_devices[] = { /* 3M panels */ @@ -1047,33 +1035,20 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M3266) }, - /* ActionStar panels */ - { .driver_data = MT_CLS_NSMU, - MT_USB_DEVICE(USB_VENDOR_ID_ACTIONSTAR, - USB_DEVICE_ID_ACTIONSTAR_1011) }, - /* Atmel panels */ { .driver_data = MT_CLS_SERIAL, MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, - USB_DEVICE_ID_ATMEL_MULTITOUCH) }, - { .driver_data = MT_CLS_SERIAL, - MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, USB_DEVICE_ID_ATMEL_MXT_DIGITIZER) }, /* Baanto multitouch devices */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_BAANTO, USB_DEVICE_ID_BAANTO_MT_190W2) }, + /* Cando panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) }, - { .driver_data = MT_CLS_DUAL_CONTACT_NUMBER, - MT_USB_DEVICE(USB_VENDOR_ID_CANDO, - USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) }, - { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, - MT_USB_DEVICE(USB_VENDOR_ID_CANDO, - USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) }, { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) }, @@ -1088,16 +1063,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_CVTOUCH, USB_DEVICE_ID_CVTOUCH_SCREEN) }, - /* Cypress panel */ - { .driver_data = MT_CLS_CYPRESS, - HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, - USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, - - /* Data Modul easyMaxTouch */ - { .driver_data = MT_CLS_DEFAULT, - MT_USB_DEVICE(USB_VENDOR_ID_DATA_MODUL, - USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH) }, - /* eGalax devices (resistive) */ { .driver_data = MT_CLS_EGALAX, MT_USB_DEVICE(USB_VENDOR_ID_DWAV, @@ -1156,11 +1121,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001) }, - /* Elo TouchSystems IntelliTouch Plus panel */ - { .driver_data = MT_CLS_DUAL_CONTACT_ID, - MT_USB_DEVICE(USB_VENDOR_ID_ELO, - USB_DEVICE_ID_ELO_TS2515) }, - /* Flatfrog Panels */ { .driver_data = MT_CLS_FLATFROG, MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, @@ -1204,37 +1164,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, - /* Ideacom panel */ - { .driver_data = MT_CLS_SERIAL, - MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM, - USB_DEVICE_ID_IDEACOM_IDC6650) }, - { .driver_data = MT_CLS_SERIAL, - MT_USB_DEVICE(USB_VENDOR_ID_IDEACOM, - USB_DEVICE_ID_IDEACOM_IDC6651) }, - /* Ilitek dual touch panel */ { .driver_data = MT_CLS_NSMU, MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, - /* IRTOUCH panels */ - { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, - MT_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, - USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, - - /* LG Display panels */ - { .driver_data = MT_CLS_DEFAULT, - MT_USB_DEVICE(USB_VENDOR_ID_LG, - USB_DEVICE_ID_LG_MULTITOUCH) }, - - /* Lumio panels */ - { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, - MT_USB_DEVICE(USB_VENDOR_ID_LUMIO, - USB_DEVICE_ID_CRYSTALTOUCH) }, - { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, - MT_USB_DEVICE(USB_VENDOR_ID_LUMIO, - USB_DEVICE_ID_CRYSTALTOUCH_DUAL) }, - /* MosArt panels */ { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, MT_USB_DEVICE(USB_VENDOR_ID_ASUS, @@ -1246,11 +1180,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) }, - /* Nexio panels */ - { .driver_data = MT_CLS_DEFAULT, - MT_USB_DEVICE(USB_VENDOR_ID_NEXIO, - USB_DEVICE_ID_NEXIO_MULTITOUCH_420)}, - /* Panasonic panels */ { .driver_data = MT_CLS_PANASONIC, MT_USB_DEVICE(USB_VENDOR_ID_PANASONIC, @@ -1264,11 +1193,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_PCT) }, - /* PenMount panels */ - { .driver_data = MT_CLS_CONFIDENCE, - MT_USB_DEVICE(USB_VENDOR_ID_PENMOUNT, - USB_DEVICE_ID_PENMOUNT_PCI) }, - /* PixArt optical touch screen */ { .driver_data = MT_CLS_INRANGE_CONTACTNUMBER, MT_USB_DEVICE(USB_VENDOR_ID_PIXART, @@ -1282,44 +1206,18 @@ static const struct hid_device_id mt_devices[] = { /* PixCir-based panels */ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, - MT_USB_DEVICE(USB_VENDOR_ID_HANVON, - USB_DEVICE_ID_HANVON_MULTITOUCH) }, - { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, MT_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, /* Quanta-based panels */ { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, - USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) }, - { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, - MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, - { .driver_data = MT_CLS_CONFIDENCE_CONTACT_ID, - MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, - USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008) }, - - /* SiS panels */ - { .driver_data = MT_CLS_DEFAULT, - HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, - USB_DEVICE_ID_SIS9200_TOUCH) }, - { .driver_data = MT_CLS_DEFAULT, - HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, - USB_DEVICE_ID_SIS817_TOUCH) }, - { .driver_data = MT_CLS_DEFAULT, - HID_USB_DEVICE(USB_VENDOR_ID_SIS_TOUCH, - USB_DEVICE_ID_SIS1030_TOUCH) }, /* Stantum panels */ { .driver_data = MT_CLS_CONFIDENCE, - MT_USB_DEVICE(USB_VENDOR_ID_STANTUM, - USB_DEVICE_ID_MTP)}, - { .driver_data = MT_CLS_CONFIDENCE, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, USB_DEVICE_ID_MTP_STM)}, - { .driver_data = MT_CLS_DEFAULT, - MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_SITRONIX, - USB_DEVICE_ID_MTP_SITRONIX)}, /* TopSeed panels */ { .driver_data = MT_CLS_TOPSEED, @@ -1378,11 +1276,6 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_XIROKU, USB_DEVICE_ID_XIROKU_CSR2) }, - /* Zytronic panels */ - { .driver_data = MT_CLS_SERIAL, - MT_USB_DEVICE(USB_VENDOR_ID_ZYTRONIC, - USB_DEVICE_ID_ZYTRONIC_ZXY100) }, - /* Generic MT device */ { HID_DEVICE(HID_BUS_ANY, HID_GROUP_MULTITOUCH, HID_ANY_ID, HID_ANY_ID) }, -- cgit v0.10.2 From e55f62008671f9200e124bcb3c736cfc3e661c2a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 28 Feb 2014 11:41:24 -0500 Subject: HID: multitouch: remove pen special handling Pens have a special handling in hid-mt as hybrid pen/touch devices are quite common now. However, some fancy devices presents also useful collections like mouse or keyboard. The special case for the pen may not be a special case, and treat it as a generic case. Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3e81f4e..8250cc0 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -100,7 +100,6 @@ struct mt_device { int cc_value_index; /* contact count value index in the field */ unsigned last_slot_field; /* the last field of a slot */ unsigned mt_report_id; /* the report ID of the multitouch device */ - unsigned pen_report_id; /* the report ID of the pen device */ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ __s16 inputmode_index; /* InputMode HID feature index in the report */ __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, @@ -342,45 +341,6 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td, f->usages[f->length++] = usage->hid; } -static int mt_pen_input_mapping(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - struct mt_device *td = hid_get_drvdata(hdev); - - td->pen_report_id = field->report->id; - - return 0; -} - -static int mt_pen_input_mapped(struct hid_device *hdev, struct hid_input *hi, - struct hid_field *field, struct hid_usage *usage, - unsigned long **bit, int *max) -{ - return 0; -} - -static int mt_pen_event(struct hid_device *hid, struct hid_field *field, - struct hid_usage *usage, __s32 value) -{ - /* let hid-input handle it */ - return 0; -} - -static void mt_pen_report(struct hid_device *hid, struct hid_report *report) -{ - struct hid_field *field = report->field[0]; - - input_sync(field->hidinput->input); -} - -static void mt_pen_input_configured(struct hid_device *hdev, - struct hid_input *hi) -{ - /* force BTN_STYLUS to allow tablet matching in udev */ - __set_bit(BTN_STYLUS, hi->input->keybit); -} - static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) @@ -767,7 +727,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, return -1; if (field->physical == HID_DG_STYLUS) - return mt_pen_input_mapping(hdev, hi, field, usage, bit, max); + return 0; return mt_touch_input_mapping(hdev, hi, field, usage, bit, max); } @@ -777,7 +737,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, unsigned long **bit, int *max) { if (field->physical == HID_DG_STYLUS) - return mt_pen_input_mapped(hdev, hi, field, usage, bit, max); + return 0; return mt_touch_input_mapped(hdev, hi, field, usage, bit, max); } @@ -790,25 +750,22 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, if (field->report->id == td->mt_report_id) return mt_touch_event(hid, field, usage, value); - if (field->report->id == td->pen_report_id) - return mt_pen_event(hid, field, usage, value); - - /* ignore other reports */ - return 1; + return 0; } static void mt_report(struct hid_device *hid, struct hid_report *report) { struct mt_device *td = hid_get_drvdata(hid); + struct hid_field *field = report->field[0]; if (!(hid->claimed & HID_CLAIMED_INPUT)) return; if (report->id == td->mt_report_id) - mt_touch_report(hid, report); + return mt_touch_report(hid, report); - if (report->id == td->pen_report_id) - mt_pen_report(hid, report); + if (field && field->hidinput && field->hidinput->input) + input_sync(field->hidinput->input); } static void mt_set_input_mode(struct hid_device *hdev) @@ -895,7 +852,8 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) if (hi->report->field[0]->physical == HID_DG_STYLUS) { suffix = "Pen"; - mt_pen_input_configured(hdev, hi); + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); } if (suffix) { @@ -957,7 +915,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->maxcontact_report_id = -1; td->cc_index = -1; td->mt_report_id = -1; - td->pen_report_id = -1; hid_set_drvdata(hdev, td); td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields), -- cgit v0.10.2 From 6aef704e38293524067505eeafec9c811b18d66a Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 28 Feb 2014 11:41:25 -0500 Subject: HID: multitouch: add support of other generic collections in hid-mt The ANTON Touch Pad is a device which can switch from a multitouch touchpad to a mouse. It thus presents several generic collections which are currently ignored by hid-multitouch. Enable them by not ignoring them in mt_input_mapping. Adding also a suffix for them depending on their application. Reported-by: Edel Maks Signed-off-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 92b40c0..ca9b206 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -67,6 +67,9 @@ #define USB_VENDOR_ID_ALPS 0x0433 #define USB_DEVICE_ID_IBM_GAMEPAD 0x1101 +#define USB_VENDOR_ID_ANTON 0x1130 +#define USB_DEVICE_ID_ANTON_TOUCH_PAD 0x3101 + #define USB_VENDOR_ID_APPLE 0x05ac #define USB_DEVICE_ID_APPLE_MIGHTYMOUSE 0x0304 #define USB_DEVICE_ID_APPLE_MAGICMOUSE 0x030d diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 8250cc0..0d31139 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -84,6 +84,7 @@ struct mt_class { __s32 sn_pressure; /* Signal/noise ratio for pressure events */ __u8 maxcontacts; bool is_indirect; /* true for touchpads */ + bool export_all_inputs; /* do not ignore mouse, keyboards, etc... */ }; struct mt_fields { @@ -133,6 +134,7 @@ static void mt_post_parse(struct mt_device *td); /* reserved 0x0010 */ /* reserved 0x0011 */ #define MT_CLS_WIN_8 0x0012 +#define MT_CLS_EXPORT_ALL_INPUTS 0x0013 /* vendor specific classes */ #define MT_CLS_3M 0x0101 @@ -196,6 +198,10 @@ static struct mt_class mt_classes[] = { MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | MT_QUIRK_CONTACT_CNT_ACCURATE }, + { .name = MT_CLS_EXPORT_ALL_INPUTS, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_CONTACT_CNT_ACCURATE, + .export_all_inputs = true }, /* * vendor specific classes @@ -718,28 +724,52 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { - /* Only map fields from TouchScreen or TouchPad collections. - * We need to ignore fields that belong to other collections - * such as Mouse that might have the same GenericDesktop usages. */ - if (field->application != HID_DG_TOUCHSCREEN && + struct mt_device *td = hid_get_drvdata(hdev); + + /* + * If mtclass.export_all_inputs is not set, only map fields from + * TouchScreen or TouchPad collections. We need to ignore fields + * that belong to other collections such as Mouse that might have + * the same GenericDesktop usages. + */ + if (!td->mtclass.export_all_inputs && + field->application != HID_DG_TOUCHSCREEN && field->application != HID_DG_PEN && field->application != HID_DG_TOUCHPAD) return -1; + /* + * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" + * for the stylus. + */ if (field->physical == HID_DG_STYLUS) return 0; - return mt_touch_input_mapping(hdev, hi, field, usage, bit, max); + if (field->application == HID_DG_TOUCHSCREEN || + field->application == HID_DG_TOUCHPAD) + return mt_touch_input_mapping(hdev, hi, field, usage, bit, max); + + /* let hid-core decide for the others */ + return 0; } static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, struct hid_field *field, struct hid_usage *usage, unsigned long **bit, int *max) { + /* + * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" + * for the stylus. + */ if (field->physical == HID_DG_STYLUS) return 0; - return mt_touch_input_mapped(hdev, hi, field, usage, bit, max); + if (field->application == HID_DG_TOUCHSCREEN || + field->application == HID_DG_TOUCHPAD) + return mt_touch_input_mapped(hdev, hi, field, usage, bit, max); + + /* let hid-core decide for the others */ + return 0; } static int mt_event(struct hid_device *hid, struct hid_field *field, @@ -846,14 +876,49 @@ static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) struct mt_device *td = hid_get_drvdata(hdev); char *name; const char *suffix = NULL; + struct hid_field *field = hi->report->field[0]; if (hi->report->id == td->mt_report_id) mt_touch_input_configured(hdev, hi); + /* + * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN" + * for the stylus. Check this first, and then rely on the application + * field. + */ if (hi->report->field[0]->physical == HID_DG_STYLUS) { suffix = "Pen"; /* force BTN_STYLUS to allow tablet matching in udev */ __set_bit(BTN_STYLUS, hi->input->keybit); + } else { + switch (field->application) { + case HID_GD_KEYBOARD: + suffix = "Keyboard"; + break; + case HID_GD_KEYPAD: + suffix = "Keypad"; + break; + case HID_GD_MOUSE: + suffix = "Mouse"; + break; + case HID_DG_STYLUS: + suffix = "Pen"; + /* force BTN_STYLUS to allow tablet matching in udev */ + __set_bit(BTN_STYLUS, hi->input->keybit); + break; + case HID_DG_TOUCHSCREEN: + /* we do not set suffix = "Touchscreen" */ + break; + case HID_GD_SYSTEM_CONTROL: + suffix = "System Control"; + break; + case HID_CP_CONSUMER_CONTROL: + suffix = "Consumer Control"; + break; + default: + suffix = "UNKNOWN"; + break; + } } if (suffix) { @@ -992,6 +1057,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M3266) }, + /* Anton devices */ + { .driver_data = MT_CLS_EXPORT_ALL_INPUTS, + MT_USB_DEVICE(USB_VENDOR_ID_ANTON, + USB_DEVICE_ID_ANTON_TOUCH_PAD) }, + /* Atmel panels */ { .driver_data = MT_CLS_SERIAL, MT_USB_DEVICE(USB_VENDOR_ID_ATMEL, diff --git a/include/linux/hid.h b/include/linux/hid.h index 5eb282e..e224516 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -201,6 +201,7 @@ struct hid_item { #define HID_GD_VBRZ 0x00010045 #define HID_GD_VNO 0x00010046 #define HID_GD_FEATURE 0x00010047 +#define HID_GD_SYSTEM_CONTROL 0x00010080 #define HID_GD_UP 0x00010090 #define HID_GD_DOWN 0x00010091 #define HID_GD_RIGHT 0x00010092 @@ -208,6 +209,8 @@ struct hid_item { #define HID_DC_BATTERYSTRENGTH 0x00060020 +#define HID_CP_CONSUMER_CONTROL 0x000c0001 + #define HID_DG_DIGITIZER 0x000d0001 #define HID_DG_PEN 0x000d0002 #define HID_DG_LIGHTPEN 0x000d0003 -- cgit v0.10.2 From 9abebedb123a577ecc5b69b2a2515499e430be24 Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Wed, 19 Mar 2014 13:39:03 -0700 Subject: HID: multitouch: add support for Win 8.1 multitouch touchpads Multitouch touchpads built for Win 8.1 need to be sent an input mode feature report in order to start reporting multitouch events. This is the same process sent to Win 7 multitouch touchscreens except the value of the feature report is 3 for touchpads. Signed-off-by: Andrew Duggan Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 0d31139..59742f4 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -68,6 +68,9 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_HOVERING (1 << 11) #define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12) +#define MT_INPUTMODE_TOUCHSCREEN 0x02 +#define MT_INPUTMODE_TOUCHPAD 0x03 + struct mt_slot { __s32 x, y, cx, cy, p, w, h; __s32 contactid; /* the device ContactID assigned to this slot */ @@ -105,6 +108,7 @@ struct mt_device { __s16 inputmode_index; /* InputMode HID feature index in the report */ __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, -1 if non-existent */ + __u8 inputmode_value; /* InputMode HID feature value */ __u8 num_received; /* how many contacts we received */ __u8 num_expected; /* expected last contact index */ __u8 maxcontacts; @@ -363,8 +367,10 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, * Model touchscreens providing buttons as touchpads. */ if (field->application == HID_DG_TOUCHPAD || - (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) + (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) { td->mt_flags |= INPUT_MT_POINTER; + td->inputmode_value = MT_INPUTMODE_TOUCHPAD; + } if (usage->usage_index) prev_usage = &field->usage[usage->usage_index - 1]; @@ -810,7 +816,7 @@ static void mt_set_input_mode(struct hid_device *hdev) re = &(hdev->report_enum[HID_FEATURE_REPORT]); r = re->report_id_hash[td->inputmode]; if (r) { - r->field[0]->value[td->inputmode_index] = 0x02; + r->field[0]->value[td->inputmode_index] = td->inputmode_value; hid_hw_request(hdev, r, HID_REQ_SET_REPORT); } } @@ -978,6 +984,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) td->mtclass = *mtclass; td->inputmode = -1; td->maxcontact_report_id = -1; + td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN; td->cc_index = -1; td->mt_report_id = -1; hid_set_drvdata(hdev, td); -- cgit v0.10.2 From 4522643aa9630be17238edf1b4c0b690c5dd7f5d Mon Sep 17 00:00:00 2001 From: Petri Gynther Date: Mon, 24 Mar 2014 13:50:01 -0700 Subject: HID: uhid: Add UHID_CREATE2 + UHID_INPUT2 UHID_CREATE2: HID report descriptor data (rd_data) is an array in struct uhid_create2_req, instead of a pointer. Enables use from languages that don't support pointers, e.g. Python. UHID_INPUT2: Data array is the last field of struct uhid_input2_req. Enables userspace to write only the required bytes to kernel (ev.type + ev.u.input2.size + the part of the data array that matters), instead of the entire struct uhid_input2_req. Note: UHID_CREATE2 increases the total size of struct uhid_event slightly, thus increasing the size of messages that are queued for userspace. However, this won't affect the userspace processing of these events. [Jiri Kosina : adjust to hid_get_raw_report() and hid_output_raw_report() API changes] Signed-off-by: Petri Gynther Reviewed-by: David Herrmann Signed-off-by: Jiri Kosina diff --git a/Documentation/hid/uhid.txt b/Documentation/hid/uhid.txt index dc35a2b..ee65936 100644 --- a/Documentation/hid/uhid.txt +++ b/Documentation/hid/uhid.txt @@ -93,6 +93,11 @@ the request was handled successfully. event to the kernel. The payload is of type struct uhid_create_req and contains information about your device. You can start I/O now. + UHID_CREATE2: + Same as UHID_CREATE, but the HID report descriptor data (rd_data) is an array + inside struct uhid_create2_req, instead of a pointer to a separate array. + Enables use from languages that don't support pointers, e.g. Python. + UHID_DESTROY: This destroys the internal HID device. No further I/O will be accepted. There may still be pending messages that you can receive with read() but no further @@ -105,6 +110,12 @@ the request was handled successfully. contains a data-payload. This is the raw data that you read from your device. The kernel will parse the HID reports and react on it. + UHID_INPUT2: + Same as UHID_INPUT, but the data array is the last field of uhid_input2_req. + Enables userspace to write only the required bytes to kernel (ev.type + + ev.u.input2.size + the part of the data array that matters), instead of + the entire struct uhid_input2_req. + UHID_FEATURE_ANSWER: If you receive a UHID_FEATURE request you must answer with this request. You must copy the "id" field from the request into the answer. Set the "err" field diff --git a/drivers/hid/uhid.c b/drivers/hid/uhid.c index 7ed79be..0d078c3 100644 --- a/drivers/hid/uhid.c +++ b/drivers/hid/uhid.c @@ -428,6 +428,67 @@ err_free: return ret; } +static int uhid_dev_create2(struct uhid_device *uhid, + const struct uhid_event *ev) +{ + struct hid_device *hid; + int ret; + + if (uhid->running) + return -EALREADY; + + uhid->rd_size = ev->u.create2.rd_size; + if (uhid->rd_size <= 0 || uhid->rd_size > HID_MAX_DESCRIPTOR_SIZE) + return -EINVAL; + + uhid->rd_data = kmalloc(uhid->rd_size, GFP_KERNEL); + if (!uhid->rd_data) + return -ENOMEM; + + memcpy(uhid->rd_data, ev->u.create2.rd_data, uhid->rd_size); + + hid = hid_allocate_device(); + if (IS_ERR(hid)) { + ret = PTR_ERR(hid); + goto err_free; + } + + strncpy(hid->name, ev->u.create2.name, 127); + hid->name[127] = 0; + strncpy(hid->phys, ev->u.create2.phys, 63); + hid->phys[63] = 0; + strncpy(hid->uniq, ev->u.create2.uniq, 63); + hid->uniq[63] = 0; + + hid->ll_driver = &uhid_hid_driver; + hid->bus = ev->u.create2.bus; + hid->vendor = ev->u.create2.vendor; + hid->product = ev->u.create2.product; + hid->version = ev->u.create2.version; + hid->country = ev->u.create2.country; + hid->driver_data = uhid; + hid->dev.parent = uhid_misc.this_device; + + uhid->hid = hid; + uhid->running = true; + + ret = hid_add_device(hid); + if (ret) { + hid_err(hid, "Cannot register HID device\n"); + goto err_hid; + } + + return 0; + +err_hid: + hid_destroy_device(hid); + uhid->hid = NULL; + uhid->running = false; +err_free: + kfree(uhid->rd_data); + return ret; +} + static int uhid_dev_destroy(struct uhid_device *uhid) { if (!uhid->running) @@ -456,6 +517,17 @@ static int uhid_dev_input(struct uhid_device *uhid, struct uhid_event *ev) return 0; } +static int uhid_dev_input2(struct uhid_device *uhid, struct uhid_event *ev) +{ + if (!uhid->running) + return -EINVAL; + + hid_input_report(uhid->hid, HID_INPUT_REPORT, ev->u.input2.data, + min_t(size_t, ev->u.input2.size, UHID_DATA_MAX), 0); + + return 0; +} + static int uhid_dev_feature_answer(struct uhid_device *uhid, struct uhid_event *ev) { @@ -592,12 +664,18 @@ static ssize_t uhid_char_write(struct file *file, const char __user *buffer, case UHID_CREATE: ret = uhid_dev_create(uhid, &uhid->input_buf); break; + case UHID_CREATE2: + ret = uhid_dev_create2(uhid, &uhid->input_buf); + break; case UHID_DESTROY: ret = uhid_dev_destroy(uhid); break; case UHID_INPUT: ret = uhid_dev_input(uhid, &uhid->input_buf); break; + case UHID_INPUT2: + ret = uhid_dev_input2(uhid, &uhid->input_buf); + break; case UHID_FEATURE_ANSWER: ret = uhid_dev_feature_answer(uhid, &uhid->input_buf); break; diff --git a/include/uapi/linux/uhid.h b/include/uapi/linux/uhid.h index 414b74b..1e3b09c 100644 --- a/include/uapi/linux/uhid.h +++ b/include/uapi/linux/uhid.h @@ -21,6 +21,7 @@ #include #include +#include enum uhid_event_type { UHID_CREATE, @@ -34,6 +35,8 @@ enum uhid_event_type { UHID_INPUT, UHID_FEATURE, UHID_FEATURE_ANSWER, + UHID_CREATE2, + UHID_INPUT2, }; struct uhid_create_req { @@ -50,6 +53,19 @@ struct uhid_create_req { __u32 country; } __attribute__((__packed__)); +struct uhid_create2_req { + __u8 name[128]; + __u8 phys[64]; + __u8 uniq[64]; + __u16 rd_size; + __u16 bus; + __u32 vendor; + __u32 product; + __u32 version; + __u32 country; + __u8 rd_data[HID_MAX_DESCRIPTOR_SIZE]; +} __attribute__((__packed__)); + #define UHID_DATA_MAX 4096 enum uhid_report_type { @@ -63,6 +79,11 @@ struct uhid_input_req { __u16 size; } __attribute__((__packed__)); +struct uhid_input2_req { + __u16 size; + __u8 data[UHID_DATA_MAX]; +} __attribute__((__packed__)); + struct uhid_output_req { __u8 data[UHID_DATA_MAX]; __u16 size; @@ -100,6 +121,8 @@ struct uhid_event { struct uhid_output_ev_req output_ev; struct uhid_feature_req feature; struct uhid_feature_answer_req feature_answer; + struct uhid_create2_req create2; + struct uhid_input2_req input2; } u; } __attribute__((__packed__)); -- cgit v0.10.2 From 914c578391c7cf55d88e2a553208e7523d0ddf1a Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Sat, 15 Mar 2014 09:41:15 -0400 Subject: HID: sony: Fix Sixaxis cable state detection Byte 31 of the Sixaxis report can change depending on whether or not the controller is rumbling. Using bit 3 is the only reliable way to detect the state of the cable regardless of rumble activity. Signed-off-by: Frank Praznik Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index b1aa6f0..31ba01a 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -864,7 +864,7 @@ static void sixaxis_parse_report(struct sony_sc *sc, __u8 *rd, int size) battery_capacity = sixaxis_battery_capacity[index]; battery_charging = 0; } - cable_state = !((rd[31] >> 4) & 0x01); + cable_state = !(rd[31] & 0x04); spin_lock_irqsave(&sc->lock, flags); sc->cable_state = cable_state; -- cgit v0.10.2 From 2078b9bb240ea31ff3ea715881d1ec03d83e6de4 Mon Sep 17 00:00:00 2001 From: Frank Praznik Date: Sat, 15 Mar 2014 09:41:16 -0400 Subject: HID: sony: Set the quriks flag for Bluetooth controllers The Sixaxis and DualShock 4 want HID output reports sent on the control endpoint when connected via Bluetooth. Set the HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP flag for these devices so hidraw write() works properly. Signed-off-by: Frank Praznik Signed-off-by: Jiri Kosina diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 31ba01a..c364be1 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1664,11 +1664,21 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) sc->worker_initialized = 1; INIT_WORK(&sc->state_worker, sixaxis_state_worker); } else if (sc->quirks & SIXAXIS_CONTROLLER_BT) { + /* + * The Sixaxis wants output reports sent on the ctrl endpoint + * when connected via Bluetooth. + */ + hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; ret = sixaxis_set_operational_bt(hdev); sc->worker_initialized = 1; INIT_WORK(&sc->state_worker, sixaxis_state_worker); } else if (sc->quirks & DUALSHOCK4_CONTROLLER) { if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) { + /* + * The DualShock 4 wants output reports sent on the ctrl + * endpoint when connected via Bluetooth. + */ + hdev->quirks |= HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP; ret = dualshock4_set_operational_bt(hdev); if (ret < 0) { hid_err(hdev, "failed to set the Dualshock 4 operational mode\n"); -- cgit v0.10.2