2 * HID driver for Lenovo ThinkPad USB Keyboard with TrackPoint
4 * Copyright (c) 2012 Bernhard Seibold
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the Free
10 * Software Foundation; either version 2 of the License, or (at your option)
14 #include <linux/module.h>
15 #include <linux/sysfs.h>
16 #include <linux/device.h>
17 #include <linux/usb.h>
18 #include <linux/hid.h>
19 #include <linux/input.h>
20 #include <linux/leds.h>
21 #include "usbhid/usbhid.h"
25 /* This is only used for the trackpoint part of the driver, hence _tp */
26 struct tpkbd_data_pointer
{
28 struct led_classdev led_mute
;
29 struct led_classdev led_micmute
;
32 int release_to_select
;
38 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
40 static int tpkbd_input_mapping(struct hid_device
*hdev
,
41 struct hid_input
*hi
, struct hid_field
*field
,
42 struct hid_usage
*usage
, unsigned long **bit
, int *max
)
44 struct usbhid_device
*uhdev
;
46 uhdev
= (struct usbhid_device
*) hdev
->driver_data
;
47 if (uhdev
->ifnum
== 1 && usage
->hid
== (HID_UP_BUTTON
| 0x0010)) {
48 map_key_clear(KEY_MICMUTE
);
56 static int tpkbd_features_set(struct hid_device
*hdev
)
58 struct hid_report
*report
;
59 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
61 report
= hdev
->report_enum
[HID_FEATURE_REPORT
].report_id_hash
[4];
63 report
->field
[0]->value
[0] = data_pointer
->press_to_select
? 0x01 : 0x02;
64 report
->field
[0]->value
[0] |= data_pointer
->dragging
? 0x04 : 0x08;
65 report
->field
[0]->value
[0] |= data_pointer
->release_to_select
? 0x10 : 0x20;
66 report
->field
[0]->value
[0] |= data_pointer
->select_right
? 0x80 : 0x40;
67 report
->field
[1]->value
[0] = 0x03; // unknown setting, imitate windows driver
68 report
->field
[2]->value
[0] = data_pointer
->sensitivity
;
69 report
->field
[3]->value
[0] = data_pointer
->press_speed
;
71 usbhid_submit_report(hdev
, report
, USB_DIR_OUT
);
75 static ssize_t
pointer_press_to_select_show(struct device
*dev
,
76 struct device_attribute
*attr
,
79 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
80 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
82 return snprintf(buf
, PAGE_SIZE
, "%u\n", data_pointer
->press_to_select
);
85 static ssize_t
pointer_press_to_select_store(struct device
*dev
,
86 struct device_attribute
*attr
,
90 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
91 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
94 if (kstrtoint(buf
, 10, &value
))
96 if (value
< 0 || value
> 1)
99 data_pointer
->press_to_select
= value
;
100 tpkbd_features_set(hdev
);
105 static ssize_t
pointer_dragging_show(struct device
*dev
,
106 struct device_attribute
*attr
,
109 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
110 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
112 return snprintf(buf
, PAGE_SIZE
, "%u\n", data_pointer
->dragging
);
115 static ssize_t
pointer_dragging_store(struct device
*dev
,
116 struct device_attribute
*attr
,
120 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
121 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
124 if (kstrtoint(buf
, 10, &value
))
126 if (value
< 0 || value
> 1)
129 data_pointer
->dragging
= value
;
130 tpkbd_features_set(hdev
);
135 static ssize_t
pointer_release_to_select_show(struct device
*dev
,
136 struct device_attribute
*attr
,
139 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
140 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
142 return snprintf(buf
, PAGE_SIZE
, "%u\n", data_pointer
->release_to_select
);
145 static ssize_t
pointer_release_to_select_store(struct device
*dev
,
146 struct device_attribute
*attr
,
150 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
151 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
154 if (kstrtoint(buf
, 10, &value
))
156 if (value
< 0 || value
> 1)
159 data_pointer
->release_to_select
= value
;
160 tpkbd_features_set(hdev
);
165 static ssize_t
pointer_select_right_show(struct device
*dev
,
166 struct device_attribute
*attr
,
169 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
170 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
172 return snprintf(buf
, PAGE_SIZE
, "%u\n", data_pointer
->select_right
);
175 static ssize_t
pointer_select_right_store(struct device
*dev
,
176 struct device_attribute
*attr
,
180 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
181 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
184 if (kstrtoint(buf
, 10, &value
))
186 if (value
< 0 || value
> 1)
189 data_pointer
->select_right
= value
;
190 tpkbd_features_set(hdev
);
195 static ssize_t
pointer_sensitivity_show(struct device
*dev
,
196 struct device_attribute
*attr
,
199 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
200 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
202 return snprintf(buf
, PAGE_SIZE
, "%u\n",
203 data_pointer
->sensitivity
);
206 static ssize_t
pointer_sensitivity_store(struct device
*dev
,
207 struct device_attribute
*attr
,
211 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
212 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
215 if (kstrtoint(buf
, 10, &value
) || value
< 1 || value
> 255)
218 data_pointer
->sensitivity
= value
;
219 tpkbd_features_set(hdev
);
224 static ssize_t
pointer_press_speed_show(struct device
*dev
,
225 struct device_attribute
*attr
,
228 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
229 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
231 data_pointer
= hid_get_drvdata(hdev
);
233 return snprintf(buf
, PAGE_SIZE
, "%u\n",
234 data_pointer
->press_speed
);
237 static ssize_t
pointer_press_speed_store(struct device
*dev
,
238 struct device_attribute
*attr
,
242 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
243 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
246 if (kstrtoint(buf
, 10, &value
) || value
< 1 || value
> 255)
249 data_pointer
->press_speed
= value
;
250 tpkbd_features_set(hdev
);
255 static struct device_attribute dev_attr_pointer_press_to_select
=
256 __ATTR(press_to_select
, S_IWUSR
| S_IRUGO
,
257 pointer_press_to_select_show
,
258 pointer_press_to_select_store
);
260 static struct device_attribute dev_attr_pointer_dragging
=
261 __ATTR(dragging
, S_IWUSR
| S_IRUGO
,
262 pointer_dragging_show
,
263 pointer_dragging_store
);
265 static struct device_attribute dev_attr_pointer_release_to_select
=
266 __ATTR(release_to_select
, S_IWUSR
| S_IRUGO
,
267 pointer_release_to_select_show
,
268 pointer_release_to_select_store
);
270 static struct device_attribute dev_attr_pointer_select_right
=
271 __ATTR(select_right
, S_IWUSR
| S_IRUGO
,
272 pointer_select_right_show
,
273 pointer_select_right_store
);
275 static struct device_attribute dev_attr_pointer_sensitivity
=
276 __ATTR(sensitivity
, S_IWUSR
| S_IRUGO
,
277 pointer_sensitivity_show
,
278 pointer_sensitivity_store
);
280 static struct device_attribute dev_attr_pointer_press_speed
=
281 __ATTR(press_speed
, S_IWUSR
| S_IRUGO
,
282 pointer_press_speed_show
,
283 pointer_press_speed_store
);
285 static struct attribute
*tpkbd_attributes_pointer
[] = {
286 &dev_attr_pointer_press_to_select
.attr
,
287 &dev_attr_pointer_dragging
.attr
,
288 &dev_attr_pointer_release_to_select
.attr
,
289 &dev_attr_pointer_select_right
.attr
,
290 &dev_attr_pointer_sensitivity
.attr
,
291 &dev_attr_pointer_press_speed
.attr
,
295 static const struct attribute_group tpkbd_attr_group_pointer
= {
296 .attrs
= tpkbd_attributes_pointer
,
299 static enum led_brightness
tpkbd_led_brightness_get(
300 struct led_classdev
*led_cdev
)
302 struct device
*dev
= led_cdev
->dev
->parent
;
303 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
304 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
307 if (led_cdev
== &data_pointer
->led_micmute
)
310 return data_pointer
->led_state
& (1 << led_nr
)
315 static void tpkbd_led_brightness_set(struct led_classdev
*led_cdev
,
316 enum led_brightness value
)
318 struct device
*dev
= led_cdev
->dev
->parent
;
319 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
320 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
321 struct hid_report
*report
;
324 if (led_cdev
== &data_pointer
->led_micmute
)
327 if (value
== LED_OFF
)
328 data_pointer
->led_state
&= ~(1 << led_nr
);
330 data_pointer
->led_state
|= 1 << led_nr
;
332 report
= hdev
->report_enum
[HID_OUTPUT_REPORT
].report_id_hash
[3];
333 report
->field
[0]->value
[0] = (data_pointer
->led_state
>> 0) & 1;
334 report
->field
[0]->value
[1] = (data_pointer
->led_state
>> 1) & 1;
335 usbhid_submit_report(hdev
, report
, USB_DIR_OUT
);
338 static int tpkbd_probe_tp(struct hid_device
*hdev
)
340 struct device
*dev
= &hdev
->dev
;
341 struct tpkbd_data_pointer
*data_pointer
;
342 size_t name_sz
= strlen(dev_name(dev
)) + 16;
343 char *name_mute
, *name_micmute
;
346 if (sysfs_create_group(&hdev
->dev
.kobj
,
347 &tpkbd_attr_group_pointer
)) {
348 hid_warn(hdev
, "Could not create sysfs group\n");
351 data_pointer
= kzalloc(sizeof(struct tpkbd_data_pointer
), GFP_KERNEL
);
352 if (data_pointer
== NULL
) {
353 hid_err(hdev
, "Could not allocate memory for driver data\n");
357 // set same default values as windows driver
358 data_pointer
->sensitivity
= 0xa0;
359 data_pointer
->press_speed
= 0x38;
361 name_mute
= kzalloc(name_sz
, GFP_KERNEL
);
362 if (name_mute
== NULL
) {
363 hid_err(hdev
, "Could not allocate memory for led data\n");
367 snprintf(name_mute
, name_sz
, "%s:amber:mute", dev_name(dev
));
369 name_micmute
= kzalloc(name_sz
, GFP_KERNEL
);
370 if (name_micmute
== NULL
) {
371 hid_err(hdev
, "Could not allocate memory for led data\n");
375 snprintf(name_micmute
, name_sz
, "%s:amber:micmute", dev_name(dev
));
377 hid_set_drvdata(hdev
, data_pointer
);
379 data_pointer
->led_mute
.name
= name_mute
;
380 data_pointer
->led_mute
.brightness_get
= tpkbd_led_brightness_get
;
381 data_pointer
->led_mute
.brightness_set
= tpkbd_led_brightness_set
;
382 data_pointer
->led_mute
.dev
= dev
;
383 led_classdev_register(dev
, &data_pointer
->led_mute
);
385 data_pointer
->led_micmute
.name
= name_micmute
;
386 data_pointer
->led_micmute
.brightness_get
= tpkbd_led_brightness_get
;
387 data_pointer
->led_micmute
.brightness_set
= tpkbd_led_brightness_set
;
388 data_pointer
->led_micmute
.dev
= dev
;
389 led_classdev_register(dev
, &data_pointer
->led_micmute
);
391 tpkbd_features_set(hdev
);
402 static int tpkbd_probe(struct hid_device
*hdev
,
403 const struct hid_device_id
*id
)
406 struct usbhid_device
*uhdev
;
408 ret
= hid_parse(hdev
);
410 hid_err(hdev
, "hid_parse failed\n");
414 ret
= hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
416 hid_err(hdev
, "hid_hw_start failed\n");
420 uhdev
= (struct usbhid_device
*) hdev
->driver_data
;
422 if (uhdev
->ifnum
== 1)
423 return tpkbd_probe_tp(hdev
);
430 static void tpkbd_remove_tp(struct hid_device
*hdev
)
432 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
434 sysfs_remove_group(&hdev
->dev
.kobj
,
435 &tpkbd_attr_group_pointer
);
437 led_classdev_unregister(&data_pointer
->led_micmute
);
438 led_classdev_unregister(&data_pointer
->led_mute
);
440 hid_set_drvdata(hdev
, NULL
);
441 kfree(data_pointer
->led_micmute
.name
);
442 kfree(data_pointer
->led_mute
.name
);
446 static void tpkbd_remove(struct hid_device
*hdev
)
448 struct usbhid_device
*uhdev
;
450 uhdev
= (struct usbhid_device
*) hdev
->driver_data
;
451 if (uhdev
->ifnum
== 1)
452 tpkbd_remove_tp(hdev
);
457 static const struct hid_device_id tpkbd_devices
[] = {
458 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO
, USB_DEVICE_ID_LENOVO_TPKBD
) },
462 MODULE_DEVICE_TABLE(hid
, tpkbd_devices
);
464 static struct hid_driver tpkbd_driver
= {
465 .name
= "lenovo_tpkbd",
466 .id_table
= tpkbd_devices
,
467 .input_mapping
= tpkbd_input_mapping
,
468 .probe
= tpkbd_probe
,
469 .remove
= tpkbd_remove
,
471 module_hid_driver(tpkbd_driver
);
473 MODULE_LICENSE("GPL");