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.2-rc6 476 lines 12 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 */ 13 14/* 15 * This program is free software; you can redistribute it and/or modify it 16 * under the terms of the GNU General Public License as published by the Free 17 * Software Foundation; either version 2 of the License, or (at your option) 18 * any later version. 19 */ 20 21#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22 23#include <linux/device.h> 24#include <linux/hid.h> 25#include <linux/module.h> 26#include <linux/slab.h> 27#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 28#include <linux/power_supply.h> 29#endif 30 31#include "hid-ids.h" 32 33struct wacom_data { 34 __u16 tool; 35 unsigned char butstate; 36 unsigned char high_speed; 37#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 38 int battery_capacity; 39 struct power_supply battery; 40 struct power_supply ac; 41#endif 42}; 43 44#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 45/*percent of battery capacity, 0 means AC online*/ 46static unsigned short batcap[8] = { 1, 15, 25, 35, 50, 70, 100, 0 }; 47 48static enum power_supply_property wacom_battery_props[] = { 49 POWER_SUPPLY_PROP_PRESENT, 50 POWER_SUPPLY_PROP_CAPACITY 51}; 52 53static enum power_supply_property wacom_ac_props[] = { 54 POWER_SUPPLY_PROP_PRESENT, 55 POWER_SUPPLY_PROP_ONLINE 56}; 57 58static int wacom_battery_get_property(struct power_supply *psy, 59 enum power_supply_property psp, 60 union power_supply_propval *val) 61{ 62 struct wacom_data *wdata = container_of(psy, 63 struct wacom_data, battery); 64 int power_state = batcap[wdata->battery_capacity]; 65 int ret = 0; 66 67 switch (psp) { 68 case POWER_SUPPLY_PROP_PRESENT: 69 val->intval = 1; 70 break; 71 case POWER_SUPPLY_PROP_CAPACITY: 72 /* show 100% battery capacity when charging */ 73 if (power_state == 0) 74 val->intval = 100; 75 else 76 val->intval = power_state; 77 break; 78 default: 79 ret = -EINVAL; 80 break; 81 } 82 return ret; 83} 84 85static int wacom_ac_get_property(struct power_supply *psy, 86 enum power_supply_property psp, 87 union power_supply_propval *val) 88{ 89 struct wacom_data *wdata = container_of(psy, struct wacom_data, ac); 90 int power_state = batcap[wdata->battery_capacity]; 91 int ret = 0; 92 93 switch (psp) { 94 case POWER_SUPPLY_PROP_PRESENT: 95 /* fall through */ 96 case POWER_SUPPLY_PROP_ONLINE: 97 if (power_state == 0) 98 val->intval = 1; 99 else 100 val->intval = 0; 101 break; 102 default: 103 ret = -EINVAL; 104 break; 105 } 106 return ret; 107} 108#endif 109 110static void wacom_poke(struct hid_device *hdev, u8 speed) 111{ 112 struct wacom_data *wdata = hid_get_drvdata(hdev); 113 int limit, ret; 114 char rep_data[2]; 115 116 rep_data[0] = 0x03 ; rep_data[1] = 0x00; 117 limit = 3; 118 do { 119 ret = hdev->hid_output_raw_report(hdev, rep_data, 2, 120 HID_FEATURE_REPORT); 121 } while (ret < 0 && limit-- > 0); 122 123 if (ret >= 0) { 124 if (speed == 0) 125 rep_data[0] = 0x05; 126 else 127 rep_data[0] = 0x06; 128 129 rep_data[1] = 0x00; 130 limit = 3; 131 do { 132 ret = hdev->hid_output_raw_report(hdev, rep_data, 2, 133 HID_FEATURE_REPORT); 134 } while (ret < 0 && limit-- > 0); 135 136 if (ret >= 0) { 137 wdata->high_speed = speed; 138 return; 139 } 140 } 141 142 /* 143 * Note that if the raw queries fail, it's not a hard failure and it 144 * is safe to continue 145 */ 146 hid_warn(hdev, "failed to poke device, command %d, err %d\n", 147 rep_data[0], ret); 148 return; 149} 150 151static ssize_t wacom_show_speed(struct device *dev, 152 struct device_attribute 153 *attr, char *buf) 154{ 155 struct wacom_data *wdata = dev_get_drvdata(dev); 156 157 return snprintf(buf, PAGE_SIZE, "%i\n", wdata->high_speed); 158} 159 160static ssize_t wacom_store_speed(struct device *dev, 161 struct device_attribute *attr, 162 const char *buf, size_t count) 163{ 164 struct hid_device *hdev = container_of(dev, struct hid_device, dev); 165 int new_speed; 166 167 if (sscanf(buf, "%1d", &new_speed ) != 1) 168 return -EINVAL; 169 170 if (new_speed == 0 || new_speed == 1) { 171 wacom_poke(hdev, new_speed); 172 return strnlen(buf, PAGE_SIZE); 173 } else 174 return -EINVAL; 175} 176 177static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP, 178 wacom_show_speed, wacom_store_speed); 179 180static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report, 181 u8 *raw_data, int size) 182{ 183 struct wacom_data *wdata = hid_get_drvdata(hdev); 184 struct hid_input *hidinput; 185 struct input_dev *input; 186 unsigned char *data = (unsigned char *) raw_data; 187 int tool, x, y, rw; 188 189 if (!(hdev->claimed & HID_CLAIMED_INPUT)) 190 return 0; 191 192 tool = 0; 193 hidinput = list_entry(hdev->inputs.next, struct hid_input, list); 194 input = hidinput->input; 195 196 /* Check if this is a tablet report */ 197 if (data[0] != 0x03) 198 return 0; 199 200 /* Get X & Y positions */ 201 x = le16_to_cpu(*(__le16 *) &data[2]); 202 y = le16_to_cpu(*(__le16 *) &data[4]); 203 204 /* Get current tool identifier */ 205 if (data[1] & 0x90) { /* If pen is in the in/active area */ 206 switch ((data[1] >> 5) & 3) { 207 case 0: /* Pen */ 208 tool = BTN_TOOL_PEN; 209 break; 210 211 case 1: /* Rubber */ 212 tool = BTN_TOOL_RUBBER; 213 break; 214 215 case 2: /* Mouse with wheel */ 216 case 3: /* Mouse without wheel */ 217 tool = BTN_TOOL_MOUSE; 218 break; 219 } 220 221 /* Reset tool if out of active tablet area */ 222 if (!(data[1] & 0x10)) 223 tool = 0; 224 } 225 226 /* If tool changed, notify input subsystem */ 227 if (wdata->tool != tool) { 228 if (wdata->tool) { 229 /* Completely reset old tool state */ 230 if (wdata->tool == BTN_TOOL_MOUSE) { 231 input_report_key(input, BTN_LEFT, 0); 232 input_report_key(input, BTN_RIGHT, 0); 233 input_report_key(input, BTN_MIDDLE, 0); 234 input_report_abs(input, ABS_DISTANCE, 235 input_abs_get_max(input, ABS_DISTANCE)); 236 } else { 237 input_report_key(input, BTN_TOUCH, 0); 238 input_report_key(input, BTN_STYLUS, 0); 239 input_report_key(input, BTN_STYLUS2, 0); 240 input_report_abs(input, ABS_PRESSURE, 0); 241 } 242 input_report_key(input, wdata->tool, 0); 243 input_sync(input); 244 } 245 wdata->tool = tool; 246 if (tool) 247 input_report_key(input, tool, 1); 248 } 249 250 if (tool) { 251 input_report_abs(input, ABS_X, x); 252 input_report_abs(input, ABS_Y, y); 253 254 switch ((data[1] >> 5) & 3) { 255 case 2: /* Mouse with wheel */ 256 input_report_key(input, BTN_MIDDLE, data[1] & 0x04); 257 rw = (data[6] & 0x01) ? -1 : 258 (data[6] & 0x02) ? 1 : 0; 259 input_report_rel(input, REL_WHEEL, rw); 260 /* fall through */ 261 262 case 3: /* Mouse without wheel */ 263 input_report_key(input, BTN_LEFT, data[1] & 0x01); 264 input_report_key(input, BTN_RIGHT, data[1] & 0x02); 265 /* Compute distance between mouse and tablet */ 266 rw = 44 - (data[6] >> 2); 267 if (rw < 0) 268 rw = 0; 269 else if (rw > 31) 270 rw = 31; 271 input_report_abs(input, ABS_DISTANCE, rw); 272 break; 273 274 default: 275 input_report_abs(input, ABS_PRESSURE, 276 data[6] | (((__u16) (data[1] & 0x08)) << 5)); 277 input_report_key(input, BTN_TOUCH, data[1] & 0x01); 278 input_report_key(input, BTN_STYLUS, data[1] & 0x02); 279 input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04); 280 break; 281 } 282 283 input_sync(input); 284 } 285 286 /* Report the state of the two buttons at the top of the tablet 287 * as two extra fingerpad keys (buttons 4 & 5). */ 288 rw = data[7] & 0x03; 289 if (rw != wdata->butstate) { 290 wdata->butstate = rw; 291 input_report_key(input, BTN_0, rw & 0x02); 292 input_report_key(input, BTN_1, rw & 0x01); 293 input_report_key(input, BTN_TOOL_FINGER, 0xf0); 294 input_event(input, EV_MSC, MSC_SERIAL, 0xf0); 295 input_sync(input); 296 } 297 298#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 299 /* Store current battery capacity */ 300 rw = (data[7] >> 2 & 0x07); 301 if (rw != wdata->battery_capacity) 302 wdata->battery_capacity = rw; 303#endif 304 return 1; 305} 306 307static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi, 308 struct hid_field *field, struct hid_usage *usage, unsigned long **bit, 309 int *max) 310{ 311 struct input_dev *input = hi->input; 312 313 __set_bit(INPUT_PROP_POINTER, input->propbit); 314 315 /* Basics */ 316 input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL); 317 318 __set_bit(REL_WHEEL, input->relbit); 319 320 __set_bit(BTN_TOOL_PEN, input->keybit); 321 __set_bit(BTN_TOUCH, input->keybit); 322 __set_bit(BTN_STYLUS, input->keybit); 323 __set_bit(BTN_STYLUS2, input->keybit); 324 __set_bit(BTN_LEFT, input->keybit); 325 __set_bit(BTN_RIGHT, input->keybit); 326 __set_bit(BTN_MIDDLE, input->keybit); 327 328 /* Pad */ 329 input->evbit[0] |= BIT(EV_MSC); 330 331 __set_bit(MSC_SERIAL, input->mscbit); 332 333 __set_bit(BTN_0, input->keybit); 334 __set_bit(BTN_1, input->keybit); 335 __set_bit(BTN_TOOL_FINGER, input->keybit); 336 337 /* Distance, rubber and mouse */ 338 __set_bit(BTN_TOOL_RUBBER, input->keybit); 339 __set_bit(BTN_TOOL_MOUSE, input->keybit); 340 341 input_set_abs_params(input, ABS_X, 0, 16704, 4, 0); 342 input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0); 343 input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0); 344 input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0); 345 346 return 0; 347} 348 349static int wacom_probe(struct hid_device *hdev, 350 const struct hid_device_id *id) 351{ 352 struct wacom_data *wdata; 353 int ret; 354 355 wdata = kzalloc(sizeof(*wdata), GFP_KERNEL); 356 if (wdata == NULL) { 357 hid_err(hdev, "can't alloc wacom descriptor\n"); 358 return -ENOMEM; 359 } 360 361 hid_set_drvdata(hdev, wdata); 362 363 /* Parse the HID report now */ 364 ret = hid_parse(hdev); 365 if (ret) { 366 hid_err(hdev, "parse failed\n"); 367 goto err_free; 368 } 369 370 ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 371 if (ret) { 372 hid_err(hdev, "hw start failed\n"); 373 goto err_free; 374 } 375 376 ret = device_create_file(&hdev->dev, &dev_attr_speed); 377 if (ret) 378 hid_warn(hdev, 379 "can't create sysfs speed attribute err: %d\n", ret); 380 381 /* Set Wacom mode 2 with high reporting speed */ 382 wacom_poke(hdev, 1); 383 384#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 385 wdata->battery.properties = wacom_battery_props; 386 wdata->battery.num_properties = ARRAY_SIZE(wacom_battery_props); 387 wdata->battery.get_property = wacom_battery_get_property; 388 wdata->battery.name = "wacom_battery"; 389 wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY; 390 wdata->battery.use_for_apm = 0; 391 392 ret = power_supply_register(&hdev->dev, &wdata->battery); 393 if (ret) { 394 hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n", 395 ret); 396 goto err_battery; 397 } 398 399 wdata->ac.properties = wacom_ac_props; 400 wdata->ac.num_properties = ARRAY_SIZE(wacom_ac_props); 401 wdata->ac.get_property = wacom_ac_get_property; 402 wdata->ac.name = "wacom_ac"; 403 wdata->ac.type = POWER_SUPPLY_TYPE_MAINS; 404 wdata->ac.use_for_apm = 0; 405 406 ret = power_supply_register(&hdev->dev, &wdata->ac); 407 if (ret) { 408 hid_warn(hdev, 409 "can't create ac battery attribute, err: %d\n", ret); 410 goto err_ac; 411 } 412#endif 413 return 0; 414 415#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 416err_ac: 417 power_supply_unregister(&wdata->battery); 418err_battery: 419 device_remove_file(&hdev->dev, &dev_attr_speed); 420 hid_hw_stop(hdev); 421#endif 422err_free: 423 kfree(wdata); 424 return ret; 425} 426 427static void wacom_remove(struct hid_device *hdev) 428{ 429#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 430 struct wacom_data *wdata = hid_get_drvdata(hdev); 431#endif 432 device_remove_file(&hdev->dev, &dev_attr_speed); 433 hid_hw_stop(hdev); 434 435#ifdef CONFIG_HID_WACOM_POWER_SUPPLY 436 power_supply_unregister(&wdata->battery); 437 power_supply_unregister(&wdata->ac); 438#endif 439 kfree(hid_get_drvdata(hdev)); 440} 441 442static const struct hid_device_id wacom_devices[] = { 443 { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, 444 445 { } 446}; 447MODULE_DEVICE_TABLE(hid, wacom_devices); 448 449static struct hid_driver wacom_driver = { 450 .name = "wacom", 451 .id_table = wacom_devices, 452 .probe = wacom_probe, 453 .remove = wacom_remove, 454 .raw_event = wacom_raw_event, 455 .input_mapped = wacom_input_mapped, 456}; 457 458static int __init wacom_init(void) 459{ 460 int ret; 461 462 ret = hid_register_driver(&wacom_driver); 463 if (ret) 464 pr_err("can't register wacom driver\n"); 465 return ret; 466} 467 468static void __exit wacom_exit(void) 469{ 470 hid_unregister_driver(&wacom_driver); 471} 472 473module_init(wacom_init); 474module_exit(wacom_exit); 475MODULE_LICENSE("GPL"); 476