linux/drivers/hid/hid-wacom.c
<<
>>
Prefs
   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#include <linux/device.h>
  22#include <linux/hid.h>
  23#include <linux/module.h>
  24
  25#include "hid-ids.h"
  26
  27struct wacom_data {
  28        __u16 tool;
  29        unsigned char butstate;
  30};
  31
  32static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
  33                u8 *raw_data, int size)
  34{
  35        struct wacom_data *wdata = hid_get_drvdata(hdev);
  36        struct hid_input *hidinput;
  37        struct input_dev *input;
  38        unsigned char *data = (unsigned char *) raw_data;
  39        int tool, x, y, rw;
  40
  41        if (!(hdev->claimed & HID_CLAIMED_INPUT))
  42                return 0;
  43
  44        tool = 0;
  45        hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
  46        input = hidinput->input;
  47
  48        /* Check if this is a tablet report */
  49        if (data[0] != 0x03)
  50                return 0;
  51
  52        /* Get X & Y positions */
  53        x = le16_to_cpu(*(__le16 *) &data[2]);
  54        y = le16_to_cpu(*(__le16 *) &data[4]);
  55
  56        /* Get current tool identifier */
  57        if (data[1] & 0x90) { /* If pen is in the in/active area */
  58                switch ((data[1] >> 5) & 3) {
  59                case 0: /* Pen */
  60                        tool = BTN_TOOL_PEN;
  61                        break;
  62
  63                case 1: /* Rubber */
  64                        tool = BTN_TOOL_RUBBER;
  65                        break;
  66
  67                case 2: /* Mouse with wheel */
  68                case 3: /* Mouse without wheel */
  69                        tool = BTN_TOOL_MOUSE;
  70                        break;
  71                }
  72
  73                /* Reset tool if out of active tablet area */
  74                if (!(data[1] & 0x10))
  75                        tool = 0;
  76        }
  77
  78        /* If tool changed, notify input subsystem */
  79        if (wdata->tool != tool) {
  80                if (wdata->tool) {
  81                        /* Completely reset old tool state */
  82                        if (wdata->tool == BTN_TOOL_MOUSE) {
  83                                input_report_key(input, BTN_LEFT, 0);
  84                                input_report_key(input, BTN_RIGHT, 0);
  85                                input_report_key(input, BTN_MIDDLE, 0);
  86                                input_report_abs(input, ABS_DISTANCE,
  87                                                input->absmax[ABS_DISTANCE]);
  88                        } else {
  89                                input_report_key(input, BTN_TOUCH, 0);
  90                                input_report_key(input, BTN_STYLUS, 0);
  91                                input_report_key(input, BTN_STYLUS2, 0);
  92                                input_report_abs(input, ABS_PRESSURE, 0);
  93                        }
  94                        input_report_key(input, wdata->tool, 0);
  95                        input_sync(input);
  96                }
  97                wdata->tool = tool;
  98                if (tool)
  99                        input_report_key(input, tool, 1);
 100        }
 101
 102        if (tool) {
 103                input_report_abs(input, ABS_X, x);
 104                input_report_abs(input, ABS_Y, y);
 105
 106                switch ((data[1] >> 5) & 3) {
 107                case 2: /* Mouse with wheel */
 108                        input_report_key(input, BTN_MIDDLE, data[1] & 0x04);
 109                        rw = (data[6] & 0x01) ? -1 :
 110                                (data[6] & 0x02) ? 1 : 0;
 111                        input_report_rel(input, REL_WHEEL, rw);
 112                        /* fall through */
 113
 114                case 3: /* Mouse without wheel */
 115                        input_report_key(input, BTN_LEFT, data[1] & 0x01);
 116                        input_report_key(input, BTN_RIGHT, data[1] & 0x02);
 117                        /* Compute distance between mouse and tablet */
 118                        rw = 44 - (data[6] >> 2);
 119                        if (rw < 0)
 120                                rw = 0;
 121                        else if (rw > 31)
 122                                rw = 31;
 123                        input_report_abs(input, ABS_DISTANCE, rw);
 124                        break;
 125
 126                default:
 127                        input_report_abs(input, ABS_PRESSURE,
 128                                        data[6] | (((__u16) (data[1] & 0x08)) << 5));
 129                        input_report_key(input, BTN_TOUCH, data[1] & 0x01);
 130                        input_report_key(input, BTN_STYLUS, data[1] & 0x02);
 131                        input_report_key(input, BTN_STYLUS2, (tool == BTN_TOOL_PEN) && data[1] & 0x04);
 132                        break;
 133                }
 134
 135                input_sync(input);
 136        }
 137
 138        /* Report the state of the two buttons at the top of the tablet
 139         * as two extra fingerpad keys (buttons 4 & 5). */
 140        rw = data[7] & 0x03;
 141        if (rw != wdata->butstate) {
 142                wdata->butstate = rw;
 143                input_report_key(input, BTN_0, rw & 0x02);
 144                input_report_key(input, BTN_1, rw & 0x01);
 145                input_event(input, EV_MSC, MSC_SERIAL, 0xf0);
 146                input_sync(input);
 147        }
 148
 149        return 1;
 150}
 151
 152static int wacom_probe(struct hid_device *hdev,
 153                const struct hid_device_id *id)
 154{
 155        struct hid_input *hidinput;
 156        struct input_dev *input;
 157        struct wacom_data *wdata;
 158        int ret;
 159
 160        wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
 161        if (wdata == NULL) {
 162                dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
 163                return -ENOMEM;
 164        }
 165
 166        hid_set_drvdata(hdev, wdata);
 167
 168        ret = hid_parse(hdev);
 169        if (ret) {
 170                dev_err(&hdev->dev, "parse failed\n");
 171                goto err_free;
 172        }
 173
 174        ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 175        if (ret) {
 176                dev_err(&hdev->dev, "hw start failed\n");
 177                goto err_free;
 178        }
 179
 180        hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
 181        input = hidinput->input;
 182
 183        /* Basics */
 184        input->evbit[0] |= BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_REL);
 185        input->absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) |
 186                BIT(ABS_PRESSURE) | BIT(ABS_DISTANCE);
 187        input->relbit[0] |= BIT(REL_WHEEL);
 188        set_bit(BTN_TOOL_PEN, input->keybit);
 189        set_bit(BTN_TOUCH, input->keybit);
 190        set_bit(BTN_STYLUS, input->keybit);
 191        set_bit(BTN_STYLUS2, input->keybit);
 192        set_bit(BTN_LEFT, input->keybit);
 193        set_bit(BTN_RIGHT, input->keybit);
 194        set_bit(BTN_MIDDLE, input->keybit);
 195
 196        /* Pad */
 197        input->evbit[0] |= BIT(EV_MSC);
 198        input->mscbit[0] |= BIT(MSC_SERIAL);
 199
 200        /* Distance, rubber and mouse */
 201        input->absbit[0] |= BIT(ABS_DISTANCE);
 202        set_bit(BTN_TOOL_RUBBER, input->keybit);
 203        set_bit(BTN_TOOL_MOUSE, input->keybit);
 204
 205        input->absmax[ABS_PRESSURE] = 511;
 206        input->absmax[ABS_DISTANCE] = 32;
 207
 208        input->absmax[ABS_X] = 16704;
 209        input->absmax[ABS_Y] = 12064;
 210        input->absfuzz[ABS_X] = 4;
 211        input->absfuzz[ABS_Y] = 4;
 212
 213        return 0;
 214err_free:
 215        kfree(wdata);
 216        return ret;
 217}
 218
 219static void wacom_remove(struct hid_device *hdev)
 220{
 221        hid_hw_stop(hdev);
 222        kfree(hid_get_drvdata(hdev));
 223}
 224
 225static const struct hid_device_id wacom_devices[] = {
 226        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
 227
 228        { }
 229};
 230MODULE_DEVICE_TABLE(hid, wacom_devices);
 231
 232static struct hid_driver wacom_driver = {
 233        .name = "wacom",
 234        .id_table = wacom_devices,
 235        .probe = wacom_probe,
 236        .remove = wacom_remove,
 237        .raw_event = wacom_raw_event,
 238};
 239
 240static int __init wacom_init(void)
 241{
 242        int ret;
 243
 244        ret = hid_register_driver(&wacom_driver);
 245        if (ret)
 246                printk(KERN_ERR "can't register wacom driver\n");
 247        printk(KERN_ERR "wacom driver registered\n");
 248        return ret;
 249}
 250
 251static void __exit wacom_exit(void)
 252{
 253        hid_unregister_driver(&wacom_driver);
 254}
 255
 256module_init(wacom_init);
 257module_exit(wacom_exit);
 258MODULE_LICENSE("GPL");
 259
 260