Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Input: add support for Wacom W8001 penabled serial touchscreen

The Wacom W8001 sensor is a sensor device (uses electromagnetic
resonance) and it is interfaced via its serial microcontroller
to the host.

Signed-off-by: Jaya Kumar <jayakumar.lkml@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>

authored by

Jaya Kumar and committed by
Dmitry Torokhov
3eb1aa43 e42b6646

+340
+13
drivers/input/touchscreen/Kconfig
··· 95 95 To compile this driver as a module, choose M here: the 96 96 module will be called elo. 97 97 98 + config TOUCHSCREEN_WACOM_W8001 99 + tristate "Wacom W8001 penabled serial touchscreen" 100 + select SERIO 101 + help 102 + Say Y here if you have an Wacom W8001 penabled serial touchscreen 103 + connected to your system. 104 + 105 + If unsure, say N. 106 + 107 + To compile this driver as a module, choose M here: the 108 + module will be called wacom_w8001. 109 + 110 + 98 111 config TOUCHSCREEN_MTOUCH 99 112 tristate "MicroTouch serial touchscreens" 100 113 select SERIO
+1
drivers/input/touchscreen/Makefile
··· 26 26 obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT) += touchright.o 27 27 obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN) += touchwin.o 28 28 obj-$(CONFIG_TOUCHSCREEN_UCB1400) += ucb1400_ts.o 29 + obj-$(CONFIG_TOUCHSCREEN_WACOM_W8001) += wacom_w8001.o 29 30 obj-$(CONFIG_TOUCHSCREEN_WM97XX) += wm97xx-ts.o 30 31 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705) += wm9705.o 31 32 wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712) += wm9712.o
+325
drivers/input/touchscreen/wacom_w8001.c
··· 1 + /* 2 + * Wacom W8001 penabled serial touchscreen driver 3 + * 4 + * Copyright (c) 2008 Jaya Kumar 5 + * 6 + * This file is subject to the terms and conditions of the GNU General Public 7 + * License. See the file COPYING in the main directory of this archive for 8 + * more details. 9 + * 10 + * Layout based on Elo serial touchscreen driver by Vojtech Pavlik 11 + */ 12 + 13 + #include <linux/errno.h> 14 + #include <linux/kernel.h> 15 + #include <linux/module.h> 16 + #include <linux/slab.h> 17 + #include <linux/input.h> 18 + #include <linux/serio.h> 19 + #include <linux/init.h> 20 + #include <linux/ctype.h> 21 + 22 + #define DRIVER_DESC "Wacom W8001 serial touchscreen driver" 23 + 24 + MODULE_AUTHOR("Jaya Kumar <jayakumar.lkml@gmail.com>"); 25 + MODULE_DESCRIPTION(DRIVER_DESC); 26 + MODULE_LICENSE("GPL"); 27 + 28 + /* 29 + * Definitions & global arrays. 30 + */ 31 + 32 + #define W8001_MAX_LENGTH 11 33 + #define W8001_PACKET_LEN 11 34 + #define W8001_LEAD_MASK 0x80 35 + #define W8001_LEAD_BYTE 0x80 36 + #define W8001_TAB_MASK 0x40 37 + #define W8001_TAB_BYTE 0x40 38 + 39 + #define W8001_QUERY_PACKET 0x20 40 + 41 + struct w8001_coord { 42 + u8 rdy; 43 + u8 tsw; 44 + u8 f1; 45 + u8 f2; 46 + u16 x; 47 + u16 y; 48 + u16 pen_pressure; 49 + u8 tilt_x; 50 + u8 tilt_y; 51 + }; 52 + 53 + /* 54 + * Per-touchscreen data. 55 + */ 56 + 57 + struct w8001 { 58 + struct input_dev *dev; 59 + struct serio *serio; 60 + struct mutex cmd_mutex; 61 + struct completion cmd_done; 62 + int id; 63 + int idx; 64 + unsigned char expected_packet; 65 + unsigned char data[W8001_MAX_LENGTH]; 66 + unsigned char response[W8001_PACKET_LEN]; 67 + char phys[32]; 68 + }; 69 + 70 + static int parse_data(u8 *data, struct w8001_coord *coord) 71 + { 72 + coord->rdy = data[0] & 0x20; 73 + coord->tsw = data[0] & 0x01; 74 + coord->f1 = data[0] & 0x02; 75 + coord->f2 = data[0] & 0x04; 76 + 77 + coord->x = (data[1] & 0x7F) << 9; 78 + coord->x |= (data[2] & 0x7F) << 2; 79 + coord->x |= (data[6] & 0x60) >> 5; 80 + 81 + coord->y = (data[3] & 0x7F) << 9; 82 + coord->y |= (data[4] & 0x7F) << 2; 83 + coord->y |= (data[6] & 0x18) >> 3; 84 + 85 + coord->pen_pressure = data[5] & 0x7F; 86 + coord->pen_pressure |= (data[6] & 0x07) << 7 ; 87 + 88 + coord->tilt_x = data[7] & 0x7F; 89 + coord->tilt_y = data[8] & 0x7F; 90 + 91 + return 0; 92 + } 93 + 94 + static void w8001_process_data(struct w8001 *w8001, unsigned char data) 95 + { 96 + struct input_dev *dev = w8001->dev; 97 + u8 tmp; 98 + struct w8001_coord coord; 99 + 100 + w8001->data[w8001->idx] = data; 101 + switch (w8001->idx++) { 102 + case 0: 103 + if ((data & W8001_LEAD_MASK) != W8001_LEAD_BYTE) { 104 + pr_debug("w8001: unsynchronized data: 0x%02x\n", data); 105 + w8001->idx = 0; 106 + } 107 + break; 108 + case 8: 109 + tmp = w8001->data[0] & W8001_TAB_MASK; 110 + if (unlikely(tmp == W8001_TAB_BYTE)) 111 + break; 112 + w8001->idx = 0; 113 + memset(&coord, 0, sizeof(coord)); 114 + parse_data(w8001->data, &coord); 115 + input_report_abs(dev, ABS_X, coord.x); 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; 121 + case 10: 122 + w8001->idx = 0; 123 + memcpy(w8001->response, &w8001->data, W8001_PACKET_LEN); 124 + w8001->expected_packet = W8001_QUERY_PACKET; 125 + complete(&w8001->cmd_done); 126 + break; 127 + } 128 + } 129 + 130 + 131 + static irqreturn_t w8001_interrupt(struct serio *serio, 132 + unsigned char data, unsigned int flags) 133 + { 134 + struct w8001 *w8001 = serio_get_drvdata(serio); 135 + 136 + w8001_process_data(w8001, data); 137 + 138 + return IRQ_HANDLED; 139 + } 140 + 141 + static int w8001_async_command(struct w8001 *w8001, unsigned char *packet, 142 + int len) 143 + { 144 + int rc = -1; 145 + int i; 146 + 147 + mutex_lock(&w8001->cmd_mutex); 148 + 149 + for (i = 0; i < len; i++) { 150 + if (serio_write(w8001->serio, packet[i])) 151 + goto out; 152 + } 153 + rc = 0; 154 + 155 + out: 156 + mutex_unlock(&w8001->cmd_mutex); 157 + return rc; 158 + } 159 + 160 + static int w8001_command(struct w8001 *w8001, unsigned char *packet, int len) 161 + { 162 + int rc = -1; 163 + int i; 164 + 165 + mutex_lock(&w8001->cmd_mutex); 166 + 167 + serio_pause_rx(w8001->serio); 168 + init_completion(&w8001->cmd_done); 169 + serio_continue_rx(w8001->serio); 170 + 171 + for (i = 0; i < len; i++) { 172 + if (serio_write(w8001->serio, packet[i])) 173 + goto out; 174 + } 175 + 176 + wait_for_completion_timeout(&w8001->cmd_done, HZ); 177 + 178 + if (w8001->expected_packet == W8001_QUERY_PACKET) { 179 + /* We are back in reporting mode, the query was ACKed */ 180 + memcpy(packet, w8001->response, W8001_PACKET_LEN); 181 + rc = 0; 182 + } 183 + 184 + out: 185 + mutex_unlock(&w8001->cmd_mutex); 186 + return rc; 187 + } 188 + 189 + static int w8001_setup(struct w8001 *w8001) 190 + { 191 + struct w8001_coord coord; 192 + struct input_dev *dev = w8001->dev; 193 + unsigned char start[1] = { '1' }; 194 + unsigned char query[11] = { '*' }; 195 + 196 + if (w8001_command(w8001, query, 1)) 197 + return -1; 198 + 199 + memset(&coord, 0, sizeof(coord)); 200 + parse_data(query, &coord); 201 + 202 + input_set_abs_params(dev, ABS_X, 0, coord.x, 0, 0); 203 + input_set_abs_params(dev, ABS_Y, 0, coord.y, 0, 0); 204 + input_set_abs_params(dev, ABS_PRESSURE, 0, coord.pen_pressure, 0, 0); 205 + input_set_abs_params(dev, ABS_TILT_X, 0, coord.tilt_x, 0, 0); 206 + input_set_abs_params(dev, ABS_TILT_Y, 0, coord.tilt_y, 0, 0); 207 + 208 + if (w8001_async_command(w8001, start, 1)) 209 + return -1; 210 + 211 + return 0; 212 + } 213 + 214 + /* 215 + * w8001_disconnect() is the opposite of w8001_connect() 216 + */ 217 + 218 + static void w8001_disconnect(struct serio *serio) 219 + { 220 + struct w8001 *w8001 = serio_get_drvdata(serio); 221 + 222 + input_get_device(w8001->dev); 223 + input_unregister_device(w8001->dev); 224 + serio_close(serio); 225 + serio_set_drvdata(serio, NULL); 226 + input_put_device(w8001->dev); 227 + kfree(w8001); 228 + } 229 + 230 + /* 231 + * w8001_connect() is the routine that is called when someone adds a 232 + * new serio device that supports the w8001 protocol and registers it as 233 + * an input device. 234 + */ 235 + 236 + static int w8001_connect(struct serio *serio, struct serio_driver *drv) 237 + { 238 + struct w8001 *w8001; 239 + struct input_dev *input_dev; 240 + int err; 241 + 242 + w8001 = kzalloc(sizeof(struct w8001), GFP_KERNEL); 243 + input_dev = input_allocate_device(); 244 + if (!w8001 || !input_dev) { 245 + err = -ENOMEM; 246 + goto fail1; 247 + } 248 + 249 + w8001->serio = serio; 250 + w8001->id = serio->id.id; 251 + w8001->dev = input_dev; 252 + mutex_init(&w8001->cmd_mutex); 253 + init_completion(&w8001->cmd_done); 254 + snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys); 255 + 256 + input_dev->name = "Wacom W8001 Penabled Serial TouchScreen"; 257 + input_dev->phys = w8001->phys; 258 + input_dev->id.bustype = BUS_RS232; 259 + input_dev->id.vendor = SERIO_W8001; 260 + input_dev->id.product = w8001->id; 261 + input_dev->id.version = 0x0100; 262 + input_dev->dev.parent = &serio->dev; 263 + 264 + input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); 265 + input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH); 266 + 267 + serio_set_drvdata(serio, w8001); 268 + err = serio_open(serio, drv); 269 + if (err) 270 + goto fail2; 271 + 272 + if (w8001_setup(w8001)) 273 + goto fail3; 274 + 275 + err = input_register_device(w8001->dev); 276 + if (err) 277 + goto fail3; 278 + 279 + return 0; 280 + 281 + fail3: 282 + serio_close(serio); 283 + fail2: 284 + serio_set_drvdata(serio, NULL); 285 + fail1: 286 + input_free_device(input_dev); 287 + kfree(w8001); 288 + return err; 289 + } 290 + 291 + static struct serio_device_id w8001_serio_ids[] = { 292 + { 293 + .type = SERIO_RS232, 294 + .proto = SERIO_W8001, 295 + .id = SERIO_ANY, 296 + .extra = SERIO_ANY, 297 + }, 298 + { 0 } 299 + }; 300 + 301 + MODULE_DEVICE_TABLE(serio, w8001_serio_ids); 302 + 303 + static struct serio_driver w8001_drv = { 304 + .driver = { 305 + .name = "w8001", 306 + }, 307 + .description = DRIVER_DESC, 308 + .id_table = w8001_serio_ids, 309 + .interrupt = w8001_interrupt, 310 + .connect = w8001_connect, 311 + .disconnect = w8001_disconnect, 312 + }; 313 + 314 + static int __init w8001_init(void) 315 + { 316 + return serio_register_driver(&w8001_drv); 317 + } 318 + 319 + static void __exit w8001_exit(void) 320 + { 321 + serio_unregister_driver(&w8001_drv); 322 + } 323 + 324 + module_init(w8001_init); 325 + module_exit(w8001_exit);
+1
include/linux/serio.h
··· 213 213 #define SERIO_ZHENHUA 0x36 214 214 #define SERIO_INEXIO 0x37 215 215 #define SERIO_TOUCHIT213 0x37 216 + #define SERIO_W8001 0x39 216 217 217 218 #endif