HID: lenovo: Rename hid-lenovo-tpkbd to hid-lenovo
[deliverable/linux.git] / drivers / hid / hid-lenovo.c
1 /*
2 * HID driver for Lenovo ThinkPad USB Keyboard with TrackPoint
3 *
4 * Copyright (c) 2012 Bernhard Seibold
5 */
6
7 /*
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)
11 * any later version.
12 */
13
14 #include <linux/module.h>
15 #include <linux/sysfs.h>
16 #include <linux/device.h>
17 #include <linux/hid.h>
18 #include <linux/input.h>
19 #include <linux/leds.h>
20
21 #include "hid-ids.h"
22
23 struct lenovo_drvdata_tpkbd {
24 int led_state;
25 struct led_classdev led_mute;
26 struct led_classdev led_micmute;
27 int press_to_select;
28 int dragging;
29 int release_to_select;
30 int select_right;
31 int sensitivity;
32 int press_speed;
33 };
34
35 #define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
36
37 static int lenovo_input_mapping_tpkbd(struct hid_device *hdev,
38 struct hid_input *hi, struct hid_field *field,
39 struct hid_usage *usage, unsigned long **bit, int *max)
40 {
41 if (usage->hid == (HID_UP_BUTTON | 0x0010)) {
42 /* mark the device as pointer */
43 hid_set_drvdata(hdev, (void *)1);
44 map_key_clear(KEY_MICMUTE);
45 return 1;
46 }
47 return 0;
48 }
49
50 #undef map_key_clear
51
52 static int lenovo_features_set_tpkbd(struct hid_device *hdev)
53 {
54 struct hid_report *report;
55 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
56
57 report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4];
58
59 report->field[0]->value[0] = data_pointer->press_to_select ? 0x01 : 0x02;
60 report->field[0]->value[0] |= data_pointer->dragging ? 0x04 : 0x08;
61 report->field[0]->value[0] |= data_pointer->release_to_select ? 0x10 : 0x20;
62 report->field[0]->value[0] |= data_pointer->select_right ? 0x80 : 0x40;
63 report->field[1]->value[0] = 0x03; // unknown setting, imitate windows driver
64 report->field[2]->value[0] = data_pointer->sensitivity;
65 report->field[3]->value[0] = data_pointer->press_speed;
66
67 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
68 return 0;
69 }
70
71 static ssize_t attr_press_to_select_show_tpkbd(struct device *dev,
72 struct device_attribute *attr,
73 char *buf)
74 {
75 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
76 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
77
78 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select);
79 }
80
81 static ssize_t attr_press_to_select_store_tpkbd(struct device *dev,
82 struct device_attribute *attr,
83 const char *buf,
84 size_t count)
85 {
86 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
87 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
88 int value;
89
90 if (kstrtoint(buf, 10, &value))
91 return -EINVAL;
92 if (value < 0 || value > 1)
93 return -EINVAL;
94
95 data_pointer->press_to_select = value;
96 lenovo_features_set_tpkbd(hdev);
97
98 return count;
99 }
100
101 static ssize_t attr_dragging_show_tpkbd(struct device *dev,
102 struct device_attribute *attr,
103 char *buf)
104 {
105 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
106 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
107
108 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging);
109 }
110
111 static ssize_t attr_dragging_store_tpkbd(struct device *dev,
112 struct device_attribute *attr,
113 const char *buf,
114 size_t count)
115 {
116 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
117 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
118 int value;
119
120 if (kstrtoint(buf, 10, &value))
121 return -EINVAL;
122 if (value < 0 || value > 1)
123 return -EINVAL;
124
125 data_pointer->dragging = value;
126 lenovo_features_set_tpkbd(hdev);
127
128 return count;
129 }
130
131 static ssize_t attr_release_to_select_show_tpkbd(struct device *dev,
132 struct device_attribute *attr,
133 char *buf)
134 {
135 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
136 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
137
138 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select);
139 }
140
141 static ssize_t attr_release_to_select_store_tpkbd(struct device *dev,
142 struct device_attribute *attr,
143 const char *buf,
144 size_t count)
145 {
146 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
147 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
148 int value;
149
150 if (kstrtoint(buf, 10, &value))
151 return -EINVAL;
152 if (value < 0 || value > 1)
153 return -EINVAL;
154
155 data_pointer->release_to_select = value;
156 lenovo_features_set_tpkbd(hdev);
157
158 return count;
159 }
160
161 static ssize_t attr_select_right_show_tpkbd(struct device *dev,
162 struct device_attribute *attr,
163 char *buf)
164 {
165 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
166 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
167
168 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right);
169 }
170
171 static ssize_t attr_select_right_store_tpkbd(struct device *dev,
172 struct device_attribute *attr,
173 const char *buf,
174 size_t count)
175 {
176 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
177 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
178 int value;
179
180 if (kstrtoint(buf, 10, &value))
181 return -EINVAL;
182 if (value < 0 || value > 1)
183 return -EINVAL;
184
185 data_pointer->select_right = value;
186 lenovo_features_set_tpkbd(hdev);
187
188 return count;
189 }
190
191 static ssize_t attr_sensitivity_show_tpkbd(struct device *dev,
192 struct device_attribute *attr,
193 char *buf)
194 {
195 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
196 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
197
198 return snprintf(buf, PAGE_SIZE, "%u\n",
199 data_pointer->sensitivity);
200 }
201
202 static ssize_t attr_sensitivity_store_tpkbd(struct device *dev,
203 struct device_attribute *attr,
204 const char *buf,
205 size_t count)
206 {
207 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
208 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
209 int value;
210
211 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
212 return -EINVAL;
213
214 data_pointer->sensitivity = value;
215 lenovo_features_set_tpkbd(hdev);
216
217 return count;
218 }
219
220 static ssize_t attr_press_speed_show_tpkbd(struct device *dev,
221 struct device_attribute *attr,
222 char *buf)
223 {
224 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
225 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
226
227 return snprintf(buf, PAGE_SIZE, "%u\n",
228 data_pointer->press_speed);
229 }
230
231 static ssize_t attr_press_speed_store_tpkbd(struct device *dev,
232 struct device_attribute *attr,
233 const char *buf,
234 size_t count)
235 {
236 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
237 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
238 int value;
239
240 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
241 return -EINVAL;
242
243 data_pointer->press_speed = value;
244 lenovo_features_set_tpkbd(hdev);
245
246 return count;
247 }
248
249 static struct device_attribute dev_attr_press_to_select_tpkbd =
250 __ATTR(press_to_select, S_IWUSR | S_IRUGO,
251 attr_press_to_select_show_tpkbd,
252 attr_press_to_select_store_tpkbd);
253
254 static struct device_attribute dev_attr_dragging_tpkbd =
255 __ATTR(dragging, S_IWUSR | S_IRUGO,
256 attr_dragging_show_tpkbd,
257 attr_dragging_store_tpkbd);
258
259 static struct device_attribute dev_attr_release_to_select_tpkbd =
260 __ATTR(release_to_select, S_IWUSR | S_IRUGO,
261 attr_release_to_select_show_tpkbd,
262 attr_release_to_select_store_tpkbd);
263
264 static struct device_attribute dev_attr_select_right_tpkbd =
265 __ATTR(select_right, S_IWUSR | S_IRUGO,
266 attr_select_right_show_tpkbd,
267 attr_select_right_store_tpkbd);
268
269 static struct device_attribute dev_attr_sensitivity_tpkbd =
270 __ATTR(sensitivity, S_IWUSR | S_IRUGO,
271 attr_sensitivity_show_tpkbd,
272 attr_sensitivity_store_tpkbd);
273
274 static struct device_attribute dev_attr_press_speed_tpkbd =
275 __ATTR(press_speed, S_IWUSR | S_IRUGO,
276 attr_press_speed_show_tpkbd,
277 attr_press_speed_store_tpkbd);
278
279 static struct attribute *lenovo_attributes_tpkbd[] = {
280 &dev_attr_press_to_select_tpkbd.attr,
281 &dev_attr_dragging_tpkbd.attr,
282 &dev_attr_release_to_select_tpkbd.attr,
283 &dev_attr_select_right_tpkbd.attr,
284 &dev_attr_sensitivity_tpkbd.attr,
285 &dev_attr_press_speed_tpkbd.attr,
286 NULL
287 };
288
289 static const struct attribute_group lenovo_attr_group_tpkbd = {
290 .attrs = lenovo_attributes_tpkbd,
291 };
292
293 static enum led_brightness lenovo_led_brightness_get_tpkbd(
294 struct led_classdev *led_cdev)
295 {
296 struct device *dev = led_cdev->dev->parent;
297 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
298 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
299 int led_nr = 0;
300
301 if (led_cdev == &data_pointer->led_micmute)
302 led_nr = 1;
303
304 return data_pointer->led_state & (1 << led_nr)
305 ? LED_FULL
306 : LED_OFF;
307 }
308
309 static void lenovo_led_brightness_set_tpkbd(struct led_classdev *led_cdev,
310 enum led_brightness value)
311 {
312 struct device *dev = led_cdev->dev->parent;
313 struct hid_device *hdev = container_of(dev, struct hid_device, dev);
314 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
315 struct hid_report *report;
316 int led_nr = 0;
317
318 if (led_cdev == &data_pointer->led_micmute)
319 led_nr = 1;
320
321 if (value == LED_OFF)
322 data_pointer->led_state &= ~(1 << led_nr);
323 else
324 data_pointer->led_state |= 1 << led_nr;
325
326 report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
327 report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
328 report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
329 hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
330 }
331
332 static int lenovo_probe_tpkbd(struct hid_device *hdev)
333 {
334 struct device *dev = &hdev->dev;
335 struct lenovo_drvdata_tpkbd *data_pointer;
336 size_t name_sz = strlen(dev_name(dev)) + 16;
337 char *name_mute, *name_micmute;
338 int i;
339
340 /* Validate required reports. */
341 for (i = 0; i < 4; i++) {
342 if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1))
343 return -ENODEV;
344 }
345 if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2))
346 return -ENODEV;
347
348 if (sysfs_create_group(&hdev->dev.kobj,
349 &lenovo_attr_group_tpkbd)) {
350 hid_warn(hdev, "Could not create sysfs group\n");
351 }
352
353 data_pointer = devm_kzalloc(&hdev->dev,
354 sizeof(struct lenovo_drvdata_tpkbd),
355 GFP_KERNEL);
356 if (data_pointer == NULL) {
357 hid_err(hdev, "Could not allocate memory for driver data\n");
358 return -ENOMEM;
359 }
360
361 // set same default values as windows driver
362 data_pointer->sensitivity = 0xa0;
363 data_pointer->press_speed = 0x38;
364
365 name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
366 name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL);
367 if (name_mute == NULL || name_micmute == NULL) {
368 hid_err(hdev, "Could not allocate memory for led data\n");
369 return -ENOMEM;
370 }
371 snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev));
372 snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev));
373
374 hid_set_drvdata(hdev, data_pointer);
375
376 data_pointer->led_mute.name = name_mute;
377 data_pointer->led_mute.brightness_get = lenovo_led_brightness_get_tpkbd;
378 data_pointer->led_mute.brightness_set = lenovo_led_brightness_set_tpkbd;
379 data_pointer->led_mute.dev = dev;
380 led_classdev_register(dev, &data_pointer->led_mute);
381
382 data_pointer->led_micmute.name = name_micmute;
383 data_pointer->led_micmute.brightness_get =
384 lenovo_led_brightness_get_tpkbd;
385 data_pointer->led_micmute.brightness_set =
386 lenovo_led_brightness_set_tpkbd;
387 data_pointer->led_micmute.dev = dev;
388 led_classdev_register(dev, &data_pointer->led_micmute);
389
390 lenovo_features_set_tpkbd(hdev);
391
392 return 0;
393 }
394
395 static int lenovo_probe(struct hid_device *hdev,
396 const struct hid_device_id *id)
397 {
398 int ret;
399
400 ret = hid_parse(hdev);
401 if (ret) {
402 hid_err(hdev, "hid_parse failed\n");
403 goto err;
404 }
405
406 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
407 if (ret) {
408 hid_err(hdev, "hid_hw_start failed\n");
409 goto err;
410 }
411
412 if (hid_get_drvdata(hdev)) {
413 hid_set_drvdata(hdev, NULL);
414 ret = lenovo_probe_tpkbd(hdev);
415 if (ret)
416 goto err_hid;
417 }
418
419 return 0;
420 err_hid:
421 hid_hw_stop(hdev);
422 err:
423 return ret;
424 }
425
426 static void lenovo_remove_tpkbd(struct hid_device *hdev)
427 {
428 struct lenovo_drvdata_tpkbd *data_pointer = hid_get_drvdata(hdev);
429
430 sysfs_remove_group(&hdev->dev.kobj,
431 &lenovo_attr_group_tpkbd);
432
433 led_classdev_unregister(&data_pointer->led_micmute);
434 led_classdev_unregister(&data_pointer->led_mute);
435
436 hid_set_drvdata(hdev, NULL);
437 }
438
439 static void lenovo_remove(struct hid_device *hdev)
440 {
441 if (hid_get_drvdata(hdev))
442 lenovo_remove_tpkbd(hdev);
443
444 hid_hw_stop(hdev);
445 }
446
447 static const struct hid_device_id lenovo_devices[] = {
448 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
449 { }
450 };
451
452 MODULE_DEVICE_TABLE(hid, lenovo_devices);
453
454 static struct hid_driver lenovo_driver = {
455 .name = "lenovo",
456 .id_table = lenovo_devices,
457 .input_mapping = lenovo_input_mapping_tpkbd,
458 .probe = lenovo_probe,
459 .remove = lenovo_remove,
460 };
461 module_hid_driver(lenovo_driver);
462
463 MODULE_LICENSE("GPL");
This page took 0.041064 seconds and 6 git commands to generate.