12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2eeb01a57SYusuke Fujimaki /*
3b94f7d5dSYusuke Fujimaki * HID driver for Asus notebook built-in keyboard.
4eeb01a57SYusuke Fujimaki * Fixes small logical maximum to match usage maximum.
5eeb01a57SYusuke Fujimaki *
6b94f7d5dSYusuke Fujimaki * Currently supported devices are:
7b94f7d5dSYusuke Fujimaki * EeeBook X205TA
8b94f7d5dSYusuke Fujimaki * VivoBook E200HA
9b94f7d5dSYusuke Fujimaki *
10eeb01a57SYusuke Fujimaki * Copyright (c) 2016 Yusuke Fujimaki <usk.fujimaki@gmail.com>
11eeb01a57SYusuke Fujimaki *
12eeb01a57SYusuke Fujimaki * This module based on hid-ortek by
13eeb01a57SYusuke Fujimaki * Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
14eeb01a57SYusuke Fujimaki * Copyright (c) 2011 Jiri Kosina
159ce12d8bSBrendan McGrath *
169ce12d8bSBrendan McGrath * This module has been updated to add support for Asus i2c touchpad.
179ce12d8bSBrendan McGrath *
189ce12d8bSBrendan McGrath * Copyright (c) 2016 Brendan McGrath <redmcg@redmandi.dyndns.org>
199ce12d8bSBrendan McGrath * Copyright (c) 2016 Victor Vlasenko <victor.vlasenko@sysgears.com>
209ce12d8bSBrendan McGrath * Copyright (c) 2016 Frederik Wenigwieser <frederik.wenigwieser@gmail.com>
21eeb01a57SYusuke Fujimaki */
22eeb01a57SYusuke Fujimaki
23eeb01a57SYusuke Fujimaki /*
24eeb01a57SYusuke Fujimaki */
25eeb01a57SYusuke Fujimaki
26762f948cSHans de Goede #include <linux/dmi.h>
27eeb01a57SYusuke Fujimaki #include <linux/hid.h>
28eeb01a57SYusuke Fujimaki #include <linux/module.h>
293b692c55SDaniel Drake #include <linux/platform_data/x86/asus-wmi.h>
309ce12d8bSBrendan McGrath #include <linux/input/mt.h>
3157573c54SHans de Goede #include <linux/usb.h> /* For to_usb_interface for T100 touchpad intf check */
326311d329SNOGUCHI Hiroshi #include <linux/power_supply.h>
33a2654c1fSThomas Weißschuh #include <linux/leds.h>
34eeb01a57SYusuke Fujimaki
35eeb01a57SYusuke Fujimaki #include "hid-ids.h"
36eeb01a57SYusuke Fujimaki
379ce12d8bSBrendan McGrath MODULE_AUTHOR("Yusuke Fujimaki <usk.fujimaki@gmail.com>");
389ce12d8bSBrendan McGrath MODULE_AUTHOR("Brendan McGrath <redmcg@redmandi.dyndns.org>");
399ce12d8bSBrendan McGrath MODULE_AUTHOR("Victor Vlasenko <victor.vlasenko@sysgears.com>");
409ce12d8bSBrendan McGrath MODULE_AUTHOR("Frederik Wenigwieser <frederik.wenigwieser@gmail.com>");
419ce12d8bSBrendan McGrath MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad");
429ce12d8bSBrendan McGrath
4357573c54SHans de Goede #define T100_TPAD_INTF 2
44e271f6c2SHans de Goede #define MEDION_E1239T_TPAD_INTF 1
4557573c54SHans de Goede
46350bd245SHans de Goede #define E1239T_TP_TOGGLE_REPORT_ID 0x05
4773c75d39SHans de Goede #define T100CHI_MOUSE_REPORT_ID 0x06
489ce12d8bSBrendan McGrath #define FEATURE_REPORT_ID 0x0d
499ce12d8bSBrendan McGrath #define INPUT_REPORT_ID 0x5d
50af22a610SCarlo Caione #define FEATURE_KBD_REPORT_ID 0x5a
51af22a610SCarlo Caione #define FEATURE_KBD_REPORT_SIZE 16
52b92b8024SLuke D Jones #define FEATURE_KBD_LED_REPORT_ID1 0x5d
53b92b8024SLuke D Jones #define FEATURE_KBD_LED_REPORT_ID2 0x5e
54af22a610SCarlo Caione
55af22a610SCarlo Caione #define SUPPORT_KBD_BACKLIGHT BIT(0)
569ce12d8bSBrendan McGrath
579ce12d8bSBrendan McGrath #define MAX_TOUCH_MAJOR 8
589ce12d8bSBrendan McGrath #define MAX_PRESSURE 128
599ce12d8bSBrendan McGrath
609ce12d8bSBrendan McGrath #define BTN_LEFT_MASK 0x01
619ce12d8bSBrendan McGrath #define CONTACT_TOOL_TYPE_MASK 0x80
629ce12d8bSBrendan McGrath #define CONTACT_X_MSB_MASK 0xf0
639ce12d8bSBrendan McGrath #define CONTACT_Y_MSB_MASK 0x0f
649ce12d8bSBrendan McGrath #define CONTACT_TOUCH_MAJOR_MASK 0x07
659ce12d8bSBrendan McGrath #define CONTACT_PRESSURE_MASK 0x7f
669ce12d8bSBrendan McGrath
676311d329SNOGUCHI Hiroshi #define BATTERY_REPORT_ID (0x03)
686311d329SNOGUCHI Hiroshi #define BATTERY_REPORT_SIZE (1 + 8)
696311d329SNOGUCHI Hiroshi #define BATTERY_LEVEL_MAX ((u8)255)
706311d329SNOGUCHI Hiroshi #define BATTERY_STAT_DISCONNECT (0)
716311d329SNOGUCHI Hiroshi #define BATTERY_STAT_CHARGING (1)
726311d329SNOGUCHI Hiroshi #define BATTERY_STAT_FULL (2)
736311d329SNOGUCHI Hiroshi
749ce12d8bSBrendan McGrath #define QUIRK_FIX_NOTEBOOK_REPORT BIT(0)
759ce12d8bSBrendan McGrath #define QUIRK_NO_INIT_REPORTS BIT(1)
769ce12d8bSBrendan McGrath #define QUIRK_SKIP_INPUT_MAPPING BIT(2)
779ce12d8bSBrendan McGrath #define QUIRK_IS_MULTITOUCH BIT(3)
780485b1ecSMatjaz Hegedic #define QUIRK_NO_CONSUMER_USAGES BIT(4)
79af22a610SCarlo Caione #define QUIRK_USE_KBD_BACKLIGHT BIT(5)
8076dd1fbeSHans de Goede #define QUIRK_T100_KEYBOARD BIT(6)
815703e52cSHans de Goede #define QUIRK_T100CHI BIT(7)
82832e1eeeSMaxime Bellengé #define QUIRK_G752_KEYBOARD BIT(8)
83a94f66aeSHans de Goede #define QUIRK_T90CHI BIT(9)
84a94f66aeSHans de Goede #define QUIRK_MEDION_E1239T BIT(10)
85a94f66aeSHans de Goede #define QUIRK_ROG_NKEY_KEYBOARD BIT(11)
8687c7ee7aSLuke D. Jones #define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12)
879ce12d8bSBrendan McGrath
88a93913e1SMatjaz Hegedic #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \
890485b1ecSMatjaz Hegedic QUIRK_NO_INIT_REPORTS | \
900485b1ecSMatjaz Hegedic QUIRK_NO_CONSUMER_USAGES)
91c81760b9SHans de Goede #define I2C_TOUCHPAD_QUIRKS (QUIRK_NO_INIT_REPORTS | \
929ce12d8bSBrendan McGrath QUIRK_SKIP_INPUT_MAPPING | \
939ce12d8bSBrendan McGrath QUIRK_IS_MULTITOUCH)
949ce12d8bSBrendan McGrath
959ce12d8bSBrendan McGrath #define TRKID_SGN ((TRKID_MAX + 1) >> 1)
969ce12d8bSBrendan McGrath
97af22a610SCarlo Caione struct asus_kbd_leds {
98af22a610SCarlo Caione struct led_classdev cdev;
99af22a610SCarlo Caione struct hid_device *hdev;
100af22a610SCarlo Caione struct work_struct work;
101af22a610SCarlo Caione unsigned int brightness;
102315c5370SPietro Borrello spinlock_t lock;
103af22a610SCarlo Caione bool removed;
104af22a610SCarlo Caione };
105af22a610SCarlo Caione
106c81760b9SHans de Goede struct asus_touchpad_info {
107c81760b9SHans de Goede int max_x;
108c81760b9SHans de Goede int max_y;
109b61d43e6SHans de Goede int res_x;
110b61d43e6SHans de Goede int res_y;
111c81760b9SHans de Goede int contact_size;
112c81760b9SHans de Goede int max_contacts;
113a61f9e42SHans de Goede int report_size;
114c81760b9SHans de Goede };
115c81760b9SHans de Goede
1169ce12d8bSBrendan McGrath struct asus_drvdata {
1179ce12d8bSBrendan McGrath unsigned long quirks;
1186311d329SNOGUCHI Hiroshi struct hid_device *hdev;
1199ce12d8bSBrendan McGrath struct input_dev *input;
120350bd245SHans de Goede struct input_dev *tp_kbd_input;
121af22a610SCarlo Caione struct asus_kbd_leds *kbd_backlight;
122c81760b9SHans de Goede const struct asus_touchpad_info *tp;
123af22a610SCarlo Caione bool enable_backlight;
1246311d329SNOGUCHI Hiroshi struct power_supply *battery;
1256311d329SNOGUCHI Hiroshi struct power_supply_desc battery_desc;
1266311d329SNOGUCHI Hiroshi int battery_capacity;
1276311d329SNOGUCHI Hiroshi int battery_stat;
1286311d329SNOGUCHI Hiroshi bool battery_in_query;
1296311d329SNOGUCHI Hiroshi unsigned long battery_next_query;
1309ce12d8bSBrendan McGrath };
1319ce12d8bSBrendan McGrath
1326311d329SNOGUCHI Hiroshi static int asus_report_battery(struct asus_drvdata *, u8 *, int);
1336311d329SNOGUCHI Hiroshi
134c81760b9SHans de Goede static const struct asus_touchpad_info asus_i2c_tp = {
135c81760b9SHans de Goede .max_x = 2794,
136c81760b9SHans de Goede .max_y = 1758,
137c81760b9SHans de Goede .contact_size = 5,
138c81760b9SHans de Goede .max_contacts = 5,
139a61f9e42SHans de Goede .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
140c81760b9SHans de Goede };
141c81760b9SHans de Goede
142c81760b9SHans de Goede static const struct asus_touchpad_info asus_t100ta_tp = {
143c81760b9SHans de Goede .max_x = 2240,
14425cc2611SHans de Goede .max_y = 1120,
145b61d43e6SHans de Goede .res_x = 30, /* units/mm */
146b61d43e6SHans de Goede .res_y = 27, /* units/mm */
147c81760b9SHans de Goede .contact_size = 5,
148c81760b9SHans de Goede .max_contacts = 5,
149a61f9e42SHans de Goede .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
150c81760b9SHans de Goede };
151c81760b9SHans de Goede
152762f948cSHans de Goede static const struct asus_touchpad_info asus_t100ha_tp = {
153762f948cSHans de Goede .max_x = 2640,
154762f948cSHans de Goede .max_y = 1320,
155762f948cSHans de Goede .res_x = 30, /* units/mm */
156762f948cSHans de Goede .res_y = 29, /* units/mm */
157762f948cSHans de Goede .contact_size = 5,
158762f948cSHans de Goede .max_contacts = 5,
159a61f9e42SHans de Goede .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
160762f948cSHans de Goede };
161762f948cSHans de Goede
162dbd3ef28SHans de Goede static const struct asus_touchpad_info asus_t200ta_tp = {
163dbd3ef28SHans de Goede .max_x = 3120,
164dbd3ef28SHans de Goede .max_y = 1716,
165dbd3ef28SHans de Goede .res_x = 30, /* units/mm */
166dbd3ef28SHans de Goede .res_y = 28, /* units/mm */
167dbd3ef28SHans de Goede .contact_size = 5,
168dbd3ef28SHans de Goede .max_contacts = 5,
169a61f9e42SHans de Goede .report_size = 28 /* 2 byte header + 5 * 5 + 1 byte footer */,
170dbd3ef28SHans de Goede };
171dbd3ef28SHans de Goede
17273c75d39SHans de Goede static const struct asus_touchpad_info asus_t100chi_tp = {
17373c75d39SHans de Goede .max_x = 2640,
17473c75d39SHans de Goede .max_y = 1320,
17573c75d39SHans de Goede .res_x = 31, /* units/mm */
17673c75d39SHans de Goede .res_y = 29, /* units/mm */
17773c75d39SHans de Goede .contact_size = 3,
17873c75d39SHans de Goede .max_contacts = 4,
179a61f9e42SHans de Goede .report_size = 15 /* 2 byte header + 3 * 4 + 1 byte footer */,
18073c75d39SHans de Goede };
18173c75d39SHans de Goede
182e271f6c2SHans de Goede static const struct asus_touchpad_info medion_e1239t_tp = {
183e271f6c2SHans de Goede .max_x = 2640,
184e271f6c2SHans de Goede .max_y = 1380,
185e271f6c2SHans de Goede .res_x = 29, /* units/mm */
186e271f6c2SHans de Goede .res_y = 28, /* units/mm */
187e271f6c2SHans de Goede .contact_size = 5,
188e271f6c2SHans de Goede .max_contacts = 5,
189e271f6c2SHans de Goede .report_size = 32 /* 2 byte header + 5 * 5 + 5 byte footer */,
190e271f6c2SHans de Goede };
191e271f6c2SHans de Goede
asus_report_contact_down(struct asus_drvdata * drvdat,int toolType,u8 * data)192c81760b9SHans de Goede static void asus_report_contact_down(struct asus_drvdata *drvdat,
1939ce12d8bSBrendan McGrath int toolType, u8 *data)
1949ce12d8bSBrendan McGrath {
195c81760b9SHans de Goede struct input_dev *input = drvdat->input;
196c81760b9SHans de Goede int touch_major, pressure, x, y;
197c81760b9SHans de Goede
198c81760b9SHans de Goede x = (data[0] & CONTACT_X_MSB_MASK) << 4 | data[1];
199c81760b9SHans de Goede y = drvdat->tp->max_y - ((data[0] & CONTACT_Y_MSB_MASK) << 8 | data[2]);
2009ce12d8bSBrendan McGrath
20173c75d39SHans de Goede input_report_abs(input, ABS_MT_POSITION_X, x);
20273c75d39SHans de Goede input_report_abs(input, ABS_MT_POSITION_Y, y);
20373c75d39SHans de Goede
20473c75d39SHans de Goede if (drvdat->tp->contact_size < 5)
20573c75d39SHans de Goede return;
20673c75d39SHans de Goede
2079ce12d8bSBrendan McGrath if (toolType == MT_TOOL_PALM) {
2089ce12d8bSBrendan McGrath touch_major = MAX_TOUCH_MAJOR;
2099ce12d8bSBrendan McGrath pressure = MAX_PRESSURE;
2109ce12d8bSBrendan McGrath } else {
2119ce12d8bSBrendan McGrath touch_major = (data[3] >> 4) & CONTACT_TOUCH_MAJOR_MASK;
2129ce12d8bSBrendan McGrath pressure = data[4] & CONTACT_PRESSURE_MASK;
2139ce12d8bSBrendan McGrath }
2149ce12d8bSBrendan McGrath
2159ce12d8bSBrendan McGrath input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major);
2169ce12d8bSBrendan McGrath input_report_abs(input, ABS_MT_PRESSURE, pressure);
2179ce12d8bSBrendan McGrath }
2189ce12d8bSBrendan McGrath
2199ce12d8bSBrendan McGrath /* Required for Synaptics Palm Detection */
asus_report_tool_width(struct asus_drvdata * drvdat)220c81760b9SHans de Goede static void asus_report_tool_width(struct asus_drvdata *drvdat)
2219ce12d8bSBrendan McGrath {
222c81760b9SHans de Goede struct input_mt *mt = drvdat->input->mt;
2239ce12d8bSBrendan McGrath struct input_mt_slot *oldest;
2247f9dbf54SColin Ian King int oldid, i;
2259ce12d8bSBrendan McGrath
22673c75d39SHans de Goede if (drvdat->tp->contact_size < 5)
22773c75d39SHans de Goede return;
22873c75d39SHans de Goede
2299ce12d8bSBrendan McGrath oldest = NULL;
2309ce12d8bSBrendan McGrath oldid = mt->trkid;
2319ce12d8bSBrendan McGrath
2329ce12d8bSBrendan McGrath for (i = 0; i < mt->num_slots; ++i) {
2339ce12d8bSBrendan McGrath struct input_mt_slot *ps = &mt->slots[i];
2349ce12d8bSBrendan McGrath int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
2359ce12d8bSBrendan McGrath
2369ce12d8bSBrendan McGrath if (id < 0)
2379ce12d8bSBrendan McGrath continue;
2389ce12d8bSBrendan McGrath if ((id - oldid) & TRKID_SGN) {
2399ce12d8bSBrendan McGrath oldest = ps;
2409ce12d8bSBrendan McGrath oldid = id;
2419ce12d8bSBrendan McGrath }
2429ce12d8bSBrendan McGrath }
2439ce12d8bSBrendan McGrath
2449ce12d8bSBrendan McGrath if (oldest) {
245c81760b9SHans de Goede input_report_abs(drvdat->input, ABS_TOOL_WIDTH,
2469ce12d8bSBrendan McGrath input_mt_get_value(oldest, ABS_MT_TOUCH_MAJOR));
2479ce12d8bSBrendan McGrath }
2489ce12d8bSBrendan McGrath }
2499ce12d8bSBrendan McGrath
asus_report_input(struct asus_drvdata * drvdat,u8 * data,int size)250c81760b9SHans de Goede static int asus_report_input(struct asus_drvdata *drvdat, u8 *data, int size)
2519ce12d8bSBrendan McGrath {
25273c75d39SHans de Goede int i, toolType = MT_TOOL_FINGER;
2539ce12d8bSBrendan McGrath u8 *contactData = data + 2;
2549ce12d8bSBrendan McGrath
255a61f9e42SHans de Goede if (size != drvdat->tp->report_size)
256c81760b9SHans de Goede return 0;
257c81760b9SHans de Goede
258c81760b9SHans de Goede for (i = 0; i < drvdat->tp->max_contacts; i++) {
2599ce12d8bSBrendan McGrath bool down = !!(data[1] & BIT(i+3));
26073c75d39SHans de Goede
26173c75d39SHans de Goede if (drvdat->tp->contact_size >= 5)
26273c75d39SHans de Goede toolType = contactData[3] & CONTACT_TOOL_TYPE_MASK ?
2639ce12d8bSBrendan McGrath MT_TOOL_PALM : MT_TOOL_FINGER;
2649ce12d8bSBrendan McGrath
265c81760b9SHans de Goede input_mt_slot(drvdat->input, i);
266c81760b9SHans de Goede input_mt_report_slot_state(drvdat->input, toolType, down);
2679ce12d8bSBrendan McGrath
2689ce12d8bSBrendan McGrath if (down) {
269c81760b9SHans de Goede asus_report_contact_down(drvdat, toolType, contactData);
270c81760b9SHans de Goede contactData += drvdat->tp->contact_size;
2719ce12d8bSBrendan McGrath }
2729ce12d8bSBrendan McGrath }
2739ce12d8bSBrendan McGrath
274c81760b9SHans de Goede input_report_key(drvdat->input, BTN_LEFT, data[1] & BTN_LEFT_MASK);
275c81760b9SHans de Goede asus_report_tool_width(drvdat);
2769ce12d8bSBrendan McGrath
277c81760b9SHans de Goede input_mt_sync_frame(drvdat->input);
278c81760b9SHans de Goede input_sync(drvdat->input);
279c81760b9SHans de Goede
280c81760b9SHans de Goede return 1;
2819ce12d8bSBrendan McGrath }
2829ce12d8bSBrendan McGrath
asus_e1239t_event(struct asus_drvdata * drvdat,u8 * data,int size)283350bd245SHans de Goede static int asus_e1239t_event(struct asus_drvdata *drvdat, u8 *data, int size)
284350bd245SHans de Goede {
285350bd245SHans de Goede if (size != 3)
286350bd245SHans de Goede return 0;
287350bd245SHans de Goede
288350bd245SHans de Goede /* Handle broken mute key which only sends press events */
289350bd245SHans de Goede if (!drvdat->tp &&
290350bd245SHans de Goede data[0] == 0x02 && data[1] == 0xe2 && data[2] == 0x00) {
291350bd245SHans de Goede input_report_key(drvdat->input, KEY_MUTE, 1);
292350bd245SHans de Goede input_sync(drvdat->input);
293350bd245SHans de Goede input_report_key(drvdat->input, KEY_MUTE, 0);
294350bd245SHans de Goede input_sync(drvdat->input);
295350bd245SHans de Goede return 1;
296350bd245SHans de Goede }
297350bd245SHans de Goede
298350bd245SHans de Goede /* Handle custom touchpad toggle key which only sends press events */
299350bd245SHans de Goede if (drvdat->tp_kbd_input &&
300350bd245SHans de Goede data[0] == 0x05 && data[1] == 0x02 && data[2] == 0x28) {
301350bd245SHans de Goede input_report_key(drvdat->tp_kbd_input, KEY_F21, 1);
302350bd245SHans de Goede input_sync(drvdat->tp_kbd_input);
303350bd245SHans de Goede input_report_key(drvdat->tp_kbd_input, KEY_F21, 0);
304350bd245SHans de Goede input_sync(drvdat->tp_kbd_input);
305350bd245SHans de Goede return 1;
306350bd245SHans de Goede }
307350bd245SHans de Goede
308350bd245SHans de Goede return 0;
309350bd245SHans de Goede }
310350bd245SHans de Goede
asus_event(struct hid_device * hdev,struct hid_field * field,struct hid_usage * usage,__s32 value)311e98e3809SHans de Goede static int asus_event(struct hid_device *hdev, struct hid_field *field,
312e98e3809SHans de Goede struct hid_usage *usage, __s32 value)
313e98e3809SHans de Goede {
314e98e3809SHans de Goede if ((usage->hid & HID_USAGE_PAGE) == 0xff310000 &&
315c07a0254SHans de Goede (usage->hid & HID_USAGE) != 0x00 &&
316c07a0254SHans de Goede (usage->hid & HID_USAGE) != 0xff && !usage->type) {
317e98e3809SHans de Goede hid_warn(hdev, "Unmapped Asus vendor usagepage code 0x%02x\n",
318e98e3809SHans de Goede usage->hid & HID_USAGE);
319e98e3809SHans de Goede }
320e98e3809SHans de Goede
321e98e3809SHans de Goede return 0;
322e98e3809SHans de Goede }
323e98e3809SHans de Goede
asus_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)3249ce12d8bSBrendan McGrath static int asus_raw_event(struct hid_device *hdev,
3259ce12d8bSBrendan McGrath struct hid_report *report, u8 *data, int size)
3269ce12d8bSBrendan McGrath {
3279ce12d8bSBrendan McGrath struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
3289ce12d8bSBrendan McGrath
3296311d329SNOGUCHI Hiroshi if (drvdata->battery && data[0] == BATTERY_REPORT_ID)
3306311d329SNOGUCHI Hiroshi return asus_report_battery(drvdata, data, size);
3316311d329SNOGUCHI Hiroshi
332c81760b9SHans de Goede if (drvdata->tp && data[0] == INPUT_REPORT_ID)
333c81760b9SHans de Goede return asus_report_input(drvdata, data, size);
3349ce12d8bSBrendan McGrath
335350bd245SHans de Goede if (drvdata->quirks & QUIRK_MEDION_E1239T)
336350bd245SHans de Goede return asus_e1239t_event(drvdata, data, size);
337350bd245SHans de Goede
338b92b8024SLuke D Jones /*
339b92b8024SLuke D Jones * Skip these report ID, the device emits a continuous stream associated
340b92b8024SLuke D Jones * with the AURA mode it is in which looks like an 'echo'.
341b92b8024SLuke D Jones */
34218fa9a90SLuke D. Jones if (report->id == FEATURE_KBD_LED_REPORT_ID1 || report->id == FEATURE_KBD_LED_REPORT_ID2)
343b92b8024SLuke D Jones return -1;
344c980512bSLuke D Jones if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
345c980512bSLuke D Jones /*
346c980512bSLuke D Jones * G713 and G733 send these codes on some keypresses, depending on
347c980512bSLuke D Jones * the key pressed it can trigger a shutdown event if not caught.
348c980512bSLuke D Jones */
349c980512bSLuke D Jones if (data[0] == 0x02 && data[1] == 0x30) {
350c980512bSLuke D Jones return -1;
351c980512bSLuke D Jones }
352c980512bSLuke D Jones }
353c980512bSLuke D Jones
35487c7ee7aSLuke D. Jones if (drvdata->quirks & QUIRK_ROG_CLAYMORE_II_KEYBOARD) {
35587c7ee7aSLuke D. Jones /*
35687c7ee7aSLuke D. Jones * CLAYMORE II keyboard sends this packet when it goes to sleep
35787c7ee7aSLuke D. Jones * this causes the whole system to go into suspend.
35887c7ee7aSLuke D. Jones */
35987c7ee7aSLuke D. Jones
36087c7ee7aSLuke D. Jones if(size == 2 && data[0] == 0x02 && data[1] == 0x00) {
36187c7ee7aSLuke D. Jones return -1;
36287c7ee7aSLuke D. Jones }
36387c7ee7aSLuke D. Jones }
36487c7ee7aSLuke D. Jones
3659ce12d8bSBrendan McGrath return 0;
3669ce12d8bSBrendan McGrath }
3679ce12d8bSBrendan McGrath
asus_kbd_set_report(struct hid_device * hdev,const u8 * buf,size_t buf_size)3685ce0fb87SDenis Benato static int asus_kbd_set_report(struct hid_device *hdev, const u8 *buf, size_t buf_size)
369af22a610SCarlo Caione {
370af22a610SCarlo Caione unsigned char *dmabuf;
371af22a610SCarlo Caione int ret;
372af22a610SCarlo Caione
373af22a610SCarlo Caione dmabuf = kmemdup(buf, buf_size, GFP_KERNEL);
374af22a610SCarlo Caione if (!dmabuf)
375af22a610SCarlo Caione return -ENOMEM;
376af22a610SCarlo Caione
377b92b8024SLuke D Jones /*
378b92b8024SLuke D Jones * The report ID should be set from the incoming buffer due to LED and key
379b92b8024SLuke D Jones * interfaces having different pages
380b92b8024SLuke D Jones */
381b92b8024SLuke D Jones ret = hid_hw_raw_request(hdev, buf[0], dmabuf,
382af22a610SCarlo Caione buf_size, HID_FEATURE_REPORT,
383af22a610SCarlo Caione HID_REQ_SET_REPORT);
384af22a610SCarlo Caione kfree(dmabuf);
385af22a610SCarlo Caione
386af22a610SCarlo Caione return ret;
387af22a610SCarlo Caione }
388af22a610SCarlo Caione
asus_kbd_init(struct hid_device * hdev)389af22a610SCarlo Caione static int asus_kbd_init(struct hid_device *hdev)
390af22a610SCarlo Caione {
3915ce0fb87SDenis Benato const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x41, 0x53, 0x55, 0x53, 0x20, 0x54,
392af22a610SCarlo Caione 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
393af22a610SCarlo Caione int ret;
394af22a610SCarlo Caione
395af22a610SCarlo Caione ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
396af22a610SCarlo Caione if (ret < 0)
397af22a610SCarlo Caione hid_err(hdev, "Asus failed to send init command: %d\n", ret);
398af22a610SCarlo Caione
399af22a610SCarlo Caione return ret;
400af22a610SCarlo Caione }
401af22a610SCarlo Caione
asus_kbd_get_functions(struct hid_device * hdev,unsigned char * kbd_func)402af22a610SCarlo Caione static int asus_kbd_get_functions(struct hid_device *hdev,
403af22a610SCarlo Caione unsigned char *kbd_func)
404af22a610SCarlo Caione {
4055ce0fb87SDenis Benato const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0x05, 0x20, 0x31, 0x00, 0x08 };
406af22a610SCarlo Caione u8 *readbuf;
407af22a610SCarlo Caione int ret;
408af22a610SCarlo Caione
409af22a610SCarlo Caione ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
410af22a610SCarlo Caione if (ret < 0) {
411af22a610SCarlo Caione hid_err(hdev, "Asus failed to send configuration command: %d\n", ret);
412af22a610SCarlo Caione return ret;
413af22a610SCarlo Caione }
414af22a610SCarlo Caione
415af22a610SCarlo Caione readbuf = kzalloc(FEATURE_KBD_REPORT_SIZE, GFP_KERNEL);
416af22a610SCarlo Caione if (!readbuf)
417af22a610SCarlo Caione return -ENOMEM;
418af22a610SCarlo Caione
419af22a610SCarlo Caione ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, readbuf,
420af22a610SCarlo Caione FEATURE_KBD_REPORT_SIZE, HID_FEATURE_REPORT,
421af22a610SCarlo Caione HID_REQ_GET_REPORT);
422af22a610SCarlo Caione if (ret < 0) {
423af22a610SCarlo Caione hid_err(hdev, "Asus failed to request functions: %d\n", ret);
424af22a610SCarlo Caione kfree(readbuf);
425af22a610SCarlo Caione return ret;
426af22a610SCarlo Caione }
427af22a610SCarlo Caione
428af22a610SCarlo Caione *kbd_func = readbuf[6];
429af22a610SCarlo Caione
430af22a610SCarlo Caione kfree(readbuf);
431af22a610SCarlo Caione return ret;
432af22a610SCarlo Caione }
433af22a610SCarlo Caione
rog_nkey_led_init(struct hid_device * hdev)434b92b8024SLuke D Jones static int rog_nkey_led_init(struct hid_device *hdev)
435b92b8024SLuke D Jones {
4365ce0fb87SDenis Benato const u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 };
437b92b8024SLuke D Jones u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20,
438b92b8024SLuke D Jones 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 };
439b92b8024SLuke D Jones u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1,
440b92b8024SLuke D Jones 0x05, 0x20, 0x31, 0x00, 0x08 };
441b92b8024SLuke D Jones int ret;
442b92b8024SLuke D Jones
443b92b8024SLuke D Jones hid_info(hdev, "Asus initialise N-KEY Device");
444b92b8024SLuke D Jones /* The first message is an init start */
445b92b8024SLuke D Jones ret = asus_kbd_set_report(hdev, buf_init_start, sizeof(buf_init_start));
446b92b8024SLuke D Jones if (ret < 0) {
447b92b8024SLuke D Jones hid_warn(hdev, "Asus failed to send init start command: %d\n", ret);
448b92b8024SLuke D Jones return ret;
449b92b8024SLuke D Jones }
450b92b8024SLuke D Jones /* Followed by a string */
451b92b8024SLuke D Jones ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2));
452b92b8024SLuke D Jones if (ret < 0) {
453b92b8024SLuke D Jones hid_warn(hdev, "Asus failed to send init command 1.0: %d\n", ret);
454b92b8024SLuke D Jones return ret;
455b92b8024SLuke D Jones }
456b92b8024SLuke D Jones /* Followed by a string */
457b92b8024SLuke D Jones ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3));
458b92b8024SLuke D Jones if (ret < 0) {
459b92b8024SLuke D Jones hid_warn(hdev, "Asus failed to send init command 1.1: %d\n", ret);
460b92b8024SLuke D Jones return ret;
461b92b8024SLuke D Jones }
462b92b8024SLuke D Jones
463b92b8024SLuke D Jones /* begin second report ID with same data */
464b92b8024SLuke D Jones buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2;
465b92b8024SLuke D Jones buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2;
466b92b8024SLuke D Jones
467b92b8024SLuke D Jones ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2));
468b92b8024SLuke D Jones if (ret < 0) {
469b92b8024SLuke D Jones hid_warn(hdev, "Asus failed to send init command 2.0: %d\n", ret);
470b92b8024SLuke D Jones return ret;
471b92b8024SLuke D Jones }
472b92b8024SLuke D Jones ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3));
473b92b8024SLuke D Jones if (ret < 0)
474b92b8024SLuke D Jones hid_warn(hdev, "Asus failed to send init command 2.1: %d\n", ret);
475b92b8024SLuke D Jones
476b92b8024SLuke D Jones return ret;
477b92b8024SLuke D Jones }
478b92b8024SLuke D Jones
asus_schedule_work(struct asus_kbd_leds * led)4794ab3a086SPietro Borrello static void asus_schedule_work(struct asus_kbd_leds *led)
4804ab3a086SPietro Borrello {
4814ab3a086SPietro Borrello unsigned long flags;
4824ab3a086SPietro Borrello
4834ab3a086SPietro Borrello spin_lock_irqsave(&led->lock, flags);
4844ab3a086SPietro Borrello if (!led->removed)
4854ab3a086SPietro Borrello schedule_work(&led->work);
4864ab3a086SPietro Borrello spin_unlock_irqrestore(&led->lock, flags);
4874ab3a086SPietro Borrello }
4884ab3a086SPietro Borrello
asus_kbd_backlight_set(struct led_classdev * led_cdev,enum led_brightness brightness)489af22a610SCarlo Caione static void asus_kbd_backlight_set(struct led_classdev *led_cdev,
490af22a610SCarlo Caione enum led_brightness brightness)
491af22a610SCarlo Caione {
492af22a610SCarlo Caione struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
493af22a610SCarlo Caione cdev);
494315c5370SPietro Borrello unsigned long flags;
495315c5370SPietro Borrello
496315c5370SPietro Borrello spin_lock_irqsave(&led->lock, flags);
497af22a610SCarlo Caione led->brightness = brightness;
498315c5370SPietro Borrello spin_unlock_irqrestore(&led->lock, flags);
499315c5370SPietro Borrello
5004ab3a086SPietro Borrello asus_schedule_work(led);
501af22a610SCarlo Caione }
502af22a610SCarlo Caione
asus_kbd_backlight_get(struct led_classdev * led_cdev)503af22a610SCarlo Caione static enum led_brightness asus_kbd_backlight_get(struct led_classdev *led_cdev)
504af22a610SCarlo Caione {
505af22a610SCarlo Caione struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds,
506af22a610SCarlo Caione cdev);
507315c5370SPietro Borrello enum led_brightness brightness;
508315c5370SPietro Borrello unsigned long flags;
509af22a610SCarlo Caione
510315c5370SPietro Borrello spin_lock_irqsave(&led->lock, flags);
511315c5370SPietro Borrello brightness = led->brightness;
512315c5370SPietro Borrello spin_unlock_irqrestore(&led->lock, flags);
513315c5370SPietro Borrello
514315c5370SPietro Borrello return brightness;
515af22a610SCarlo Caione }
516af22a610SCarlo Caione
asus_kbd_backlight_work(struct work_struct * work)517af22a610SCarlo Caione static void asus_kbd_backlight_work(struct work_struct *work)
518af22a610SCarlo Caione {
519af22a610SCarlo Caione struct asus_kbd_leds *led = container_of(work, struct asus_kbd_leds, work);
520af22a610SCarlo Caione u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4, 0x00 };
521af22a610SCarlo Caione int ret;
522315c5370SPietro Borrello unsigned long flags;
523af22a610SCarlo Caione
524315c5370SPietro Borrello spin_lock_irqsave(&led->lock, flags);
525af22a610SCarlo Caione buf[4] = led->brightness;
526315c5370SPietro Borrello spin_unlock_irqrestore(&led->lock, flags);
527af22a610SCarlo Caione
528af22a610SCarlo Caione ret = asus_kbd_set_report(led->hdev, buf, sizeof(buf));
529af22a610SCarlo Caione if (ret < 0)
530af22a610SCarlo Caione hid_err(led->hdev, "Asus failed to set keyboard backlight: %d\n", ret);
531af22a610SCarlo Caione }
532af22a610SCarlo Caione
5333b692c55SDaniel Drake /* WMI-based keyboard backlight LED control (via asus-wmi driver) takes
5343b692c55SDaniel Drake * precedence. We only activate HID-based backlight control when the
5353b692c55SDaniel Drake * WMI control is not available.
5363b692c55SDaniel Drake */
asus_kbd_wmi_led_control_present(struct hid_device * hdev)5373b692c55SDaniel Drake static bool asus_kbd_wmi_led_control_present(struct hid_device *hdev)
5383b692c55SDaniel Drake {
5393b692c55SDaniel Drake u32 value;
5403b692c55SDaniel Drake int ret;
5413b692c55SDaniel Drake
5423fc202e8SArnd Bergmann if (!IS_ENABLED(CONFIG_ASUS_WMI))
5433fc202e8SArnd Bergmann return false;
5443fc202e8SArnd Bergmann
545e0668f28SYurii Pavlovskyi ret = asus_wmi_evaluate_method(ASUS_WMI_METHODID_DSTS,
5463b692c55SDaniel Drake ASUS_WMI_DEVID_KBD_BACKLIGHT, 0, &value);
5473b692c55SDaniel Drake hid_dbg(hdev, "WMI backlight check: rc %d value %x", ret, value);
5483b692c55SDaniel Drake if (ret)
5493b692c55SDaniel Drake return false;
5503b692c55SDaniel Drake
5513b692c55SDaniel Drake return !!(value & ASUS_WMI_DSTS_PRESENCE_BIT);
5523b692c55SDaniel Drake }
5533b692c55SDaniel Drake
asus_kbd_register_leds(struct hid_device * hdev)554af22a610SCarlo Caione static int asus_kbd_register_leds(struct hid_device *hdev)
555af22a610SCarlo Caione {
556af22a610SCarlo Caione struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
557af22a610SCarlo Caione unsigned char kbd_func;
558af22a610SCarlo Caione int ret;
559af22a610SCarlo Caione
560b92b8024SLuke D Jones if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) {
561b92b8024SLuke D Jones ret = rog_nkey_led_init(hdev);
562b92b8024SLuke D Jones if (ret < 0)
563b92b8024SLuke D Jones return ret;
564b92b8024SLuke D Jones } else {
565af22a610SCarlo Caione /* Initialize keyboard */
566af22a610SCarlo Caione ret = asus_kbd_init(hdev);
567af22a610SCarlo Caione if (ret < 0)
568af22a610SCarlo Caione return ret;
569af22a610SCarlo Caione
570af22a610SCarlo Caione /* Get keyboard functions */
571af22a610SCarlo Caione ret = asus_kbd_get_functions(hdev, &kbd_func);
572af22a610SCarlo Caione if (ret < 0)
573af22a610SCarlo Caione return ret;
574af22a610SCarlo Caione
575af22a610SCarlo Caione /* Check for backlight support */
576af22a610SCarlo Caione if (!(kbd_func & SUPPORT_KBD_BACKLIGHT))
577af22a610SCarlo Caione return -ENODEV;
578b92b8024SLuke D Jones }
579af22a610SCarlo Caione
580af22a610SCarlo Caione drvdata->kbd_backlight = devm_kzalloc(&hdev->dev,
581af22a610SCarlo Caione sizeof(struct asus_kbd_leds),
582af22a610SCarlo Caione GFP_KERNEL);
583af22a610SCarlo Caione if (!drvdata->kbd_backlight)
584af22a610SCarlo Caione return -ENOMEM;
585af22a610SCarlo Caione
586af22a610SCarlo Caione drvdata->kbd_backlight->removed = false;
587af22a610SCarlo Caione drvdata->kbd_backlight->brightness = 0;
588af22a610SCarlo Caione drvdata->kbd_backlight->hdev = hdev;
589af22a610SCarlo Caione drvdata->kbd_backlight->cdev.name = "asus::kbd_backlight";
590af22a610SCarlo Caione drvdata->kbd_backlight->cdev.max_brightness = 3;
591af22a610SCarlo Caione drvdata->kbd_backlight->cdev.brightness_set = asus_kbd_backlight_set;
592af22a610SCarlo Caione drvdata->kbd_backlight->cdev.brightness_get = asus_kbd_backlight_get;
593af22a610SCarlo Caione INIT_WORK(&drvdata->kbd_backlight->work, asus_kbd_backlight_work);
594315c5370SPietro Borrello spin_lock_init(&drvdata->kbd_backlight->lock);
595af22a610SCarlo Caione
596af22a610SCarlo Caione ret = devm_led_classdev_register(&hdev->dev, &drvdata->kbd_backlight->cdev);
597af22a610SCarlo Caione if (ret < 0) {
598af22a610SCarlo Caione /* No need to have this still around */
599af22a610SCarlo Caione devm_kfree(&hdev->dev, drvdata->kbd_backlight);
600af22a610SCarlo Caione }
601af22a610SCarlo Caione
602af22a610SCarlo Caione return ret;
603af22a610SCarlo Caione }
604af22a610SCarlo Caione
6056311d329SNOGUCHI Hiroshi /*
6066311d329SNOGUCHI Hiroshi * [0] REPORT_ID (same value defined in report descriptor)
6076311d329SNOGUCHI Hiroshi * [1] rest battery level. range [0..255]
6086311d329SNOGUCHI Hiroshi * [2]..[7] Bluetooth hardware address (MAC address)
6096311d329SNOGUCHI Hiroshi * [8] charging status
6106311d329SNOGUCHI Hiroshi * = 0 : AC offline / discharging
6116311d329SNOGUCHI Hiroshi * = 1 : AC online / charging
6126311d329SNOGUCHI Hiroshi * = 2 : AC online / fully charged
6136311d329SNOGUCHI Hiroshi */
asus_parse_battery(struct asus_drvdata * drvdata,u8 * data,int size)6146311d329SNOGUCHI Hiroshi static int asus_parse_battery(struct asus_drvdata *drvdata, u8 *data, int size)
6156311d329SNOGUCHI Hiroshi {
6166311d329SNOGUCHI Hiroshi u8 sts;
6176311d329SNOGUCHI Hiroshi u8 lvl;
6186311d329SNOGUCHI Hiroshi int val;
6196311d329SNOGUCHI Hiroshi
6206311d329SNOGUCHI Hiroshi lvl = data[1];
6216311d329SNOGUCHI Hiroshi sts = data[8];
6226311d329SNOGUCHI Hiroshi
6236311d329SNOGUCHI Hiroshi drvdata->battery_capacity = ((int)lvl * 100) / (int)BATTERY_LEVEL_MAX;
6246311d329SNOGUCHI Hiroshi
6256311d329SNOGUCHI Hiroshi switch (sts) {
6266311d329SNOGUCHI Hiroshi case BATTERY_STAT_CHARGING:
6276311d329SNOGUCHI Hiroshi val = POWER_SUPPLY_STATUS_CHARGING;
6286311d329SNOGUCHI Hiroshi break;
6296311d329SNOGUCHI Hiroshi case BATTERY_STAT_FULL:
6306311d329SNOGUCHI Hiroshi val = POWER_SUPPLY_STATUS_FULL;
6316311d329SNOGUCHI Hiroshi break;
6326311d329SNOGUCHI Hiroshi case BATTERY_STAT_DISCONNECT:
6336311d329SNOGUCHI Hiroshi default:
6346311d329SNOGUCHI Hiroshi val = POWER_SUPPLY_STATUS_DISCHARGING;
6356311d329SNOGUCHI Hiroshi break;
6366311d329SNOGUCHI Hiroshi }
6376311d329SNOGUCHI Hiroshi drvdata->battery_stat = val;
6386311d329SNOGUCHI Hiroshi
6396311d329SNOGUCHI Hiroshi return 0;
6406311d329SNOGUCHI Hiroshi }
6416311d329SNOGUCHI Hiroshi
asus_report_battery(struct asus_drvdata * drvdata,u8 * data,int size)6426311d329SNOGUCHI Hiroshi static int asus_report_battery(struct asus_drvdata *drvdata, u8 *data, int size)
6436311d329SNOGUCHI Hiroshi {
6446311d329SNOGUCHI Hiroshi /* notify only the autonomous event by device */
6456311d329SNOGUCHI Hiroshi if ((drvdata->battery_in_query == false) &&
6466311d329SNOGUCHI Hiroshi (size == BATTERY_REPORT_SIZE))
6476311d329SNOGUCHI Hiroshi power_supply_changed(drvdata->battery);
6486311d329SNOGUCHI Hiroshi
6496311d329SNOGUCHI Hiroshi return 0;
6506311d329SNOGUCHI Hiroshi }
6516311d329SNOGUCHI Hiroshi
asus_battery_query(struct asus_drvdata * drvdata)6526311d329SNOGUCHI Hiroshi static int asus_battery_query(struct asus_drvdata *drvdata)
6536311d329SNOGUCHI Hiroshi {
6546311d329SNOGUCHI Hiroshi u8 *buf;
6556311d329SNOGUCHI Hiroshi int ret = 0;
6566311d329SNOGUCHI Hiroshi
6576311d329SNOGUCHI Hiroshi buf = kmalloc(BATTERY_REPORT_SIZE, GFP_KERNEL);
6586311d329SNOGUCHI Hiroshi if (!buf)
6596311d329SNOGUCHI Hiroshi return -ENOMEM;
6606311d329SNOGUCHI Hiroshi
6616311d329SNOGUCHI Hiroshi drvdata->battery_in_query = true;
6626311d329SNOGUCHI Hiroshi ret = hid_hw_raw_request(drvdata->hdev, BATTERY_REPORT_ID,
6636311d329SNOGUCHI Hiroshi buf, BATTERY_REPORT_SIZE,
6646311d329SNOGUCHI Hiroshi HID_INPUT_REPORT, HID_REQ_GET_REPORT);
6656311d329SNOGUCHI Hiroshi drvdata->battery_in_query = false;
6666311d329SNOGUCHI Hiroshi if (ret == BATTERY_REPORT_SIZE)
6676311d329SNOGUCHI Hiroshi ret = asus_parse_battery(drvdata, buf, BATTERY_REPORT_SIZE);
6686311d329SNOGUCHI Hiroshi else
6696311d329SNOGUCHI Hiroshi ret = -ENODATA;
6706311d329SNOGUCHI Hiroshi
6716311d329SNOGUCHI Hiroshi kfree(buf);
6726311d329SNOGUCHI Hiroshi
6736311d329SNOGUCHI Hiroshi return ret;
6746311d329SNOGUCHI Hiroshi }
6756311d329SNOGUCHI Hiroshi
6766311d329SNOGUCHI Hiroshi static enum power_supply_property asus_battery_props[] = {
6776311d329SNOGUCHI Hiroshi POWER_SUPPLY_PROP_STATUS,
6786311d329SNOGUCHI Hiroshi POWER_SUPPLY_PROP_PRESENT,
6796311d329SNOGUCHI Hiroshi POWER_SUPPLY_PROP_CAPACITY,
6806311d329SNOGUCHI Hiroshi POWER_SUPPLY_PROP_SCOPE,
6816311d329SNOGUCHI Hiroshi POWER_SUPPLY_PROP_MODEL_NAME,
6826311d329SNOGUCHI Hiroshi };
6836311d329SNOGUCHI Hiroshi
6846311d329SNOGUCHI Hiroshi #define QUERY_MIN_INTERVAL (60 * HZ) /* 60[sec] */
6856311d329SNOGUCHI Hiroshi
asus_battery_get_property(struct power_supply * psy,enum power_supply_property psp,union power_supply_propval * val)6866311d329SNOGUCHI Hiroshi static int asus_battery_get_property(struct power_supply *psy,
6876311d329SNOGUCHI Hiroshi enum power_supply_property psp,
6886311d329SNOGUCHI Hiroshi union power_supply_propval *val)
6896311d329SNOGUCHI Hiroshi {
6906311d329SNOGUCHI Hiroshi struct asus_drvdata *drvdata = power_supply_get_drvdata(psy);
6916311d329SNOGUCHI Hiroshi int ret = 0;
6926311d329SNOGUCHI Hiroshi
6936311d329SNOGUCHI Hiroshi switch (psp) {
6946311d329SNOGUCHI Hiroshi case POWER_SUPPLY_PROP_STATUS:
6956311d329SNOGUCHI Hiroshi case POWER_SUPPLY_PROP_CAPACITY:
6966311d329SNOGUCHI Hiroshi if (time_before(drvdata->battery_next_query, jiffies)) {
6976311d329SNOGUCHI Hiroshi drvdata->battery_next_query =
6986311d329SNOGUCHI Hiroshi jiffies + QUERY_MIN_INTERVAL;
6996311d329SNOGUCHI Hiroshi ret = asus_battery_query(drvdata);
7006311d329SNOGUCHI Hiroshi if (ret)
7016311d329SNOGUCHI Hiroshi return ret;
7026311d329SNOGUCHI Hiroshi }
7036311d329SNOGUCHI Hiroshi if (psp == POWER_SUPPLY_PROP_STATUS)
7046311d329SNOGUCHI Hiroshi val->intval = drvdata->battery_stat;
7056311d329SNOGUCHI Hiroshi else
7066311d329SNOGUCHI Hiroshi val->intval = drvdata->battery_capacity;
7076311d329SNOGUCHI Hiroshi break;
7086311d329SNOGUCHI Hiroshi case POWER_SUPPLY_PROP_PRESENT:
7096311d329SNOGUCHI Hiroshi val->intval = 1;
7106311d329SNOGUCHI Hiroshi break;
7116311d329SNOGUCHI Hiroshi case POWER_SUPPLY_PROP_SCOPE:
7126311d329SNOGUCHI Hiroshi val->intval = POWER_SUPPLY_SCOPE_DEVICE;
7136311d329SNOGUCHI Hiroshi break;
7146311d329SNOGUCHI Hiroshi case POWER_SUPPLY_PROP_MODEL_NAME:
7156311d329SNOGUCHI Hiroshi val->strval = drvdata->hdev->name;
7166311d329SNOGUCHI Hiroshi break;
7176311d329SNOGUCHI Hiroshi default:
7186311d329SNOGUCHI Hiroshi ret = -EINVAL;
7196311d329SNOGUCHI Hiroshi break;
7206311d329SNOGUCHI Hiroshi }
7216311d329SNOGUCHI Hiroshi
7226311d329SNOGUCHI Hiroshi return ret;
7236311d329SNOGUCHI Hiroshi }
7246311d329SNOGUCHI Hiroshi
asus_battery_probe(struct hid_device * hdev)7256311d329SNOGUCHI Hiroshi static int asus_battery_probe(struct hid_device *hdev)
7266311d329SNOGUCHI Hiroshi {
7276311d329SNOGUCHI Hiroshi struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
7286311d329SNOGUCHI Hiroshi struct power_supply_config pscfg = { .drv_data = drvdata };
7296311d329SNOGUCHI Hiroshi int ret = 0;
7306311d329SNOGUCHI Hiroshi
7316311d329SNOGUCHI Hiroshi drvdata->battery_capacity = 0;
7326311d329SNOGUCHI Hiroshi drvdata->battery_stat = POWER_SUPPLY_STATUS_UNKNOWN;
7336311d329SNOGUCHI Hiroshi drvdata->battery_in_query = false;
7346311d329SNOGUCHI Hiroshi
7356311d329SNOGUCHI Hiroshi drvdata->battery_desc.properties = asus_battery_props;
7366311d329SNOGUCHI Hiroshi drvdata->battery_desc.num_properties = ARRAY_SIZE(asus_battery_props);
7376311d329SNOGUCHI Hiroshi drvdata->battery_desc.get_property = asus_battery_get_property;
7386311d329SNOGUCHI Hiroshi drvdata->battery_desc.type = POWER_SUPPLY_TYPE_BATTERY;
7396311d329SNOGUCHI Hiroshi drvdata->battery_desc.use_for_apm = 0;
7406311d329SNOGUCHI Hiroshi drvdata->battery_desc.name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
7416311d329SNOGUCHI Hiroshi "asus-keyboard-%s-battery",
7426311d329SNOGUCHI Hiroshi strlen(hdev->uniq) ?
7436311d329SNOGUCHI Hiroshi hdev->uniq : dev_name(&hdev->dev));
7446311d329SNOGUCHI Hiroshi if (!drvdata->battery_desc.name)
7456311d329SNOGUCHI Hiroshi return -ENOMEM;
7466311d329SNOGUCHI Hiroshi
7476311d329SNOGUCHI Hiroshi drvdata->battery_next_query = jiffies;
7486311d329SNOGUCHI Hiroshi
7496311d329SNOGUCHI Hiroshi drvdata->battery = devm_power_supply_register(&hdev->dev,
7506311d329SNOGUCHI Hiroshi &(drvdata->battery_desc), &pscfg);
7516311d329SNOGUCHI Hiroshi if (IS_ERR(drvdata->battery)) {
7526311d329SNOGUCHI Hiroshi ret = PTR_ERR(drvdata->battery);
7536311d329SNOGUCHI Hiroshi drvdata->battery = NULL;
7546311d329SNOGUCHI Hiroshi hid_err(hdev, "Unable to register battery device\n");
7556311d329SNOGUCHI Hiroshi return ret;
7566311d329SNOGUCHI Hiroshi }
7576311d329SNOGUCHI Hiroshi
7586311d329SNOGUCHI Hiroshi power_supply_powers(drvdata->battery, &hdev->dev);
7596311d329SNOGUCHI Hiroshi
7606311d329SNOGUCHI Hiroshi return ret;
7616311d329SNOGUCHI Hiroshi }
7626311d329SNOGUCHI Hiroshi
asus_input_configured(struct hid_device * hdev,struct hid_input * hi)7639ce12d8bSBrendan McGrath static int asus_input_configured(struct hid_device *hdev, struct hid_input *hi)
7649ce12d8bSBrendan McGrath {
765c8b1b3ddSBrendan McGrath struct input_dev *input = hi->input;
7669ce12d8bSBrendan McGrath struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
7679ce12d8bSBrendan McGrath
76873c75d39SHans de Goede /* T100CHI uses MULTI_INPUT, bind the touchpad to the mouse hid_input */
76973c75d39SHans de Goede if (drvdata->quirks & QUIRK_T100CHI &&
77073c75d39SHans de Goede hi->report->id != T100CHI_MOUSE_REPORT_ID)
77173c75d39SHans de Goede return 0;
77273c75d39SHans de Goede
773350bd245SHans de Goede /* Handle MULTI_INPUT on E1239T mouse/touchpad USB interface */
774350bd245SHans de Goede if (drvdata->tp && (drvdata->quirks & QUIRK_MEDION_E1239T)) {
775350bd245SHans de Goede switch (hi->report->id) {
776350bd245SHans de Goede case E1239T_TP_TOGGLE_REPORT_ID:
777350bd245SHans de Goede input_set_capability(input, EV_KEY, KEY_F21);
778350bd245SHans de Goede input->name = "Asus Touchpad Keys";
779350bd245SHans de Goede drvdata->tp_kbd_input = input;
780350bd245SHans de Goede return 0;
781350bd245SHans de Goede case INPUT_REPORT_ID:
782350bd245SHans de Goede break; /* Touchpad report, handled below */
783350bd245SHans de Goede default:
784350bd245SHans de Goede return 0; /* Ignore other reports */
785350bd245SHans de Goede }
786350bd245SHans de Goede }
787350bd245SHans de Goede
788c81760b9SHans de Goede if (drvdata->tp) {
7899ce12d8bSBrendan McGrath int ret;
7909ce12d8bSBrendan McGrath
791c81760b9SHans de Goede input_set_abs_params(input, ABS_MT_POSITION_X, 0,
792c81760b9SHans de Goede drvdata->tp->max_x, 0, 0);
793c81760b9SHans de Goede input_set_abs_params(input, ABS_MT_POSITION_Y, 0,
794c81760b9SHans de Goede drvdata->tp->max_y, 0, 0);
795b61d43e6SHans de Goede input_abs_set_res(input, ABS_MT_POSITION_X, drvdata->tp->res_x);
796b61d43e6SHans de Goede input_abs_set_res(input, ABS_MT_POSITION_Y, drvdata->tp->res_y);
79773c75d39SHans de Goede
79873c75d39SHans de Goede if (drvdata->tp->contact_size >= 5) {
79973c75d39SHans de Goede input_set_abs_params(input, ABS_TOOL_WIDTH, 0,
80073c75d39SHans de Goede MAX_TOUCH_MAJOR, 0, 0);
80173c75d39SHans de Goede input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0,
80273c75d39SHans de Goede MAX_TOUCH_MAJOR, 0, 0);
80373c75d39SHans de Goede input_set_abs_params(input, ABS_MT_PRESSURE, 0,
80473c75d39SHans de Goede MAX_PRESSURE, 0, 0);
80573c75d39SHans de Goede }
8069ce12d8bSBrendan McGrath
8079ce12d8bSBrendan McGrath __set_bit(BTN_LEFT, input->keybit);
8089ce12d8bSBrendan McGrath __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
8099ce12d8bSBrendan McGrath
810c81760b9SHans de Goede ret = input_mt_init_slots(input, drvdata->tp->max_contacts,
811c81760b9SHans de Goede INPUT_MT_POINTER);
8129ce12d8bSBrendan McGrath
8139ce12d8bSBrendan McGrath if (ret) {
8149ce12d8bSBrendan McGrath hid_err(hdev, "Asus input mt init slots failed: %d\n", ret);
8159ce12d8bSBrendan McGrath return ret;
8169ce12d8bSBrendan McGrath }
817c8b1b3ddSBrendan McGrath }
8189ce12d8bSBrendan McGrath
8199ce12d8bSBrendan McGrath drvdata->input = input;
8209ce12d8bSBrendan McGrath
8213b692c55SDaniel Drake if (drvdata->enable_backlight &&
8223b692c55SDaniel Drake !asus_kbd_wmi_led_control_present(hdev) &&
8233b692c55SDaniel Drake asus_kbd_register_leds(hdev))
824af22a610SCarlo Caione hid_warn(hdev, "Failed to initialize backlight.\n");
825af22a610SCarlo Caione
8269ce12d8bSBrendan McGrath return 0;
8279ce12d8bSBrendan McGrath }
8289ce12d8bSBrendan McGrath
829a93913e1SMatjaz Hegedic #define asus_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, \
8301caccc25SChris Chiu max, EV_KEY, (c))
asus_input_mapping(struct hid_device * hdev,struct hid_input * hi,struct hid_field * field,struct hid_usage * usage,unsigned long ** bit,int * max)8319ce12d8bSBrendan McGrath static int asus_input_mapping(struct hid_device *hdev,
8329ce12d8bSBrendan McGrath struct hid_input *hi, struct hid_field *field,
8339ce12d8bSBrendan McGrath struct hid_usage *usage, unsigned long **bit,
8349ce12d8bSBrendan McGrath int *max)
8359ce12d8bSBrendan McGrath {
8369ce12d8bSBrendan McGrath struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
8379ce12d8bSBrendan McGrath
8389ce12d8bSBrendan McGrath if (drvdata->quirks & QUIRK_SKIP_INPUT_MAPPING) {
8399ce12d8bSBrendan McGrath /* Don't map anything from the HID report.
8409ce12d8bSBrendan McGrath * We do it all manually in asus_input_configured
8419ce12d8bSBrendan McGrath */
8429ce12d8bSBrendan McGrath return -1;
8439ce12d8bSBrendan McGrath }
8449ce12d8bSBrendan McGrath
84573c75d39SHans de Goede /*
84673c75d39SHans de Goede * Ignore a bunch of bogus collections in the T100CHI descriptor.
84773c75d39SHans de Goede * This avoids a bunch of non-functional hid_input devices getting
84873c75d39SHans de Goede * created because of the T100CHI using HID_QUIRK_MULTI_INPUT.
84973c75d39SHans de Goede */
850a80b2f30SHans de Goede if ((drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) &&
851a80b2f30SHans de Goede (field->application == (HID_UP_GENDESK | 0x0080) ||
852a80b2f30SHans de Goede field->application == HID_GD_MOUSE ||
85373c75d39SHans de Goede usage->hid == (HID_UP_GENDEVCTRLS | 0x0024) ||
85473c75d39SHans de Goede usage->hid == (HID_UP_GENDEVCTRLS | 0x0025) ||
855a80b2f30SHans de Goede usage->hid == (HID_UP_GENDEVCTRLS | 0x0026)))
85673c75d39SHans de Goede return -1;
85773c75d39SHans de Goede
858b92b8024SLuke D Jones /* ASUS-specific keyboard hotkeys and led backlight */
859b92b8024SLuke D Jones if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) {
8601caccc25SChris Chiu switch (usage->hid & HID_USAGE) {
861a93913e1SMatjaz Hegedic case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break;
862a93913e1SMatjaz Hegedic case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
863e3d9234fSVinícius Angiolucci Reis case 0x35: asus_map_key_clear(KEY_DISPLAY_OFF); break;
864a93913e1SMatjaz Hegedic case 0x6c: asus_map_key_clear(KEY_SLEEP); break;
8652340bad5SHans de Goede case 0x7c: asus_map_key_clear(KEY_MICMUTE); break;
866a93913e1SMatjaz Hegedic case 0x82: asus_map_key_clear(KEY_CAMERA); break;
867802b24b4SMatjaz Hegedic case 0x88: asus_map_key_clear(KEY_RFKILL); break;
868a93913e1SMatjaz Hegedic case 0xb5: asus_map_key_clear(KEY_CALC); break;
869a93913e1SMatjaz Hegedic case 0xc4: asus_map_key_clear(KEY_KBDILLUMUP); break;
870a93913e1SMatjaz Hegedic case 0xc5: asus_map_key_clear(KEY_KBDILLUMDOWN); break;
87173920f61SLuke D. Jones case 0xc7: asus_map_key_clear(KEY_KBDILLUMTOGGLE); break;
8721caccc25SChris Chiu
873e6c7e271SLuke D. Jones case 0x6b: asus_map_key_clear(KEY_F21); break; /* ASUS touchpad toggle */
874e6c7e271SLuke D. Jones case 0x38: asus_map_key_clear(KEY_PROG1); break; /* ROG key */
875e6c7e271SLuke D. Jones case 0xba: asus_map_key_clear(KEY_PROG2); break; /* Fn+C ASUS Splendid */
876e6c7e271SLuke D. Jones case 0x5c: asus_map_key_clear(KEY_PROG3); break; /* Fn+Space Power4Gear */
877e6c7e271SLuke D. Jones case 0x99: asus_map_key_clear(KEY_PROG4); break; /* Fn+F5 "fan" symbol */
878e6c7e271SLuke D. Jones case 0xae: asus_map_key_clear(KEY_PROG4); break; /* Fn+F5 "fan" symbol */
879e6c7e271SLuke D. Jones case 0x92: asus_map_key_clear(KEY_CALC); break; /* Fn+Ret "Calc" symbol */
880e6c7e271SLuke D. Jones case 0xb2: asus_map_key_clear(KEY_PROG2); break; /* Fn+Left previous aura */
881e6c7e271SLuke D. Jones case 0xb3: asus_map_key_clear(KEY_PROG3); break; /* Fn+Left next aura */
882e6c7e271SLuke D. Jones case 0x6a: asus_map_key_clear(KEY_F13); break; /* Screenpad toggle */
883e6c7e271SLuke D. Jones case 0x4b: asus_map_key_clear(KEY_F14); break; /* Arrows/Pg-Up/Dn toggle */
8845ec4596aSLuke D. Jones case 0xa5: asus_map_key_clear(KEY_F15); break; /* ROG Ally left back */
8855ec4596aSLuke D. Jones case 0xa6: asus_map_key_clear(KEY_F16); break; /* ROG Ally QAM button */
8865ec4596aSLuke D. Jones case 0xa7: asus_map_key_clear(KEY_F17); break; /* ROG Ally ROG long-press */
8875ec4596aSLuke D. Jones case 0xa8: asus_map_key_clear(KEY_F18); break; /* ROG Ally ROG long-press-release */
88873920f61SLuke D. Jones
8891caccc25SChris Chiu default:
8900485b1ecSMatjaz Hegedic /* ASUS lazily declares 256 usages, ignore the rest,
8910485b1ecSMatjaz Hegedic * as some make the keyboard appear as a pointer device. */
8920485b1ecSMatjaz Hegedic return -1;
8931caccc25SChris Chiu }
894af22a610SCarlo Caione
895af22a610SCarlo Caione /*
896af22a610SCarlo Caione * Check and enable backlight only on devices with UsagePage ==
897af22a610SCarlo Caione * 0xff31 to avoid initializing the keyboard firmware multiple
898af22a610SCarlo Caione * times on devices with multiple HID descriptors but same
899af22a610SCarlo Caione * PID/VID.
900af22a610SCarlo Caione */
901af22a610SCarlo Caione if (drvdata->quirks & QUIRK_USE_KBD_BACKLIGHT)
902af22a610SCarlo Caione drvdata->enable_backlight = true;
903af22a610SCarlo Caione
9044e4c60f8SHans de Goede set_bit(EV_REP, hi->input->evbit);
9051caccc25SChris Chiu return 1;
9061caccc25SChris Chiu }
9071caccc25SChris Chiu
9085be91803SDaniel Drake if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) {
9095be91803SDaniel Drake switch (usage->hid & HID_USAGE) {
9105be91803SDaniel Drake case 0xff01: asus_map_key_clear(BTN_1); break;
9115be91803SDaniel Drake case 0xff02: asus_map_key_clear(BTN_2); break;
9125be91803SDaniel Drake case 0xff03: asus_map_key_clear(BTN_3); break;
9135be91803SDaniel Drake case 0xff04: asus_map_key_clear(BTN_4); break;
9145be91803SDaniel Drake case 0xff05: asus_map_key_clear(BTN_5); break;
9155be91803SDaniel Drake case 0xff06: asus_map_key_clear(BTN_6); break;
9165be91803SDaniel Drake case 0xff07: asus_map_key_clear(BTN_7); break;
9175be91803SDaniel Drake case 0xff08: asus_map_key_clear(BTN_8); break;
9185be91803SDaniel Drake case 0xff09: asus_map_key_clear(BTN_9); break;
9195be91803SDaniel Drake case 0xff0a: asus_map_key_clear(BTN_A); break;
9205be91803SDaniel Drake case 0xff0b: asus_map_key_clear(BTN_B); break;
9215be91803SDaniel Drake case 0x00f1: asus_map_key_clear(KEY_WLAN); break;
9225be91803SDaniel Drake case 0x00f2: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break;
9235be91803SDaniel Drake case 0x00f3: asus_map_key_clear(KEY_BRIGHTNESSUP); break;
9245be91803SDaniel Drake case 0x00f4: asus_map_key_clear(KEY_DISPLAY_OFF); break;
9255be91803SDaniel Drake case 0x00f7: asus_map_key_clear(KEY_CAMERA); break;
9265be91803SDaniel Drake case 0x00f8: asus_map_key_clear(KEY_PROG1); break;
9275be91803SDaniel Drake default:
9285be91803SDaniel Drake return 0;
9295be91803SDaniel Drake }
9305be91803SDaniel Drake
9314e4c60f8SHans de Goede set_bit(EV_REP, hi->input->evbit);
9325be91803SDaniel Drake return 1;
9335be91803SDaniel Drake }
9345be91803SDaniel Drake
9350485b1ecSMatjaz Hegedic if (drvdata->quirks & QUIRK_NO_CONSUMER_USAGES &&
9360485b1ecSMatjaz Hegedic (usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER) {
9370485b1ecSMatjaz Hegedic switch (usage->hid & HID_USAGE) {
9380485b1ecSMatjaz Hegedic case 0xe2: /* Mute */
9390485b1ecSMatjaz Hegedic case 0xe9: /* Volume up */
9400485b1ecSMatjaz Hegedic case 0xea: /* Volume down */
9410485b1ecSMatjaz Hegedic return 0;
9420485b1ecSMatjaz Hegedic default:
9430485b1ecSMatjaz Hegedic /* Ignore dummy Consumer usages which make the
9440485b1ecSMatjaz Hegedic * keyboard incorrectly appear as a pointer device.
9450485b1ecSMatjaz Hegedic */
9460485b1ecSMatjaz Hegedic return -1;
9470485b1ecSMatjaz Hegedic }
9480485b1ecSMatjaz Hegedic }
9490485b1ecSMatjaz Hegedic
950350bd245SHans de Goede /*
951350bd245SHans de Goede * The mute button is broken and only sends press events, we
952350bd245SHans de Goede * deal with this in our raw_event handler, so do not map it.
953350bd245SHans de Goede */
954350bd245SHans de Goede if ((drvdata->quirks & QUIRK_MEDION_E1239T) &&
955350bd245SHans de Goede usage->hid == (HID_UP_CONSUMER | 0xe2)) {
956350bd245SHans de Goede input_set_capability(hi->input, EV_KEY, KEY_MUTE);
957350bd245SHans de Goede return -1;
958350bd245SHans de Goede }
959350bd245SHans de Goede
9609ce12d8bSBrendan McGrath return 0;
9619ce12d8bSBrendan McGrath }
9629ce12d8bSBrendan McGrath
asus_start_multitouch(struct hid_device * hdev)9639ce12d8bSBrendan McGrath static int asus_start_multitouch(struct hid_device *hdev)
9649ce12d8bSBrendan McGrath {
9659ce12d8bSBrendan McGrath int ret;
966b9ec7009SColin Ian King static const unsigned char buf[] = {
967b9ec7009SColin Ian King FEATURE_REPORT_ID, 0x00, 0x03, 0x01, 0x00
968b9ec7009SColin Ian King };
9699ce12d8bSBrendan McGrath unsigned char *dmabuf = kmemdup(buf, sizeof(buf), GFP_KERNEL);
9709ce12d8bSBrendan McGrath
9719ce12d8bSBrendan McGrath if (!dmabuf) {
9729ce12d8bSBrendan McGrath ret = -ENOMEM;
9739ce12d8bSBrendan McGrath hid_err(hdev, "Asus failed to alloc dma buf: %d\n", ret);
9749ce12d8bSBrendan McGrath return ret;
9759ce12d8bSBrendan McGrath }
9769ce12d8bSBrendan McGrath
9779ce12d8bSBrendan McGrath ret = hid_hw_raw_request(hdev, dmabuf[0], dmabuf, sizeof(buf),
9789ce12d8bSBrendan McGrath HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
9799ce12d8bSBrendan McGrath
9809ce12d8bSBrendan McGrath kfree(dmabuf);
9819ce12d8bSBrendan McGrath
9829ce12d8bSBrendan McGrath if (ret != sizeof(buf)) {
9839ce12d8bSBrendan McGrath hid_err(hdev, "Asus failed to start multitouch: %d\n", ret);
9849ce12d8bSBrendan McGrath return ret;
9859ce12d8bSBrendan McGrath }
9869ce12d8bSBrendan McGrath
9879ce12d8bSBrendan McGrath return 0;
9889ce12d8bSBrendan McGrath }
9899ce12d8bSBrendan McGrath
asus_resume(struct hid_device * hdev)9909fc2827cSDenis Benato static int __maybe_unused asus_resume(struct hid_device *hdev) {
9919fc2827cSDenis Benato struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
9929fc2827cSDenis Benato int ret = 0;
9939fc2827cSDenis Benato
9949fc2827cSDenis Benato if (drvdata->kbd_backlight) {
9959fc2827cSDenis Benato const u8 buf[] = { FEATURE_KBD_REPORT_ID, 0xba, 0xc5, 0xc4,
9969fc2827cSDenis Benato drvdata->kbd_backlight->cdev.brightness };
9979fc2827cSDenis Benato ret = asus_kbd_set_report(hdev, buf, sizeof(buf));
9989fc2827cSDenis Benato if (ret < 0) {
9999fc2827cSDenis Benato hid_err(hdev, "Asus failed to set keyboard backlight: %d\n", ret);
10009fc2827cSDenis Benato goto asus_resume_err;
10019fc2827cSDenis Benato }
10029fc2827cSDenis Benato }
10039fc2827cSDenis Benato
10049fc2827cSDenis Benato asus_resume_err:
10059fc2827cSDenis Benato return ret;
10069fc2827cSDenis Benato }
10079fc2827cSDenis Benato
asus_reset_resume(struct hid_device * hdev)10089ce12d8bSBrendan McGrath static int __maybe_unused asus_reset_resume(struct hid_device *hdev)
10099ce12d8bSBrendan McGrath {
10109ce12d8bSBrendan McGrath struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
10119ce12d8bSBrendan McGrath
1012c81760b9SHans de Goede if (drvdata->tp)
10139ce12d8bSBrendan McGrath return asus_start_multitouch(hdev);
10149ce12d8bSBrendan McGrath
10159ce12d8bSBrendan McGrath return 0;
10169ce12d8bSBrendan McGrath }
10179ce12d8bSBrendan McGrath
asus_probe(struct hid_device * hdev,const struct hid_device_id * id)10189ce12d8bSBrendan McGrath static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id)
10199ce12d8bSBrendan McGrath {
10209ce12d8bSBrendan McGrath int ret;
10219ce12d8bSBrendan McGrath struct asus_drvdata *drvdata;
10229ce12d8bSBrendan McGrath
10239ce12d8bSBrendan McGrath drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
10249ce12d8bSBrendan McGrath if (drvdata == NULL) {
10259ce12d8bSBrendan McGrath hid_err(hdev, "Can't alloc Asus descriptor\n");
10269ce12d8bSBrendan McGrath return -ENOMEM;
10279ce12d8bSBrendan McGrath }
10289ce12d8bSBrendan McGrath
10299ce12d8bSBrendan McGrath hid_set_drvdata(hdev, drvdata);
10309ce12d8bSBrendan McGrath
10319ce12d8bSBrendan McGrath drvdata->quirks = id->driver_data;
10329ce12d8bSBrendan McGrath
10336311d329SNOGUCHI Hiroshi /*
10346311d329SNOGUCHI Hiroshi * T90CHI's keyboard dock returns same ID values as T100CHI's dock.
10356311d329SNOGUCHI Hiroshi * Thus, identify T90CHI dock with product name string.
10366311d329SNOGUCHI Hiroshi */
1037300c64d7SNOGUCHI Hiroshi if (strstr(hdev->name, "T90CHI")) {
1038300c64d7SNOGUCHI Hiroshi drvdata->quirks &= ~QUIRK_T100CHI;
1039300c64d7SNOGUCHI Hiroshi drvdata->quirks |= QUIRK_T90CHI;
1040300c64d7SNOGUCHI Hiroshi }
1041300c64d7SNOGUCHI Hiroshi
1042c81760b9SHans de Goede if (drvdata->quirks & QUIRK_IS_MULTITOUCH)
1043c81760b9SHans de Goede drvdata->tp = &asus_i2c_tp;
1044c81760b9SHans de Goede
1045f83baa0cSGreg Kroah-Hartman if ((drvdata->quirks & QUIRK_T100_KEYBOARD) && hid_is_usb(hdev)) {
104657573c54SHans de Goede struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
104757573c54SHans de Goede
1048c81760b9SHans de Goede if (intf->altsetting->desc.bInterfaceNumber == T100_TPAD_INTF) {
1049c81760b9SHans de Goede drvdata->quirks = QUIRK_SKIP_INPUT_MAPPING;
1050762f948cSHans de Goede /*
1051dbd3ef28SHans de Goede * The T100HA uses the same USB-ids as the T100TAF and
1052dbd3ef28SHans de Goede * the T200TA uses the same USB-ids as the T100TA, while
1053dbd3ef28SHans de Goede * both have different max x/y values as the T100TA[F].
1054762f948cSHans de Goede */
1055762f948cSHans de Goede if (dmi_match(DMI_PRODUCT_NAME, "T100HAN"))
1056762f948cSHans de Goede drvdata->tp = &asus_t100ha_tp;
1057dbd3ef28SHans de Goede else if (dmi_match(DMI_PRODUCT_NAME, "T200TA"))
1058dbd3ef28SHans de Goede drvdata->tp = &asus_t200ta_tp;
1059762f948cSHans de Goede else
1060c81760b9SHans de Goede drvdata->tp = &asus_t100ta_tp;
1061c81760b9SHans de Goede }
106257573c54SHans de Goede }
106357573c54SHans de Goede
106473c75d39SHans de Goede if (drvdata->quirks & QUIRK_T100CHI) {
106573c75d39SHans de Goede /*
106673c75d39SHans de Goede * All functionality is on a single HID interface and for
106773c75d39SHans de Goede * userspace the touchpad must be a separate input_dev.
106873c75d39SHans de Goede */
106939335d1cSBenjamin Tissoires hdev->quirks |= HID_QUIRK_MULTI_INPUT;
107073c75d39SHans de Goede drvdata->tp = &asus_t100chi_tp;
107173c75d39SHans de Goede }
107273c75d39SHans de Goede
1073f83baa0cSGreg Kroah-Hartman if ((drvdata->quirks & QUIRK_MEDION_E1239T) && hid_is_usb(hdev)) {
1074e271f6c2SHans de Goede struct usb_host_interface *alt =
1075e271f6c2SHans de Goede to_usb_interface(hdev->dev.parent)->altsetting;
1076e271f6c2SHans de Goede
1077e271f6c2SHans de Goede if (alt->desc.bInterfaceNumber == MEDION_E1239T_TPAD_INTF) {
1078350bd245SHans de Goede /* For separate input-devs for tp and tp toggle key */
1079350bd245SHans de Goede hdev->quirks |= HID_QUIRK_MULTI_INPUT;
1080e271f6c2SHans de Goede drvdata->quirks |= QUIRK_SKIP_INPUT_MAPPING;
1081e271f6c2SHans de Goede drvdata->tp = &medion_e1239t_tp;
1082e271f6c2SHans de Goede }
1083e271f6c2SHans de Goede }
1084e271f6c2SHans de Goede
10859ce12d8bSBrendan McGrath if (drvdata->quirks & QUIRK_NO_INIT_REPORTS)
10869ce12d8bSBrendan McGrath hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS;
10879ce12d8bSBrendan McGrath
10886311d329SNOGUCHI Hiroshi drvdata->hdev = hdev;
10896311d329SNOGUCHI Hiroshi
10906311d329SNOGUCHI Hiroshi if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) {
10916311d329SNOGUCHI Hiroshi ret = asus_battery_probe(hdev);
10926311d329SNOGUCHI Hiroshi if (ret) {
10936311d329SNOGUCHI Hiroshi hid_err(hdev,
10946311d329SNOGUCHI Hiroshi "Asus hid battery_probe failed: %d\n", ret);
10956311d329SNOGUCHI Hiroshi return ret;
10966311d329SNOGUCHI Hiroshi }
10976311d329SNOGUCHI Hiroshi }
10986311d329SNOGUCHI Hiroshi
10999ce12d8bSBrendan McGrath ret = hid_parse(hdev);
11009ce12d8bSBrendan McGrath if (ret) {
11019ce12d8bSBrendan McGrath hid_err(hdev, "Asus hid parse failed: %d\n", ret);
11029ce12d8bSBrendan McGrath return ret;
11039ce12d8bSBrendan McGrath }
11049ce12d8bSBrendan McGrath
11059ce12d8bSBrendan McGrath ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
11069ce12d8bSBrendan McGrath if (ret) {
11079ce12d8bSBrendan McGrath hid_err(hdev, "Asus hw start failed: %d\n", ret);
11089ce12d8bSBrendan McGrath return ret;
11099ce12d8bSBrendan McGrath }
11109ce12d8bSBrendan McGrath
11119ce12d8bSBrendan McGrath if (!drvdata->input) {
11129ce12d8bSBrendan McGrath hid_err(hdev, "Asus input not registered\n");
11139ce12d8bSBrendan McGrath ret = -ENOMEM;
11149ce12d8bSBrendan McGrath goto err_stop_hw;
11159ce12d8bSBrendan McGrath }
11169ce12d8bSBrendan McGrath
1117c81760b9SHans de Goede if (drvdata->tp) {
11189ce12d8bSBrendan McGrath drvdata->input->name = "Asus TouchPad";
1119c8b1b3ddSBrendan McGrath } else {
1120c8b1b3ddSBrendan McGrath drvdata->input->name = "Asus Keyboard";
1121c8b1b3ddSBrendan McGrath }
11229ce12d8bSBrendan McGrath
1123c81760b9SHans de Goede if (drvdata->tp) {
11249ce12d8bSBrendan McGrath ret = asus_start_multitouch(hdev);
11259ce12d8bSBrendan McGrath if (ret)
11269ce12d8bSBrendan McGrath goto err_stop_hw;
11279ce12d8bSBrendan McGrath }
11289ce12d8bSBrendan McGrath
11299ce12d8bSBrendan McGrath return 0;
11309ce12d8bSBrendan McGrath err_stop_hw:
11319ce12d8bSBrendan McGrath hid_hw_stop(hdev);
11329ce12d8bSBrendan McGrath return ret;
11339ce12d8bSBrendan McGrath }
11349ce12d8bSBrendan McGrath
asus_remove(struct hid_device * hdev)1135af22a610SCarlo Caione static void asus_remove(struct hid_device *hdev)
1136af22a610SCarlo Caione {
1137af22a610SCarlo Caione struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
1138315c5370SPietro Borrello unsigned long flags;
1139af22a610SCarlo Caione
1140af22a610SCarlo Caione if (drvdata->kbd_backlight) {
1141315c5370SPietro Borrello spin_lock_irqsave(&drvdata->kbd_backlight->lock, flags);
1142af22a610SCarlo Caione drvdata->kbd_backlight->removed = true;
1143315c5370SPietro Borrello spin_unlock_irqrestore(&drvdata->kbd_backlight->lock, flags);
1144315c5370SPietro Borrello
1145af22a610SCarlo Caione cancel_work_sync(&drvdata->kbd_backlight->work);
1146af22a610SCarlo Caione }
1147715e944fSCarlo Caione
1148715e944fSCarlo Caione hid_hw_stop(hdev);
1149af22a610SCarlo Caione }
1150af22a610SCarlo Caione
1151832e1eeeSMaxime Bellengé static const __u8 asus_g752_fixed_rdesc[] = {
1152832e1eeeSMaxime Bellengé 0x19, 0x00, /* Usage Minimum (0x00) */
1153832e1eeeSMaxime Bellengé 0x2A, 0xFF, 0x00, /* Usage Maximum (0xFF) */
1154832e1eeeSMaxime Bellengé };
1155832e1eeeSMaxime Bellengé
asus_report_fixup(struct hid_device * hdev,__u8 * rdesc,unsigned int * rsize)1156eeb01a57SYusuke Fujimaki static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc,
1157eeb01a57SYusuke Fujimaki unsigned int *rsize)
1158eeb01a57SYusuke Fujimaki {
11599ce12d8bSBrendan McGrath struct asus_drvdata *drvdata = hid_get_drvdata(hdev);
11609ce12d8bSBrendan McGrath
11619ce12d8bSBrendan McGrath if (drvdata->quirks & QUIRK_FIX_NOTEBOOK_REPORT &&
11629ce12d8bSBrendan McGrath *rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x65) {
1163b94f7d5dSYusuke Fujimaki hid_info(hdev, "Fixing up Asus notebook report descriptor\n");
1164eeb01a57SYusuke Fujimaki rdesc[55] = 0xdd;
1165eeb01a57SYusuke Fujimaki }
116633edee4fSHans de Goede /* For the T100TA/T200TA keyboard dock */
116776dd1fbeSHans de Goede if (drvdata->quirks & QUIRK_T100_KEYBOARD &&
116833edee4fSHans de Goede (*rsize == 76 || *rsize == 101) &&
116933edee4fSHans de Goede rdesc[73] == 0x81 && rdesc[74] == 0x01) {
117076dd1fbeSHans de Goede hid_info(hdev, "Fixing up Asus T100 keyb report descriptor\n");
117176dd1fbeSHans de Goede rdesc[74] &= ~HID_MAIN_ITEM_CONSTANT;
117276dd1fbeSHans de Goede }
1173300c64d7SNOGUCHI Hiroshi /* For the T100CHI/T90CHI keyboard dock */
1174300c64d7SNOGUCHI Hiroshi if (drvdata->quirks & (QUIRK_T100CHI | QUIRK_T90CHI)) {
1175300c64d7SNOGUCHI Hiroshi int rsize_orig;
1176300c64d7SNOGUCHI Hiroshi int offs;
1177300c64d7SNOGUCHI Hiroshi
1178300c64d7SNOGUCHI Hiroshi if (drvdata->quirks & QUIRK_T100CHI) {
1179300c64d7SNOGUCHI Hiroshi rsize_orig = 403;
1180300c64d7SNOGUCHI Hiroshi offs = 388;
1181300c64d7SNOGUCHI Hiroshi } else {
1182300c64d7SNOGUCHI Hiroshi rsize_orig = 306;
1183300c64d7SNOGUCHI Hiroshi offs = 291;
1184300c64d7SNOGUCHI Hiroshi }
1185300c64d7SNOGUCHI Hiroshi
11865703e52cSHans de Goede /*
11875703e52cSHans de Goede * Change Usage (76h) to Usage Minimum (00h), Usage Maximum
11885703e52cSHans de Goede * (FFh) and clear the flags in the Input() byte.
11895703e52cSHans de Goede * Note the descriptor has a bogus 0 byte at the end so we
11905703e52cSHans de Goede * only need 1 extra byte.
11915703e52cSHans de Goede */
1192300c64d7SNOGUCHI Hiroshi if (*rsize == rsize_orig &&
1193300c64d7SNOGUCHI Hiroshi rdesc[offs] == 0x09 && rdesc[offs + 1] == 0x76) {
1194300c64d7SNOGUCHI Hiroshi *rsize = rsize_orig + 1;
11955703e52cSHans de Goede rdesc = kmemdup(rdesc, *rsize, GFP_KERNEL);
11965703e52cSHans de Goede if (!rdesc)
11975703e52cSHans de Goede return NULL;
11985703e52cSHans de Goede
1199300c64d7SNOGUCHI Hiroshi hid_info(hdev, "Fixing up %s keyb report descriptor\n",
1200300c64d7SNOGUCHI Hiroshi drvdata->quirks & QUIRK_T100CHI ?
1201300c64d7SNOGUCHI Hiroshi "T100CHI" : "T90CHI");
1202300c64d7SNOGUCHI Hiroshi memmove(rdesc + offs + 4, rdesc + offs + 2, 12);
1203300c64d7SNOGUCHI Hiroshi rdesc[offs] = 0x19;
1204300c64d7SNOGUCHI Hiroshi rdesc[offs + 1] = 0x00;
1205300c64d7SNOGUCHI Hiroshi rdesc[offs + 2] = 0x29;
1206300c64d7SNOGUCHI Hiroshi rdesc[offs + 3] = 0xff;
1207300c64d7SNOGUCHI Hiroshi rdesc[offs + 14] = 0x00;
12085703e52cSHans de Goede }
1209300c64d7SNOGUCHI Hiroshi }
1210300c64d7SNOGUCHI Hiroshi
1211832e1eeeSMaxime Bellengé if (drvdata->quirks & QUIRK_G752_KEYBOARD &&
1212832e1eeeSMaxime Bellengé *rsize == 75 && rdesc[61] == 0x15 && rdesc[62] == 0x00) {
1213832e1eeeSMaxime Bellengé /* report is missing usage mninum and maximum */
1214832e1eeeSMaxime Bellengé __u8 *new_rdesc;
1215832e1eeeSMaxime Bellengé size_t new_size = *rsize + sizeof(asus_g752_fixed_rdesc);
1216832e1eeeSMaxime Bellengé
1217832e1eeeSMaxime Bellengé new_rdesc = devm_kzalloc(&hdev->dev, new_size, GFP_KERNEL);
1218832e1eeeSMaxime Bellengé if (new_rdesc == NULL)
1219832e1eeeSMaxime Bellengé return rdesc;
1220832e1eeeSMaxime Bellengé
1221832e1eeeSMaxime Bellengé hid_info(hdev, "Fixing up Asus G752 keyb report descriptor\n");
1222832e1eeeSMaxime Bellengé /* copy the valid part */
1223832e1eeeSMaxime Bellengé memcpy(new_rdesc, rdesc, 61);
1224832e1eeeSMaxime Bellengé /* insert missing part */
1225832e1eeeSMaxime Bellengé memcpy(new_rdesc + 61, asus_g752_fixed_rdesc, sizeof(asus_g752_fixed_rdesc));
1226832e1eeeSMaxime Bellengé /* copy remaining data */
1227832e1eeeSMaxime Bellengé memcpy(new_rdesc + 61 + sizeof(asus_g752_fixed_rdesc), rdesc + 61, *rsize - 61);
1228832e1eeeSMaxime Bellengé
1229832e1eeeSMaxime Bellengé *rsize = new_size;
1230832e1eeeSMaxime Bellengé rdesc = new_rdesc;
1231832e1eeeSMaxime Bellengé }
123276dd1fbeSHans de Goede
12331c0cc9d1SJosh Kilmer if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD &&
12341c0cc9d1SJosh Kilmer *rsize == 331 && rdesc[190] == 0x85 && rdesc[191] == 0x5a &&
12351c0cc9d1SJosh Kilmer rdesc[204] == 0x95 && rdesc[205] == 0x05) {
12361c0cc9d1SJosh Kilmer hid_info(hdev, "Fixing up Asus N-KEY keyb report descriptor\n");
12371c0cc9d1SJosh Kilmer rdesc[205] = 0x01;
12381c0cc9d1SJosh Kilmer }
12391c0cc9d1SJosh Kilmer
124018fa9a90SLuke D. Jones /* match many more n-key devices */
12419de62e88SAndrew Ballance if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD && *rsize > 15) {
12429de62e88SAndrew Ballance for (int i = 0; i < *rsize - 15; i++) {
124318fa9a90SLuke D. Jones /* offset to the count from 0x5a report part always 14 */
124418fa9a90SLuke D. Jones if (rdesc[i] == 0x85 && rdesc[i + 1] == 0x5a &&
124518fa9a90SLuke D. Jones rdesc[i + 14] == 0x95 && rdesc[i + 15] == 0x05) {
124618fa9a90SLuke D. Jones hid_info(hdev, "Fixing up Asus N-Key report descriptor\n");
124718fa9a90SLuke D. Jones rdesc[i + 15] = 0x01;
124818fa9a90SLuke D. Jones break;
124918fa9a90SLuke D. Jones }
125018fa9a90SLuke D. Jones }
125118fa9a90SLuke D. Jones }
125218fa9a90SLuke D. Jones
1253eeb01a57SYusuke Fujimaki return rdesc;
1254eeb01a57SYusuke Fujimaki }
1255eeb01a57SYusuke Fujimaki
1256eeb01a57SYusuke Fujimaki static const struct hid_device_id asus_devices[] = {
12579ce12d8bSBrendan McGrath { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
1258a93913e1SMatjaz Hegedic USB_DEVICE_ID_ASUSTEK_I2C_KEYBOARD), I2C_KEYBOARD_QUIRKS},
12599ce12d8bSBrendan McGrath { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK,
1260c81760b9SHans de Goede USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS },
12611caccc25SChris Chiu { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
1262339ee3fcSMustafa Kuscu USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1), QUIRK_USE_KBD_BACKLIGHT },
12631caccc25SChris Chiu { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
1264af22a610SCarlo Caione USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT },
126576dd1fbeSHans de Goede { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
1266832e1eeeSMaxime Bellengé USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD },
1267832e1eeeSMaxime Bellengé { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
12682340bad5SHans de Goede USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD),
12692340bad5SHans de Goede QUIRK_USE_KBD_BACKLIGHT },
12702340bad5SHans de Goede { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
1271b92b8024SLuke D Jones USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD),
1272b92b8024SLuke D Jones QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
1273b92b8024SLuke D Jones { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
12749a0b44fbSLuke D Jones USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2),
12759a0b44fbSLuke D Jones QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
12769a0b44fbSLuke D Jones { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
127774e47b2cSLuke D. Jones USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD3),
127874e47b2cSLuke D. Jones QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
127974e47b2cSLuke D. Jones { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
12801815b323SLuke D. Jones USB_DEVICE_ID_ASUSTEK_ROG_Z13_LIGHTBAR),
12811815b323SLuke D. Jones QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
12821815b323SLuke D. Jones { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
12835ec4596aSLuke D. Jones USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY),
12845ec4596aSLuke D. Jones QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
12855ec4596aSLuke D. Jones { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
1286*ea912d38SLuke D. Jones USB_DEVICE_ID_ASUSTEK_ROG_NKEY_ALLY_X),
1287*ea912d38SLuke D. Jones QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD },
1288*ea912d38SLuke D. Jones { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
128987c7ee7aSLuke D. Jones USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD),
129087c7ee7aSLuke D. Jones QUIRK_ROG_CLAYMORE_II_KEYBOARD },
129187c7ee7aSLuke D. Jones { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
1292762f948cSHans de Goede USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD),
1293762f948cSHans de Goede QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
1294762f948cSHans de Goede { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK,
1295762f948cSHans de Goede USB_DEVICE_ID_ASUSTEK_T100TAF_KEYBOARD),
129676dd1fbeSHans de Goede QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES },
12975be91803SDaniel Drake { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_ASUS_AK1D) },
129838b2d78cSDaniel Drake { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) },
12995be91803SDaniel Drake { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) },
13005703e52cSHans de Goede { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ASUSTEK,
13015703e52cSHans de Goede USB_DEVICE_ID_ASUSTEK_T100CHI_KEYBOARD), QUIRK_T100CHI },
1302e271f6c2SHans de Goede { HID_USB_DEVICE(USB_VENDOR_ID_ITE, USB_DEVICE_ID_ITE_MEDION_E1239T),
1303e271f6c2SHans de Goede QUIRK_MEDION_E1239T },
1304a94f66aeSHans de Goede /*
1305a94f66aeSHans de Goede * Note bind to the HID_GROUP_GENERIC group, so that we only bind to the keyboard
1306a94f66aeSHans de Goede * part, while letting hid-multitouch.c handle the touchpad.
1307a94f66aeSHans de Goede */
1308a94f66aeSHans de Goede { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC,
1309a94f66aeSHans de Goede USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T101HA_KEYBOARD) },
1310eeb01a57SYusuke Fujimaki { }
1311eeb01a57SYusuke Fujimaki };
1312eeb01a57SYusuke Fujimaki MODULE_DEVICE_TABLE(hid, asus_devices);
1313eeb01a57SYusuke Fujimaki
1314eeb01a57SYusuke Fujimaki static struct hid_driver asus_driver = {
1315eeb01a57SYusuke Fujimaki .name = "asus",
1316eeb01a57SYusuke Fujimaki .id_table = asus_devices,
13179ce12d8bSBrendan McGrath .report_fixup = asus_report_fixup,
13189ce12d8bSBrendan McGrath .probe = asus_probe,
1319af22a610SCarlo Caione .remove = asus_remove,
13209ce12d8bSBrendan McGrath .input_mapping = asus_input_mapping,
13219ce12d8bSBrendan McGrath .input_configured = asus_input_configured,
13229ce12d8bSBrendan McGrath #ifdef CONFIG_PM
13239ce12d8bSBrendan McGrath .reset_resume = asus_reset_resume,
13249fc2827cSDenis Benato .resume = asus_resume,
13259ce12d8bSBrendan McGrath #endif
1326e98e3809SHans de Goede .event = asus_event,
13279ce12d8bSBrendan McGrath .raw_event = asus_raw_event
1328eeb01a57SYusuke Fujimaki };
1329eeb01a57SYusuke Fujimaki module_hid_driver(asus_driver);
1330eeb01a57SYusuke Fujimaki
1331eeb01a57SYusuke Fujimaki MODULE_LICENSE("GPL");
1332