Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/hid/hid

Pull HID updates from Jiri Kosina:

 - hid-mcp2221 GPIO support, from Rishi Gupta

 - MT_CLS_WIN_8_DUAL obsolete quirk removal from hid-multitouch, from
   Kai-Heng Feng

 - a bunch of new hardware support to hid-asus driver, from Hans de
   Goede

 - other assorted small fixes, cleanups and device-specific quirks

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid:
  HID: multitouch: Remove MT_CLS_WIN_8_DUAL
  HID: multitouch: enable multi-input as a quirk for some devices
  HID: sony: Fix for broken buttons on DS3 USB dongles
  HID: Add quirks for Trust Panora Graphic Tablet
  HID: apple: Swap the Fn and Left Control keys on Apple keyboards
  HID: asus: Add depends on USB_HID to HID_ASUS Kconfig option
  HID: asus: Fix mute and touchpad-toggle keys on Medion Akoya E1239T
  HID: asus: Add support for multi-touch touchpad on Medion Akoya E1239T
  HID: asus: Add report_size to struct asus_touchpad_info
  HID: asus: Add hid_is_using_ll_driver(usb_hid_driver) check
  HID: asus: Simplify skipping of mappings for Asus T100CHI keyboard-dock
  HID: asus: Only set EV_REP if we are adding a mapping
  HID: i2c-hid: add Schneider SCL142ALM to descriptor override
  HID: intel-ish-hid: avoid bogus uninitialized-variable warning
  HID: mcp2221: add GPIO functionality support
  HID: fix typo in Kconfig
  HID: logitech: drop outdated references to unifying receivers
  • Loading branch information
Linus Torvalds committed Jun 4, 2020
2 parents 631d691 + 16ba7e3 commit a789d5f
Show file tree
Hide file tree
Showing 12 changed files with 364 additions and 74 deletions.
11 changes: 6 additions & 5 deletions drivers/hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ config HIDRAW
---help---
Say Y here if you want to support HID devices (from the USB
specification standpoint) that aren't strictly user interface
devices, like monitor controls and Uninterruptable Power Supplies.
devices, like monitor controls and Uninterruptible Power Supplies.

This module supports these devices separately using a separate
event interface on /dev/hidraw.
Expand Down Expand Up @@ -149,6 +149,7 @@ config HID_APPLEIR

config HID_ASUS
tristate "Asus"
depends on USB_HID
depends on LEDS_CLASS
depends on ASUS_WMI || ASUS_WMI=n
select POWER_SUPPLY
Expand Down Expand Up @@ -538,14 +539,14 @@ config HID_LOGITECH
Support for Logitech devices that are not fully compliant with HID standard.

config HID_LOGITECH_DJ
tristate "Logitech Unifying receivers full support"
tristate "Logitech receivers full support"
depends on USB_HID
depends on HIDRAW
depends on HID_LOGITECH
select HID_LOGITECH_HIDPP
---help---
Say Y if you want support for Logitech Unifying receivers and devices.
Unifying receivers are capable of pairing up to 6 Logitech compliant
Say Y if you want support for Logitech receivers and devices.
Logitech receivers are capable of pairing multiple Logitech compliant
devices to the same receiver. Without this driver it will be handled by
generic USB_HID driver and all incoming events will be multiplexed
into a single mouse and a single keyboard device.
Expand Down Expand Up @@ -1140,7 +1141,7 @@ config HID_SENSOR_CUSTOM_SENSOR
to decide how to interpret these special sensor ids and process in
the user space. Currently some manufacturers are using these ids for
sensor calibration and debugging other sensors. Manufacturers
should't use these special custom sensor ids to export any of the
shouldn't use these special custom sensor ids to export any of the
standard sensors.
Select this config option for custom/generic sensor support.

Expand Down
30 changes: 28 additions & 2 deletions drivers/hid/hid-apple.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,12 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\")
"(For people who want to keep Windows PC keyboard muscle memory. "
"[0] = as-is, Mac layout. 1 = swapped, Windows layout.)");

static unsigned int swap_fn_leftctrl;
module_param(swap_fn_leftctrl, uint, 0644);
MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
"(For people who want to keep PC keyboard muscle memory. "
"[0] = as-is, Mac layout, 1 = swapped, PC layout)");

struct apple_sc {
unsigned long quirks;
unsigned int fn_on;
Expand Down Expand Up @@ -162,6 +168,11 @@ static const struct apple_key_translation swapped_option_cmd_keys[] = {
{ }
};

static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
{ KEY_FN, KEY_LEFTCTRL },
{ }
};

static const struct apple_key_translation *apple_find_translation(
const struct apple_key_translation *table, u16 from)
{
Expand All @@ -183,9 +194,11 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
bool do_translate;
u16 code = 0;

if (usage->code == KEY_FN) {
u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);

if (usage->code == fn_keycode) {
asc->fn_on = !!value;
input_event(input, usage->type, usage->code, value);
input_event(input, usage->type, KEY_FN, value);
return 1;
}

Expand Down Expand Up @@ -270,6 +283,14 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
}
}

if (swap_fn_leftctrl) {
trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code);
if (trans) {
input_event(input, usage->type, trans->to, value);
return 1;
}
}

return 0;
}

Expand Down Expand Up @@ -333,6 +354,11 @@ static void apple_setup_input(struct input_dev *input)

for (trans = apple_iso_keyboard; trans->from; trans++)
set_bit(trans->to, input->keybit);

if (swap_fn_leftctrl) {
for (trans = swapped_fn_leftctrl_keys; trans->from; trans++)
set_bit(trans->to, input->keybit);
}
}

static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
Expand Down
122 changes: 103 additions & 19 deletions drivers/hid/hid-asus.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 | \
Expand All @@ -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;
Expand All @@ -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 = {
Expand All @@ -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 = {
Expand All @@ -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 = {
Expand All @@ -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 = {
Expand All @@ -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,
Expand Down Expand Up @@ -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++) {
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -764,6 +822,7 @@ static int asus_input_mapping(struct hid_device *hdev,
return 0;
}

set_bit(EV_REP, hi->input->evbit);
return 1;
}

Expand All @@ -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;
}

Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Expand Down
Loading

0 comments on commit a789d5f

Please sign in to comment.