diff options
author | Peter Hutterer <peter.hutterer@who-t.net> | 2010-08-29 01:00:05 -0400 |
---|---|---|
committer | Dmitry Torokhov <dmitry.torokhov@gmail.com> | 2010-08-29 01:46:04 -0400 |
commit | 2072f8db625cbdaba839fe7bb1b607d06884e685 (patch) | |
tree | a091298fb8b89f5fe6505072e4dc99f3b0ba9e98 /drivers/input/touchscreen | |
parent | ba4d695a90c9176fca8e45d6c872bbf4e8bed315 (diff) |
Input: wacom_w8001 - send BTN_TOOL_PEN/RUBBER and BTN_STYLUS events
The protocol used by the w8001 supports status fields for tip, side
switch and eraser as well as a RDY field for proximity.
The protocol has a double usage for the f2 bit in the packet. If set,
the data is either pen + side2 button or eraser. Assume eraser if the
device comes into proximity with the f2 bit set, otherwise trigger the
side2 button. If the device comes into proximity with the f2 bit and
that bit disappears afterwards, fake proximity out for the eraser and
proximity in for the pen.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Diffstat (limited to 'drivers/input/touchscreen')
-rw-r--r-- | drivers/input/touchscreen/wacom_w8001.c | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c index 56dc35c94bb1..bc642f1be376 100644 --- a/drivers/input/touchscreen/wacom_w8001.c +++ b/drivers/input/touchscreen/wacom_w8001.c | |||
@@ -62,6 +62,7 @@ struct w8001 { | |||
62 | unsigned char response[W8001_MAX_LENGTH]; | 62 | unsigned char response[W8001_MAX_LENGTH]; |
63 | unsigned char data[W8001_MAX_LENGTH]; | 63 | unsigned char data[W8001_MAX_LENGTH]; |
64 | char phys[32]; | 64 | char phys[32]; |
65 | int type; | ||
65 | }; | 66 | }; |
66 | 67 | ||
67 | static void parse_data(u8 *data, struct w8001_coord *coord) | 68 | static void parse_data(u8 *data, struct w8001_coord *coord) |
@@ -88,11 +89,52 @@ static void parse_data(u8 *data, struct w8001_coord *coord) | |||
88 | coord->tilt_y = data[8] & 0x7F; | 89 | coord->tilt_y = data[8] & 0x7F; |
89 | } | 90 | } |
90 | 91 | ||
92 | static void report_pen_events(struct w8001 *w8001, struct w8001_coord *coord) | ||
93 | { | ||
94 | struct input_dev *dev = w8001->dev; | ||
95 | |||
96 | /* | ||
97 | * We have 1 bit for proximity (rdy) and 3 bits for tip, side, | ||
98 | * side2/eraser. If rdy && f2 are set, this can be either pen + side2, | ||
99 | * or eraser. assume | ||
100 | * - if dev is already in proximity and f2 is toggled → pen + side2 | ||
101 | * - if dev comes into proximity with f2 set → eraser | ||
102 | * If f2 disappears after assuming eraser, fake proximity out for | ||
103 | * eraser and in for pen. | ||
104 | */ | ||
105 | |||
106 | if (!w8001->type) { | ||
107 | w8001->type = coord->f2 ? BTN_TOOL_RUBBER : BTN_TOOL_PEN; | ||
108 | } else if (w8001->type == BTN_TOOL_RUBBER) { | ||
109 | if (!coord->f2) { | ||
110 | input_report_abs(dev, ABS_PRESSURE, 0); | ||
111 | input_report_key(dev, BTN_TOUCH, 0); | ||
112 | input_report_key(dev, BTN_STYLUS, 0); | ||
113 | input_report_key(dev, BTN_STYLUS2, 0); | ||
114 | input_report_key(dev, BTN_TOOL_RUBBER, 0); | ||
115 | input_sync(dev); | ||
116 | w8001->type = BTN_TOOL_PEN; | ||
117 | } | ||
118 | } else { | ||
119 | input_report_key(dev, BTN_STYLUS2, coord->f2); | ||
120 | } | ||
121 | |||
122 | input_report_abs(dev, ABS_X, coord->x); | ||
123 | input_report_abs(dev, ABS_Y, coord->y); | ||
124 | input_report_abs(dev, ABS_PRESSURE, coord->pen_pressure); | ||
125 | input_report_key(dev, BTN_TOUCH, coord->tsw); | ||
126 | input_report_key(dev, BTN_STYLUS, coord->f1); | ||
127 | input_report_key(dev, w8001->type, coord->rdy); | ||
128 | input_sync(dev); | ||
129 | |||
130 | if (!coord->rdy) | ||
131 | w8001->type = 0; | ||
132 | } | ||
133 | |||
91 | static irqreturn_t w8001_interrupt(struct serio *serio, | 134 | static irqreturn_t w8001_interrupt(struct serio *serio, |
92 | unsigned char data, unsigned int flags) | 135 | unsigned char data, unsigned int flags) |
93 | { | 136 | { |
94 | struct w8001 *w8001 = serio_get_drvdata(serio); | 137 | struct w8001 *w8001 = serio_get_drvdata(serio); |
95 | struct input_dev *dev = w8001->dev; | ||
96 | struct w8001_coord coord; | 138 | struct w8001_coord coord; |
97 | unsigned char tmp; | 139 | unsigned char tmp; |
98 | 140 | ||
@@ -112,11 +154,7 @@ static irqreturn_t w8001_interrupt(struct serio *serio, | |||
112 | 154 | ||
113 | w8001->idx = 0; | 155 | w8001->idx = 0; |
114 | parse_data(w8001->data, &coord); | 156 | parse_data(w8001->data, &coord); |
115 | input_report_abs(dev, ABS_X, coord.x); | 157 | report_pen_events(w8001, &coord); |
116 | input_report_abs(dev, ABS_Y, coord.y); | ||
117 | input_report_abs(dev, ABS_PRESSURE, coord.pen_pressure); | ||
118 | input_report_key(dev, BTN_TOUCH, coord.tsw); | ||
119 | input_sync(dev); | ||
120 | break; | 158 | break; |
121 | 159 | ||
122 | case 10: | 160 | case 10: |
@@ -221,6 +259,10 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv) | |||
221 | 259 | ||
222 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 260 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
223 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); | 261 | input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); |
262 | input_dev->keybit[BIT_WORD(BTN_TOOL_PEN)] |= BIT_MASK(BTN_TOOL_PEN); | ||
263 | input_dev->keybit[BIT_WORD(BTN_TOOL_RUBBER)] |= BIT_MASK(BTN_TOOL_RUBBER); | ||
264 | input_dev->keybit[BIT_WORD(BTN_STYLUS)] |= BIT_MASK(BTN_STYLUS); | ||
265 | input_dev->keybit[BIT_WORD(BTN_STYLUS2)] |= BIT_MASK(BTN_STYLUS2); | ||
224 | 266 | ||
225 | serio_set_drvdata(serio, w8001); | 267 | serio_set_drvdata(serio, w8001); |
226 | err = serio_open(serio, drv); | 268 | err = serio_open(serio, drv); |