162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * HID driver for some ITE "special" devices 462306a36Sopenharmony_ci * Copyright (c) 2017 Hans de Goede <hdegoede@redhat.com> 562306a36Sopenharmony_ci */ 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci#include <linux/device.h> 862306a36Sopenharmony_ci#include <linux/input.h> 962306a36Sopenharmony_ci#include <linux/hid.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "hid-ids.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define QUIRK_TOUCHPAD_ON_OFF_REPORT BIT(0) 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_cistatic __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) 1762306a36Sopenharmony_ci{ 1862306a36Sopenharmony_ci unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) { 2162306a36Sopenharmony_ci /* For Acer Aspire Switch 10 SW5-012 keyboard-dock */ 2262306a36Sopenharmony_ci if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) { 2362306a36Sopenharmony_ci hid_info(hdev, "Fixing up Acer Sw5-012 ITE keyboard report descriptor\n"); 2462306a36Sopenharmony_ci rdesc[163] = HID_MAIN_ITEM_RELATIVE; 2562306a36Sopenharmony_ci } 2662306a36Sopenharmony_ci /* For Acer One S1002/S1003 keyboard-dock */ 2762306a36Sopenharmony_ci if (*rsize == 188 && rdesc[185] == 0x81 && rdesc[186] == 0x02) { 2862306a36Sopenharmony_ci hid_info(hdev, "Fixing up Acer S1002/S1003 ITE keyboard report descriptor\n"); 2962306a36Sopenharmony_ci rdesc[186] = HID_MAIN_ITEM_RELATIVE; 3062306a36Sopenharmony_ci } 3162306a36Sopenharmony_ci /* For Acer Aspire Switch 10E (SW3-016) keyboard-dock */ 3262306a36Sopenharmony_ci if (*rsize == 210 && rdesc[184] == 0x81 && rdesc[185] == 0x02) { 3362306a36Sopenharmony_ci hid_info(hdev, "Fixing up Acer Aspire Switch 10E (SW3-016) ITE keyboard report descriptor\n"); 3462306a36Sopenharmony_ci rdesc[185] = HID_MAIN_ITEM_RELATIVE; 3562306a36Sopenharmony_ci } 3662306a36Sopenharmony_ci } 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci return rdesc; 3962306a36Sopenharmony_ci} 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_cistatic int ite_input_mapping(struct hid_device *hdev, 4262306a36Sopenharmony_ci struct hid_input *hi, struct hid_field *field, 4362306a36Sopenharmony_ci struct hid_usage *usage, unsigned long **bit, 4462306a36Sopenharmony_ci int *max) 4562306a36Sopenharmony_ci{ 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci if ((quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) && 5062306a36Sopenharmony_ci (usage->hid & HID_USAGE_PAGE) == 0x00880000) { 5162306a36Sopenharmony_ci if (usage->hid == 0x00880078) { 5262306a36Sopenharmony_ci /* Touchpad on, userspace expects F22 for this */ 5362306a36Sopenharmony_ci hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_F22); 5462306a36Sopenharmony_ci return 1; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci if (usage->hid == 0x00880079) { 5762306a36Sopenharmony_ci /* Touchpad off, userspace expects F23 for this */ 5862306a36Sopenharmony_ci hid_map_usage_clear(hi, usage, bit, max, EV_KEY, KEY_F23); 5962306a36Sopenharmony_ci return 1; 6062306a36Sopenharmony_ci } 6162306a36Sopenharmony_ci return -1; 6262306a36Sopenharmony_ci } 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci return 0; 6562306a36Sopenharmony_ci} 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_cistatic int ite_event(struct hid_device *hdev, struct hid_field *field, 6862306a36Sopenharmony_ci struct hid_usage *usage, __s32 value) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct input_dev *input; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (!(hdev->claimed & HID_CLAIMED_INPUT) || !field->hidinput) 7362306a36Sopenharmony_ci return 0; 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci input = field->hidinput->input; 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci /* 7862306a36Sopenharmony_ci * The ITE8595 always reports 0 as value for the rfkill button. Luckily 7962306a36Sopenharmony_ci * it is the only button in its report, and it sends a report on 8062306a36Sopenharmony_ci * release only, so receiving a report means the button was pressed. 8162306a36Sopenharmony_ci */ 8262306a36Sopenharmony_ci if (usage->hid == HID_GD_RFKILL_BTN) { 8362306a36Sopenharmony_ci input_event(input, EV_KEY, KEY_RFKILL, 1); 8462306a36Sopenharmony_ci input_sync(input); 8562306a36Sopenharmony_ci input_event(input, EV_KEY, KEY_RFKILL, 0); 8662306a36Sopenharmony_ci input_sync(input); 8762306a36Sopenharmony_ci return 1; 8862306a36Sopenharmony_ci } 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci return 0; 9162306a36Sopenharmony_ci} 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_cistatic int ite_probe(struct hid_device *hdev, const struct hid_device_id *id) 9462306a36Sopenharmony_ci{ 9562306a36Sopenharmony_ci int ret; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci hid_set_drvdata(hdev, (void *)id->driver_data); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ci ret = hid_open_report(hdev); 10062306a36Sopenharmony_ci if (ret) 10162306a36Sopenharmony_ci return ret; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci return hid_hw_start(hdev, HID_CONNECT_DEFAULT); 10462306a36Sopenharmony_ci} 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_cistatic const struct hid_device_id ite_devices[] = { 10762306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE8595) }, 10862306a36Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_258A, USB_DEVICE_ID_258A_6A88) }, 10962306a36Sopenharmony_ci /* ITE8595 USB kbd ctlr, with Synaptics touchpad connected to it. */ 11062306a36Sopenharmony_ci { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, 11162306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 11262306a36Sopenharmony_ci USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012), 11362306a36Sopenharmony_ci .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, 11462306a36Sopenharmony_ci /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ 11562306a36Sopenharmony_ci { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, 11662306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 11762306a36Sopenharmony_ci USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002), 11862306a36Sopenharmony_ci .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, 11962306a36Sopenharmony_ci /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ 12062306a36Sopenharmony_ci { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, 12162306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 12262306a36Sopenharmony_ci USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003), 12362306a36Sopenharmony_ci .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, 12462306a36Sopenharmony_ci /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ 12562306a36Sopenharmony_ci { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, 12662306a36Sopenharmony_ci USB_VENDOR_ID_SYNAPTICS, 12762306a36Sopenharmony_ci USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_017), 12862306a36Sopenharmony_ci .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, 12962306a36Sopenharmony_ci { } 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(hid, ite_devices); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_cistatic struct hid_driver ite_driver = { 13462306a36Sopenharmony_ci .name = "itetech", 13562306a36Sopenharmony_ci .id_table = ite_devices, 13662306a36Sopenharmony_ci .probe = ite_probe, 13762306a36Sopenharmony_ci .report_fixup = ite_report_fixup, 13862306a36Sopenharmony_ci .input_mapping = ite_input_mapping, 13962306a36Sopenharmony_ci .event = ite_event, 14062306a36Sopenharmony_ci}; 14162306a36Sopenharmony_cimodule_hid_driver(ite_driver); 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ciMODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>"); 14462306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 145