xref: /linux/drivers/input/mouse/vsxxxaa.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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