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 hid_hw_request(hdev
, report
, HID_REQ_SET_REPORT
);
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 return snprintf(buf
, PAGE_SIZE
, "%u\n",
232 data_pointer
->press_speed
);
235 static ssize_t
pointer_press_speed_store(struct device
*dev
,
236 struct device_attribute
*attr
,
240 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
241 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
244 if (kstrtoint(buf
, 10, &value
) || value
< 1 || value
> 255)
247 data_pointer
->press_speed
= value
;
248 tpkbd_features_set(hdev
);
253 static struct device_attribute dev_attr_pointer_press_to_select
=
254 __ATTR(press_to_select
, S_IWUSR
| S_IRUGO
,
255 pointer_press_to_select_show
,
256 pointer_press_to_select_store
);
258 static struct device_attribute dev_attr_pointer_dragging
=
259 __ATTR(dragging
, S_IWUSR
| S_IRUGO
,
260 pointer_dragging_show
,
261 pointer_dragging_store
);
263 static struct device_attribute dev_attr_pointer_release_to_select
=
264 __ATTR(release_to_select
, S_IWUSR
| S_IRUGO
,
265 pointer_release_to_select_show
,
266 pointer_release_to_select_store
);
268 static struct device_attribute dev_attr_pointer_select_right
=
269 __ATTR(select_right
, S_IWUSR
| S_IRUGO
,
270 pointer_select_right_show
,
271 pointer_select_right_store
);
273 static struct device_attribute dev_attr_pointer_sensitivity
=
274 __ATTR(sensitivity
, S_IWUSR
| S_IRUGO
,
275 pointer_sensitivity_show
,
276 pointer_sensitivity_store
);
278 static struct device_attribute dev_attr_pointer_press_speed
=
279 __ATTR(press_speed
, S_IWUSR
| S_IRUGO
,
280 pointer_press_speed_show
,
281 pointer_press_speed_store
);
283 static struct attribute
*tpkbd_attributes_pointer
[] = {
284 &dev_attr_pointer_press_to_select
.attr
,
285 &dev_attr_pointer_dragging
.attr
,
286 &dev_attr_pointer_release_to_select
.attr
,
287 &dev_attr_pointer_select_right
.attr
,
288 &dev_attr_pointer_sensitivity
.attr
,
289 &dev_attr_pointer_press_speed
.attr
,
293 static const struct attribute_group tpkbd_attr_group_pointer
= {
294 .attrs
= tpkbd_attributes_pointer
,
297 static enum led_brightness
tpkbd_led_brightness_get(
298 struct led_classdev
*led_cdev
)
300 struct device
*dev
= led_cdev
->dev
->parent
;
301 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
302 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
305 if (led_cdev
== &data_pointer
->led_micmute
)
308 return data_pointer
->led_state
& (1 << led_nr
)
313 static void tpkbd_led_brightness_set(struct led_classdev
*led_cdev
,
314 enum led_brightness value
)
316 struct device
*dev
= led_cdev
->dev
->parent
;
317 struct hid_device
*hdev
= container_of(dev
, struct hid_device
, dev
);
318 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
319 struct hid_report
*report
;
322 if (led_cdev
== &data_pointer
->led_micmute
)
325 if (value
== LED_OFF
)
326 data_pointer
->led_state
&= ~(1 << led_nr
);
328 data_pointer
->led_state
|= 1 << led_nr
;
330 report
= hdev
->report_enum
[HID_OUTPUT_REPORT
].report_id_hash
[3];
331 report
->field
[0]->value
[0] = (data_pointer
->led_state
>> 0) & 1;
332 report
->field
[0]->value
[1] = (data_pointer
->led_state
>> 1) & 1;
333 hid_hw_request(hdev
, report
, HID_REQ_SET_REPORT
);
336 static int tpkbd_probe_tp(struct hid_device
*hdev
)
338 struct device
*dev
= &hdev
->dev
;
339 struct tpkbd_data_pointer
*data_pointer
;
340 size_t name_sz
= strlen(dev_name(dev
)) + 16;
341 char *name_mute
, *name_micmute
;
344 if (sysfs_create_group(&hdev
->dev
.kobj
,
345 &tpkbd_attr_group_pointer
)) {
346 hid_warn(hdev
, "Could not create sysfs group\n");
349 data_pointer
= kzalloc(sizeof(struct tpkbd_data_pointer
), GFP_KERNEL
);
350 if (data_pointer
== NULL
) {
351 hid_err(hdev
, "Could not allocate memory for driver data\n");
355 // set same default values as windows driver
356 data_pointer
->sensitivity
= 0xa0;
357 data_pointer
->press_speed
= 0x38;
359 name_mute
= kzalloc(name_sz
, GFP_KERNEL
);
360 if (name_mute
== NULL
) {
361 hid_err(hdev
, "Could not allocate memory for led data\n");
365 snprintf(name_mute
, name_sz
, "%s:amber:mute", dev_name(dev
));
367 name_micmute
= kzalloc(name_sz
, GFP_KERNEL
);
368 if (name_micmute
== NULL
) {
369 hid_err(hdev
, "Could not allocate memory for led data\n");
373 snprintf(name_micmute
, name_sz
, "%s:amber:micmute", dev_name(dev
));
375 hid_set_drvdata(hdev
, data_pointer
);
377 data_pointer
->led_mute
.name
= name_mute
;
378 data_pointer
->led_mute
.brightness_get
= tpkbd_led_brightness_get
;
379 data_pointer
->led_mute
.brightness_set
= tpkbd_led_brightness_set
;
380 data_pointer
->led_mute
.dev
= dev
;
381 led_classdev_register(dev
, &data_pointer
->led_mute
);
383 data_pointer
->led_micmute
.name
= name_micmute
;
384 data_pointer
->led_micmute
.brightness_get
= tpkbd_led_brightness_get
;
385 data_pointer
->led_micmute
.brightness_set
= tpkbd_led_brightness_set
;
386 data_pointer
->led_micmute
.dev
= dev
;
387 led_classdev_register(dev
, &data_pointer
->led_micmute
);
389 tpkbd_features_set(hdev
);
400 static int tpkbd_probe(struct hid_device
*hdev
,
401 const struct hid_device_id
*id
)
404 struct usbhid_device
*uhdev
;
406 ret
= hid_parse(hdev
);
408 hid_err(hdev
, "hid_parse failed\n");
412 ret
= hid_hw_start(hdev
, HID_CONNECT_DEFAULT
);
414 hid_err(hdev
, "hid_hw_start failed\n");
418 uhdev
= (struct usbhid_device
*) hdev
->driver_data
;
420 if (uhdev
->ifnum
== 1)
421 return tpkbd_probe_tp(hdev
);
428 static void tpkbd_remove_tp(struct hid_device
*hdev
)
430 struct tpkbd_data_pointer
*data_pointer
= hid_get_drvdata(hdev
);
432 sysfs_remove_group(&hdev
->dev
.kobj
,
433 &tpkbd_attr_group_pointer
);
435 led_classdev_unregister(&data_pointer
->led_micmute
);
436 led_classdev_unregister(&data_pointer
->led_mute
);
438 hid_set_drvdata(hdev
, NULL
);
439 kfree(data_pointer
->led_micmute
.name
);
440 kfree(data_pointer
->led_mute
.name
);
444 static void tpkbd_remove(struct hid_device
*hdev
)
446 struct usbhid_device
*uhdev
;
448 uhdev
= (struct usbhid_device
*) hdev
->driver_data
;
449 if (uhdev
->ifnum
== 1)
450 tpkbd_remove_tp(hdev
);
455 static const struct hid_device_id tpkbd_devices
[] = {
456 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO
, USB_DEVICE_ID_LENOVO_TPKBD
) },
460 MODULE_DEVICE_TABLE(hid
, tpkbd_devices
);
462 static struct hid_driver tpkbd_driver
= {
463 .name
= "lenovo_tpkbd",
464 .id_table
= tpkbd_devices
,
465 .input_mapping
= tpkbd_input_mapping
,
466 .probe
= tpkbd_probe
,
467 .remove
= tpkbd_remove
,
469 module_hid_driver(tpkbd_driver
);
471 MODULE_LICENSE("GPL");