Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.13-rc6 462 lines 13 kB view raw
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/* This is only used for the trackpoint part of the driver, hence _tp */ 24struct tpkbd_data_pointer { 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 38static int tpkbd_input_mapping(struct hid_device *hdev, 39 struct hid_input *hi, struct hid_field *field, 40 struct hid_usage *usage, unsigned long **bit, int *max) 41{ 42 if (usage->hid == (HID_UP_BUTTON | 0x0010)) { 43 /* mark the device as pointer */ 44 hid_set_drvdata(hdev, (void *)1); 45 map_key_clear(KEY_MICMUTE); 46 return 1; 47 } 48 return 0; 49} 50 51#undef map_key_clear 52 53static int tpkbd_features_set(struct hid_device *hdev) 54{ 55 struct hid_report *report; 56 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 57 58 report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[4]; 59 60 report->field[0]->value[0] = data_pointer->press_to_select ? 0x01 : 0x02; 61 report->field[0]->value[0] |= data_pointer->dragging ? 0x04 : 0x08; 62 report->field[0]->value[0] |= data_pointer->release_to_select ? 0x10 : 0x20; 63 report->field[0]->value[0] |= data_pointer->select_right ? 0x80 : 0x40; 64 report->field[1]->value[0] = 0x03; // unknown setting, imitate windows driver 65 report->field[2]->value[0] = data_pointer->sensitivity; 66 report->field[3]->value[0] = data_pointer->press_speed; 67 68 hid_hw_request(hdev, report, HID_REQ_SET_REPORT); 69 return 0; 70} 71 72static ssize_t pointer_press_to_select_show(struct device *dev, 73 struct device_attribute *attr, 74 char *buf) 75{ 76 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 77 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 78 79 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->press_to_select); 80} 81 82static ssize_t pointer_press_to_select_store(struct device *dev, 83 struct device_attribute *attr, 84 const char *buf, 85 size_t count) 86{ 87 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 88 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 89 int value; 90 91 if (kstrtoint(buf, 10, &value)) 92 return -EINVAL; 93 if (value < 0 || value > 1) 94 return -EINVAL; 95 96 data_pointer->press_to_select = value; 97 tpkbd_features_set(hdev); 98 99 return count; 100} 101 102static ssize_t pointer_dragging_show(struct device *dev, 103 struct device_attribute *attr, 104 char *buf) 105{ 106 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 107 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 108 109 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->dragging); 110} 111 112static ssize_t pointer_dragging_store(struct device *dev, 113 struct device_attribute *attr, 114 const char *buf, 115 size_t count) 116{ 117 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 118 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 119 int value; 120 121 if (kstrtoint(buf, 10, &value)) 122 return -EINVAL; 123 if (value < 0 || value > 1) 124 return -EINVAL; 125 126 data_pointer->dragging = value; 127 tpkbd_features_set(hdev); 128 129 return count; 130} 131 132static ssize_t pointer_release_to_select_show(struct device *dev, 133 struct device_attribute *attr, 134 char *buf) 135{ 136 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 137 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 138 139 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->release_to_select); 140} 141 142static ssize_t pointer_release_to_select_store(struct device *dev, 143 struct device_attribute *attr, 144 const char *buf, 145 size_t count) 146{ 147 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 148 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 149 int value; 150 151 if (kstrtoint(buf, 10, &value)) 152 return -EINVAL; 153 if (value < 0 || value > 1) 154 return -EINVAL; 155 156 data_pointer->release_to_select = value; 157 tpkbd_features_set(hdev); 158 159 return count; 160} 161 162static ssize_t pointer_select_right_show(struct device *dev, 163 struct device_attribute *attr, 164 char *buf) 165{ 166 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 167 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 168 169 return snprintf(buf, PAGE_SIZE, "%u\n", data_pointer->select_right); 170} 171 172static ssize_t pointer_select_right_store(struct device *dev, 173 struct device_attribute *attr, 174 const char *buf, 175 size_t count) 176{ 177 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 178 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 179 int value; 180 181 if (kstrtoint(buf, 10, &value)) 182 return -EINVAL; 183 if (value < 0 || value > 1) 184 return -EINVAL; 185 186 data_pointer->select_right = value; 187 tpkbd_features_set(hdev); 188 189 return count; 190} 191 192static ssize_t pointer_sensitivity_show(struct device *dev, 193 struct device_attribute *attr, 194 char *buf) 195{ 196 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 197 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 198 199 return snprintf(buf, PAGE_SIZE, "%u\n", 200 data_pointer->sensitivity); 201} 202 203static ssize_t pointer_sensitivity_store(struct device *dev, 204 struct device_attribute *attr, 205 const char *buf, 206 size_t count) 207{ 208 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 209 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 210 int value; 211 212 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) 213 return -EINVAL; 214 215 data_pointer->sensitivity = value; 216 tpkbd_features_set(hdev); 217 218 return count; 219} 220 221static ssize_t pointer_press_speed_show(struct device *dev, 222 struct device_attribute *attr, 223 char *buf) 224{ 225 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 226 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 227 228 return snprintf(buf, PAGE_SIZE, "%u\n", 229 data_pointer->press_speed); 230} 231 232static ssize_t pointer_press_speed_store(struct device *dev, 233 struct device_attribute *attr, 234 const char *buf, 235 size_t count) 236{ 237 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 238 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 239 int value; 240 241 if (kstrtoint(buf, 10, &value) || value < 1 || value > 255) 242 return -EINVAL; 243 244 data_pointer->press_speed = value; 245 tpkbd_features_set(hdev); 246 247 return count; 248} 249 250static struct device_attribute dev_attr_pointer_press_to_select = 251 __ATTR(press_to_select, S_IWUSR | S_IRUGO, 252 pointer_press_to_select_show, 253 pointer_press_to_select_store); 254 255static struct device_attribute dev_attr_pointer_dragging = 256 __ATTR(dragging, S_IWUSR | S_IRUGO, 257 pointer_dragging_show, 258 pointer_dragging_store); 259 260static struct device_attribute dev_attr_pointer_release_to_select = 261 __ATTR(release_to_select, S_IWUSR | S_IRUGO, 262 pointer_release_to_select_show, 263 pointer_release_to_select_store); 264 265static struct device_attribute dev_attr_pointer_select_right = 266 __ATTR(select_right, S_IWUSR | S_IRUGO, 267 pointer_select_right_show, 268 pointer_select_right_store); 269 270static struct device_attribute dev_attr_pointer_sensitivity = 271 __ATTR(sensitivity, S_IWUSR | S_IRUGO, 272 pointer_sensitivity_show, 273 pointer_sensitivity_store); 274 275static struct device_attribute dev_attr_pointer_press_speed = 276 __ATTR(press_speed, S_IWUSR | S_IRUGO, 277 pointer_press_speed_show, 278 pointer_press_speed_store); 279 280static struct attribute *tpkbd_attributes_pointer[] = { 281 &dev_attr_pointer_press_to_select.attr, 282 &dev_attr_pointer_dragging.attr, 283 &dev_attr_pointer_release_to_select.attr, 284 &dev_attr_pointer_select_right.attr, 285 &dev_attr_pointer_sensitivity.attr, 286 &dev_attr_pointer_press_speed.attr, 287 NULL 288}; 289 290static const struct attribute_group tpkbd_attr_group_pointer = { 291 .attrs = tpkbd_attributes_pointer, 292}; 293 294static enum led_brightness tpkbd_led_brightness_get( 295 struct led_classdev *led_cdev) 296{ 297 struct device *dev = led_cdev->dev->parent; 298 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 299 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 300 int led_nr = 0; 301 302 if (led_cdev == &data_pointer->led_micmute) 303 led_nr = 1; 304 305 return data_pointer->led_state & (1 << led_nr) 306 ? LED_FULL 307 : LED_OFF; 308} 309 310static void tpkbd_led_brightness_set(struct led_classdev *led_cdev, 311 enum led_brightness value) 312{ 313 struct device *dev = led_cdev->dev->parent; 314 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 315 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 316 struct hid_report *report; 317 int led_nr = 0; 318 319 if (led_cdev == &data_pointer->led_micmute) 320 led_nr = 1; 321 322 if (value == LED_OFF) 323 data_pointer->led_state &= ~(1 << led_nr); 324 else 325 data_pointer->led_state |= 1 << led_nr; 326 327 report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3]; 328 report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1; 329 report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1; 330 hid_hw_request(hdev, report, HID_REQ_SET_REPORT); 331} 332 333static int tpkbd_probe_tp(struct hid_device *hdev) 334{ 335 struct device *dev = &hdev->dev; 336 struct tpkbd_data_pointer *data_pointer; 337 size_t name_sz = strlen(dev_name(dev)) + 16; 338 char *name_mute, *name_micmute; 339 int i; 340 341 /* Validate required reports. */ 342 for (i = 0; i < 4; i++) { 343 if (!hid_validate_values(hdev, HID_FEATURE_REPORT, 4, i, 1)) 344 return -ENODEV; 345 } 346 if (!hid_validate_values(hdev, HID_OUTPUT_REPORT, 3, 0, 2)) 347 return -ENODEV; 348 349 if (sysfs_create_group(&hdev->dev.kobj, 350 &tpkbd_attr_group_pointer)) { 351 hid_warn(hdev, "Could not create sysfs group\n"); 352 } 353 354 data_pointer = devm_kzalloc(&hdev->dev, 355 sizeof(struct tpkbd_data_pointer), 356 GFP_KERNEL); 357 if (data_pointer == NULL) { 358 hid_err(hdev, "Could not allocate memory for driver data\n"); 359 return -ENOMEM; 360 } 361 362 // set same default values as windows driver 363 data_pointer->sensitivity = 0xa0; 364 data_pointer->press_speed = 0x38; 365 366 name_mute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); 367 name_micmute = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); 368 if (name_mute == NULL || name_micmute == NULL) { 369 hid_err(hdev, "Could not allocate memory for led data\n"); 370 return -ENOMEM; 371 } 372 snprintf(name_mute, name_sz, "%s:amber:mute", dev_name(dev)); 373 snprintf(name_micmute, name_sz, "%s:amber:micmute", dev_name(dev)); 374 375 hid_set_drvdata(hdev, data_pointer); 376 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); 382 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); 388 389 tpkbd_features_set(hdev); 390 391 return 0; 392} 393 394static int tpkbd_probe(struct hid_device *hdev, 395 const struct hid_device_id *id) 396{ 397 int ret; 398 399 ret = hid_parse(hdev); 400 if (ret) { 401 hid_err(hdev, "hid_parse failed\n"); 402 goto err; 403 } 404 405 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 406 if (ret) { 407 hid_err(hdev, "hid_hw_start failed\n"); 408 goto err; 409 } 410 411 if (hid_get_drvdata(hdev)) { 412 hid_set_drvdata(hdev, NULL); 413 ret = tpkbd_probe_tp(hdev); 414 if (ret) 415 goto err_hid; 416 } 417 418 return 0; 419err_hid: 420 hid_hw_stop(hdev); 421err: 422 return ret; 423} 424 425static void tpkbd_remove_tp(struct hid_device *hdev) 426{ 427 struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev); 428 429 sysfs_remove_group(&hdev->dev.kobj, 430 &tpkbd_attr_group_pointer); 431 432 led_classdev_unregister(&data_pointer->led_micmute); 433 led_classdev_unregister(&data_pointer->led_mute); 434 435 hid_set_drvdata(hdev, NULL); 436} 437 438static void tpkbd_remove(struct hid_device *hdev) 439{ 440 if (hid_get_drvdata(hdev)) 441 tpkbd_remove_tp(hdev); 442 443 hid_hw_stop(hdev); 444} 445 446static const struct hid_device_id tpkbd_devices[] = { 447 { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) }, 448 { } 449}; 450 451MODULE_DEVICE_TABLE(hid, tpkbd_devices); 452 453static struct hid_driver tpkbd_driver = { 454 .name = "lenovo_tpkbd", 455 .id_table = tpkbd_devices, 456 .input_mapping = tpkbd_input_mapping, 457 .probe = tpkbd_probe, 458 .remove = tpkbd_remove, 459}; 460module_hid_driver(tpkbd_driver); 461 462MODULE_LICENSE("GPL");