aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/input
diff options
context:
space:
mode:
authorPeter Hutterer <peter.hutterer@who-t.net>2010-08-29 01:00:05 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-08-29 01:46:04 -0400
commit2072f8db625cbdaba839fe7bb1b607d06884e685 (patch)
treea091298fb8b89f5fe6505072e4dc99f3b0ba9e98 /drivers/input
parentba4d695a90c9176fca8e45d6c872bbf4e8bed315 (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')
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c54
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
67static void parse_data(u8 *data, struct w8001_coord *coord) 68static 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
92static 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
91static irqreturn_t w8001_interrupt(struct serio *serio, 134static 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);