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