mirror of https://gitee.com/openkylin/linux.git
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/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
This commit is contained in:
commit
a789d5f8a9
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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,
|
||||
|
|
|
@ -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) ||
|
||||
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))
|
||||
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;
|
||||
}
|
||||
|
||||
/* 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);
|
||||
|
|
|
@ -76,12 +76,9 @@
|
|||
|
||||
#define USB_VENDOR_ID_ALPS_JP 0x044E
|
||||
#define HID_DEVICE_ID_ALPS_U1_DUAL 0x120B
|
||||
#define HID_DEVICE_ID_ALPS_U1_DUAL_PTP 0x121F
|
||||
#define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP 0x1220
|
||||
#define HID_DEVICE_ID_ALPS_U1 0x1215
|
||||
#define HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY 0x121E
|
||||
#define HID_DEVICE_ID_ALPS_T4_BTNLESS 0x120C
|
||||
#define HID_DEVICE_ID_ALPS_1222 0x1222
|
||||
|
||||
#define USB_VENDOR_ID_AMI 0x046b
|
||||
#define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE 0xff10
|
||||
|
@ -281,9 +278,6 @@
|
|||
|
||||
#define USB_VENDOR_ID_CIDC 0x1677
|
||||
|
||||
#define I2C_VENDOR_ID_CIRQUE 0x0488
|
||||
#define I2C_PRODUCT_ID_CIRQUE_121F 0x121F
|
||||
|
||||
#define USB_VENDOR_ID_CJTOUCH 0x24b8
|
||||
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0020 0x0020
|
||||
#define USB_DEVICE_ID_CJTOUCH_MULTI_TOUCH_0040 0x0040
|
||||
|
@ -640,6 +634,7 @@
|
|||
#define I2C_DEVICE_ID_ITE_LENOVO_LEGION_Y720 0x837a
|
||||
#define USB_DEVICE_ID_ITE_LENOVO_YOGA900 0x8396
|
||||
#define USB_DEVICE_ID_ITE8595 0x8595
|
||||
#define USB_DEVICE_ID_ITE_MEDION_E1239T 0xce50
|
||||
|
||||
#define USB_VENDOR_ID_JABRA 0x0b0e
|
||||
#define USB_DEVICE_ID_JABRA_SPEAK_410 0x0412
|
||||
|
@ -730,8 +725,6 @@
|
|||
#define USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL 0x6049
|
||||
#define USB_DEVICE_ID_LENOVO_TPPRODOCK 0x6067
|
||||
#define USB_DEVICE_ID_LENOVO_X1_COVER 0x6085
|
||||
#define USB_DEVICE_ID_LENOVO_X1_TAB 0x60a3
|
||||
#define USB_DEVICE_ID_LENOVO_X1_TAB3 0x60b5
|
||||
#define USB_DEVICE_ID_LENOVO_PIXART_USB_MOUSE_608D 0x608d
|
||||
|
||||
#define USB_VENDOR_ID_LG 0x1fd2
|
||||
|
@ -1157,6 +1150,9 @@
|
|||
#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882 0x8882
|
||||
#define USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883 0x8883
|
||||
|
||||
#define USB_VENDOR_ID_TRUST 0x145f
|
||||
#define USB_DEVICE_ID_TRUST_PANORA_TABLET 0x0212
|
||||
|
||||
#define USB_VENDOR_ID_TURBOX 0x062a
|
||||
#define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201
|
||||
#define USB_DEVICE_ID_ASUS_MD_5110 0x5110
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* HID driver for Logitech Unifying receivers
|
||||
* HID driver for Logitech receivers
|
||||
*
|
||||
* Copyright (c) 2011 Logitech
|
||||
*/
|
||||
|
@ -701,7 +701,7 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
|
|||
type_str, dj_hiddev->product);
|
||||
} else {
|
||||
snprintf(dj_hiddev->name, sizeof(dj_hiddev->name),
|
||||
"Logitech Unifying Device. Wireless PID:%04x",
|
||||
"Logitech Wireless Device PID:%04x",
|
||||
dj_hiddev->product);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* HIDPP protocol for Logitech Unifying receivers
|
||||
* HIDPP protocol for Logitech receivers
|
||||
*
|
||||
* Copyright (c) 2011 Logitech (c)
|
||||
* Copyright (c) 2012-2013 Google (c)
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <linux/hid.h>
|
||||
#include <linux/hidraw.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/gpio/driver.h>
|
||||
#include "hid-ids.h"
|
||||
|
||||
/* Commands codes in a raw output report */
|
||||
|
@ -27,6 +28,8 @@ enum {
|
|||
MCP2221_I2C_PARAM_OR_STATUS = 0x10,
|
||||
MCP2221_I2C_SET_SPEED = 0x20,
|
||||
MCP2221_I2C_CANCEL = 0x10,
|
||||
MCP2221_GPIO_SET = 0x50,
|
||||
MCP2221_GPIO_GET = 0x51,
|
||||
};
|
||||
|
||||
/* Response codes in a raw input report */
|
||||
|
@ -42,6 +45,8 @@ enum {
|
|||
MCP2221_I2C_WRADDRL_SEND = 0x21,
|
||||
MCP2221_I2C_ADDR_NACK = 0x25,
|
||||
MCP2221_I2C_READ_COMPL = 0x55,
|
||||
MCP2221_ALT_F_NOT_GPIOV = 0xEE,
|
||||
MCP2221_ALT_F_NOT_GPIOD = 0xEF,
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -59,6 +64,9 @@ struct mcp2221 {
|
|||
int rxbuf_idx;
|
||||
int status;
|
||||
u8 cur_i2c_clk_div;
|
||||
struct gpio_chip *gc;
|
||||
u8 gp_idx;
|
||||
u8 gpio_dir;
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -526,6 +534,110 @@ static const struct i2c_algorithm mcp_i2c_algo = {
|
|||
.functionality = mcp_i2c_func,
|
||||
};
|
||||
|
||||
static int mcp_gpio_get(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
struct mcp2221 *mcp = gpiochip_get_data(gc);
|
||||
|
||||
mcp->txbuf[0] = MCP2221_GPIO_GET;
|
||||
|
||||
mcp->gp_idx = (offset + 1) * 2;
|
||||
|
||||
mutex_lock(&mcp->lock);
|
||||
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
|
||||
mutex_unlock(&mcp->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void mcp_gpio_set(struct gpio_chip *gc,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
struct mcp2221 *mcp = gpiochip_get_data(gc);
|
||||
|
||||
memset(mcp->txbuf, 0, 18);
|
||||
mcp->txbuf[0] = MCP2221_GPIO_SET;
|
||||
|
||||
mcp->gp_idx = ((offset + 1) * 4) - 1;
|
||||
|
||||
mcp->txbuf[mcp->gp_idx - 1] = 1;
|
||||
mcp->txbuf[mcp->gp_idx] = !!value;
|
||||
|
||||
mutex_lock(&mcp->lock);
|
||||
mcp_send_data_req_status(mcp, mcp->txbuf, 18);
|
||||
mutex_unlock(&mcp->lock);
|
||||
}
|
||||
|
||||
static int mcp_gpio_dir_set(struct mcp2221 *mcp,
|
||||
unsigned int offset, u8 val)
|
||||
{
|
||||
memset(mcp->txbuf, 0, 18);
|
||||
mcp->txbuf[0] = MCP2221_GPIO_SET;
|
||||
|
||||
mcp->gp_idx = (offset + 1) * 5;
|
||||
|
||||
mcp->txbuf[mcp->gp_idx - 1] = 1;
|
||||
mcp->txbuf[mcp->gp_idx] = val;
|
||||
|
||||
return mcp_send_data_req_status(mcp, mcp->txbuf, 18);
|
||||
}
|
||||
|
||||
static int mcp_gpio_direction_input(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
struct mcp2221 *mcp = gpiochip_get_data(gc);
|
||||
|
||||
mutex_lock(&mcp->lock);
|
||||
ret = mcp_gpio_dir_set(mcp, offset, 0);
|
||||
mutex_unlock(&mcp->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int mcp_gpio_direction_output(struct gpio_chip *gc,
|
||||
unsigned int offset, int value)
|
||||
{
|
||||
int ret;
|
||||
struct mcp2221 *mcp = gpiochip_get_data(gc);
|
||||
|
||||
mutex_lock(&mcp->lock);
|
||||
ret = mcp_gpio_dir_set(mcp, offset, 1);
|
||||
mutex_unlock(&mcp->lock);
|
||||
|
||||
/* Can't configure as output, bailout early */
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
mcp_gpio_set(gc, offset, value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcp_gpio_get_direction(struct gpio_chip *gc,
|
||||
unsigned int offset)
|
||||
{
|
||||
int ret;
|
||||
struct mcp2221 *mcp = gpiochip_get_data(gc);
|
||||
|
||||
mcp->txbuf[0] = MCP2221_GPIO_GET;
|
||||
|
||||
mcp->gp_idx = (offset + 1) * 2;
|
||||
|
||||
mutex_lock(&mcp->lock);
|
||||
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
|
||||
mutex_unlock(&mcp->lock);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (mcp->gpio_dir)
|
||||
return GPIO_LINE_DIRECTION_IN;
|
||||
|
||||
return GPIO_LINE_DIRECTION_OUT;
|
||||
}
|
||||
|
||||
/* Gives current state of i2c engine inside mcp2221 */
|
||||
static int mcp_get_i2c_eng_state(struct mcp2221 *mcp,
|
||||
u8 *data, u8 idx)
|
||||
|
@ -638,6 +750,39 @@ static int mcp2221_raw_event(struct hid_device *hdev,
|
|||
complete(&mcp->wait_in_report);
|
||||
break;
|
||||
|
||||
case MCP2221_GPIO_GET:
|
||||
switch (data[1]) {
|
||||
case MCP2221_SUCCESS:
|
||||
if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) ||
|
||||
(data[mcp->gp_idx + 1] == MCP2221_ALT_F_NOT_GPIOD)) {
|
||||
mcp->status = -ENOENT;
|
||||
} else {
|
||||
mcp->status = !!data[mcp->gp_idx];
|
||||
mcp->gpio_dir = !!data[mcp->gp_idx + 1];
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mcp->status = -EAGAIN;
|
||||
}
|
||||
complete(&mcp->wait_in_report);
|
||||
break;
|
||||
|
||||
case MCP2221_GPIO_SET:
|
||||
switch (data[1]) {
|
||||
case MCP2221_SUCCESS:
|
||||
if ((data[mcp->gp_idx] == MCP2221_ALT_F_NOT_GPIOV) ||
|
||||
(data[mcp->gp_idx - 1] == MCP2221_ALT_F_NOT_GPIOV)) {
|
||||
mcp->status = -ENOENT;
|
||||
} else {
|
||||
mcp->status = 0;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
mcp->status = -EAGAIN;
|
||||
}
|
||||
complete(&mcp->wait_in_report);
|
||||
break;
|
||||
|
||||
default:
|
||||
mcp->status = -EIO;
|
||||
complete(&mcp->wait_in_report);
|
||||
|
@ -702,8 +847,32 @@ static int mcp2221_probe(struct hid_device *hdev,
|
|||
}
|
||||
i2c_set_adapdata(&mcp->adapter, mcp);
|
||||
|
||||
/* Setup GPIO chip */
|
||||
mcp->gc = devm_kzalloc(&hdev->dev, sizeof(*mcp->gc), GFP_KERNEL);
|
||||
if (!mcp->gc) {
|
||||
ret = -ENOMEM;
|
||||
goto err_gc;
|
||||
}
|
||||
|
||||
mcp->gc->label = "mcp2221_gpio";
|
||||
mcp->gc->direction_input = mcp_gpio_direction_input;
|
||||
mcp->gc->direction_output = mcp_gpio_direction_output;
|
||||
mcp->gc->get_direction = mcp_gpio_get_direction;
|
||||
mcp->gc->set = mcp_gpio_set;
|
||||
mcp->gc->get = mcp_gpio_get;
|
||||
mcp->gc->ngpio = 4;
|
||||
mcp->gc->base = -1;
|
||||
mcp->gc->can_sleep = 1;
|
||||
mcp->gc->parent = &hdev->dev;
|
||||
|
||||
ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp);
|
||||
if (ret)
|
||||
goto err_gc;
|
||||
|
||||
return 0;
|
||||
|
||||
err_gc:
|
||||
i2c_del_adapter(&mcp->adapter);
|
||||
err_i2c:
|
||||
hid_hw_close(mcp->hdev);
|
||||
err_hstop:
|
||||
|
|
|
@ -69,6 +69,7 @@ MODULE_LICENSE("GPL");
|
|||
#define MT_QUIRK_ASUS_CUSTOM_UP BIT(17)
|
||||
#define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18)
|
||||
#define MT_QUIRK_SEPARATE_APP_REPORT BIT(19)
|
||||
#define MT_QUIRK_FORCE_MULTI_INPUT BIT(20)
|
||||
|
||||
#define MT_INPUTMODE_TOUCHSCREEN 0x02
|
||||
#define MT_INPUTMODE_TOUCHPAD 0x03
|
||||
|
@ -188,7 +189,8 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
|
|||
/* reserved 0x0011 */
|
||||
#define MT_CLS_WIN_8 0x0012
|
||||
#define MT_CLS_EXPORT_ALL_INPUTS 0x0013
|
||||
#define MT_CLS_WIN_8_DUAL 0x0014
|
||||
/* reserved 0x0014 */
|
||||
#define MT_CLS_WIN_8_FORCE_MULTI_INPUT 0x0015
|
||||
|
||||
/* vendor specific classes */
|
||||
#define MT_CLS_3M 0x0101
|
||||
|
@ -272,12 +274,14 @@ static const struct mt_class mt_classes[] = {
|
|||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE,
|
||||
.export_all_inputs = true },
|
||||
{ .name = MT_CLS_WIN_8_DUAL,
|
||||
{ .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
|
||||
.quirks = MT_QUIRK_ALWAYS_VALID |
|
||||
MT_QUIRK_IGNORE_DUPLICATES |
|
||||
MT_QUIRK_HOVERING |
|
||||
MT_QUIRK_CONTACT_CNT_ACCURATE |
|
||||
MT_QUIRK_WIN8_PTP_BUTTONS,
|
||||
MT_QUIRK_STICKY_FINGERS |
|
||||
MT_QUIRK_WIN8_PTP_BUTTONS |
|
||||
MT_QUIRK_FORCE_MULTI_INPUT,
|
||||
.export_all_inputs = true },
|
||||
|
||||
/*
|
||||
|
@ -754,8 +758,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
|
|||
MT_STORE_FIELD(inrange_state);
|
||||
return 1;
|
||||
case HID_DG_CONFIDENCE:
|
||||
if ((cls->name == MT_CLS_WIN_8 ||
|
||||
cls->name == MT_CLS_WIN_8_DUAL) &&
|
||||
if (cls->name == MT_CLS_WIN_8 &&
|
||||
(field->application == HID_DG_TOUCHPAD ||
|
||||
field->application == HID_DG_TOUCHSCREEN))
|
||||
app->quirks |= MT_QUIRK_CONFIDENCE;
|
||||
|
@ -1714,6 +1717,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
|
|||
if (id->group != HID_GROUP_MULTITOUCH_WIN_8)
|
||||
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
|
||||
|
||||
if (mtclass->quirks & MT_QUIRK_FORCE_MULTI_INPUT) {
|
||||
hdev->quirks &= ~HID_QUIRK_INPUT_PER_APP;
|
||||
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
|
||||
}
|
||||
|
||||
timer_setup(&td->release_timer, mt_expired_timeout, 0);
|
||||
|
||||
ret = hid_parse(hdev);
|
||||
|
@ -1786,32 +1794,6 @@ static const struct hid_device_id mt_devices[] = {
|
|||
MT_USB_DEVICE(USB_VENDOR_ID_3M,
|
||||
USB_DEVICE_ID_3M3266) },
|
||||
|
||||
/* Alps devices */
|
||||
{ .driver_data = MT_CLS_WIN_8_DUAL,
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_ALPS_JP,
|
||||
HID_DEVICE_ID_ALPS_U1_DUAL_PTP) },
|
||||
{ .driver_data = MT_CLS_WIN_8_DUAL,
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_ALPS_JP,
|
||||
HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP) },
|
||||
{ .driver_data = MT_CLS_WIN_8_DUAL,
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_ALPS_JP,
|
||||
HID_DEVICE_ID_ALPS_1222) },
|
||||
|
||||
/* 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) },
|
||||
|
||||
/* Lenovo X1 TAB Gen 3 */
|
||||
{ .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_TAB3) },
|
||||
|
||||
/* Anton devices */
|
||||
{ .driver_data = MT_CLS_EXPORT_ALL_INPUTS,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ANTON,
|
||||
|
@ -1846,12 +1828,6 @@ static const struct hid_device_id mt_devices[] = {
|
|||
MT_USB_DEVICE(USB_VENDOR_ID_CHUNGHWAT,
|
||||
USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH) },
|
||||
|
||||
/* Cirque devices */
|
||||
{ .driver_data = MT_CLS_WIN_8_DUAL,
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
I2C_VENDOR_ID_CIRQUE,
|
||||
I2C_PRODUCT_ID_CIRQUE_121F) },
|
||||
|
||||
/* CJTouch panels */
|
||||
{ .driver_data = MT_CLS_NSMU,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_CJTOUCH,
|
||||
|
@ -1926,6 +1902,11 @@ static const struct hid_device_id mt_devices[] = {
|
|||
MT_USB_DEVICE(USB_VENDOR_ID_DWAV,
|
||||
USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_C002) },
|
||||
|
||||
/* Elan devices */
|
||||
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_ELAN, 0x313a) },
|
||||
|
||||
/* Elitegroup panel */
|
||||
{ .driver_data = MT_CLS_SERIAL,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_ELITEGROUP,
|
||||
|
@ -2056,6 +2037,11 @@ static const struct hid_device_id mt_devices[] = {
|
|||
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
|
||||
USB_DEVICE_ID_MTP_STM)},
|
||||
|
||||
/* Synaptics devices */
|
||||
{ .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT,
|
||||
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
|
||||
USB_VENDOR_ID_SYNAPTICS, 0xce08) },
|
||||
|
||||
/* TopSeed panels */
|
||||
{ .driver_data = MT_CLS_TOPSEED,
|
||||
MT_USB_DEVICE(USB_VENDOR_ID_TOPSEED2,
|
||||
|
|
|
@ -168,6 +168,7 @@ static const struct hid_device_id hid_quirks[] = {
|
|||
{ HID_USB_DEVICE(USB_VENDOR_ID_TOUCHPACK, USB_DEVICE_ID_TOUCHPACK_RTS), HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8882), HID_QUIRK_NOGET },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TPV, USB_DEVICE_ID_TPV_OPTICAL_TOUCHSCREEN_8883), HID_QUIRK_NOGET },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TRUST, USB_DEVICE_ID_TRUST_PANORA_TABLET), HID_QUIRK_MULTI_INPUT | HID_QUIRK_HIDINPUT_FORCE },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_KEYBOARD), HID_QUIRK_NOGET },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_KNA5), HID_QUIRK_MULTI_INPUT },
|
||||
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_TWA60), HID_QUIRK_MULTI_INPUT },
|
||||
|
|
|
@ -867,6 +867,23 @@ static u8 *sony_report_fixup(struct hid_device *hdev, u8 *rdesc,
|
|||
if (sc->quirks & PS3REMOTE)
|
||||
return ps3remote_fixup(hdev, rdesc, rsize);
|
||||
|
||||
/*
|
||||
* Some knock-off USB dongles incorrectly report their button count
|
||||
* as 13 instead of 16 causing three non-functional buttons.
|
||||
*/
|
||||
if ((sc->quirks & SIXAXIS_CONTROLLER_USB) && *rsize >= 45 &&
|
||||
/* Report Count (13) */
|
||||
rdesc[23] == 0x95 && rdesc[24] == 0x0D &&
|
||||
/* Usage Maximum (13) */
|
||||
rdesc[37] == 0x29 && rdesc[38] == 0x0D &&
|
||||
/* Report Count (3) */
|
||||
rdesc[43] == 0x95 && rdesc[44] == 0x03) {
|
||||
hid_info(hdev, "Fixing up USB dongle report descriptor\n");
|
||||
rdesc[24] = 0x10;
|
||||
rdesc[38] = 0x10;
|
||||
rdesc[44] = 0x00;
|
||||
}
|
||||
|
||||
return rdesc;
|
||||
}
|
||||
|
||||
|
|
|
@ -389,6 +389,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = {
|
|||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{
|
||||
.ident = "Schneider SCL142ALM",
|
||||
.matches = {
|
||||
DMI_EXACT_MATCH(DMI_SYS_VENDOR, "SCHNEIDER"),
|
||||
DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "SCL142ALM"),
|
||||
},
|
||||
.driver_data = (void *)&sipodev_desc
|
||||
},
|
||||
{ } /* Terminate list */
|
||||
};
|
||||
|
||||
|
|
|
@ -480,6 +480,7 @@ static int ish_query_loader_prop(struct ishtp_cl_data *client_data,
|
|||
sizeof(ldr_xfer_query_resp));
|
||||
if (rv < 0) {
|
||||
client_data->flag_retry = true;
|
||||
*fw_info = (struct shim_fw_info){};
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
@ -489,6 +490,7 @@ static int ish_query_loader_prop(struct ishtp_cl_data *client_data,
|
|||
"data size %d is not equal to size of loader_xfer_query_response %zu\n",
|
||||
rv, sizeof(struct loader_xfer_query_response));
|
||||
client_data->flag_retry = true;
|
||||
*fw_info = (struct shim_fw_info){};
|
||||
return -EMSGSIZE;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue