diff options
Diffstat (limited to 'drivers/hid/hid-asus.c')
-rw-r--r-- | drivers/hid/hid-asus.c | 122 |
1 files changed, 103 insertions, 19 deletions
diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index e6e4c841fb06..c183caf89d49 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -40,7 +40,9 @@ MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>"); MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define T100_TPAD_INTF 2 +#define MEDION_E1239T_TPAD_INTF 1 +#define E1239T_TP_TOGGLE_REPORT_ID 0x05 #define T100CHI_MOUSE_REPORT_ID 0x06 #define FEATURE_REPORT_ID 0x0d #define INPUT_REPORT_ID 0x5d @@ -77,6 +79,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_G752_KEYBOARD BIT(8) #define QUIRK_T101HA_DOCK BIT(9) #define QUIRK_T90CHI BIT(10) +#define QUIRK_MEDION_E1239T BIT(11) #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ QUIRK_NO_INIT_REPORTS | \ @@ -102,12 +105,14 @@ struct asus_touchpad_info { int res_y; int contact_size; int max_contacts; + int report_size; }; struct asus_drvdata { unsigned long quirks; struct hid_device *hdev; struct input_dev *input; + struct input_dev *tp_kbd_input; struct asus_kbd_leds *kbd_backlight; const struct asus_touchpad_info *tp; bool enable_backlight; @@ -126,6 +131,7 @@ static const struct asus_touchpad_info asus_i2c_tp = { .max_y = 1758, .contact_size = 5, .max_contacts = 5, + .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, }; static const struct asus_touchpad_info asus_t100ta_tp = { @@ -135,6 +141,7 @@ static const struct asus_touchpad_info asus_t100ta_tp = { .res_y = 27, /* units/mm */ .contact_size = 5, .max_contacts = 5, + .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, }; static const struct asus_touchpad_info asus_t100ha_tp = { @@ -144,6 +151,7 @@ static const struct asus_touchpad_info asus_t100ha_tp = { .res_y = 29, /* units/mm */ .contact_size = 5, .max_contacts = 5, + .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, }; static const struct asus_touchpad_info asus_t200ta_tp = { @@ -153,6 +161,7 @@ static const struct asus_touchpad_info asus_t200ta_tp = { .res_y = 28, /* units/mm */ .contact_size = 5, .max_contacts = 5, + .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */, }; static const struct asus_touchpad_info asus_t100chi_tp = { @@ -162,6 +171,17 @@ static const struct asus_touchpad_info asus_t100chi_tp = { .res_y = 29, /* units/mm */ .contact_size = 3, .max_contacts = 4, + .report_size = 15 /* 2 byte header + 3 * 4 + 1 byte footer */, +}; + +static const struct asus_touchpad_info medion_e1239t_tp = { + .max_x = 2640, + .max_y = 1380, + .res_x = 29, /* units/mm */ + .res_y = 28, /* units/mm */ + .contact_size = 5, + .max_contacts = 5, + .report_size = 32 /* 2 byte header + 5 * 5 + 5 byte footer */, }; static void asus_report_contact_down(struct asus_drvdata *drvdat, @@ -229,7 +249,7 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size) int i, toolType = MT_TOOL_FINGER; u8 *contactData = data + 2; - if (size != 3 + drvdat->tp->contact_size * drvdat->tp->max_contacts) + if (size != drvdat->tp->report_size) return 0; for (i = 0; i < drvdat->tp->max_contacts; i++) { @@ -257,6 +277,34 @@ static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size) return 1; } +static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size) +{ + if (size != 3) + return 0; + + /* Handle broken mute key which only sends press events */ + if (!drvdat->tp && + data[0] == 0x02 && data[1] == 0xe2 && data[2] == 0x00) { + input_report_key(drvdat->input, KEY_MUTE, 1); + input_sync(drvdat->input); + input_report_key(drvdat->input, KEY_MUTE, 0); + input_sync(drvdat->input); + return 1; + } + + /* Handle custom touchpad toggle key which only sends press events */ + if (drvdat->tp_kbd_input && + data[0] == 0x05 && data[1] == 0x02 && data[2] == 0x28) { + input_report_key(drvdat->tp_kbd_input, KEY_F21, 1); + input_sync(drvdat->tp_kbd_input); + input_report_key(drvdat->tp_kbd_input, KEY_F21, 0); + input_sync(drvdat->tp_kbd_input); + return 1; + } + + return 0; +} + static int asus_event(struct hid_device *hdev, struct hid_field *field, struct hid_usage *usage, __s32 value) { @@ -281,6 +329,9 @@ static int asus_raw_event(struct hid_device *hdev, if (drvdata->tp && data[0] == INPUT_REPORT_ID) return asus_report_input(drvdata, data, size); + if (drvdata->quirks & QUIRK_MEDION_E1239T) + return asus_e1239t_event(drvdata, data, size); + return 0; } @@ -615,6 +666,21 @@ static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi) hi->report->id != T100CHI_MOUSE_REPORT_ID) return 0; + /* Handle MULTI_INPUT on E1239T mouse/touchpad USB interface */ + if (drvdata->tp && (drvdata->quirks & QUIRK_MEDION_E1239T)) { + switch (hi->report->id) { + case E1239T_TP_TOGGLE_REPORT_ID: + input_set_capability(input, EV_KEY, KEY_F21); + input->name = "Asus Touchpad Keys"; + drvdata->tp_kbd_input = input; + return 0; + case INPUT_REPORT_ID: + break; /* Touchpad report, handled below */ + default: + return 0; /* Ignore other reports */ + } + } + if (drvdata->tp) { int ret; @@ -677,24 +743,16 @@ static int asus_input_mapping(struct hid_device *hdev, * This avoids a bunch of non-functional hid_input devices getting * created because of the T100CHI using HID_QUIRK_MULTI_INPUT. */ - if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) { - if (field->application == (HID_UP_GENDESK | 0x0080) || - usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) || - usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) || - usage->hid == (HID_UP_GENDEVCTRLS | 0x0026)) - return -1; - /* - * We use the hid_input for the mouse report for the touchpad, - * keep the left button, to avoid the core removing it. - */ - if (field->application == HID_GD_MOUSE && - usage->hid != (HID_UP_BUTTON | 1)) - return -1; - } + if ((drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) && + (field->application == (HID_UP_GENDESK | 0x0080) || + field->application == HID_GD_MOUSE || + usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) || + usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) || + usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))) + return -1; /* ASUS-specific keyboard hotkeys */ if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) { - set_bit(EV_REP, hi->input->evbit); switch (usage->hid & HID_USAGE) { case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; @@ -737,11 +795,11 @@ static int asus_input_mapping(struct hid_device *hdev, if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT) drvdata->enable_backlight = true; + set_bit(EV_REP, hi->input->evbit); return 1; } if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) { - set_bit(EV_REP, hi->input->evbit); switch (usage->hid & HID_USAGE) { case 0xff01: asus_map_key_clear(BTN_1); break; case 0xff02: asus_map_key_clear(BTN_2); break; @@ -764,6 +822,7 @@ static int asus_input_mapping(struct hid_device *hdev, return 0; } + set_bit(EV_REP, hi->input->evbit); return 1; } @@ -782,6 +841,16 @@ static int asus_input_mapping(struct hid_device *hdev, } } + /* + * The mute button is broken and only sends press events, we + * deal with this in our raw_event handler, so do not map it. + */ + if ((drvdata->quirks & QUIRK_MEDION_E1239T) && + usage->hid == (HID_UP_CONSUMER | 0xe2)) { + input_set_capability(hi->input, EV_KEY, KEY_MUTE); + return -1; + } + return 0; } @@ -849,7 +918,8 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) if (drvdata->quirks & QUIRK_IS_MULTITOUCH) drvdata->tp = &asus_i2c_tp; - if (drvdata->quirks & QUIRK_T100_KEYBOARD) { + if ((drvdata->quirks & QUIRK_T100_KEYBOARD) && + hid_is_using_ll_driver(hdev, &usb_hid_driver)) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) { @@ -877,6 +947,19 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) drvdata->tp = &asus_t100chi_tp; } + if ((drvdata->quirks & QUIRK_MEDION_E1239T) && + hid_is_using_ll_driver(hdev, &usb_hid_driver)) { + struct usb_host_interface *alt = + to_usb_interface(hdev->dev.parent)->altsetting; + + if (alt->desc.bInterfaceNumber == MEDION_E1239T_TPAD_INTF) { + /* For separate input-devs for tp and tp toggle key */ + hdev->quirks |= HID_QUIRK_MULTI_INPUT; + drvdata->quirks |= QUIRK_SKIP_INPUT_MAPPING; + drvdata->tp = &medion_e1239t_tp; + } + } + if (drvdata->quirks & QUIRK_NO_INIT_REPORTS) hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; @@ -1056,7 +1139,8 @@ static const struct hid_device_id asus_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), QUIRK_T100CHI }, - + { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE_MEDION_E1239T), + QUIRK_MEDION_E1239T }, { } }; MODULE_DEVICE_TABLE(hid, asus_devices); |