11a59d1b8SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * Driver for DEC VSXXX-AA mouse (hockey-puck mouse, ball or two rollers)
41da177e4SLinus Torvalds * DEC VSXXX-GA mouse (rectangular mouse, with ball)
51da177e4SLinus Torvalds * DEC VSXXX-AB tablet (digitizer with hair cross or stylus)
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Copyright (C) 2003-2004 by Jan-Benedict Glaw <jbglaw@lug-owl.de>
81da177e4SLinus Torvalds *
91da177e4SLinus Torvalds * The packet format was initially taken from a patch to GPM which is (C) 2001
101da177e4SLinus Torvalds * by Karsten Merker <merker@linuxtag.org>
111da177e4SLinus Torvalds * and Maciej W. Rozycki <macro@ds2.pg.gda.pl>
121da177e4SLinus Torvalds * Later on, I had access to the device's documentation (referenced below).
131da177e4SLinus Torvalds */
141da177e4SLinus Torvalds
151da177e4SLinus Torvalds /*
161da177e4SLinus Torvalds * Building an adaptor to DE9 / DB25 RS232
171da177e4SLinus Torvalds * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
181da177e4SLinus Torvalds *
191da177e4SLinus Torvalds * DISCLAIMER: Use this description AT YOUR OWN RISK! I'll not pay for
201da177e4SLinus Torvalds * anything if you break your mouse, your computer or whatever!
211da177e4SLinus Torvalds *
221da177e4SLinus Torvalds * In theory, this mouse is a simple RS232 device. In practice, it has got
231da177e4SLinus Torvalds * a quite uncommon plug and the requirement to additionally get a power
241da177e4SLinus Torvalds * supply at +5V and -12V.
251da177e4SLinus Torvalds *
261da177e4SLinus Torvalds * If you look at the socket/jack (_not_ at the plug), we use this pin
271da177e4SLinus Torvalds * numbering:
281da177e4SLinus Torvalds * _______
291da177e4SLinus Torvalds * / 7 6 5 \
301da177e4SLinus Torvalds * | 4 --- 3 |
311da177e4SLinus Torvalds * \ 2 1 /
321da177e4SLinus Torvalds * -------
331da177e4SLinus Torvalds *
341da177e4SLinus Torvalds * DEC socket DE9 DB25 Note
351da177e4SLinus Torvalds * 1 (GND) 5 7 -
361da177e4SLinus Torvalds * 2 (RxD) 2 3 -
371da177e4SLinus Torvalds * 3 (TxD) 3 2 -
381da177e4SLinus Torvalds * 4 (-12V) - - Somewhere from the PSU. At ATX, it's
391da177e4SLinus Torvalds * the thin blue wire at pin 12 of the
401da177e4SLinus Torvalds * ATX power connector. Only required for
411da177e4SLinus Torvalds * VSXXX-AA/-GA mice.
421da177e4SLinus Torvalds * 5 (+5V) - - PSU (red wires of ATX power connector
431da177e4SLinus Torvalds * on pin 4, 6, 19 or 20) or HDD power
441da177e4SLinus Torvalds * connector (also red wire).
451da177e4SLinus Torvalds * 6 (+12V) - - HDD power connector, yellow wire. Only
461da177e4SLinus Torvalds * required for VSXXX-AB digitizer.
471da177e4SLinus Torvalds * 7 (dev. avail.) - - The mouse shorts this one to pin 1.
481da177e4SLinus Torvalds * This way, the host computer can detect
491da177e4SLinus Torvalds * the mouse. To use it with the adaptor,
501da177e4SLinus Torvalds * simply don't connect this pin.
511da177e4SLinus Torvalds *
521da177e4SLinus Torvalds * So to get a working adaptor, you need to connect the mouse with three
531da177e4SLinus Torvalds * wires to a RS232 port and two or three additional wires for +5V, +12V and
541da177e4SLinus Torvalds * -12V to the PSU.
551da177e4SLinus Torvalds *
561da177e4SLinus Torvalds * Flow specification for the link is 4800, 8o1.
571da177e4SLinus Torvalds *
581da177e4SLinus Torvalds * The mice and tablet are described in "VCB02 Video Subsystem - Technical
591da177e4SLinus Torvalds * Manual", DEC EK-104AA-TM-001. You'll find it at MANX, a search engine
601da177e4SLinus Torvalds * specific for DEC documentation. Try
611da177e4SLinus Torvalds * http://www.vt100.net/manx/details?pn=EK-104AA-TM-001;id=21;cp=1
621da177e4SLinus Torvalds */
631da177e4SLinus Torvalds
641da177e4SLinus Torvalds #include <linux/delay.h>
651da177e4SLinus Torvalds #include <linux/module.h>
661da177e4SLinus Torvalds #include <linux/slab.h>
671da177e4SLinus Torvalds #include <linux/interrupt.h>
681da177e4SLinus Torvalds #include <linux/input.h>
691da177e4SLinus Torvalds #include <linux/serio.h>
701da177e4SLinus Torvalds
711da177e4SLinus Torvalds #define DRIVER_DESC "Driver for DEC VSXXX-AA and -GA mice and VSXXX-AB tablet"
721da177e4SLinus Torvalds
731da177e4SLinus Torvalds MODULE_AUTHOR("Jan-Benedict Glaw <jbglaw@lug-owl.de>");
741da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
751da177e4SLinus Torvalds MODULE_LICENSE("GPL");
761da177e4SLinus Torvalds
771da177e4SLinus Torvalds #undef VSXXXAA_DEBUG
781da177e4SLinus Torvalds #ifdef VSXXXAA_DEBUG
791da177e4SLinus Torvalds #define DBG(x...) printk(x)
801da177e4SLinus Torvalds #else
811da177e4SLinus Torvalds #define DBG(x...) do {} while (0)
821da177e4SLinus Torvalds #endif
831da177e4SLinus Torvalds
841da177e4SLinus Torvalds #define VSXXXAA_INTRO_MASK 0x80
851da177e4SLinus Torvalds #define VSXXXAA_INTRO_HEAD 0x80
8621602325SDmitry Torokhov #define IS_HDR_BYTE(x) \
8721602325SDmitry Torokhov (((x) & VSXXXAA_INTRO_MASK) == VSXXXAA_INTRO_HEAD)
881da177e4SLinus Torvalds
891da177e4SLinus Torvalds #define VSXXXAA_PACKET_MASK 0xe0
901da177e4SLinus Torvalds #define VSXXXAA_PACKET_REL 0x80
911da177e4SLinus Torvalds #define VSXXXAA_PACKET_ABS 0xc0
921da177e4SLinus Torvalds #define VSXXXAA_PACKET_POR 0xa0
9321602325SDmitry Torokhov #define MATCH_PACKET_TYPE(data, type) \
9421602325SDmitry Torokhov (((data) & VSXXXAA_PACKET_MASK) == (type))
951da177e4SLinus Torvalds
961da177e4SLinus Torvalds
971da177e4SLinus Torvalds
981da177e4SLinus Torvalds struct vsxxxaa {
992e5b636bSDmitry Torokhov struct input_dev *dev;
1001da177e4SLinus Torvalds struct serio *serio;
1011da177e4SLinus Torvalds #define BUFLEN 15 /* At least 5 is needed for a full tablet packet */
1021da177e4SLinus Torvalds unsigned char buf[BUFLEN];
1031da177e4SLinus Torvalds unsigned char count;
1041da177e4SLinus Torvalds unsigned char version;
1051da177e4SLinus Torvalds unsigned char country;
1061da177e4SLinus Torvalds unsigned char type;
1071da177e4SLinus Torvalds char name[64];
1081da177e4SLinus Torvalds char phys[32];
1091da177e4SLinus Torvalds };
1101da177e4SLinus Torvalds
vsxxxaa_drop_bytes(struct vsxxxaa * mouse,int num)11121602325SDmitry Torokhov static void vsxxxaa_drop_bytes(struct vsxxxaa *mouse, int num)
1121da177e4SLinus Torvalds {
11321602325SDmitry Torokhov if (num >= mouse->count) {
1141da177e4SLinus Torvalds mouse->count = 0;
11521602325SDmitry Torokhov } else {
1164db1f47cSDmitry Torokhov memmove(mouse->buf, mouse->buf + num, BUFLEN - num);
1171da177e4SLinus Torvalds mouse->count -= num;
1181da177e4SLinus Torvalds }
1191da177e4SLinus Torvalds }
1201da177e4SLinus Torvalds
vsxxxaa_queue_byte(struct vsxxxaa * mouse,unsigned char byte)12121602325SDmitry Torokhov static void vsxxxaa_queue_byte(struct vsxxxaa *mouse, unsigned char byte)
1221da177e4SLinus Torvalds {
1231da177e4SLinus Torvalds if (mouse->count == BUFLEN) {
1241da177e4SLinus Torvalds printk(KERN_ERR "%s on %s: Dropping a byte of full buffer.\n",
1251da177e4SLinus Torvalds mouse->name, mouse->phys);
1261da177e4SLinus Torvalds vsxxxaa_drop_bytes(mouse, 1);
1271da177e4SLinus Torvalds }
12821602325SDmitry Torokhov
1291da177e4SLinus Torvalds DBG(KERN_INFO "Queueing byte 0x%02x\n", byte);
1301da177e4SLinus Torvalds
1311da177e4SLinus Torvalds mouse->buf[mouse->count++] = byte;
1321da177e4SLinus Torvalds }
1331da177e4SLinus Torvalds
vsxxxaa_detection_done(struct vsxxxaa * mouse)13421602325SDmitry Torokhov static void vsxxxaa_detection_done(struct vsxxxaa *mouse)
1351da177e4SLinus Torvalds {
1361da177e4SLinus Torvalds switch (mouse->type) {
1371da177e4SLinus Torvalds case 0x02:
138a9f08ad7SWolfram Sang strscpy(mouse->name, "DEC VSXXX-AA/-GA mouse",
13908ffce45SDmitry Torokhov sizeof(mouse->name));
1401da177e4SLinus Torvalds break;
1411da177e4SLinus Torvalds
1421da177e4SLinus Torvalds case 0x04:
143a9f08ad7SWolfram Sang strscpy(mouse->name, "DEC VSXXX-AB digitizer",
14408ffce45SDmitry Torokhov sizeof(mouse->name));
1451da177e4SLinus Torvalds break;
1461da177e4SLinus Torvalds
1471da177e4SLinus Torvalds default:
14808ffce45SDmitry Torokhov snprintf(mouse->name, sizeof(mouse->name),
14908ffce45SDmitry Torokhov "unknown DEC pointer device (type = 0x%02x)",
15008ffce45SDmitry Torokhov mouse->type);
1511da177e4SLinus Torvalds break;
1521da177e4SLinus Torvalds }
1531da177e4SLinus Torvalds
15408ffce45SDmitry Torokhov printk(KERN_INFO
15508ffce45SDmitry Torokhov "Found %s version 0x%02x from country 0x%02x on port %s\n",
15608ffce45SDmitry Torokhov mouse->name, mouse->version, mouse->country, mouse->phys);
1571da177e4SLinus Torvalds }
1581da177e4SLinus Torvalds
1591da177e4SLinus Torvalds /*
1601da177e4SLinus Torvalds * Returns number of bytes to be dropped, 0 if packet is okay.
1611da177e4SLinus Torvalds */
vsxxxaa_check_packet(struct vsxxxaa * mouse,int packet_len)16221602325SDmitry Torokhov static int vsxxxaa_check_packet(struct vsxxxaa *mouse, int packet_len)
1631da177e4SLinus Torvalds {
1641da177e4SLinus Torvalds int i;
1651da177e4SLinus Torvalds
1661da177e4SLinus Torvalds /* First byte must be a header byte */
1671da177e4SLinus Torvalds if (!IS_HDR_BYTE(mouse->buf[0])) {
1681da177e4SLinus Torvalds DBG("vsck: len=%d, 1st=0x%02x\n", packet_len, mouse->buf[0]);
1691da177e4SLinus Torvalds return 1;
1701da177e4SLinus Torvalds }
1711da177e4SLinus Torvalds
1721da177e4SLinus Torvalds /* Check all following bytes */
1731da177e4SLinus Torvalds for (i = 1; i < packet_len; i++) {
1741da177e4SLinus Torvalds if (IS_HDR_BYTE(mouse->buf[i])) {
17521602325SDmitry Torokhov printk(KERN_ERR
17621602325SDmitry Torokhov "Need to drop %d bytes of a broken packet.\n",
1771da177e4SLinus Torvalds i - 1);
1781da177e4SLinus Torvalds DBG(KERN_INFO "check: len=%d, b[%d]=0x%02x\n",
1791da177e4SLinus Torvalds packet_len, i, mouse->buf[i]);
1801da177e4SLinus Torvalds return i - 1;
1811da177e4SLinus Torvalds }
1821da177e4SLinus Torvalds }
1831da177e4SLinus Torvalds
1841da177e4SLinus Torvalds return 0;
1851da177e4SLinus Torvalds }
1861da177e4SLinus Torvalds
vsxxxaa_smells_like_packet(struct vsxxxaa * mouse,unsigned char type,size_t len)18721602325SDmitry Torokhov static inline int vsxxxaa_smells_like_packet(struct vsxxxaa *mouse,
18821602325SDmitry Torokhov unsigned char type, size_t len)
1891da177e4SLinus Torvalds {
19021602325SDmitry Torokhov return mouse->count >= len && MATCH_PACKET_TYPE(mouse->buf[0], type);
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds
vsxxxaa_handle_REL_packet(struct vsxxxaa * mouse)19321602325SDmitry Torokhov static void vsxxxaa_handle_REL_packet(struct vsxxxaa *mouse)
1941da177e4SLinus Torvalds {
1952e5b636bSDmitry Torokhov struct input_dev *dev = mouse->dev;
1961da177e4SLinus Torvalds unsigned char *buf = mouse->buf;
1971da177e4SLinus Torvalds int left, middle, right;
1981da177e4SLinus Torvalds int dx, dy;
1991da177e4SLinus Torvalds
2001da177e4SLinus Torvalds /*
2011da177e4SLinus Torvalds * Check for normal stream packets. This is three bytes,
2021da177e4SLinus Torvalds * with the first byte's 3 MSB set to 100.
2031da177e4SLinus Torvalds *
2041da177e4SLinus Torvalds * [0]: 1 0 0 SignX SignY Left Middle Right
2051da177e4SLinus Torvalds * [1]: 0 dx dx dx dx dx dx dx
2061da177e4SLinus Torvalds * [2]: 0 dy dy dy dy dy dy dy
2071da177e4SLinus Torvalds */
2081da177e4SLinus Torvalds
2091da177e4SLinus Torvalds /*
2101da177e4SLinus Torvalds * Low 7 bit of byte 1 are abs(dx), bit 7 is
2111da177e4SLinus Torvalds * 0, bit 4 of byte 0 is direction.
2121da177e4SLinus Torvalds */
2131da177e4SLinus Torvalds dx = buf[1] & 0x7f;
2141da177e4SLinus Torvalds dx *= ((buf[0] >> 4) & 0x01) ? 1 : -1;
2151da177e4SLinus Torvalds
2161da177e4SLinus Torvalds /*
2171da177e4SLinus Torvalds * Low 7 bit of byte 2 are abs(dy), bit 7 is
2181da177e4SLinus Torvalds * 0, bit 3 of byte 0 is direction.
2191da177e4SLinus Torvalds */
2201da177e4SLinus Torvalds dy = buf[2] & 0x7f;
2211da177e4SLinus Torvalds dy *= ((buf[0] >> 3) & 0x01) ? -1 : 1;
2221da177e4SLinus Torvalds
2231da177e4SLinus Torvalds /*
2241da177e4SLinus Torvalds * Get button state. It's the low three bits
2251da177e4SLinus Torvalds * (for three buttons) of byte 0.
2261da177e4SLinus Torvalds */
22721602325SDmitry Torokhov left = buf[0] & 0x04;
22821602325SDmitry Torokhov middle = buf[0] & 0x02;
22921602325SDmitry Torokhov right = buf[0] & 0x01;
2301da177e4SLinus Torvalds
2311da177e4SLinus Torvalds vsxxxaa_drop_bytes(mouse, 3);
2321da177e4SLinus Torvalds
2331da177e4SLinus Torvalds DBG(KERN_INFO "%s on %s: dx=%d, dy=%d, buttons=%s%s%s\n",
2341da177e4SLinus Torvalds mouse->name, mouse->phys, dx, dy,
2351da177e4SLinus Torvalds left ? "L" : "l", middle ? "M" : "m", right ? "R" : "r");
2361da177e4SLinus Torvalds
2371da177e4SLinus Torvalds /*
2381da177e4SLinus Torvalds * Report what we've found so far...
2391da177e4SLinus Torvalds */
2401da177e4SLinus Torvalds input_report_key(dev, BTN_LEFT, left);
2411da177e4SLinus Torvalds input_report_key(dev, BTN_MIDDLE, middle);
2421da177e4SLinus Torvalds input_report_key(dev, BTN_RIGHT, right);
2431da177e4SLinus Torvalds input_report_key(dev, BTN_TOUCH, 0);
2441da177e4SLinus Torvalds input_report_rel(dev, REL_X, dx);
2451da177e4SLinus Torvalds input_report_rel(dev, REL_Y, dy);
2461da177e4SLinus Torvalds input_sync(dev);
2471da177e4SLinus Torvalds }
2481da177e4SLinus Torvalds
vsxxxaa_handle_ABS_packet(struct vsxxxaa * mouse)24921602325SDmitry Torokhov static void vsxxxaa_handle_ABS_packet(struct vsxxxaa *mouse)
2501da177e4SLinus Torvalds {
2512e5b636bSDmitry Torokhov struct input_dev *dev = mouse->dev;
2521da177e4SLinus Torvalds unsigned char *buf = mouse->buf;
2531da177e4SLinus Torvalds int left, middle, right, touch;
2541da177e4SLinus Torvalds int x, y;
2551da177e4SLinus Torvalds
2561da177e4SLinus Torvalds /*
2571da177e4SLinus Torvalds * Tablet position / button packet
2581da177e4SLinus Torvalds *
2591da177e4SLinus Torvalds * [0]: 1 1 0 B4 B3 B2 B1 Pr
2601da177e4SLinus Torvalds * [1]: 0 0 X5 X4 X3 X2 X1 X0
2611da177e4SLinus Torvalds * [2]: 0 0 X11 X10 X9 X8 X7 X6
2621da177e4SLinus Torvalds * [3]: 0 0 Y5 Y4 Y3 Y2 Y1 Y0
2631da177e4SLinus Torvalds * [4]: 0 0 Y11 Y10 Y9 Y8 Y7 Y6
2641da177e4SLinus Torvalds */
2651da177e4SLinus Torvalds
2661da177e4SLinus Torvalds /*
2671da177e4SLinus Torvalds * Get X/Y position. Y axis needs to be inverted since VSXXX-AB
2681da177e4SLinus Torvalds * counts down->top while monitor counts top->bottom.
2691da177e4SLinus Torvalds */
2701da177e4SLinus Torvalds x = ((buf[2] & 0x3f) << 6) | (buf[1] & 0x3f);
2711da177e4SLinus Torvalds y = ((buf[4] & 0x3f) << 6) | (buf[3] & 0x3f);
2721da177e4SLinus Torvalds y = 1023 - y;
2731da177e4SLinus Torvalds
2741da177e4SLinus Torvalds /*
2751da177e4SLinus Torvalds * Get button state. It's bits <4..1> of byte 0.
2761da177e4SLinus Torvalds */
27721602325SDmitry Torokhov left = buf[0] & 0x02;
27821602325SDmitry Torokhov middle = buf[0] & 0x04;
27921602325SDmitry Torokhov right = buf[0] & 0x08;
28021602325SDmitry Torokhov touch = buf[0] & 0x10;
2811da177e4SLinus Torvalds
2821da177e4SLinus Torvalds vsxxxaa_drop_bytes(mouse, 5);
2831da177e4SLinus Torvalds
2841da177e4SLinus Torvalds DBG(KERN_INFO "%s on %s: x=%d, y=%d, buttons=%s%s%s%s\n",
2851da177e4SLinus Torvalds mouse->name, mouse->phys, x, y,
2861da177e4SLinus Torvalds left ? "L" : "l", middle ? "M" : "m",
2871da177e4SLinus Torvalds right ? "R" : "r", touch ? "T" : "t");
2881da177e4SLinus Torvalds
2891da177e4SLinus Torvalds /*
2901da177e4SLinus Torvalds * Report what we've found so far...
2911da177e4SLinus Torvalds */
2921da177e4SLinus Torvalds input_report_key(dev, BTN_LEFT, left);
2931da177e4SLinus Torvalds input_report_key(dev, BTN_MIDDLE, middle);
2941da177e4SLinus Torvalds input_report_key(dev, BTN_RIGHT, right);
2951da177e4SLinus Torvalds input_report_key(dev, BTN_TOUCH, touch);
2961da177e4SLinus Torvalds input_report_abs(dev, ABS_X, x);
2971da177e4SLinus Torvalds input_report_abs(dev, ABS_Y, y);
2981da177e4SLinus Torvalds input_sync(dev);
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds
vsxxxaa_handle_POR_packet(struct vsxxxaa * mouse)30121602325SDmitry Torokhov static void vsxxxaa_handle_POR_packet(struct vsxxxaa *mouse)
3021da177e4SLinus Torvalds {
3032e5b636bSDmitry Torokhov struct input_dev *dev = mouse->dev;
3041da177e4SLinus Torvalds unsigned char *buf = mouse->buf;
3051da177e4SLinus Torvalds int left, middle, right;
3061da177e4SLinus Torvalds unsigned char error;
3071da177e4SLinus Torvalds
3081da177e4SLinus Torvalds /*
3091da177e4SLinus Torvalds * Check for Power-On-Reset packets. These are sent out
310c03983acSJean Delvare * after plugging the mouse in, or when explicitly
3111da177e4SLinus Torvalds * requested by sending 'T'.
3121da177e4SLinus Torvalds *
3131da177e4SLinus Torvalds * [0]: 1 0 1 0 R3 R2 R1 R0
3141da177e4SLinus Torvalds * [1]: 0 M2 M1 M0 D3 D2 D1 D0
3151da177e4SLinus Torvalds * [2]: 0 E6 E5 E4 E3 E2 E1 E0
3161da177e4SLinus Torvalds * [3]: 0 0 0 0 0 Left Middle Right
3171da177e4SLinus Torvalds *
3181da177e4SLinus Torvalds * M: manufacturer location code
3191da177e4SLinus Torvalds * R: revision code
3201da177e4SLinus Torvalds * E: Error code. If it's in the range of 0x00..0x1f, only some
32125985edcSLucas De Marchi * minor problem occurred. Errors >= 0x20 are considered bad
3221da177e4SLinus Torvalds * and the device may not work properly...
3231da177e4SLinus Torvalds * D: <0010> == mouse, <0100> == tablet
3241da177e4SLinus Torvalds */
3251da177e4SLinus Torvalds
3261da177e4SLinus Torvalds mouse->version = buf[0] & 0x0f;
3271da177e4SLinus Torvalds mouse->country = (buf[1] >> 4) & 0x07;
3281da177e4SLinus Torvalds mouse->type = buf[1] & 0x0f;
3291da177e4SLinus Torvalds error = buf[2] & 0x7f;
3301da177e4SLinus Torvalds
3311da177e4SLinus Torvalds /*
3321da177e4SLinus Torvalds * Get button state. It's the low three bits
3331da177e4SLinus Torvalds * (for three buttons) of byte 0. Maybe even the bit <3>
3341da177e4SLinus Torvalds * has some meaning if a tablet is attached.
3351da177e4SLinus Torvalds */
33621602325SDmitry Torokhov left = buf[0] & 0x04;
33721602325SDmitry Torokhov middle = buf[0] & 0x02;
33821602325SDmitry Torokhov right = buf[0] & 0x01;
3391da177e4SLinus Torvalds
3401da177e4SLinus Torvalds vsxxxaa_drop_bytes(mouse, 4);
3411da177e4SLinus Torvalds vsxxxaa_detection_done(mouse);
3421da177e4SLinus Torvalds
3431da177e4SLinus Torvalds if (error <= 0x1f) {
3441da177e4SLinus Torvalds /* No (serious) error. Report buttons */
3451da177e4SLinus Torvalds input_report_key(dev, BTN_LEFT, left);
3461da177e4SLinus Torvalds input_report_key(dev, BTN_MIDDLE, middle);
3471da177e4SLinus Torvalds input_report_key(dev, BTN_RIGHT, right);
3481da177e4SLinus Torvalds input_report_key(dev, BTN_TOUCH, 0);
3491da177e4SLinus Torvalds input_sync(dev);
3501da177e4SLinus Torvalds
3511da177e4SLinus Torvalds if (error != 0)
3521da177e4SLinus Torvalds printk(KERN_INFO "Your %s on %s reports error=0x%02x\n",
3531da177e4SLinus Torvalds mouse->name, mouse->phys, error);
3541da177e4SLinus Torvalds
3551da177e4SLinus Torvalds }
3561da177e4SLinus Torvalds
3571da177e4SLinus Torvalds /*
3581da177e4SLinus Torvalds * If the mouse was hot-plugged, we need to force differential mode
3591da177e4SLinus Torvalds * now... However, give it a second to recover from it's reset.
3601da177e4SLinus Torvalds */
36121602325SDmitry Torokhov printk(KERN_NOTICE
36221602325SDmitry Torokhov "%s on %s: Forcing standard packet format, "
3631da177e4SLinus Torvalds "incremental streaming mode and 72 samples/sec\n",
3641da177e4SLinus Torvalds mouse->name, mouse->phys);
365dd0d5443SDmitry Torokhov serio_write(mouse->serio, 'S'); /* Standard format */
3661da177e4SLinus Torvalds mdelay(50);
367dd0d5443SDmitry Torokhov serio_write(mouse->serio, 'R'); /* Incremental */
3681da177e4SLinus Torvalds mdelay(50);
369dd0d5443SDmitry Torokhov serio_write(mouse->serio, 'L'); /* 72 samples/sec */
3701da177e4SLinus Torvalds }
3711da177e4SLinus Torvalds
vsxxxaa_parse_buffer(struct vsxxxaa * mouse)37221602325SDmitry Torokhov static void vsxxxaa_parse_buffer(struct vsxxxaa *mouse)
3731da177e4SLinus Torvalds {
3741da177e4SLinus Torvalds unsigned char *buf = mouse->buf;
3751da177e4SLinus Torvalds int stray_bytes;
3761da177e4SLinus Torvalds
3771da177e4SLinus Torvalds /*
3781da177e4SLinus Torvalds * Parse buffer to death...
3791da177e4SLinus Torvalds */
3801da177e4SLinus Torvalds do {
3811da177e4SLinus Torvalds /*
3821da177e4SLinus Torvalds * Out of sync? Throw away what we don't understand. Each
3831da177e4SLinus Torvalds * packet starts with a byte whose bit 7 is set. Unhandled
3841da177e4SLinus Torvalds * packets (ie. which we don't know about or simply b0rk3d
3851da177e4SLinus Torvalds * data...) will get shifted out of the buffer after some
3861da177e4SLinus Torvalds * activity on the mouse.
3871da177e4SLinus Torvalds */
3881da177e4SLinus Torvalds while (mouse->count > 0 && !IS_HDR_BYTE(buf[0])) {
3891da177e4SLinus Torvalds printk(KERN_ERR "%s on %s: Dropping a byte to regain "
3901da177e4SLinus Torvalds "sync with mouse data stream...\n",
3911da177e4SLinus Torvalds mouse->name, mouse->phys);
3921da177e4SLinus Torvalds vsxxxaa_drop_bytes(mouse, 1);
3931da177e4SLinus Torvalds }
3941da177e4SLinus Torvalds
3951da177e4SLinus Torvalds /*
3961da177e4SLinus Torvalds * Check for packets we know about.
3971da177e4SLinus Torvalds */
3981da177e4SLinus Torvalds
3991da177e4SLinus Torvalds if (vsxxxaa_smells_like_packet(mouse, VSXXXAA_PACKET_REL, 3)) {
4001da177e4SLinus Torvalds /* Check for broken packet */
4011da177e4SLinus Torvalds stray_bytes = vsxxxaa_check_packet(mouse, 3);
40221602325SDmitry Torokhov if (!stray_bytes)
4037d12e780SDavid Howells vsxxxaa_handle_REL_packet(mouse);
4041da177e4SLinus Torvalds
40521602325SDmitry Torokhov } else if (vsxxxaa_smells_like_packet(mouse,
40621602325SDmitry Torokhov VSXXXAA_PACKET_ABS, 5)) {
4071da177e4SLinus Torvalds /* Check for broken packet */
4081da177e4SLinus Torvalds stray_bytes = vsxxxaa_check_packet(mouse, 5);
40921602325SDmitry Torokhov if (!stray_bytes)
4107d12e780SDavid Howells vsxxxaa_handle_ABS_packet(mouse);
4111da177e4SLinus Torvalds
41221602325SDmitry Torokhov } else if (vsxxxaa_smells_like_packet(mouse,
41321602325SDmitry Torokhov VSXXXAA_PACKET_POR, 4)) {
4141da177e4SLinus Torvalds /* Check for broken packet */
4151da177e4SLinus Torvalds stray_bytes = vsxxxaa_check_packet(mouse, 4);
41621602325SDmitry Torokhov if (!stray_bytes)
41721602325SDmitry Torokhov vsxxxaa_handle_POR_packet(mouse);
41821602325SDmitry Torokhov
41921602325SDmitry Torokhov } else {
42021602325SDmitry Torokhov break; /* No REL, ABS or POR packet found */
42121602325SDmitry Torokhov }
42221602325SDmitry Torokhov
4231da177e4SLinus Torvalds if (stray_bytes > 0) {
4241da177e4SLinus Torvalds printk(KERN_ERR "Dropping %d bytes now...\n",
4251da177e4SLinus Torvalds stray_bytes);
4261da177e4SLinus Torvalds vsxxxaa_drop_bytes(mouse, stray_bytes);
4271da177e4SLinus Torvalds }
4281da177e4SLinus Torvalds
4291da177e4SLinus Torvalds } while (1);
4301da177e4SLinus Torvalds }
4311da177e4SLinus Torvalds
vsxxxaa_interrupt(struct serio * serio,unsigned char data,unsigned int flags)43221602325SDmitry Torokhov static irqreturn_t vsxxxaa_interrupt(struct serio *serio,
43321602325SDmitry Torokhov unsigned char data, unsigned int flags)
4341da177e4SLinus Torvalds {
4351da177e4SLinus Torvalds struct vsxxxaa *mouse = serio_get_drvdata(serio);
4361da177e4SLinus Torvalds
4371da177e4SLinus Torvalds vsxxxaa_queue_byte(mouse, data);
4387d12e780SDavid Howells vsxxxaa_parse_buffer(mouse);
4391da177e4SLinus Torvalds
4401da177e4SLinus Torvalds return IRQ_HANDLED;
4411da177e4SLinus Torvalds }
4421da177e4SLinus Torvalds
vsxxxaa_disconnect(struct serio * serio)44321602325SDmitry Torokhov static void vsxxxaa_disconnect(struct serio *serio)
4441da177e4SLinus Torvalds {
4451da177e4SLinus Torvalds struct vsxxxaa *mouse = serio_get_drvdata(serio);
4461da177e4SLinus Torvalds
4471da177e4SLinus Torvalds serio_close(serio);
4481da177e4SLinus Torvalds serio_set_drvdata(serio, NULL);
4492e5b636bSDmitry Torokhov input_unregister_device(mouse->dev);
4501da177e4SLinus Torvalds kfree(mouse);
4511da177e4SLinus Torvalds }
4521da177e4SLinus Torvalds
vsxxxaa_connect(struct serio * serio,struct serio_driver * drv)45321602325SDmitry Torokhov static int vsxxxaa_connect(struct serio *serio, struct serio_driver *drv)
4541da177e4SLinus Torvalds {
4551da177e4SLinus Torvalds struct vsxxxaa *mouse;
4562e5b636bSDmitry Torokhov struct input_dev *input_dev;
4572e5b636bSDmitry Torokhov int err = -ENOMEM;
4581da177e4SLinus Torvalds
459*dc2f1423SErick Archer mouse = kzalloc(sizeof(*mouse), GFP_KERNEL);
4602e5b636bSDmitry Torokhov input_dev = input_allocate_device();
4612e5b636bSDmitry Torokhov if (!mouse || !input_dev)
46272155615SDmitry Torokhov goto fail1;
4631da177e4SLinus Torvalds
4642e5b636bSDmitry Torokhov mouse->dev = input_dev;
4652e5b636bSDmitry Torokhov mouse->serio = serio;
46608ffce45SDmitry Torokhov strlcat(mouse->name, "DEC VSXXX-AA/-GA mouse or VSXXX-AB digitizer",
46708ffce45SDmitry Torokhov sizeof(mouse->name));
46808ffce45SDmitry Torokhov snprintf(mouse->phys, sizeof(mouse->phys), "%s/input0", serio->phys);
4692e5b636bSDmitry Torokhov
4702e5b636bSDmitry Torokhov input_dev->name = mouse->name;
4712e5b636bSDmitry Torokhov input_dev->phys = mouse->phys;
4722e5b636bSDmitry Torokhov input_dev->id.bustype = BUS_RS232;
47328aa7f1cSDmitry Torokhov input_dev->dev.parent = &serio->dev;
4742e5b636bSDmitry Torokhov
47521602325SDmitry Torokhov __set_bit(EV_KEY, input_dev->evbit); /* We have buttons */
47621602325SDmitry Torokhov __set_bit(EV_REL, input_dev->evbit);
47721602325SDmitry Torokhov __set_bit(EV_ABS, input_dev->evbit);
47821602325SDmitry Torokhov __set_bit(BTN_LEFT, input_dev->keybit); /* We have 3 buttons */
47921602325SDmitry Torokhov __set_bit(BTN_MIDDLE, input_dev->keybit);
48021602325SDmitry Torokhov __set_bit(BTN_RIGHT, input_dev->keybit);
48121602325SDmitry Torokhov __set_bit(BTN_TOUCH, input_dev->keybit); /* ...and Tablet */
48221602325SDmitry Torokhov __set_bit(REL_X, input_dev->relbit);
48321602325SDmitry Torokhov __set_bit(REL_Y, input_dev->relbit);
4842e5b636bSDmitry Torokhov input_set_abs_params(input_dev, ABS_X, 0, 1023, 0, 0);
4852e5b636bSDmitry Torokhov input_set_abs_params(input_dev, ABS_Y, 0, 1023, 0, 0);
4861da177e4SLinus Torvalds
4871da177e4SLinus Torvalds serio_set_drvdata(serio, mouse);
4881da177e4SLinus Torvalds
4891da177e4SLinus Torvalds err = serio_open(serio, drv);
4902e5b636bSDmitry Torokhov if (err)
49172155615SDmitry Torokhov goto fail2;
4921da177e4SLinus Torvalds
4931da177e4SLinus Torvalds /*
4941da177e4SLinus Torvalds * Request selftest. Standard packet format and differential
4951da177e4SLinus Torvalds * mode will be requested after the device ID'ed successfully.
4961da177e4SLinus Torvalds */
497dd0d5443SDmitry Torokhov serio_write(serio, 'T'); /* Test */
4981da177e4SLinus Torvalds
49972155615SDmitry Torokhov err = input_register_device(input_dev);
50072155615SDmitry Torokhov if (err)
50172155615SDmitry Torokhov goto fail3;
5021da177e4SLinus Torvalds
5031da177e4SLinus Torvalds return 0;
5042e5b636bSDmitry Torokhov
50572155615SDmitry Torokhov fail3: serio_close(serio);
50672155615SDmitry Torokhov fail2: serio_set_drvdata(serio, NULL);
50772155615SDmitry Torokhov fail1: input_free_device(input_dev);
5082e5b636bSDmitry Torokhov kfree(mouse);
5092e5b636bSDmitry Torokhov return err;
5101da177e4SLinus Torvalds }
5111da177e4SLinus Torvalds
5121da177e4SLinus Torvalds static struct serio_device_id vsxxaa_serio_ids[] = {
5131da177e4SLinus Torvalds {
5141da177e4SLinus Torvalds .type = SERIO_RS232,
5151da177e4SLinus Torvalds .proto = SERIO_VSXXXAA,
5161da177e4SLinus Torvalds .id = SERIO_ANY,
5171da177e4SLinus Torvalds .extra = SERIO_ANY,
5181da177e4SLinus Torvalds },
5191da177e4SLinus Torvalds { 0 }
5201da177e4SLinus Torvalds };
5211da177e4SLinus Torvalds
5221da177e4SLinus Torvalds MODULE_DEVICE_TABLE(serio, vsxxaa_serio_ids);
5231da177e4SLinus Torvalds
5241da177e4SLinus Torvalds static struct serio_driver vsxxxaa_drv = {
5251da177e4SLinus Torvalds .driver = {
5261da177e4SLinus Torvalds .name = "vsxxxaa",
5271da177e4SLinus Torvalds },
5281da177e4SLinus Torvalds .description = DRIVER_DESC,
5291da177e4SLinus Torvalds .id_table = vsxxaa_serio_ids,
5301da177e4SLinus Torvalds .connect = vsxxxaa_connect,
5311da177e4SLinus Torvalds .interrupt = vsxxxaa_interrupt,
5321da177e4SLinus Torvalds .disconnect = vsxxxaa_disconnect,
5331da177e4SLinus Torvalds };
5341da177e4SLinus Torvalds
53565ac9f7aSAxel Lin module_serio_driver(vsxxxaa_drv);
536