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.3-rc1 623 lines 16 kB view raw
1/* 2 * Bluetooth Wacom Tablet support 3 * 4 * Copyright (c) 1999 Andreas Gal 5 * Copyright (c) 2000-2005 Vojtech Pavlik <vojtech@suse.cz> 6 * Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc 7 * Copyright (c) 2006-2007 Jiri Kosina 8 * Copyright (c) 2007 Paul Walmsley 9 * Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com> 10 * Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru> 11 * Copyright (c) 2009 Bastien Nocera <hadess@hadess.net> 12 * Copyright (c) 2011 Przemysław Firszt <przemo@firszt.eu> 13 */ 14 15/* 16 * This program is free software; you can redistribute it and/or modify it 17 * under the terms of the GNU General Public License as published by the Free 18 * Software Foundation; either version 2 of the License, or (at your option) 19 * any later version. 20 */ 21 22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 23 24#include <linux/device.h> 25#include <linux/hid.h> 26#include <linux/module.h> 27#include <linux/slab.h> 28#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 29#include <linux/power_supply.h> 30#endif 31 32#include "hid-ids.h" 33 34struct wacom_data { 35 __u16 tool; 36 unsigned char butstate; 37 __u8 features; 38 unsigned char high_speed; 39#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 40 int battery_capacity; 41 struct power_supply battery; 42 struct power_supply ac; 43#endif 44}; 45 46#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 47/*percent of battery capacity, 0 means AC online*/ 48static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 }; 49 50static enum power_supply_property wacom_battery_props[] = { 51 POWER_SUPPLY_PROP_PRESENT, 52 POWER_SUPPLY_PROP_CAPACITY, 53 POWER_SUPPLY_PROP_SCOPE, 54}; 55 56static enum power_supply_property wacom_ac_props[] = { 57 POWER_SUPPLY_PROP_PRESENT, 58 POWER_SUPPLY_PROP_ONLINE, 59 POWER_SUPPLY_PROP_SCOPE, 60}; 61 62static int wacom_battery_get_property(struct power_supply *psy, 63 enum power_supply_property psp, 64 union power_supply_propval *val) 65{ 66 struct wacom_data *wdata = container_of(psy, 67 struct wacom_data, battery); 68 int power_state = batcap[wdata->battery_capacity]; 69 int ret = 0; 70 71 switch (psp) { 72 case POWER_SUPPLY_PROP_PRESENT: 73 val->intval = 1; 74 break; 75 case POWER_SUPPLY_PROP_SCOPE: 76 val->intval = POWER_SUPPLY_SCOPE_DEVICE; 77 break; 78 case POWER_SUPPLY_PROP_CAPACITY: 79 /* show 100% battery capacity when charging */ 80 if (power_state == 0) 81 val->intval = 100; 82 else 83 val->intval = power_state; 84 break; 85 default: 86 ret = -EINVAL; 87 break; 88 } 89 return ret; 90} 91 92static int wacom_ac_get_property(struct power_supply *psy, 93 enum power_supply_property psp, 94 union power_supply_propval *val) 95{ 96 struct wacom_data *wdata = container_of(psy, struct wacom_data, ac); 97 int power_state = batcap[wdata->battery_capacity]; 98 int ret = 0; 99 100 switch (psp) { 101 case POWER_SUPPLY_PROP_PRESENT: 102 /* fall through */ 103 case POWER_SUPPLY_PROP_ONLINE: 104 if (power_state == 0) 105 val->intval = 1; 106 else 107 val->intval = 0; 108 break; 109 case POWER_SUPPLY_PROP_SCOPE: 110 val->intval = POWER_SUPPLY_SCOPE_DEVICE; 111 break; 112 default: 113 ret = -EINVAL; 114 break; 115 } 116 return ret; 117} 118#endif 119 120static void wacom_set_features(struct hid_device *hdev) 121{ 122 int ret; 123 __u8 rep_data[2]; 124 125 /*set high speed, tablet mode*/ 126 rep_data[0] = 0x03; 127 rep_data[1] = 0x20; 128 ret = hdev->hid_output_raw_report(hdev, rep_data, 2, 129 HID_FEATURE_REPORT); 130 return; 131} 132 133static void wacom_poke(struct hid_device *hdev, u8 speed) 134{ 135 struct wacom_data *wdata = hid_get_drvdata(hdev); 136 int limit, ret; 137 char rep_data[2]; 138 139 rep_data[0] = 0x03 ; rep_data[1] = 0x00; 140 limit = 3; 141 do { 142 ret = hdev->hid_output_raw_report(hdev, rep_data, 2, 143 HID_FEATURE_REPORT); 144 } while (ret < 0 && limit-- > 0); 145 146 if (ret >= 0) { 147 if (speed == 0) 148 rep_data[0] = 0x05; 149 else 150 rep_data[0] = 0x06; 151 152 rep_data[1] = 0x00; 153 limit = 3; 154 do { 155 ret = hdev->hid_output_raw_report(hdev, rep_data, 2, 156 HID_FEATURE_REPORT); 157 } while (ret < 0 && limit-- > 0); 158 159 if (ret >= 0) { 160 wdata->high_speed = speed; 161 return; 162 } 163 } 164 165 /* 166 * Note that if the raw queries fail, it's not a hard failure and it 167 * is safe to continue 168 */ 169 hid_warn(hdev, "failed to poke device, command %d, err %d\n", 170 rep_data[0], ret); 171 return; 172} 173 174static ssize_t wacom_show_speed(struct device *dev, 175 struct device_attribute 176 *attr, char *buf) 177{ 178 struct wacom_data *wdata = dev_get_drvdata(dev); 179 180 return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed); 181} 182 183static ssize_t wacom_store_speed(struct device *dev, 184 struct device_attribute *attr, 185 const char *buf, size_t count) 186{ 187 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 188 int new_speed; 189 190 if (sscanf(buf, "%1d", &new_speed ) != 1) 191 return -EINVAL; 192 193 if (new_speed == 0 || new_speed == 1) { 194 wacom_poke(hdev, new_speed); 195 return strnlen(buf, PAGE_SIZE); 196 } else 197 return -EINVAL; 198} 199 200static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, 201 wacom_show_speed, wacom_store_speed); 202 203static int wacom_gr_parse_report(struct hid_device *hdev, 204 struct wacom_data *wdata, 205 struct input_dev *input, unsigned char *data) 206{ 207 int tool, x, y, rw; 208 209 tool = 0; 210 /* Get X & Y positions */ 211 x = le16_to_cpu(*(__le16 *) &data[2]); 212 y = le16_to_cpu(*(__le16 *) &data[4]); 213 214 /* Get current tool identifier */ 215 if (data[1] & 0x90) { /* If pen is in the in/active area */ 216 switch ((data[1] >> 5) & 3) { 217 case 0: /* Pen */ 218 tool = BTN_TOOL_PEN; 219 break; 220 221 case 1: /* Rubber */ 222 tool = BTN_TOOL_RUBBER; 223 break; 224 225 case 2: /* Mouse with wheel */ 226 case 3: /* Mouse without wheel */ 227 tool = BTN_TOOL_MOUSE; 228 break; 229 } 230 231 /* Reset tool if out of active tablet area */ 232 if (!(data[1] & 0x10)) 233 tool = 0; 234 } 235 236 /* If tool changed, notify input subsystem */ 237 if (wdata->tool != tool) { 238 if (wdata->tool) { 239 /* Completely reset old tool state */ 240 if (wdata->tool == BTN_TOOL_MOUSE) { 241 input_report_key(input, BTN_LEFT, 0); 242 input_report_key(input, BTN_RIGHT, 0); 243 input_report_key(input, BTN_MIDDLE, 0); 244 input_report_abs(input, ABS_DISTANCE, 245 input_abs_get_max(input, ABS_DISTANCE)); 246 } else { 247 input_report_key(input, BTN_TOUCH, 0); 248 input_report_key(input, BTN_STYLUS, 0); 249 input_report_key(input, BTN_STYLUS2, 0); 250 input_report_abs(input, ABS_PRESSURE, 0); 251 } 252 input_report_key(input, wdata->tool, 0); 253 input_sync(input); 254 } 255 wdata->tool = tool; 256 if (tool) 257 input_report_key(input, tool, 1); 258 } 259 260 if (tool) { 261 input_report_abs(input, ABS_X, x); 262 input_report_abs(input, ABS_Y, y); 263 264 switch ((data[1] >> 5) & 3) { 265 case 2: /* Mouse with wheel */ 266 input_report_key(input, BTN_MIDDLE, data[1] & 0x04); 267 rw = (data[6] & 0x01) ? -1 : 268 (data[6] & 0x02) ? 1 : 0; 269 input_report_rel(input, REL_WHEEL, rw); 270 /* fall through */ 271 272 case 3: /* Mouse without wheel */ 273 input_report_key(input, BTN_LEFT, data[1] & 0x01); 274 input_report_key(input, BTN_RIGHT, data[1] & 0x02); 275 /* Compute distance between mouse and tablet */ 276 rw = 44 - (data[6] >> 2); 277 if (rw < 0) 278 rw = 0; 279 else if (rw > 31) 280 rw = 31; 281 input_report_abs(input, ABS_DISTANCE, rw); 282 break; 283 284 default: 285 input_report_abs(input, ABS_PRESSURE, 286 data[6] | (((__u16) (data[1] & 0x08)) << 5)); 287 input_report_key(input, BTN_TOUCH, data[1] & 0x01); 288 input_report_key(input, BTN_STYLUS, data[1] & 0x02); 289 input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04); 290 break; 291 } 292 293 input_sync(input); 294 } 295 296 /* Report the state of the two buttons at the top of the tablet 297 * as two extra fingerpad keys (buttons 4 & 5). */ 298 rw = data[7] & 0x03; 299 if (rw != wdata->butstate) { 300 wdata->butstate = rw; 301 input_report_key(input, BTN_0, rw & 0x02); 302 input_report_key(input, BTN_1, rw & 0x01); 303 input_report_key(input, BTN_TOOL_FINGER, 0xf0); 304 input_event(input, EV_MSC, MSC_SERIAL, 0xf0); 305 input_sync(input); 306 } 307 308#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 309 /* Store current battery capacity */ 310 rw = (data[7] >> 2 & 0x07); 311 if (rw != wdata->battery_capacity) 312 wdata->battery_capacity = rw; 313#endif 314 return 1; 315} 316 317static void wacom_i4_parse_pen_report(struct wacom_data *wdata, 318 struct input_dev *input, unsigned char *data) 319{ 320 __u16 x, y, pressure; 321 __u32 id; 322 323 switch (data[1]) { 324 case 0x80: /* Out of proximity report */ 325 wdata->tool = 0; 326 input_report_key(input, BTN_TOUCH, 0); 327 input_report_abs(input, ABS_PRESSURE, 0); 328 input_report_key(input, wdata->tool, 0); 329 input_sync(input); 330 break; 331 case 0xC2: /* Tool report */ 332 id = ((data[2] << 4) | (data[3] >> 4) | 333 ((data[7] & 0x0f) << 20) | 334 ((data[8] & 0xf0) << 12)) & 0xfffff; 335 336 switch (id) { 337 case 0x802: 338 wdata->tool = BTN_TOOL_PEN; 339 break; 340 case 0x80A: 341 wdata->tool = BTN_TOOL_RUBBER; 342 break; 343 } 344 break; 345 default: /* Position/pressure report */ 346 x = data[2] << 9 | data[3] << 1 | ((data[9] & 0x02) >> 1); 347 y = data[4] << 9 | data[5] << 1 | (data[9] & 0x01); 348 pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5) 349 | (data[1] & 0x01); 350 351 input_report_key(input, BTN_TOUCH, pressure > 1); 352 353 input_report_key(input, BTN_STYLUS, data[1] & 0x02); 354 input_report_key(input, BTN_STYLUS2, data[1] & 0x04); 355 input_report_key(input, wdata->tool, 1); 356 input_report_abs(input, ABS_X, x); 357 input_report_abs(input, ABS_Y, y); 358 input_report_abs(input, ABS_PRESSURE, pressure); 359 input_sync(input); 360 break; 361 } 362 363 return; 364} 365 366static void wacom_i4_parse_report(struct hid_device *hdev, 367 struct wacom_data *wdata, 368 struct input_dev *input, unsigned char *data) 369{ 370 switch (data[0]) { 371 case 0x00: /* Empty report */ 372 break; 373 case 0x02: /* Pen report */ 374 wacom_i4_parse_pen_report(wdata, input, data); 375 break; 376 case 0x03: /* Features Report */ 377 wdata->features = data[2]; 378 break; 379 case 0x0C: /* Button report */ 380 break; 381 default: 382 hid_err(hdev, "Unknown report: %d,%d\n", data[0], data[1]); 383 break; 384 } 385} 386 387static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, 388 u8 *raw_data, int size) 389{ 390 struct wacom_data *wdata = hid_get_drvdata(hdev); 391 struct hid_input *hidinput; 392 struct input_dev *input; 393 unsigned char *data = (unsigned char *) raw_data; 394 int i; 395 396 if (!(hdev->claimed & HID_CLAIMED_INPUT)) 397 return 0; 398 399 hidinput = list_entry(hdev->inputs.next, struct hid_input, list); 400 input = hidinput->input; 401 402 /* Check if this is a tablet report */ 403 if (data[0] != 0x03) 404 return 0; 405 406 switch (hdev->product) { 407 case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: 408 return wacom_gr_parse_report(hdev, wdata, input, data); 409 break; 410 case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: 411 i = 1; 412 413 switch (data[0]) { 414 case 0x04: 415 wacom_i4_parse_report(hdev, wdata, input, data + i); 416 i += 10; 417 /* fall through */ 418 case 0x03: 419 wacom_i4_parse_report(hdev, wdata, input, data + i); 420 i += 10; 421 wacom_i4_parse_report(hdev, wdata, input, data + i); 422 break; 423 default: 424 hid_err(hdev, "Unknown report: %d,%d size:%d\n", 425 data[0], data[1], size); 426 return 0; 427 } 428 } 429 return 1; 430} 431 432static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi, 433 struct hid_field *field, struct hid_usage *usage, unsigned long **bit, 434 int *max) 435{ 436 struct input_dev *input = hi->input; 437 438 __set_bit(INPUT_PROP_POINTER, input->propbit); 439 440 /* Basics */ 441 input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL); 442 443 __set_bit(REL_WHEEL, input->relbit); 444 445 __set_bit(BTN_TOOL_PEN, input->keybit); 446 __set_bit(BTN_TOUCH, input->keybit); 447 __set_bit(BTN_STYLUS, input->keybit); 448 __set_bit(BTN_STYLUS2, input->keybit); 449 __set_bit(BTN_LEFT, input->keybit); 450 __set_bit(BTN_RIGHT, input->keybit); 451 __set_bit(BTN_MIDDLE, input->keybit); 452 453 /* Pad */ 454 input->evbit[0] |= BIT(EV_MSC); 455 456 __set_bit(MSC_SERIAL, input->mscbit); 457 458 __set_bit(BTN_0, input->keybit); 459 __set_bit(BTN_1, input->keybit); 460 __set_bit(BTN_TOOL_FINGER, input->keybit); 461 462 /* Distance, rubber and mouse */ 463 __set_bit(BTN_TOOL_RUBBER, input->keybit); 464 __set_bit(BTN_TOOL_MOUSE, input->keybit); 465 466 switch (hdev->product) { 467 case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: 468 input_set_abs_params(input, ABS_X, 0, 16704, 4, 0); 469 input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0); 470 input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0); 471 input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0); 472 break; 473 case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: 474 input_set_abs_params(input, ABS_X, 0, 40640, 4, 0); 475 input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0); 476 input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0); 477 break; 478 } 479 480 return 0; 481} 482 483static int wacom_probe(struct hid_device *hdev, 484 const struct hid_device_id *id) 485{ 486 struct wacom_data *wdata; 487 int ret; 488 489 wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); 490 if (wdata == NULL) { 491 hid_err(hdev, "can't alloc wacom descriptor\n"); 492 return -ENOMEM; 493 } 494 495 hid_set_drvdata(hdev, wdata); 496 497 /* Parse the HID report now */ 498 ret = hid_parse(hdev); 499 if (ret) { 500 hid_err(hdev, "parse failed\n"); 501 goto err_free; 502 } 503 504 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 505 if (ret) { 506 hid_err(hdev, "hw start failed\n"); 507 goto err_free; 508 } 509 510 ret = device_create_file(&hdev->dev, &dev_attr_speed); 511 if (ret) 512 hid_warn(hdev, 513 "can't create sysfs speed attribute err: %d\n", ret); 514 515 switch (hdev->product) { 516 case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH: 517 /* Set Wacom mode 2 with high reporting speed */ 518 wacom_poke(hdev, 1); 519 break; 520 case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH: 521 wdata->features = 0; 522 wacom_set_features(hdev); 523 break; 524 } 525 526#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 527 wdata->battery.properties = wacom_battery_props; 528 wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props); 529 wdata->battery.get_property = wacom_battery_get_property; 530 wdata->battery.name = "wacom_battery"; 531 wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY; 532 wdata->battery.use_for_apm = 0; 533 534 power_supply_powers(&wdata->battery, &hdev->dev); 535 536 ret = power_supply_register(&hdev->dev, &wdata->battery); 537 if (ret) { 538 hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n", 539 ret); 540 goto err_battery; 541 } 542 543 wdata->ac.properties = wacom_ac_props; 544 wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props); 545 wdata->ac.get_property = wacom_ac_get_property; 546 wdata->ac.name = "wacom_ac"; 547 wdata->ac.type = POWER_SUPPLY_TYPE_MAINS; 548 wdata->ac.use_for_apm = 0; 549 550 power_supply_powers(&wdata->battery, &hdev->dev); 551 552 ret = power_supply_register(&hdev->dev, &wdata->ac); 553 if (ret) { 554 hid_warn(hdev, 555 "can't create ac battery attribute, err: %d\n", ret); 556 goto err_ac; 557 } 558#endif 559 return 0; 560 561#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 562err_ac: 563 power_supply_unregister(&wdata->battery); 564err_battery: 565 device_remove_file(&hdev->dev, &dev_attr_speed); 566 hid_hw_stop(hdev); 567#endif 568err_free: 569 kfree(wdata); 570 return ret; 571} 572 573static void wacom_remove(struct hid_device *hdev) 574{ 575#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 576 struct wacom_data *wdata = hid_get_drvdata(hdev); 577#endif 578 device_remove_file(&hdev->dev, &dev_attr_speed); 579 hid_hw_stop(hdev); 580 581#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 582 power_supply_unregister(&wdata->battery); 583 power_supply_unregister(&wdata->ac); 584#endif 585 kfree(hid_get_drvdata(hdev)); 586} 587 588static const struct hid_device_id wacom_devices[] = { 589 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, 590 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) }, 591 592 { } 593}; 594MODULE_DEVICE_TABLE(hid, wacom_devices); 595 596static struct hid_driver wacom_driver = { 597 .name = "wacom", 598 .id_table = wacom_devices, 599 .probe = wacom_probe, 600 .remove = wacom_remove, 601 .raw_event = wacom_raw_event, 602 .input_mapped = wacom_input_mapped, 603}; 604 605static int __init wacom_init(void) 606{ 607 int ret; 608 609 ret = hid_register_driver(&wacom_driver); 610 if (ret) 611 pr_err("can't register wacom driver\n"); 612 return ret; 613} 614 615static void __exit wacom_exit(void) 616{ 617 hid_unregister_driver(&wacom_driver); 618} 619 620module_init(wacom_init); 621module_exit(wacom_exit); 622MODULE_LICENSE("GPL"); 623