HID: lenovo: Add ThinkPad 10 Ultrabook Keyboard support
[linux-block.git] / drivers / hid / hid-lenovo.c
CommitLineData
2874c5fd 1// SPDX-License-Identifier: GPL-2.0-or-later
c1dcad2d 2/*
6a5b414b
JL
3 * HID driver for Lenovo:
4 * - ThinkPad USB Keyboard with TrackPoint (tpkbd)
f3d4ff0e
JL
5 * - ThinkPad Compact Bluetooth Keyboard with TrackPoint (cptkbd)
6 * - ThinkPad Compact USB Keyboard with TrackPoint (cptkbd)
c1dcad2d
BS
7 *
8 * Copyright (c) 2012 Bernhard Seibold
f3d4ff0e 9 * Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk>
a230cd52 10 *
11 * Linux IBM/Lenovo Scrollpoint mouse driver:
12 * - IBM Scrollpoint III
13 * - IBM Scrollpoint Pro
14 * - IBM Scrollpoint Optical
15 * - IBM Scrollpoint Optical 800dpi
16 * - IBM Scrollpoint Optical 800dpi Pro
17 * - Lenovo Scrollpoint Optical
18 *
19 * Copyright (c) 2012 Peter De Wachter <pdewacht@gmail.com>
20 * Copyright (c) 2018 Peter Ganzhorn <peter.ganzhorn@gmail.com>
c1dcad2d
BS
21 */
22
23/*
c1dcad2d
BS
24 */
25
26#include <linux/module.h>
27#include <linux/sysfs.h>
28#include <linux/device.h>
c1dcad2d
BS
29#include <linux/hid.h>
30#include <linux/input.h>
31#include <linux/leds.h>
c1dcad2d
BS
32
33#include "hid-ids.h"
34
b72cdfa8 35struct lenovo_drvdata {
bc04b37e 36 u8 led_report[3]; /* Must be first for proper alignment */
c1dcad2d 37 int led_state;
bc04b37e 38 struct mutex led_report_mutex;
c1dcad2d
BS
39 struct led_classdev led_mute;
40 struct led_classdev led_micmute;
41 int press_to_select;
42 int dragging;
43 int release_to_select;
44 int select_right;
45 int sensitivity;
46 int press_speed;
3cb5ff02 47 u8 middlebutton_state; /* 0:Up, 1:Down (undecided), 2:Scrolling */
f3d4ff0e
JL
48 bool fn_lock;
49};
50
c1dcad2d
BS
51#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
52
bc04b37e
HG
53#define TP10UBKBD_LED_OUTPUT_REPORT 9
54
55#define TP10UBKBD_FN_LOCK_LED 0x54
56#define TP10UBKBD_MUTE_LED 0x64
57#define TP10UBKBD_MICMUTE_LED 0x74
58
59#define TP10UBKBD_LED_OFF 1
60#define TP10UBKBD_LED_ON 2
61
62static void lenovo_led_set_tp10ubkbd(struct hid_device *hdev, u8 led_code,
63 enum led_brightness value)
64{
65 struct lenovo_drvdata *data = hid_get_drvdata(hdev);
66 int ret;
67
68 mutex_lock(&data->led_report_mutex);
69
70 data->led_report[0] = TP10UBKBD_LED_OUTPUT_REPORT;
71 data->led_report[1] = led_code;
72 data->led_report[2] = value ? TP10UBKBD_LED_ON : TP10UBKBD_LED_OFF;
73 ret = hid_hw_raw_request(hdev, data->led_report[0], data->led_report, 3,
74 HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
75 if (ret)
76 hid_err(hdev, "Set LED output report error: %d\n", ret);
77
78 mutex_unlock(&data->led_report_mutex);
79}
80
181a8b91
BT
81static const __u8 lenovo_pro_dock_need_fixup_collection[] = {
82 0x05, 0x88, /* Usage Page (Vendor Usage Page 0x88) */
83 0x09, 0x01, /* Usage (Vendor Usage 0x01) */
84 0xa1, 0x01, /* Collection (Application) */
85 0x85, 0x04, /* Report ID (4) */
86 0x19, 0x00, /* Usage Minimum (0) */
87 0x2a, 0xff, 0xff, /* Usage Maximum (65535) */
88};
89
90static __u8 *lenovo_report_fixup(struct hid_device *hdev, __u8 *rdesc,
91 unsigned int *rsize)
92{
93 switch (hdev->product) {
94 case USB_DEVICE_ID_LENOVO_TPPRODOCK:
95 /* the fixups that need to be done:
96 * - get a reasonable usage max for the vendor collection
97 * 0x8801 from the report ID 4
98 */
99 if (*rsize >= 153 &&
100 memcmp(&rdesc[140], lenovo_pro_dock_need_fixup_collection,
101 sizeof(lenovo_pro_dock_need_fixup_collection)) == 0) {
102 rdesc[151] = 0x01;
103 rdesc[152] = 0x00;
104 }
105 break;
106 }
107 return rdesc;
108}
109
94723bfa 110static int lenovo_input_mapping_tpkbd(struct hid_device *hdev,
c1dcad2d
BS
111 struct hid_input *hi, struct hid_field *field,
112 struct hid_usage *usage, unsigned long **bit, int *max)
113{
0c521836 114 if (usage->hid == (HID_UP_BUTTON | 0x0010)) {
6a5b414b 115 /* This sub-device contains trackpoint, mark it */
0c521836 116 hid_set_drvdata(hdev, (void *)1);
c1dcad2d
BS
117 map_key_clear(KEY_MICMUTE);
118 return 1;
119 }
120 return 0;
121}
122
f3d4ff0e
JL
123static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
124 struct hid_input *hi, struct hid_field *field,
125 struct hid_usage *usage, unsigned long **bit, int *max)
126{
127 /* HID_UP_LNVENDOR = USB, HID_UP_MSVENDOR = BT */
128 if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR ||
129 (usage->hid & HID_USAGE_PAGE) == HID_UP_LNVENDOR) {
f3d4ff0e
JL
130 switch (usage->hid & HID_USAGE) {
131 case 0x00f1: /* Fn-F4: Mic mute */
132 map_key_clear(KEY_MICMUTE);
133 return 1;
134 case 0x00f2: /* Fn-F5: Brightness down */
135 map_key_clear(KEY_BRIGHTNESSDOWN);
136 return 1;
137 case 0x00f3: /* Fn-F6: Brightness up */
138 map_key_clear(KEY_BRIGHTNESSUP);
139 return 1;
140 case 0x00f4: /* Fn-F7: External display (projector) */
141 map_key_clear(KEY_SWITCHVIDEOMODE);
142 return 1;
143 case 0x00f5: /* Fn-F8: Wireless */
144 map_key_clear(KEY_WLAN);
145 return 1;
146 case 0x00f6: /* Fn-F9: Control panel */
147 map_key_clear(KEY_CONFIG);
148 return 1;
149 case 0x00f8: /* Fn-F11: View open applications (3 boxes) */
150 map_key_clear(KEY_SCALE);
151 return 1;
5556eb14 152 case 0x00f9: /* Fn-F12: Open My computer (6 boxes) USB-only */
f3d4ff0e
JL
153 /* NB: This mapping is invented in raw_event below */
154 map_key_clear(KEY_FILE);
155 return 1;
5556eb14
JL
156 case 0x00fa: /* Fn-Esc: Fn-lock toggle */
157 map_key_clear(KEY_FN_ESC);
158 return 1;
94eefa27
JL
159 case 0x00fb: /* Middle mouse button (in native mode) */
160 map_key_clear(BTN_MIDDLE);
161 return 1;
162 }
163 }
164
165 /* Compatibility middle/wheel mappings should be ignored */
166 if (usage->hid == HID_GD_WHEEL)
167 return -1;
168 if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON &&
169 (usage->hid & HID_USAGE) == 0x003)
170 return -1;
171 if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER &&
172 (usage->hid & HID_USAGE) == 0x238)
173 return -1;
174
175 /* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */
176 if ((usage->hid & HID_USAGE_PAGE) == 0xff100000 ||
177 (usage->hid & HID_USAGE_PAGE) == 0xffa10000) {
178 field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE;
179 field->logical_minimum = -127;
180 field->logical_maximum = 127;
181
182 switch (usage->hid & HID_USAGE) {
183 case 0x0000:
7f65068f 184 hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
94eefa27
JL
185 return 1;
186 case 0x0001:
7f65068f 187 hid_map_usage(hi, usage, bit, max, EV_REL, REL_WHEEL);
94eefa27
JL
188 return 1;
189 default:
190 return -1;
f3d4ff0e
JL
191 }
192 }
193
194 return 0;
195}
196
a230cd52 197static int lenovo_input_mapping_scrollpoint(struct hid_device *hdev,
198 struct hid_input *hi, struct hid_field *field,
199 struct hid_usage *usage, unsigned long **bit, int *max)
200{
201 if (usage->hid == HID_GD_Z) {
202 hid_map_usage(hi, usage, bit, max, EV_REL, REL_HWHEEL);
203 return 1;
204 }
205 return 0;
206}
207
bc04b37e
HG
208static int lenovo_input_mapping_tp10_ultrabook_kbd(struct hid_device *hdev,
209 struct hid_input *hi, struct hid_field *field,
210 struct hid_usage *usage, unsigned long **bit, int *max)
211{
212 /*
213 * The ThinkPad 10 Ultrabook Keyboard uses 0x000c0001 usage for
214 * a bunch of keys which have no standard consumer page code.
215 */
216 if (usage->hid == 0x000c0001) {
217 switch (usage->usage_index) {
218 case 8: /* Fn-Esc: Fn-lock toggle */
219 map_key_clear(KEY_FN_ESC);
220 return 1;
221 case 9: /* Fn-F4: Mic mute */
222 map_key_clear(KEY_MICMUTE);
223 return 1;
224 case 10: /* Fn-F7: Control panel */
225 map_key_clear(KEY_CONFIG);
226 return 1;
227 case 11: /* Fn-F8: Search (magnifier glass) */
228 map_key_clear(KEY_SEARCH);
229 return 1;
230 case 12: /* Fn-F10: Open My computer (6 boxes) */
231 map_key_clear(KEY_FILE);
232 return 1;
233 }
234 }
235
236 return 0;
237}
238
6a5b414b
JL
239static int lenovo_input_mapping(struct hid_device *hdev,
240 struct hid_input *hi, struct hid_field *field,
241 struct hid_usage *usage, unsigned long **bit, int *max)
242{
243 switch (hdev->product) {
244 case USB_DEVICE_ID_LENOVO_TPKBD:
245 return lenovo_input_mapping_tpkbd(hdev, hi, field,
246 usage, bit, max);
f3d4ff0e
JL
247 case USB_DEVICE_ID_LENOVO_CUSBKBD:
248 case USB_DEVICE_ID_LENOVO_CBTKBD:
249 return lenovo_input_mapping_cptkbd(hdev, hi, field,
250 usage, bit, max);
a230cd52 251 case USB_DEVICE_ID_IBM_SCROLLPOINT_III:
252 case USB_DEVICE_ID_IBM_SCROLLPOINT_PRO:
253 case USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL:
254 case USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL:
255 case USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO:
256 case USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL:
257 return lenovo_input_mapping_scrollpoint(hdev, hi, field,
258 usage, bit, max);
bc04b37e
HG
259 case USB_DEVICE_ID_LENOVO_TP10UBKBD:
260 return lenovo_input_mapping_tp10_ultrabook_kbd(hdev, hi, field,
261 usage, bit, max);
6a5b414b
JL
262 default:
263 return 0;
264 }
265}
266
c1dcad2d
BS
267#undef map_key_clear
268
f3d4ff0e
JL
269/* Send a config command to the keyboard */
270static int lenovo_send_cmd_cptkbd(struct hid_device *hdev,
271 unsigned char byte2, unsigned char byte3)
272{
273 int ret;
ea36ae09
JB
274 unsigned char *buf;
275
276 buf = kzalloc(3, GFP_KERNEL);
277 if (!buf)
278 return -ENOMEM;
279
280 buf[0] = 0x18;
281 buf[1] = byte2;
282 buf[2] = byte3;
f3d4ff0e
JL
283
284 switch (hdev->product) {
285 case USB_DEVICE_ID_LENOVO_CUSBKBD:
ea36ae09 286 ret = hid_hw_raw_request(hdev, 0x13, buf, 3,
f3d4ff0e
JL
287 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
288 break;
289 case USB_DEVICE_ID_LENOVO_CBTKBD:
ea36ae09 290 ret = hid_hw_output_report(hdev, buf, 3);
f3d4ff0e
JL
291 break;
292 default:
293 ret = -EINVAL;
294 break;
295 }
296
ea36ae09
JB
297 kfree(buf);
298
f3d4ff0e
JL
299 return ret < 0 ? ret : 0; /* BT returns 0, USB returns sizeof(buf) */
300}
301
302static void lenovo_features_set_cptkbd(struct hid_device *hdev)
303{
304 int ret;
b72cdfa8 305 struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
f3d4ff0e
JL
306
307 ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
308 if (ret)
309 hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
dbfebb44
JL
310
311 ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
312 if (ret)
313 hid_err(hdev, "Sensitivity setting failed: %d\n", ret);
f3d4ff0e
JL
314}
315
ef550c5d 316static ssize_t attr_fn_lock_show(struct device *dev,
f3d4ff0e
JL
317 struct device_attribute *attr,
318 char *buf)
319{
ee79a8f8 320 struct hid_device *hdev = to_hid_device(dev);
ef550c5d 321 struct lenovo_drvdata *data = hid_get_drvdata(hdev);
f3d4ff0e 322
ef550c5d 323 return snprintf(buf, PAGE_SIZE, "%u\n", data->fn_lock);
f3d4ff0e
JL
324}
325
ef550c5d 326static ssize_t attr_fn_lock_store(struct device *dev,
f3d4ff0e
JL
327 struct device_attribute *attr,
328 const char *buf,
329 size_t count)
330{
ee79a8f8 331 struct hid_device *hdev = to_hid_device(dev);
ef550c5d 332 struct lenovo_drvdata *data = hid_get_drvdata(hdev);
f3d4ff0e
JL
333 int value;
334
335 if (kstrtoint(buf, 10, &value))
336 return -EINVAL;
337 if (value < 0 || value > 1)
338 return -EINVAL;
339
ef550c5d
HG
340 data->fn_lock = !!value;
341
342 switch (hdev->product) {
343 case USB_DEVICE_ID_LENOVO_CUSBKBD:
344 case USB_DEVICE_ID_LENOVO_CBTKBD:
345 lenovo_features_set_cptkbd(hdev);
346 break;
347 }
f3d4ff0e
JL
348
349 return count;
350}
351
e3cb0acd
JL
352static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
353 struct device_attribute *attr,
354 char *buf)
355{
ee79a8f8 356 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 357 struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
e3cb0acd
JL
358
359 return snprintf(buf, PAGE_SIZE, "%u\n",
360 cptkbd_data->sensitivity);
361}
362
363static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
364 struct device_attribute *attr,
365 const char *buf,
366 size_t count)
367{
ee79a8f8 368 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 369 struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
e3cb0acd
JL
370 int value;
371
372 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
373 return -EINVAL;
374
375 cptkbd_data->sensitivity = value;
376 lenovo_features_set_cptkbd(hdev);
377
378 return count;
379}
380
381
ef550c5d 382static struct device_attribute dev_attr_fn_lock =
f3d4ff0e 383 __ATTR(fn_lock, S_IWUSR | S_IRUGO,
ef550c5d
HG
384 attr_fn_lock_show,
385 attr_fn_lock_store);
f3d4ff0e 386
e3cb0acd
JL
387static struct device_attribute dev_attr_sensitivity_cptkbd =
388 __ATTR(sensitivity, S_IWUSR | S_IRUGO,
389 attr_sensitivity_show_cptkbd,
390 attr_sensitivity_store_cptkbd);
391
392
f3d4ff0e 393static struct attribute *lenovo_attributes_cptkbd[] = {
ef550c5d 394 &dev_attr_fn_lock.attr,
e3cb0acd 395 &dev_attr_sensitivity_cptkbd.attr,
f3d4ff0e
JL
396 NULL
397};
398
399static const struct attribute_group lenovo_attr_group_cptkbd = {
400 .attrs = lenovo_attributes_cptkbd,
401};
402
403static int lenovo_raw_event(struct hid_device *hdev,
404 struct hid_report *report, u8 *data, int size)
405{
406 /*
407 * Compact USB keyboard's Fn-F12 report holds down many other keys, and
408 * its own key is outside the usage page range. Remove extra
409 * keypresses and remap to inside usage page.
410 */
411 if (unlikely(hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD
412 && size == 3
413 && data[0] == 0x15
414 && data[1] == 0x94
415 && data[2] == 0x01)) {
5556eb14
JL
416 data[1] = 0x00;
417 data[2] = 0x01;
f3d4ff0e
JL
418 }
419
420 return 0;
421}
422
3cb5ff02
JL
423static int lenovo_event_cptkbd(struct hid_device *hdev,
424 struct hid_field *field, struct hid_usage *usage, __s32 value)
425{
b72cdfa8 426 struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
3cb5ff02
JL
427
428 /* "wheel" scroll events */
429 if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
430 usage->code == REL_HWHEEL)) {
431 /* Scroll events disable middle-click event */
432 cptkbd_data->middlebutton_state = 2;
433 return 0;
434 }
435
436 /* Middle click events */
437 if (usage->type == EV_KEY && usage->code == BTN_MIDDLE) {
438 if (value == 1) {
439 cptkbd_data->middlebutton_state = 1;
440 } else if (value == 0) {
441 if (cptkbd_data->middlebutton_state == 1) {
442 /* No scrolling inbetween, send middle-click */
443 input_event(field->hidinput->input,
444 EV_KEY, BTN_MIDDLE, 1);
445 input_sync(field->hidinput->input);
446 input_event(field->hidinput->input,
447 EV_KEY, BTN_MIDDLE, 0);
448 input_sync(field->hidinput->input);
449 }
450 cptkbd_data->middlebutton_state = 0;
451 }
452 return 1;
453 }
454
455 return 0;
456}
457
458static int lenovo_event(struct hid_device *hdev, struct hid_field *field,
459 struct hid_usage *usage, __s32 value)
460{
461 switch (hdev->product) {
462 case USB_DEVICE_ID_LENOVO_CUSBKBD:
463 case USB_DEVICE_ID_LENOVO_CBTKBD:
464 return lenovo_event_cptkbd(hdev, field, usage, value);
465 default:
466 return 0;
467 }
468}
469
94723bfa 470static int lenovo_features_set_tpkbd(struct hid_device *hdev)
c1dcad2d
BS
471{
472 struct hid_report *report;
b72cdfa8 473 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d 474
c1dcad2d
BS
475 report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
476
477 report->field[0]->value[0] = data_pointer->press_to_select ? 0x01 : 0x02;
478 report->field[0]->value[0] |= data_pointer->dragging ? 0x04 : 0x08;
479 report->field[0]->value[0] |= data_pointer->release_to_select ? 0x10 : 0x20;
480 report->field[0]->value[0] |= data_pointer->select_right ? 0x80 : 0x40;
481 report->field[1]->value[0] = 0x03; // unknown setting, imitate windows driver
482 report->field[2]->value[0] = data_pointer->sensitivity;
483 report->field[3]->value[0] = data_pointer->press_speed;
484
d8814272 485 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
c1dcad2d
BS
486 return 0;
487}
488
94723bfa 489static ssize_t attr_press_to_select_show_tpkbd(struct device *dev,
c1dcad2d
BS
490 struct device_attribute *attr,
491 char *buf)
492{
ee79a8f8 493 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 494 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
495
496 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
497}
498
94723bfa 499static ssize_t attr_press_to_select_store_tpkbd(struct device *dev,
c1dcad2d
BS
500 struct device_attribute *attr,
501 const char *buf,
502 size_t count)
503{
ee79a8f8 504 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 505 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
506 int value;
507
c1dcad2d
BS
508 if (kstrtoint(buf, 10, &value))
509 return -EINVAL;
510 if (value < 0 || value > 1)
511 return -EINVAL;
512
513 data_pointer->press_to_select = value;
94723bfa 514 lenovo_features_set_tpkbd(hdev);
c1dcad2d
BS
515
516 return count;
517}
518
94723bfa 519static ssize_t attr_dragging_show_tpkbd(struct device *dev,
c1dcad2d
BS
520 struct device_attribute *attr,
521 char *buf)
522{
ee79a8f8 523 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 524 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
525
526 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
527}
528
94723bfa 529static ssize_t attr_dragging_store_tpkbd(struct device *dev,
c1dcad2d
BS
530 struct device_attribute *attr,
531 const char *buf,
532 size_t count)
533{
ee79a8f8 534 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 535 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
536 int value;
537
c1dcad2d
BS
538 if (kstrtoint(buf, 10, &value))
539 return -EINVAL;
540 if (value < 0 || value > 1)
541 return -EINVAL;
542
543 data_pointer->dragging = value;
94723bfa 544 lenovo_features_set_tpkbd(hdev);
c1dcad2d
BS
545
546 return count;
547}
548
94723bfa 549static ssize_t attr_release_to_select_show_tpkbd(struct device *dev,
c1dcad2d
BS
550 struct device_attribute *attr,
551 char *buf)
552{
ee79a8f8 553 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 554 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
555
556 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
557}
558
94723bfa 559static ssize_t attr_release_to_select_store_tpkbd(struct device *dev,
c1dcad2d
BS
560 struct device_attribute *attr,
561 const char *buf,
562 size_t count)
563{
ee79a8f8 564 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 565 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
566 int value;
567
c1dcad2d
BS
568 if (kstrtoint(buf, 10, &value))
569 return -EINVAL;
570 if (value < 0 || value > 1)
571 return -EINVAL;
572
573 data_pointer->release_to_select = value;
94723bfa 574 lenovo_features_set_tpkbd(hdev);
c1dcad2d
BS
575
576 return count;
577}
578
94723bfa 579static ssize_t attr_select_right_show_tpkbd(struct device *dev,
c1dcad2d
BS
580 struct device_attribute *attr,
581 char *buf)
582{
ee79a8f8 583 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 584 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
585
586 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
587}
588
94723bfa 589static ssize_t attr_select_right_store_tpkbd(struct device *dev,
c1dcad2d
BS
590 struct device_attribute *attr,
591 const char *buf,
592 size_t count)
593{
ee79a8f8 594 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 595 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
596 int value;
597
c1dcad2d
BS
598 if (kstrtoint(buf, 10, &value))
599 return -EINVAL;
600 if (value < 0 || value > 1)
601 return -EINVAL;
602
603 data_pointer->select_right = value;
94723bfa 604 lenovo_features_set_tpkbd(hdev);
c1dcad2d
BS
605
606 return count;
607}
608
94723bfa 609static ssize_t attr_sensitivity_show_tpkbd(struct device *dev,
c1dcad2d
BS
610 struct device_attribute *attr,
611 char *buf)
612{
ee79a8f8 613 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 614 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
615
616 return snprintf(buf, PAGE_SIZE, "%u\n",
617 data_pointer->sensitivity);
618}
619
94723bfa 620static ssize_t attr_sensitivity_store_tpkbd(struct device *dev,
c1dcad2d
BS
621 struct device_attribute *attr,
622 const char *buf,
623 size_t count)
624{
ee79a8f8 625 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 626 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
627 int value;
628
c1dcad2d
BS
629 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
630 return -EINVAL;
631
632 data_pointer->sensitivity = value;
94723bfa 633 lenovo_features_set_tpkbd(hdev);
c1dcad2d
BS
634
635 return count;
636}
637
94723bfa 638static ssize_t attr_press_speed_show_tpkbd(struct device *dev,
c1dcad2d
BS
639 struct device_attribute *attr,
640 char *buf)
641{
ee79a8f8 642 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 643 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d 644
c1dcad2d
BS
645 return snprintf(buf, PAGE_SIZE, "%u\n",
646 data_pointer->press_speed);
647}
648
94723bfa 649static ssize_t attr_press_speed_store_tpkbd(struct device *dev,
c1dcad2d
BS
650 struct device_attribute *attr,
651 const char *buf,
652 size_t count)
653{
ee79a8f8 654 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 655 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
656 int value;
657
c1dcad2d
BS
658 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
659 return -EINVAL;
660
661 data_pointer->press_speed = value;
94723bfa 662 lenovo_features_set_tpkbd(hdev);
c1dcad2d
BS
663
664 return count;
665}
666
94723bfa 667static struct device_attribute dev_attr_press_to_select_tpkbd =
c1dcad2d 668 __ATTR(press_to_select, S_IWUSR | S_IRUGO,
94723bfa
JL
669 attr_press_to_select_show_tpkbd,
670 attr_press_to_select_store_tpkbd);
c1dcad2d 671
94723bfa 672static struct device_attribute dev_attr_dragging_tpkbd =
c1dcad2d 673 __ATTR(dragging, S_IWUSR | S_IRUGO,
94723bfa
JL
674 attr_dragging_show_tpkbd,
675 attr_dragging_store_tpkbd);
c1dcad2d 676
94723bfa 677static struct device_attribute dev_attr_release_to_select_tpkbd =
c1dcad2d 678 __ATTR(release_to_select, S_IWUSR | S_IRUGO,
94723bfa
JL
679 attr_release_to_select_show_tpkbd,
680 attr_release_to_select_store_tpkbd);
c1dcad2d 681
94723bfa 682static struct device_attribute dev_attr_select_right_tpkbd =
c1dcad2d 683 __ATTR(select_right, S_IWUSR | S_IRUGO,
94723bfa
JL
684 attr_select_right_show_tpkbd,
685 attr_select_right_store_tpkbd);
c1dcad2d 686
94723bfa 687static struct device_attribute dev_attr_sensitivity_tpkbd =
c1dcad2d 688 __ATTR(sensitivity, S_IWUSR | S_IRUGO,
94723bfa
JL
689 attr_sensitivity_show_tpkbd,
690 attr_sensitivity_store_tpkbd);
c1dcad2d 691
94723bfa 692static struct device_attribute dev_attr_press_speed_tpkbd =
c1dcad2d 693 __ATTR(press_speed, S_IWUSR | S_IRUGO,
94723bfa
JL
694 attr_press_speed_show_tpkbd,
695 attr_press_speed_store_tpkbd);
696
697static struct attribute *lenovo_attributes_tpkbd[] = {
698 &dev_attr_press_to_select_tpkbd.attr,
699 &dev_attr_dragging_tpkbd.attr,
700 &dev_attr_release_to_select_tpkbd.attr,
701 &dev_attr_select_right_tpkbd.attr,
702 &dev_attr_sensitivity_tpkbd.attr,
703 &dev_attr_press_speed_tpkbd.attr,
c1dcad2d
BS
704 NULL
705};
706
94723bfa
JL
707static const struct attribute_group lenovo_attr_group_tpkbd = {
708 .attrs = lenovo_attributes_tpkbd,
c1dcad2d
BS
709};
710
484921f5
HG
711static void lenovo_led_set_tpkbd(struct hid_device *hdev)
712{
713 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
714 struct hid_report *report;
715
716 report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
717 report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
718 report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
719 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
720}
721
722static enum led_brightness lenovo_led_brightness_get(
c1dcad2d
BS
723 struct led_classdev *led_cdev)
724{
832fbeae 725 struct device *dev = led_cdev->dev->parent;
ee79a8f8 726 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 727 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d
BS
728 int led_nr = 0;
729
c1dcad2d
BS
730 if (led_cdev == &data_pointer->led_micmute)
731 led_nr = 1;
732
733 return data_pointer->led_state & (1 << led_nr)
734 ? LED_FULL
735 : LED_OFF;
736}
737
484921f5 738static void lenovo_led_brightness_set(struct led_classdev *led_cdev,
c1dcad2d
BS
739 enum led_brightness value)
740{
832fbeae 741 struct device *dev = led_cdev->dev->parent;
ee79a8f8 742 struct hid_device *hdev = to_hid_device(dev);
b72cdfa8 743 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
bc04b37e 744 u8 tp10ubkbd_led[] = { TP10UBKBD_MUTE_LED, TP10UBKBD_MICMUTE_LED };
c1dcad2d
BS
745 int led_nr = 0;
746
c1dcad2d
BS
747 if (led_cdev == &data_pointer->led_micmute)
748 led_nr = 1;
749
750 if (value == LED_OFF)
751 data_pointer->led_state &= ~(1 << led_nr);
752 else
753 data_pointer->led_state |= 1 << led_nr;
754
484921f5
HG
755 switch (hdev->product) {
756 case USB_DEVICE_ID_LENOVO_TPKBD:
757 lenovo_led_set_tpkbd(hdev);
758 break;
bc04b37e
HG
759 case USB_DEVICE_ID_LENOVO_TP10UBKBD:
760 lenovo_led_set_tp10ubkbd(hdev, tp10ubkbd_led[led_nr], value);
761 break;
484921f5
HG
762 }
763}
764
765static int lenovo_register_leds(struct hid_device *hdev)
766{
767 struct lenovo_drvdata *data = hid_get_drvdata(hdev);
768 size_t name_sz = strlen(dev_name(&hdev->dev)) + 16;
769 char *name_mute, *name_micm;
770 int ret;
771
772 name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
773 name_micm = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
774 if (name_mute == NULL || name_micm == NULL) {
775 hid_err(hdev, "Could not allocate memory for led data\n");
776 return -ENOMEM;
777 }
778 snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(&hdev->dev));
779 snprintf(name_micm, name_sz, "%s:amber:micmute", dev_name(&hdev->dev));
780
781 data->led_mute.name = name_mute;
782 data->led_mute.brightness_get = lenovo_led_brightness_get;
783 data->led_mute.brightness_set = lenovo_led_brightness_set;
784 data->led_mute.dev = &hdev->dev;
785 ret = led_classdev_register(&hdev->dev, &data->led_mute);
786 if (ret < 0)
787 return ret;
788
789 data->led_micmute.name = name_micm;
790 data->led_micmute.brightness_get = lenovo_led_brightness_get;
791 data->led_micmute.brightness_set = lenovo_led_brightness_set;
792 data->led_micmute.dev = &hdev->dev;
793 ret = led_classdev_register(&hdev->dev, &data->led_micmute);
794 if (ret < 0) {
795 led_classdev_unregister(&data->led_mute);
796 return ret;
797 }
798
799 return 0;
c1dcad2d
BS
800}
801
94723bfa 802static int lenovo_probe_tpkbd(struct hid_device *hdev)
c1dcad2d 803{
b72cdfa8 804 struct lenovo_drvdata *data_pointer;
484921f5 805 int i, ret;
0a9cd0a8 806
6a5b414b
JL
807 /*
808 * Only register extra settings against subdevice where input_mapping
809 * set drvdata to 1, i.e. the trackpoint.
810 */
811 if (!hid_get_drvdata(hdev))
812 return 0;
813
814 hid_set_drvdata(hdev, NULL);
815
0a9cd0a8
KC
816 /* Validate required reports. */
817 for (i = 0; i < 4; i++) {
818 if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1))
819 return -ENODEV;
820 }
821 if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2))
822 return -ENODEV;
c1dcad2d 823
e0a6aad6
JL
824 ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_tpkbd);
825 if (ret)
826 hid_warn(hdev, "Could not create sysfs group: %d\n", ret);
c1dcad2d 827
01ab35f1 828 data_pointer = devm_kzalloc(&hdev->dev,
b72cdfa8 829 sizeof(struct lenovo_drvdata),
01ab35f1 830 GFP_KERNEL);
c1dcad2d
BS
831 if (data_pointer == NULL) {
832 hid_err(hdev, "Could not allocate memory for driver data\n");
b7212600
AK
833 ret = -ENOMEM;
834 goto err;
c1dcad2d
BS
835 }
836
837 // set same default values as windows driver
838 data_pointer->sensitivity = 0xa0;
839 data_pointer->press_speed = 0x38;
840
c1dcad2d
BS
841 hid_set_drvdata(hdev, data_pointer);
842
484921f5
HG
843 ret = lenovo_register_leds(hdev);
844 if (ret)
6ae16dfb 845 goto err;
c1dcad2d 846
94723bfa 847 lenovo_features_set_tpkbd(hdev);
c1dcad2d
BS
848
849 return 0;
b7212600
AK
850err:
851 sysfs_remove_group(&hdev->dev.kobj, &lenovo_attr_group_tpkbd);
852 return ret;
c1dcad2d
BS
853}
854
f3d4ff0e
JL
855static int lenovo_probe_cptkbd(struct hid_device *hdev)
856{
857 int ret;
b72cdfa8 858 struct lenovo_drvdata *cptkbd_data;
f3d4ff0e
JL
859
860 /* All the custom action happens on the USBMOUSE device for USB */
861 if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD
862 && hdev->type != HID_TYPE_USBMOUSE) {
863 hid_dbg(hdev, "Ignoring keyboard half of device\n");
864 return 0;
865 }
866
867 cptkbd_data = devm_kzalloc(&hdev->dev,
868 sizeof(*cptkbd_data),
869 GFP_KERNEL);
870 if (cptkbd_data == NULL) {
871 hid_err(hdev, "can't alloc keyboard descriptor\n");
872 return -ENOMEM;
873 }
874 hid_set_drvdata(hdev, cptkbd_data);
875
876 /*
877 * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
878 * regular keys
879 */
880 ret = lenovo_send_cmd_cptkbd(hdev, 0x01, 0x03);
881 if (ret)
882 hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
883
94eefa27
JL
884 /* Switch middle button to native mode */
885 ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
886 if (ret)
887 hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
888
e3cb0acd 889 /* Set keyboard settings to known state */
3cb5ff02 890 cptkbd_data->middlebutton_state = 0;
f3d4ff0e 891 cptkbd_data->fn_lock = true;
e3cb0acd 892 cptkbd_data->sensitivity = 0x05;
f3d4ff0e
JL
893 lenovo_features_set_cptkbd(hdev);
894
895 ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);
896 if (ret)
897 hid_warn(hdev, "Could not create sysfs group: %d\n", ret);
898
899 return 0;
900}
901
bc04b37e
HG
902static int lenovo_probe_tp10ubkbd(struct hid_device *hdev)
903{
904 struct lenovo_drvdata *data;
905
906 /* All the custom action happens on the USBMOUSE device for USB */
907 if (hdev->type != HID_TYPE_USBMOUSE)
908 return 0;
909
910 data = devm_kzalloc(&hdev->dev, sizeof(*data), GFP_KERNEL);
911 if (!data)
912 return -ENOMEM;
913
914 mutex_init(&data->led_report_mutex);
915
916 hid_set_drvdata(hdev, data);
917
918 return lenovo_register_leds(hdev);
919}
920
94723bfa 921static int lenovo_probe(struct hid_device *hdev,
c1dcad2d
BS
922 const struct hid_device_id *id)
923{
924 int ret;
c1dcad2d
BS
925
926 ret = hid_parse(hdev);
927 if (ret) {
928 hid_err(hdev, "hid_parse failed\n");
0ccdd9e7 929 goto err;
c1dcad2d
BS
930 }
931
932 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
933 if (ret) {
934 hid_err(hdev, "hid_hw_start failed\n");
0ccdd9e7 935 goto err;
c1dcad2d
BS
936 }
937
6a5b414b
JL
938 switch (hdev->product) {
939 case USB_DEVICE_ID_LENOVO_TPKBD:
94723bfa 940 ret = lenovo_probe_tpkbd(hdev);
6a5b414b 941 break;
f3d4ff0e
JL
942 case USB_DEVICE_ID_LENOVO_CUSBKBD:
943 case USB_DEVICE_ID_LENOVO_CBTKBD:
944 ret = lenovo_probe_cptkbd(hdev);
945 break;
bc04b37e
HG
946 case USB_DEVICE_ID_LENOVO_TP10UBKBD:
947 ret = lenovo_probe_tp10ubkbd(hdev);
948 break;
6a5b414b
JL
949 default:
950 ret = 0;
951 break;
0ccdd9e7 952 }
6a5b414b
JL
953 if (ret)
954 goto err_hid;
c1dcad2d
BS
955
956 return 0;
0ccdd9e7
BT
957err_hid:
958 hid_hw_stop(hdev);
959err:
c1dcad2d
BS
960 return ret;
961}
962
94723bfa 963static void lenovo_remove_tpkbd(struct hid_device *hdev)
c1dcad2d 964{
b72cdfa8 965 struct lenovo_drvdata *data_pointer = hid_get_drvdata(hdev);
c1dcad2d 966
6a5b414b
JL
967 /*
968 * Only the trackpoint half of the keyboard has drvdata and stuff that
969 * needs unregistering.
970 */
971 if (data_pointer == NULL)
972 return;
973
c1dcad2d 974 sysfs_remove_group(&hdev->dev.kobj,
94723bfa 975 &lenovo_attr_group_tpkbd);
c1dcad2d 976
c1dcad2d
BS
977 led_classdev_unregister(&data_pointer->led_micmute);
978 led_classdev_unregister(&data_pointer->led_mute);
c1dcad2d
BS
979}
980
f3d4ff0e
JL
981static void lenovo_remove_cptkbd(struct hid_device *hdev)
982{
983 sysfs_remove_group(&hdev->dev.kobj,
984 &lenovo_attr_group_cptkbd);
985}
986
bc04b37e
HG
987static void lenovo_remove_tp10ubkbd(struct hid_device *hdev)
988{
989 struct lenovo_drvdata *data = hid_get_drvdata(hdev);
990
991 if (data == NULL)
992 return;
993
994 led_classdev_unregister(&data->led_micmute);
995 led_classdev_unregister(&data->led_mute);
996}
997
94723bfa 998static void lenovo_remove(struct hid_device *hdev)
c1dcad2d 999{
6a5b414b
JL
1000 switch (hdev->product) {
1001 case USB_DEVICE_ID_LENOVO_TPKBD:
94723bfa 1002 lenovo_remove_tpkbd(hdev);
6a5b414b 1003 break;
f3d4ff0e
JL
1004 case USB_DEVICE_ID_LENOVO_CUSBKBD:
1005 case USB_DEVICE_ID_LENOVO_CBTKBD:
1006 lenovo_remove_cptkbd(hdev);
1007 break;
bc04b37e
HG
1008 case USB_DEVICE_ID_LENOVO_TP10UBKBD:
1009 lenovo_remove_tp10ubkbd(hdev);
1010 break;
6a5b414b 1011 }
c1dcad2d
BS
1012
1013 hid_hw_stop(hdev);
1014}
1015
9154301a 1016static int lenovo_input_configured(struct hid_device *hdev,
d92189eb
AF
1017 struct hid_input *hi)
1018{
1019 switch (hdev->product) {
1020 case USB_DEVICE_ID_LENOVO_TPKBD:
1021 case USB_DEVICE_ID_LENOVO_CUSBKBD:
1022 case USB_DEVICE_ID_LENOVO_CBTKBD:
1023 if (test_bit(EV_REL, hi->input->evbit)) {
1024 /* set only for trackpoint device */
1025 __set_bit(INPUT_PROP_POINTER, hi->input->propbit);
1026 __set_bit(INPUT_PROP_POINTING_STICK,
1027 hi->input->propbit);
1028 }
1029 break;
1030 }
9154301a
DT
1031
1032 return 0;
d92189eb
AF
1033}
1034
1035
94723bfa 1036static const struct hid_device_id lenovo_devices[] = {
c1dcad2d 1037 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
f3d4ff0e
JL
1038 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CUSBKBD) },
1039 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) },
181a8b91 1040 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) },
a230cd52 1041 { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_III) },
1042 { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_PRO) },
1043 { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL) },
1044 { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL) },
1045 { HID_USB_DEVICE(USB_VENDOR_ID_IBM, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO) },
1046 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL) },
bc04b37e 1047 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TP10UBKBD) },
c1dcad2d
BS
1048 { }
1049};
1050
94723bfa 1051MODULE_DEVICE_TABLE(hid, lenovo_devices);
c1dcad2d 1052
94723bfa
JL
1053static struct hid_driver lenovo_driver = {
1054 .name = "lenovo",
1055 .id_table = lenovo_devices,
d92189eb 1056 .input_configured = lenovo_input_configured,
6a5b414b 1057 .input_mapping = lenovo_input_mapping,
94723bfa
JL
1058 .probe = lenovo_probe,
1059 .remove = lenovo_remove,
f3d4ff0e 1060 .raw_event = lenovo_raw_event,
3cb5ff02 1061 .event = lenovo_event,
181a8b91 1062 .report_fixup = lenovo_report_fixup,
c1dcad2d 1063};
94723bfa 1064module_hid_driver(lenovo_driver);
c1dcad2d
BS
1065
1066MODULE_LICENSE("GPL");