2 * HID driver for Lenovo:
3 * - ThinkPad USB Keyboard with TrackPoint (tpkbd)
4 * - ThinkPad Compact Bluetooth Keyboard with TrackPoint (cptkbd)
5 * - ThinkPad Compact USB Keyboard with TrackPoint (cptkbd)
7 * Copyright (c) 2012 Bernhard Seibold
8 * Copyright (c) 2014 Jamie Lentin <jm@lentin.co.uk>
10 * Linux IBM/Lenovo Scrollpoint mouse driver:
11 * - IBM Scrollpoint III
12 * - IBM Scrollpoint Pro
13 * - IBM Scrollpoint Optical
14 * - IBM Scrollpoint Optical 800dpi
15 * - IBM Scrollpoint Optical 800dpi Pro
16 * - Lenovo Scrollpoint Optical
18 * Copyright (c) 2012 Peter De Wachter <pdewacht@gmail.com>
19 * Copyright (c) 2018 Peter Ganzhorn <peter.ganzhorn@gmail.com>
23 * This program is free software; you can redistribute it and/or modify it
24 * under the terms of the GNU General Public License as published by the Free
25 * Software Foundation; either version 2 of the License, or (at your option)
29 #include <linux/module.h>
30 #include <linux/sysfs.h>
31 #include <linux/device.h>
32 #include <linux/hid.h>
33 #include <linux/input.h>
34 #include <linux/leds.h>
38 struct lenovo_drvdata_tpkbd
{
40 struct led_classdev led_mute
;
41 struct led_classdev led_micmute
;
44 int release_to_select
;
50 struct lenovo_drvdata_cptkbd
{
51 u8 middlebutton_state
; /* 0:Up, 1:Down (undecided), 2:Scrolling */
56 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
58 static const __u8 lenovo_pro_dock_need_fixup_collection
[] = {
59 0x05, 0x88, /* Usage Page (Vendor Usage Page 0x88) */
60 0x09, 0x01, /* Usage (Vendor Usage 0x01) */
61 0xa1, 0x01, /* Collection (Application) */
62 0x85, 0x04, /* Report ID (4) */
63 0x19, 0x00, /* Usage Minimum (0) */
64 0x2a, 0xff, 0xff, /* Usage Maximum (65535) */
67 static __u8
*lenovo_report_fixup(struct hid_device
*hdev
, __u8
*rdesc
,
70 switch (hdev
->product
) {
71 case USB_DEVICE_ID_LENOVO_TPPRODOCK
:
72 /* the fixups that need to be done:
73 * - get a reasonable usage max for the vendor collection
74 * 0x8801 from the report ID 4
77 memcmp(&rdesc
[140], lenovo_pro_dock_need_fixup_collection
,
78 sizeof(lenovo_pro_dock_need_fixup_collection
)) == 0) {
87 static int lenovo_input_mapping_tpkbd(struct hid_device
*hdev
,
88 struct hid_input
*hi
, struct hid_field
*field
,
89 struct hid_usage
*usage
, unsigned long **bit
, int *max
)
91 if (usage
->hid
== (HID_UP_BUTTON
| 0x0010)) {
92 /* This sub-device contains trackpoint, mark it */
93 hid_set_drvdata(hdev
, (void *)1);
94 map_key_clear(KEY_MICMUTE
);
100 static int lenovo_input_mapping_cptkbd(struct hid_device
*hdev
,
101 struct hid_input
*hi
, struct hid_field
*field
,
102 struct hid_usage
*usage
, unsigned long **bit
, int *max
)
104 /* HID_UP_LNVENDOR = USB, HID_UP_MSVENDOR = BT */
105 if ((usage
->hid
& HID_USAGE_PAGE
) == HID_UP_MSVENDOR
||
106 (usage
->hid
& HID_USAGE_PAGE
) == HID_UP_LNVENDOR
) {
107 switch (usage
->hid
& HID_USAGE
) {
108 case 0x00f1: /* Fn-F4: Mic mute */
109 map_key_clear(KEY_MICMUTE
);
111 case 0x00f2: /* Fn-F5: Brightness down */
112 map_key_clear(KEY_BRIGHTNESSDOWN
);
114 case 0x00f3: /* Fn-F6: Brightness up */
115 map_key_clear(KEY_BRIGHTNESSUP
);
117 case 0x00f4: /* Fn-F7: External display (projector) */
118 map_key_clear(KEY_SWITCHVIDEOMODE
);
120 case 0x00f5: /* Fn-F8: Wireless */
121 map_key_clear(KEY_WLAN
);
123 case 0x00f6: /* Fn-F9: Control panel */
124 map_key_clear(KEY_CONFIG
);
126 case 0x00f8: /* Fn-F11: View open applications (3 boxes) */
127 map_key_clear(KEY_SCALE
);
129 case 0x00f9: /* Fn-F12: Open My computer (6 boxes) USB-only */
130 /* NB: This mapping is invented in raw_event below */
131 map_key_clear(KEY_FILE
);
133 case 0x00fa: /* Fn-Esc: Fn-lock toggle */
134 map_key_clear(KEY_FN_ESC
);
136 case 0x00fb: /* Middle mouse button (in native mode) */
137 map_key_clear(BTN_MIDDLE
);
142 /* Compatibility middle/wheel mappings should be ignored */
143 if (usage
->hid
== HID_GD_WHEEL
)
145 if ((usage
->hid
& HID_USAGE_PAGE
) == HID_UP_BUTTON
&&
146 (usage
->hid
& HID_USAGE
) == 0x003)
148 if ((usage
->hid
& HID_USAGE_PAGE
) == HID_UP_CONSUMER
&&
149 (usage
->hid
& HID_USAGE
) == 0x238)
152 /* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */
153 if ((usage
->hid
& HID_USAGE_PAGE
) == 0xff100000 ||
154 (usage
->hid
& HID_USAGE_PAGE
) == 0xffa10000) {
155 field
->flags
|= HID_MAIN_ITEM_RELATIVE
| HID_MAIN_ITEM_VARIABLE
;
156 field
->logical_minimum
= -127;
157 field
->logical_maximum
= 127;
159 switch (usage
->hid
& HID_USAGE
) {
161 hid_map_usage(hi
, usage
, bit
, max
, EV_REL
, REL_HWHEEL
);
164 hid_map_usage(hi
, usage
, bit
, max
, EV_REL
, REL_WHEEL
);
174 static int lenovo_input_mapping_scrollpoint(struct hid_device
*hdev
,
175 struct hid_input
*hi
, struct hid_field
*field
,
176 struct hid_usage
*usage
, unsigned long **bit
, int *max
)
178 if (usage
->hid
== HID_GD_Z
) {
179 hid_map_usage(hi
, usage
, bit
, max
, EV_REL
, REL_HWHEEL
);
185 static int lenovo_input_mapping(struct hid_device
*hdev
,
186 struct hid_input
*hi
, struct hid_field
*field
,
187 struct hid_usage
*usage
, unsigned long **bit
, int *max
)
189 switch (hdev
->product
) {
190 case USB_DEVICE_ID_LENOVO_TPKBD
:
191 return lenovo_input_mapping_tpkbd(hdev
, hi
, field
,
193 case USB_DEVICE_ID_LENOVO_CUSBKBD
:
194 case USB_DEVICE_ID_LENOVO_CBTKBD
:
195 return lenovo_input_mapping_cptkbd(hdev
, hi
, field
,
197 case USB_DEVICE_ID_IBM_SCROLLPOINT_III
:
198 case USB_DEVICE_ID_IBM_SCROLLPOINT_PRO
:
199 case USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL
:
200 case USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL
:
201 case USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO
:
202 case USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL
:
203 return lenovo_input_mapping_scrollpoint(hdev
, hi
, field
,
212 /* Send a config command to the keyboard */
213 static int lenovo_send_cmd_cptkbd(struct hid_device
*hdev
,
214 unsigned char byte2
, unsigned char byte3
)
219 buf
= kzalloc(3, GFP_KERNEL
);
227 switch (hdev
->product
) {
228 case USB_DEVICE_ID_LENOVO_CUSBKBD
:
229 ret
= hid_hw_raw_request(hdev
, 0x13, buf
, 3,
230 HID_FEATURE_REPORT
, HID_REQ_SET_REPORT
);
232 case USB_DEVICE_ID_LENOVO_CBTKBD
:
233 ret
= hid_hw_output_report(hdev
, buf
, 3);
242 return ret
< 0 ? ret
: 0; /* BT returns 0, USB returns sizeof(buf) */
245 static void lenovo_features_set_cptkbd(struct hid_device
*hdev
)
248 struct lenovo_drvdata_cptkbd
*cptkbd_data
= hid_get_drvdata(hdev
);
250 ret
= lenovo_send_cmd_cptkbd(hdev
, 0x05, cptkbd_data
->fn_lock
);
252 hid_err(hdev
, "Fn-lock setting failed: %d\n", ret
);
254 ret
= lenovo_send_cmd_cptkbd(hdev
, 0x02, cptkbd_data
->sensitivity
);
256 hid_err(hdev
, "Sensitivity setting failed: %d\n", ret
);
259 static ssize_t
attr_fn_lock_show_cptkbd(struct device
*dev
,
260 struct device_attribute
*attr
,
263 struct hid_device
*hdev
= to_hid_device(dev
);
264 struct lenovo_drvdata_cptkbd
*cptkbd_data
= hid_get_drvdata(hdev
);
266 return snprintf(buf
, PAGE_SIZE
, "%u\n", cptkbd_data
->fn_lock
);
269 static ssize_t
attr_fn_lock_store_cptkbd(struct device
*dev
,
270 struct device_attribute
*attr
,
274 struct hid_device
*hdev
= to_hid_device(dev
);
275 struct lenovo_drvdata_cptkbd
*cptkbd_data
= hid_get_drvdata(hdev
);
278 if (kstrtoint(buf
, 10, &value
))
280 if (value
< 0 || value
> 1)
283 cptkbd_data
->fn_lock
= !!value
;
284 lenovo_features_set_cptkbd(hdev
);
289 static ssize_t
attr_sensitivity_show_cptkbd(struct device
*dev
,
290 struct device_attribute
*attr
,
293 struct hid_device
*hdev
= to_hid_device(dev
);
294 struct lenovo_drvdata_cptkbd
*cptkbd_data
= hid_get_drvdata(hdev
);
296 return snprintf(buf
, PAGE_SIZE
, "%u\n",
297 cptkbd_data
->sensitivity
);
300 static ssize_t
attr_sensitivity_store_cptkbd(struct device
*dev
,
301 struct device_attribute
*attr
,
305 struct hid_device
*hdev
= to_hid_device(dev
);
306 struct lenovo_drvdata_cptkbd
*cptkbd_data
= hid_get_drvdata(hdev
);
309 if (kstrtoint(buf
, 10, &value
) || value
< 1 || value
> 255)
312 cptkbd_data
->sensitivity
= value
;
313 lenovo_features_set_cptkbd(hdev
);
319 static struct device_attribute dev_attr_fn_lock_cptkbd
=
320 __ATTR(fn_lock
, S_IWUSR
| S_IRUGO
,
321 attr_fn_lock_show_cptkbd
,
322 attr_fn_lock_store_cptkbd
);
324 static struct device_attribute dev_attr_sensitivity_cptkbd
=
325 __ATTR(sensitivity
, S_IWUSR
| S_IRUGO
,
326 attr_sensitivity_show_cptkbd
,
327 attr_sensitivity_store_cptkbd
);
330 static struct attribute
*lenovo_attributes_cptkbd
[] = {
331 &dev_attr_fn_lock_cptkbd
.attr
,
332 &dev_attr_sensitivity_cptkbd
.attr
,
336 static const struct attribute_group lenovo_attr_group_cptkbd
= {
337 .attrs
= lenovo_attributes_cptkbd
,
340 static int lenovo_raw_event(struct hid_device
*hdev
,
341 struct hid_report
*report
, u8
*data
, int size
)
344 * Compact USB keyboard's Fn-F12 report holds down many other keys, and
345 * its own key is outside the usage page range. Remove extra
346 * keypresses and remap to inside usage page.
348 if (unlikely(hdev
->product
== USB_DEVICE_ID_LENOVO_CUSBKBD
352 && data
[2] == 0x01)) {
360 static int lenovo_event_cptkbd(struct hid_device
*hdev
,
361 struct hid_field
*field
, struct hid_usage
*usage
, __s32 value
)
363 struct lenovo_drvdata_cptkbd
*cptkbd_data
= hid_get_drvdata(hdev
);
365 /* "wheel" scroll events */
366 if (usage
->type
== EV_REL
&& (usage
->code
== REL_WHEEL
||
367 usage
->code
== REL_HWHEEL
)) {
368 /* Scroll events disable middle-click event */
369 cptkbd_data
->middlebutton_state
= 2;
373 /* Middle click events */
374 if (usage
->type
== EV_KEY
&& usage
->code
== BTN_MIDDLE
) {
376 cptkbd_data
->middlebutton_state
= 1;
377 } else if (value
== 0) {
378 if (cptkbd_data
->middlebutton_state
== 1) {
379 /* No scrolling inbetween, send middle-click */
380 input_event(field
->hidinput
->input
,
381 EV_KEY
, BTN_MIDDLE
, 1);
382 input_sync(field
->hidinput
->input
);
383 input_event(field
->hidinput
->input
,
384 EV_KEY
, BTN_MIDDLE
, 0);
385 input_sync(field
->hidinput
->input
);
387 cptkbd_data
->middlebutton_state
= 0;
395 static int lenovo_event(struct hid_device
*hdev
, struct hid_field
*field
,
396 struct hid_usage
*usage
, __s32 value
)
398 switch (hdev
->product
) {
399 case USB_DEVICE_ID_LENOVO_CUSBKBD
:
400 case USB_DEVICE_ID_LENOVO_CBTKBD
:
401 return lenovo_event_cptkbd(hdev
, field
, usage
, value
);
407 static int lenovo_features_set_tpkbd(struct hid_device
*hdev
)
409 struct hid_report
*report
;
410 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
412 report
= hdev
->report_enum
[HID_FEATURE_REPORT
].report_id_hash
[4];
414 report
->field
[0]->value
[0] = data_pointer
->press_to_select
? 0x01 : 0x02;
415 report
->field
[0]->value
[0] |= data_pointer
->dragging
? 0x04 : 0x08;
416 report
->field
[0]->value
[0] |= data_pointer
->release_to_select
? 0x10 : 0x20;
417 report
->field
[0]->value
[0] |= data_pointer
->select_right
? 0x80 : 0x40;
418 report
->field
[1]->value
[0] = 0x03; // unknown setting, imitate windows driver
419 report
->field
[2]->value
[0] = data_pointer
->sensitivity
;
420 report
->field
[3]->value
[0] = data_pointer
->press_speed
;
422 hid_hw_request(hdev
, report
, HID_REQ_SET_REPORT
);
426 static ssize_t
attr_press_to_select_show_tpkbd(struct device
*dev
,
427 struct device_attribute
*attr
,
430 struct hid_device
*hdev
= to_hid_device(dev
);
431 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
433 return snprintf(buf
, PAGE_SIZE
, "%u\n", data_pointer
->press_to_select
);
436 static ssize_t
attr_press_to_select_store_tpkbd(struct device
*dev
,
437 struct device_attribute
*attr
,
441 struct hid_device
*hdev
= to_hid_device(dev
);
442 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
445 if (kstrtoint(buf
, 10, &value
))
447 if (value
< 0 || value
> 1)
450 data_pointer
->press_to_select
= value
;
451 lenovo_features_set_tpkbd(hdev
);
456 static ssize_t
attr_dragging_show_tpkbd(struct device
*dev
,
457 struct device_attribute
*attr
,
460 struct hid_device
*hdev
= to_hid_device(dev
);
461 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
463 return snprintf(buf
, PAGE_SIZE
, "%u\n", data_pointer
->dragging
);
466 static ssize_t
attr_dragging_store_tpkbd(struct device
*dev
,
467 struct device_attribute
*attr
,
471 struct hid_device
*hdev
= to_hid_device(dev
);
472 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
475 if (kstrtoint(buf
, 10, &value
))
477 if (value
< 0 || value
> 1)
480 data_pointer
->dragging
= value
;
481 lenovo_features_set_tpkbd(hdev
);
486 static ssize_t
attr_release_to_select_show_tpkbd(struct device
*dev
,
487 struct device_attribute
*attr
,
490 struct hid_device
*hdev
= to_hid_device(dev
);
491 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
493 return snprintf(buf
, PAGE_SIZE
, "%u\n", data_pointer
->release_to_select
);
496 static ssize_t
attr_release_to_select_store_tpkbd(struct device
*dev
,
497 struct device_attribute
*attr
,
501 struct hid_device
*hdev
= to_hid_device(dev
);
502 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
505 if (kstrtoint(buf
, 10, &value
))
507 if (value
< 0 || value
> 1)
510 data_pointer
->release_to_select
= value
;
511 lenovo_features_set_tpkbd(hdev
);
516 static ssize_t
attr_select_right_show_tpkbd(struct device
*dev
,
517 struct device_attribute
*attr
,
520 struct hid_device
*hdev
= to_hid_device(dev
);
521 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
523 return snprintf(buf
, PAGE_SIZE
, "%u\n", data_pointer
->select_right
);
526 static ssize_t
attr_select_right_store_tpkbd(struct device
*dev
,
527 struct device_attribute
*attr
,
531 struct hid_device
*hdev
= to_hid_device(dev
);
532 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
535 if (kstrtoint(buf
, 10, &value
))
537 if (value
< 0 || value
> 1)
540 data_pointer
->select_right
= value
;
541 lenovo_features_set_tpkbd(hdev
);
546 static ssize_t
attr_sensitivity_show_tpkbd(struct device
*dev
,
547 struct device_attribute
*attr
,
550 struct hid_device
*hdev
= to_hid_device(dev
);
551 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
553 return snprintf(buf
, PAGE_SIZE
, "%u\n",
554 data_pointer
->sensitivity
);
557 static ssize_t
attr_sensitivity_store_tpkbd(struct device
*dev
,
558 struct device_attribute
*attr
,
562 struct hid_device
*hdev
= to_hid_device(dev
);
563 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
566 if (kstrtoint(buf
, 10, &value
) || value
< 1 || value
> 255)
569 data_pointer
->sensitivity
= value
;
570 lenovo_features_set_tpkbd(hdev
);
575 static ssize_t
attr_press_speed_show_tpkbd(struct device
*dev
,
576 struct device_attribute
*attr
,
579 struct hid_device
*hdev
= to_hid_device(dev
);
580 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
582 return snprintf(buf
, PAGE_SIZE
, "%u\n",
583 data_pointer
->press_speed
);
586 static ssize_t
attr_press_speed_store_tpkbd(struct device
*dev
,
587 struct device_attribute
*attr
,
591 struct hid_device
*hdev
= to_hid_device(dev
);
592 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
595 if (kstrtoint(buf
, 10, &value
) || value
< 1 || value
> 255)
598 data_pointer
->press_speed
= value
;
599 lenovo_features_set_tpkbd(hdev
);
604 static struct device_attribute dev_attr_press_to_select_tpkbd
=
605 __ATTR(press_to_select
, S_IWUSR
| S_IRUGO
,
606 attr_press_to_select_show_tpkbd
,
607 attr_press_to_select_store_tpkbd
);
609 static struct device_attribute dev_attr_dragging_tpkbd
=
610 __ATTR(dragging
, S_IWUSR
| S_IRUGO
,
611 attr_dragging_show_tpkbd
,
612 attr_dragging_store_tpkbd
);
614 static struct device_attribute dev_attr_release_to_select_tpkbd
=
615 __ATTR(release_to_select
, S_IWUSR
| S_IRUGO
,
616 attr_release_to_select_show_tpkbd
,
617 attr_release_to_select_store_tpkbd
);
619 static struct device_attribute dev_attr_select_right_tpkbd
=
620 __ATTR(select_right
, S_IWUSR
| S_IRUGO
,
621 attr_select_right_show_tpkbd
,
622 attr_select_right_store_tpkbd
);
624 static struct device_attribute dev_attr_sensitivity_tpkbd
=
625 __ATTR(sensitivity
, S_IWUSR
| S_IRUGO
,
626 attr_sensitivity_show_tpkbd
,
627 attr_sensitivity_store_tpkbd
);
629 static struct device_attribute dev_attr_press_speed_tpkbd
=
630 __ATTR(press_speed
, S_IWUSR
| S_IRUGO
,
631 attr_press_speed_show_tpkbd
,
632 attr_press_speed_store_tpkbd
);
634 static struct attribute
*lenovo_attributes_tpkbd
[] = {
635 &dev_attr_press_to_select_tpkbd
.attr
,
636 &dev_attr_dragging_tpkbd
.attr
,
637 &dev_attr_release_to_select_tpkbd
.attr
,
638 &dev_attr_select_right_tpkbd
.attr
,
639 &dev_attr_sensitivity_tpkbd
.attr
,
640 &dev_attr_press_speed_tpkbd
.attr
,
644 static const struct attribute_group lenovo_attr_group_tpkbd
= {
645 .attrs
= lenovo_attributes_tpkbd
,
648 static enum led_brightness
lenovo_led_brightness_get_tpkbd(
649 struct led_classdev
*led_cdev
)
651 struct device
*dev
= led_cdev
->dev
->parent
;
652 struct hid_device
*hdev
= to_hid_device(dev
);
653 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
656 if (led_cdev
== &data_pointer
->led_micmute
)
659 return data_pointer
->led_state
& (1 << led_nr
)
664 static void lenovo_led_brightness_set_tpkbd(struct led_classdev
*led_cdev
,
665 enum led_brightness value
)
667 struct device
*dev
= led_cdev
->dev
->parent
;
668 struct hid_device
*hdev
= to_hid_device(dev
);
669 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
670 struct hid_report
*report
;
673 if (led_cdev
== &data_pointer
->led_micmute
)
676 if (value
== LED_OFF
)
677 data_pointer
->led_state
&= ~(1 << led_nr
);
679 data_pointer
->led_state
|= 1 << led_nr
;
681 report
= hdev
->report_enum
[HID_OUTPUT_REPORT
].report_id_hash
[3];
682 report
->field
[0]->value
[0] = (data_pointer
->led_state
>> 0) & 1;
683 report
->field
[0]->value
[1] = (data_pointer
->led_state
>> 1) & 1;
684 hid_hw_request(hdev
, report
, HID_REQ_SET_REPORT
);
687 static int lenovo_probe_tpkbd(struct hid_device
*hdev
)
689 struct device
*dev
= &hdev
->dev
;
690 struct lenovo_drvdata_tpkbd
*data_pointer
;
691 size_t name_sz
= strlen(dev_name(dev
)) + 16;
692 char *name_mute
, *name_micmute
;
697 * Only register extra settings against subdevice where input_mapping
698 * set drvdata to 1, i.e. the trackpoint.
700 if (!hid_get_drvdata(hdev
))
703 hid_set_drvdata(hdev
, NULL
);
705 /* Validate required reports. */
706 for (i
= 0; i
< 4; i
++) {
707 if (!hid_validate_values(hdev
, HID_FEATURE_REPORT
, 4, i
, 1))
710 if (!hid_validate_values(hdev
, HID_OUTPUT_REPORT
, 3, 0, 2))
713 ret
= sysfs_create_group(&hdev
->dev
.kobj
, &lenovo_attr_group_tpkbd
);
715 hid_warn(hdev
, "Could not create sysfs group: %d\n", ret
);
717 data_pointer
= devm_kzalloc(&hdev
->dev
,
718 sizeof(struct lenovo_drvdata_tpkbd
),
720 if (data_pointer
== NULL
) {
721 hid_err(hdev
, "Could not allocate memory for driver data\n");
726 // set same default values as windows driver
727 data_pointer
->sensitivity
= 0xa0;
728 data_pointer
->press_speed
= 0x38;
730 name_mute
= devm_kzalloc(&hdev
->dev
, name_sz
, GFP_KERNEL
);
731 name_micmute
= devm_kzalloc(&hdev
->dev
, name_sz
, GFP_KERNEL
);
732 if (name_mute
== NULL
|| name_micmute
== NULL
) {
733 hid_err(hdev
, "Could not allocate memory for led data\n");
737 snprintf(name_mute
, name_sz
, "%s:amber:mute", dev_name(dev
));
738 snprintf(name_micmute
, name_sz
, "%s:amber:micmute", dev_name(dev
));
740 hid_set_drvdata(hdev
, data_pointer
);
742 data_pointer
->led_mute
.name
= name_mute
;
743 data_pointer
->led_mute
.brightness_get
= lenovo_led_brightness_get_tpkbd
;
744 data_pointer
->led_mute
.brightness_set
= lenovo_led_brightness_set_tpkbd
;
745 data_pointer
->led_mute
.dev
= dev
;
746 ret
= led_classdev_register(dev
, &data_pointer
->led_mute
);
750 data_pointer
->led_micmute
.name
= name_micmute
;
751 data_pointer
->led_micmute
.brightness_get
=
752 lenovo_led_brightness_get_tpkbd
;
753 data_pointer
->led_micmute
.brightness_set
=
754 lenovo_led_brightness_set_tpkbd
;
755 data_pointer
->led_micmute
.dev
= dev
;
756 ret
= led_classdev_register(dev
, &data_pointer
->led_micmute
);
758 led_classdev_unregister(&data_pointer
->led_mute
);
762 lenovo_features_set_tpkbd(hdev
);
766 sysfs_remove_group(&hdev
->dev
.kobj
, &lenovo_attr_group_tpkbd
);
770 static int lenovo_probe_cptkbd(struct hid_device
*hdev
)
773 struct lenovo_drvdata_cptkbd
*cptkbd_data
;
775 /* All the custom action happens on the USBMOUSE device for USB */
776 if (hdev
->product
== USB_DEVICE_ID_LENOVO_CUSBKBD
777 && hdev
->type
!= HID_TYPE_USBMOUSE
) {
778 hid_dbg(hdev
, "Ignoring keyboard half of device\n");
782 cptkbd_data
= devm_kzalloc(&hdev
->dev
,
783 sizeof(*cptkbd_data
),
785 if (cptkbd_data
== NULL
) {
786 hid_err(hdev
, "can't alloc keyboard descriptor\n");
789 hid_set_drvdata(hdev
, cptkbd_data
);
792 * Tell the keyboard a driver understands it, and turn F7, F9, F11 into
795 ret
= lenovo_send_cmd_cptkbd(hdev
, 0x01, 0x03);
797 hid_warn(hdev
, "Failed to switch F7/9/11 mode: %d\n", ret
);
799 /* Switch middle button to native mode */
800 ret
= lenovo_send_cmd_cptkbd(hdev
, 0x09, 0x01);
802 hid_warn(hdev
, "Failed to switch middle button: %d\n", ret
);
804 /* Set keyboard settings to known state */
805 cptkbd_data
->middlebutton_state
= 0;
806 cptkbd_data
->fn_lock
= true;
807 cptkbd_data
->sensitivity
= 0x05;
808 lenovo_features_set_cptkbd(hdev
);
810 ret
= sysfs_create_group(&hdev
->dev
.kobj
, &lenovo_attr_group_cptkbd
);
812 hid_warn(hdev
, "Could not create sysfs group: %d\n", ret
);
817 static int lenovo_probe(struct hid_device
*hdev
,
818 const struct hid_device_id
*id
)
822 ret
= hid_parse(hdev
);
824 hid_err(hdev
, "hid_parse failed\n");
828 ret
= hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
830 hid_err(hdev
, "hid_hw_start failed\n");
834 switch (hdev
->product
) {
835 case USB_DEVICE_ID_LENOVO_TPKBD
:
836 ret
= lenovo_probe_tpkbd(hdev
);
838 case USB_DEVICE_ID_LENOVO_CUSBKBD
:
839 case USB_DEVICE_ID_LENOVO_CBTKBD
:
840 ret
= lenovo_probe_cptkbd(hdev
);
856 static void lenovo_remove_tpkbd(struct hid_device
*hdev
)
858 struct lenovo_drvdata_tpkbd
*data_pointer
= hid_get_drvdata(hdev
);
861 * Only the trackpoint half of the keyboard has drvdata and stuff that
862 * needs unregistering.
864 if (data_pointer
== NULL
)
867 sysfs_remove_group(&hdev
->dev
.kobj
,
868 &lenovo_attr_group_tpkbd
);
870 led_classdev_unregister(&data_pointer
->led_micmute
);
871 led_classdev_unregister(&data_pointer
->led_mute
);
873 hid_set_drvdata(hdev
, NULL
);
876 static void lenovo_remove_cptkbd(struct hid_device
*hdev
)
878 sysfs_remove_group(&hdev
->dev
.kobj
,
879 &lenovo_attr_group_cptkbd
);
882 static void lenovo_remove(struct hid_device
*hdev
)
884 switch (hdev
->product
) {
885 case USB_DEVICE_ID_LENOVO_TPKBD
:
886 lenovo_remove_tpkbd(hdev
);
888 case USB_DEVICE_ID_LENOVO_CUSBKBD
:
889 case USB_DEVICE_ID_LENOVO_CBTKBD
:
890 lenovo_remove_cptkbd(hdev
);
897 static int lenovo_input_configured(struct hid_device
*hdev
,
898 struct hid_input
*hi
)
900 switch (hdev
->product
) {
901 case USB_DEVICE_ID_LENOVO_TPKBD
:
902 case USB_DEVICE_ID_LENOVO_CUSBKBD
:
903 case USB_DEVICE_ID_LENOVO_CBTKBD
:
904 if (test_bit(EV_REL
, hi
->input
->evbit
)) {
905 /* set only for trackpoint device */
906 __set_bit(INPUT_PROP_POINTER
, hi
->input
->propbit
);
907 __set_bit(INPUT_PROP_POINTING_STICK
,
917 static const struct hid_device_id lenovo_devices
[] = {
918 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO
, USB_DEVICE_ID_LENOVO_TPKBD
) },
919 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO
, USB_DEVICE_ID_LENOVO_CUSBKBD
) },
920 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO
, USB_DEVICE_ID_LENOVO_CBTKBD
) },
921 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO
, USB_DEVICE_ID_LENOVO_TPPRODOCK
) },
922 { HID_USB_DEVICE(USB_VENDOR_ID_IBM
, USB_DEVICE_ID_IBM_SCROLLPOINT_III
) },
923 { HID_USB_DEVICE(USB_VENDOR_ID_IBM
, USB_DEVICE_ID_IBM_SCROLLPOINT_PRO
) },
924 { HID_USB_DEVICE(USB_VENDOR_ID_IBM
, USB_DEVICE_ID_IBM_SCROLLPOINT_OPTICAL
) },
925 { HID_USB_DEVICE(USB_VENDOR_ID_IBM
, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL
) },
926 { HID_USB_DEVICE(USB_VENDOR_ID_IBM
, USB_DEVICE_ID_IBM_SCROLLPOINT_800DPI_OPTICAL_PRO
) },
927 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO
, USB_DEVICE_ID_LENOVO_SCROLLPOINT_OPTICAL
) },
931 MODULE_DEVICE_TABLE(hid
, lenovo_devices
);
933 static struct hid_driver lenovo_driver
= {
935 .id_table
= lenovo_devices
,
936 .input_configured
= lenovo_input_configured
,
937 .input_mapping
= lenovo_input_mapping
,
938 .probe
= lenovo_probe
,
939 .remove
= lenovo_remove
,
940 .raw_event
= lenovo_raw_event
,
941 .event
= lenovo_event
,
942 .report_fixup
= lenovo_report_fixup
,
944 module_hid_driver(lenovo_driver
);
946 MODULE_LICENSE("GPL");