xref: /openbmc/linux/drivers/input/joystick/adi.c (revision 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2)
1*1da177e4SLinus Torvalds /*
2*1da177e4SLinus Torvalds  *  Copyright (c) 1998-2005 Vojtech Pavlik
3*1da177e4SLinus Torvalds  */
4*1da177e4SLinus Torvalds 
5*1da177e4SLinus Torvalds /*
6*1da177e4SLinus Torvalds  * Logitech ADI joystick family driver for Linux
7*1da177e4SLinus Torvalds  */
8*1da177e4SLinus Torvalds 
9*1da177e4SLinus Torvalds /*
10*1da177e4SLinus Torvalds  * This program is free software; you can redistribute it and/or modify
11*1da177e4SLinus Torvalds  * it under the terms of the GNU General Public License as published by
12*1da177e4SLinus Torvalds  * the Free Software Foundation; either version 2 of the License, or
13*1da177e4SLinus Torvalds  * (at your option) any later version.
14*1da177e4SLinus Torvalds  *
15*1da177e4SLinus Torvalds  * This program is distributed in the hope that it will be useful,
16*1da177e4SLinus Torvalds  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17*1da177e4SLinus Torvalds  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*1da177e4SLinus Torvalds  * GNU General Public License for more details.
19*1da177e4SLinus Torvalds  *
20*1da177e4SLinus Torvalds  * You should have received a copy of the GNU General Public License
21*1da177e4SLinus Torvalds  * along with this program; if not, write to the Free Software
22*1da177e4SLinus Torvalds  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23*1da177e4SLinus Torvalds  *
24*1da177e4SLinus Torvalds  * Should you need to contact me, the author, you can do so either by
25*1da177e4SLinus Torvalds  * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
26*1da177e4SLinus Torvalds  * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
27*1da177e4SLinus Torvalds  */
28*1da177e4SLinus Torvalds 
29*1da177e4SLinus Torvalds #include <linux/delay.h>
30*1da177e4SLinus Torvalds #include <linux/kernel.h>
31*1da177e4SLinus Torvalds #include <linux/module.h>
32*1da177e4SLinus Torvalds #include <linux/string.h>
33*1da177e4SLinus Torvalds #include <linux/slab.h>
34*1da177e4SLinus Torvalds #include <linux/input.h>
35*1da177e4SLinus Torvalds #include <linux/gameport.h>
36*1da177e4SLinus Torvalds #include <linux/init.h>
37*1da177e4SLinus Torvalds 
38*1da177e4SLinus Torvalds #define DRIVER_DESC	"Logitech ADI joystick family driver"
39*1da177e4SLinus Torvalds 
40*1da177e4SLinus Torvalds MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
41*1da177e4SLinus Torvalds MODULE_DESCRIPTION(DRIVER_DESC);
42*1da177e4SLinus Torvalds MODULE_LICENSE("GPL");
43*1da177e4SLinus Torvalds 
44*1da177e4SLinus Torvalds /*
45*1da177e4SLinus Torvalds  * Times, array sizes, flags, ids.
46*1da177e4SLinus Torvalds  */
47*1da177e4SLinus Torvalds 
48*1da177e4SLinus Torvalds #define ADI_MAX_START		200	/* Trigger to packet timeout [200us] */
49*1da177e4SLinus Torvalds #define ADI_MAX_STROBE		40	/* Single bit timeout [40us] */
50*1da177e4SLinus Torvalds #define ADI_INIT_DELAY		10	/* Delay after init packet [10ms] */
51*1da177e4SLinus Torvalds #define ADI_DATA_DELAY		4	/* Delay after data packet [4ms] */
52*1da177e4SLinus Torvalds 
53*1da177e4SLinus Torvalds #define ADI_MAX_LENGTH		256
54*1da177e4SLinus Torvalds #define ADI_MIN_LENGTH		8
55*1da177e4SLinus Torvalds #define ADI_MIN_LEN_LENGTH	10
56*1da177e4SLinus Torvalds #define ADI_MIN_ID_LENGTH	66
57*1da177e4SLinus Torvalds #define ADI_MAX_NAME_LENGTH	48
58*1da177e4SLinus Torvalds #define ADI_MAX_CNAME_LENGTH	16
59*1da177e4SLinus Torvalds #define ADI_MAX_PHYS_LENGTH	64
60*1da177e4SLinus Torvalds 
61*1da177e4SLinus Torvalds #define ADI_FLAG_HAT		0x04
62*1da177e4SLinus Torvalds #define ADI_FLAG_10BIT		0x08
63*1da177e4SLinus Torvalds 
64*1da177e4SLinus Torvalds #define ADI_ID_TPD		0x01
65*1da177e4SLinus Torvalds #define ADI_ID_WGP		0x06
66*1da177e4SLinus Torvalds #define ADI_ID_WGPE		0x08
67*1da177e4SLinus Torvalds #define ADI_ID_MAX		0x0a
68*1da177e4SLinus Torvalds 
69*1da177e4SLinus Torvalds /*
70*1da177e4SLinus Torvalds  * Names, buttons, axes ...
71*1da177e4SLinus Torvalds  */
72*1da177e4SLinus Torvalds 
73*1da177e4SLinus Torvalds static char *adi_names[] = {	"WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
74*1da177e4SLinus Torvalds 				"WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
75*1da177e4SLinus Torvalds 				"WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
76*1da177e4SLinus Torvalds 				"WingMan GamePad USB", "Unknown Device %#x" };
77*1da177e4SLinus Torvalds 
78*1da177e4SLinus Torvalds static char adi_wmgpe_abs[] =	{ ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
79*1da177e4SLinus Torvalds static char adi_wmi_abs[] =	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
80*1da177e4SLinus Torvalds static char adi_wmed3d_abs[] =	{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
81*1da177e4SLinus Torvalds static char adi_cm2_abs[] =	{ ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
82*1da177e4SLinus Torvalds static char adi_wmf_abs[] =	{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
83*1da177e4SLinus Torvalds 
84*1da177e4SLinus Torvalds static short adi_wmgpe_key[] =	{ BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z,  BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
85*1da177e4SLinus Torvalds static short adi_wmi_key[] = 	{ BTN_TRIGGER,  BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
86*1da177e4SLinus Torvalds static short adi_wmed3d_key[] =	{ BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
87*1da177e4SLinus Torvalds static short adi_cm2_key[] =	{ BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
88*1da177e4SLinus Torvalds 
89*1da177e4SLinus Torvalds static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
90*1da177e4SLinus Torvalds 			   adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
91*1da177e4SLinus Torvalds 
92*1da177e4SLinus Torvalds static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
93*1da177e4SLinus Torvalds 			    adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
94*1da177e4SLinus Torvalds 
95*1da177e4SLinus Torvalds /*
96*1da177e4SLinus Torvalds  * Hat to axis conversion arrays.
97*1da177e4SLinus Torvalds  */
98*1da177e4SLinus Torvalds 
99*1da177e4SLinus Torvalds static struct {
100*1da177e4SLinus Torvalds 	int x;
101*1da177e4SLinus Torvalds 	int y;
102*1da177e4SLinus Torvalds } adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
103*1da177e4SLinus Torvalds 
104*1da177e4SLinus Torvalds /*
105*1da177e4SLinus Torvalds  * Per-port information.
106*1da177e4SLinus Torvalds  */
107*1da177e4SLinus Torvalds 
108*1da177e4SLinus Torvalds struct adi {
109*1da177e4SLinus Torvalds 	struct input_dev dev;
110*1da177e4SLinus Torvalds 	int length;
111*1da177e4SLinus Torvalds 	int ret;
112*1da177e4SLinus Torvalds 	int idx;
113*1da177e4SLinus Torvalds 	unsigned char id;
114*1da177e4SLinus Torvalds 	char buttons;
115*1da177e4SLinus Torvalds 	char axes10;
116*1da177e4SLinus Torvalds 	char axes8;
117*1da177e4SLinus Torvalds 	signed char pad;
118*1da177e4SLinus Torvalds 	char hats;
119*1da177e4SLinus Torvalds 	char *abs;
120*1da177e4SLinus Torvalds 	short *key;
121*1da177e4SLinus Torvalds 	char name[ADI_MAX_NAME_LENGTH];
122*1da177e4SLinus Torvalds 	char cname[ADI_MAX_CNAME_LENGTH];
123*1da177e4SLinus Torvalds 	char phys[ADI_MAX_PHYS_LENGTH];
124*1da177e4SLinus Torvalds 	unsigned char data[ADI_MAX_LENGTH];
125*1da177e4SLinus Torvalds };
126*1da177e4SLinus Torvalds 
127*1da177e4SLinus Torvalds struct adi_port {
128*1da177e4SLinus Torvalds 	struct gameport *gameport;
129*1da177e4SLinus Torvalds 	struct adi adi[2];
130*1da177e4SLinus Torvalds 	int bad;
131*1da177e4SLinus Torvalds 	int reads;
132*1da177e4SLinus Torvalds };
133*1da177e4SLinus Torvalds 
134*1da177e4SLinus Torvalds /*
135*1da177e4SLinus Torvalds  * adi_read_packet() reads a Logitech ADI packet.
136*1da177e4SLinus Torvalds  */
137*1da177e4SLinus Torvalds 
138*1da177e4SLinus Torvalds static void adi_read_packet(struct adi_port *port)
139*1da177e4SLinus Torvalds {
140*1da177e4SLinus Torvalds 	struct adi *adi = port->adi;
141*1da177e4SLinus Torvalds 	struct gameport *gameport = port->gameport;
142*1da177e4SLinus Torvalds 	unsigned char u, v, w, x, z;
143*1da177e4SLinus Torvalds 	int t[2], s[2], i;
144*1da177e4SLinus Torvalds 	unsigned long flags;
145*1da177e4SLinus Torvalds 
146*1da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
147*1da177e4SLinus Torvalds 		adi[i].ret = -1;
148*1da177e4SLinus Torvalds 		t[i] = gameport_time(gameport, ADI_MAX_START);
149*1da177e4SLinus Torvalds 		s[i] = 0;
150*1da177e4SLinus Torvalds 	}
151*1da177e4SLinus Torvalds 
152*1da177e4SLinus Torvalds 	local_irq_save(flags);
153*1da177e4SLinus Torvalds 
154*1da177e4SLinus Torvalds 	gameport_trigger(gameport);
155*1da177e4SLinus Torvalds 	v = z = gameport_read(gameport);
156*1da177e4SLinus Torvalds 
157*1da177e4SLinus Torvalds 	do {
158*1da177e4SLinus Torvalds 		u = v;
159*1da177e4SLinus Torvalds 		w = u ^ (v = x = gameport_read(gameport));
160*1da177e4SLinus Torvalds 		for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
161*1da177e4SLinus Torvalds 			t[i]--;
162*1da177e4SLinus Torvalds 			if ((w & 0x30) && s[i]) {
163*1da177e4SLinus Torvalds 				if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
164*1da177e4SLinus Torvalds 					adi[i].data[++adi[i].ret] = w;
165*1da177e4SLinus Torvalds 					t[i] = gameport_time(gameport, ADI_MAX_STROBE);
166*1da177e4SLinus Torvalds 				} else t[i] = 0;
167*1da177e4SLinus Torvalds 			} else if (!(x & 0x30)) s[i] = 1;
168*1da177e4SLinus Torvalds 		}
169*1da177e4SLinus Torvalds 	} while (t[0] > 0 || t[1] > 0);
170*1da177e4SLinus Torvalds 
171*1da177e4SLinus Torvalds 	local_irq_restore(flags);
172*1da177e4SLinus Torvalds 
173*1da177e4SLinus Torvalds 	return;
174*1da177e4SLinus Torvalds }
175*1da177e4SLinus Torvalds 
176*1da177e4SLinus Torvalds /*
177*1da177e4SLinus Torvalds  * adi_move_bits() detects a possible 2-stream mode, and moves
178*1da177e4SLinus Torvalds  * the bits accordingly.
179*1da177e4SLinus Torvalds  */
180*1da177e4SLinus Torvalds 
181*1da177e4SLinus Torvalds static void adi_move_bits(struct adi_port *port, int length)
182*1da177e4SLinus Torvalds {
183*1da177e4SLinus Torvalds 	int i;
184*1da177e4SLinus Torvalds 	struct adi *adi = port->adi;
185*1da177e4SLinus Torvalds 
186*1da177e4SLinus Torvalds  	adi[0].idx = adi[1].idx = 0;
187*1da177e4SLinus Torvalds 
188*1da177e4SLinus Torvalds 	if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
189*1da177e4SLinus Torvalds 	if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
190*1da177e4SLinus Torvalds 
191*1da177e4SLinus Torvalds 	for (i = 1; i <= adi[1].ret; i++)
192*1da177e4SLinus Torvalds 		adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
193*1da177e4SLinus Torvalds 
194*1da177e4SLinus Torvalds 	adi[0].ret += adi[1].ret;
195*1da177e4SLinus Torvalds 	adi[1].ret = -1;
196*1da177e4SLinus Torvalds }
197*1da177e4SLinus Torvalds 
198*1da177e4SLinus Torvalds /*
199*1da177e4SLinus Torvalds  * adi_get_bits() gathers bits from the data packet.
200*1da177e4SLinus Torvalds  */
201*1da177e4SLinus Torvalds 
202*1da177e4SLinus Torvalds static inline int adi_get_bits(struct adi *adi, int count)
203*1da177e4SLinus Torvalds {
204*1da177e4SLinus Torvalds 	int bits = 0;
205*1da177e4SLinus Torvalds 	int i;
206*1da177e4SLinus Torvalds 	if ((adi->idx += count) > adi->ret) return 0;
207*1da177e4SLinus Torvalds 	for (i = 0; i < count; i++)
208*1da177e4SLinus Torvalds 		bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i;
209*1da177e4SLinus Torvalds 	return bits;
210*1da177e4SLinus Torvalds }
211*1da177e4SLinus Torvalds 
212*1da177e4SLinus Torvalds /*
213*1da177e4SLinus Torvalds  * adi_decode() decodes Logitech joystick data into input events.
214*1da177e4SLinus Torvalds  */
215*1da177e4SLinus Torvalds 
216*1da177e4SLinus Torvalds static int adi_decode(struct adi *adi)
217*1da177e4SLinus Torvalds {
218*1da177e4SLinus Torvalds 	struct input_dev *dev = &adi->dev;
219*1da177e4SLinus Torvalds 	char *abs = adi->abs;
220*1da177e4SLinus Torvalds 	short *key = adi->key;
221*1da177e4SLinus Torvalds 	int i, t;
222*1da177e4SLinus Torvalds 
223*1da177e4SLinus Torvalds 	if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
224*1da177e4SLinus Torvalds 		return -1;
225*1da177e4SLinus Torvalds 
226*1da177e4SLinus Torvalds 	for (i = 0; i < adi->axes10; i++)
227*1da177e4SLinus Torvalds 		input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
228*1da177e4SLinus Torvalds 
229*1da177e4SLinus Torvalds 	for (i = 0; i < adi->axes8; i++)
230*1da177e4SLinus Torvalds 		input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
231*1da177e4SLinus Torvalds 
232*1da177e4SLinus Torvalds 	for (i = 0; i < adi->buttons && i < 63; i++) {
233*1da177e4SLinus Torvalds 		if (i == adi->pad) {
234*1da177e4SLinus Torvalds 			t = adi_get_bits(adi, 4);
235*1da177e4SLinus Torvalds 			input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t       & 1));
236*1da177e4SLinus Torvalds 			input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
237*1da177e4SLinus Torvalds 		}
238*1da177e4SLinus Torvalds 		input_report_key(dev, *key++, adi_get_bits(adi, 1));
239*1da177e4SLinus Torvalds 	}
240*1da177e4SLinus Torvalds 
241*1da177e4SLinus Torvalds 	for (i = 0; i < adi->hats; i++) {
242*1da177e4SLinus Torvalds 		if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
243*1da177e4SLinus Torvalds 		input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
244*1da177e4SLinus Torvalds 		input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
245*1da177e4SLinus Torvalds 	}
246*1da177e4SLinus Torvalds 
247*1da177e4SLinus Torvalds 	for (i = 63; i < adi->buttons; i++)
248*1da177e4SLinus Torvalds 		input_report_key(dev, *key++, adi_get_bits(adi, 1));
249*1da177e4SLinus Torvalds 
250*1da177e4SLinus Torvalds 	input_sync(dev);
251*1da177e4SLinus Torvalds 
252*1da177e4SLinus Torvalds 	return 0;
253*1da177e4SLinus Torvalds }
254*1da177e4SLinus Torvalds 
255*1da177e4SLinus Torvalds /*
256*1da177e4SLinus Torvalds  * adi_read() reads the data packet and decodes it.
257*1da177e4SLinus Torvalds  */
258*1da177e4SLinus Torvalds 
259*1da177e4SLinus Torvalds static int adi_read(struct adi_port *port)
260*1da177e4SLinus Torvalds {
261*1da177e4SLinus Torvalds 	int i;
262*1da177e4SLinus Torvalds 	int result = 0;
263*1da177e4SLinus Torvalds 
264*1da177e4SLinus Torvalds 	adi_read_packet(port);
265*1da177e4SLinus Torvalds 	adi_move_bits(port, port->adi[0].length);
266*1da177e4SLinus Torvalds 
267*1da177e4SLinus Torvalds 	for (i = 0; i < 2; i++)
268*1da177e4SLinus Torvalds 		if (port->adi[i].length)
269*1da177e4SLinus Torvalds 			 result |= adi_decode(port->adi + i);
270*1da177e4SLinus Torvalds 
271*1da177e4SLinus Torvalds 	return result;
272*1da177e4SLinus Torvalds }
273*1da177e4SLinus Torvalds 
274*1da177e4SLinus Torvalds /*
275*1da177e4SLinus Torvalds  * adi_poll() repeatedly polls the Logitech joysticks.
276*1da177e4SLinus Torvalds  */
277*1da177e4SLinus Torvalds 
278*1da177e4SLinus Torvalds static void adi_poll(struct gameport *gameport)
279*1da177e4SLinus Torvalds {
280*1da177e4SLinus Torvalds 	struct adi_port *port = gameport_get_drvdata(gameport);
281*1da177e4SLinus Torvalds 
282*1da177e4SLinus Torvalds 	port->bad -= adi_read(port);
283*1da177e4SLinus Torvalds 	port->reads++;
284*1da177e4SLinus Torvalds }
285*1da177e4SLinus Torvalds 
286*1da177e4SLinus Torvalds /*
287*1da177e4SLinus Torvalds  * adi_open() is a callback from the input open routine.
288*1da177e4SLinus Torvalds  */
289*1da177e4SLinus Torvalds 
290*1da177e4SLinus Torvalds static int adi_open(struct input_dev *dev)
291*1da177e4SLinus Torvalds {
292*1da177e4SLinus Torvalds 	struct adi_port *port = dev->private;
293*1da177e4SLinus Torvalds 
294*1da177e4SLinus Torvalds 	gameport_start_polling(port->gameport);
295*1da177e4SLinus Torvalds 	return 0;
296*1da177e4SLinus Torvalds }
297*1da177e4SLinus Torvalds 
298*1da177e4SLinus Torvalds /*
299*1da177e4SLinus Torvalds  * adi_close() is a callback from the input close routine.
300*1da177e4SLinus Torvalds  */
301*1da177e4SLinus Torvalds 
302*1da177e4SLinus Torvalds static void adi_close(struct input_dev *dev)
303*1da177e4SLinus Torvalds {
304*1da177e4SLinus Torvalds 	struct adi_port *port = dev->private;
305*1da177e4SLinus Torvalds 
306*1da177e4SLinus Torvalds 	gameport_stop_polling(port->gameport);
307*1da177e4SLinus Torvalds }
308*1da177e4SLinus Torvalds 
309*1da177e4SLinus Torvalds /*
310*1da177e4SLinus Torvalds  * adi_init_digital() sends a trigger & delay sequence
311*1da177e4SLinus Torvalds  * to reset and initialize a Logitech joystick into digital mode.
312*1da177e4SLinus Torvalds  */
313*1da177e4SLinus Torvalds 
314*1da177e4SLinus Torvalds static void adi_init_digital(struct gameport *gameport)
315*1da177e4SLinus Torvalds {
316*1da177e4SLinus Torvalds 	int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
317*1da177e4SLinus Torvalds 	int i;
318*1da177e4SLinus Torvalds 
319*1da177e4SLinus Torvalds 	for (i = 0; seq[i]; i++) {
320*1da177e4SLinus Torvalds 		gameport_trigger(gameport);
321*1da177e4SLinus Torvalds 		if (seq[i] > 0) msleep(seq[i]);
322*1da177e4SLinus Torvalds 		if (seq[i] < 0) {
323*1da177e4SLinus Torvalds 			mdelay(-seq[i]);
324*1da177e4SLinus Torvalds 			udelay(-seq[i]*14);	/* It looks like mdelay() is off by approx 1.4% */
325*1da177e4SLinus Torvalds 		}
326*1da177e4SLinus Torvalds 	}
327*1da177e4SLinus Torvalds }
328*1da177e4SLinus Torvalds 
329*1da177e4SLinus Torvalds static void adi_id_decode(struct adi *adi, struct adi_port *port)
330*1da177e4SLinus Torvalds {
331*1da177e4SLinus Torvalds 	int i, t;
332*1da177e4SLinus Torvalds 
333*1da177e4SLinus Torvalds 	if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
334*1da177e4SLinus Torvalds 		return;
335*1da177e4SLinus Torvalds 
336*1da177e4SLinus Torvalds 	if (adi->ret < (t = adi_get_bits(adi, 10))) {
337*1da177e4SLinus Torvalds 		printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret);
338*1da177e4SLinus Torvalds 		return;
339*1da177e4SLinus Torvalds 	}
340*1da177e4SLinus Torvalds 
341*1da177e4SLinus Torvalds 	adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
342*1da177e4SLinus Torvalds 
343*1da177e4SLinus Torvalds 	if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
344*1da177e4SLinus Torvalds 
345*1da177e4SLinus Torvalds 	adi->length = adi_get_bits(adi, 10);
346*1da177e4SLinus Torvalds 
347*1da177e4SLinus Torvalds 	if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
348*1da177e4SLinus Torvalds 		printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
349*1da177e4SLinus Torvalds 		adi->length = 0;
350*1da177e4SLinus Torvalds 		return;
351*1da177e4SLinus Torvalds 	}
352*1da177e4SLinus Torvalds 
353*1da177e4SLinus Torvalds 	adi->axes8 = adi_get_bits(adi, 4);
354*1da177e4SLinus Torvalds 	adi->buttons = adi_get_bits(adi, 6);
355*1da177e4SLinus Torvalds 
356*1da177e4SLinus Torvalds 	if (adi_get_bits(adi, 6) != 8 && adi->hats) {
357*1da177e4SLinus Torvalds 		printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
358*1da177e4SLinus Torvalds 		adi->length = 0;
359*1da177e4SLinus Torvalds 		return;
360*1da177e4SLinus Torvalds 	}
361*1da177e4SLinus Torvalds 
362*1da177e4SLinus Torvalds 	adi->buttons += adi_get_bits(adi, 6);
363*1da177e4SLinus Torvalds 	adi->hats += adi_get_bits(adi, 4);
364*1da177e4SLinus Torvalds 
365*1da177e4SLinus Torvalds 	i = adi_get_bits(adi, 4);
366*1da177e4SLinus Torvalds 
367*1da177e4SLinus Torvalds 	if (t & ADI_FLAG_10BIT) {
368*1da177e4SLinus Torvalds 		adi->axes10 = adi->axes8 - i;
369*1da177e4SLinus Torvalds 		adi->axes8 = i;
370*1da177e4SLinus Torvalds 	}
371*1da177e4SLinus Torvalds 
372*1da177e4SLinus Torvalds 	t = adi_get_bits(adi, 4);
373*1da177e4SLinus Torvalds 
374*1da177e4SLinus Torvalds 	for (i = 0; i < t; i++)
375*1da177e4SLinus Torvalds 		adi->cname[i] = adi_get_bits(adi, 8);
376*1da177e4SLinus Torvalds 	adi->cname[i] = 0;
377*1da177e4SLinus Torvalds 
378*1da177e4SLinus Torvalds 	t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
379*1da177e4SLinus Torvalds 	if (adi->length != t && adi->length != t + (t & 1)) {
380*1da177e4SLinus Torvalds 		printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
381*1da177e4SLinus Torvalds 		adi->length = 0;
382*1da177e4SLinus Torvalds 		return;
383*1da177e4SLinus Torvalds 	}
384*1da177e4SLinus Torvalds 
385*1da177e4SLinus Torvalds 	switch (adi->id) {
386*1da177e4SLinus Torvalds 		case ADI_ID_TPD:
387*1da177e4SLinus Torvalds 			adi->pad = 4;
388*1da177e4SLinus Torvalds 			adi->buttons -= 4;
389*1da177e4SLinus Torvalds 			break;
390*1da177e4SLinus Torvalds 		case ADI_ID_WGP:
391*1da177e4SLinus Torvalds 			adi->pad = 0;
392*1da177e4SLinus Torvalds 			adi->buttons -= 4;
393*1da177e4SLinus Torvalds 			break;
394*1da177e4SLinus Torvalds 		default:
395*1da177e4SLinus Torvalds 			adi->pad = -1;
396*1da177e4SLinus Torvalds 			break;
397*1da177e4SLinus Torvalds 	}
398*1da177e4SLinus Torvalds }
399*1da177e4SLinus Torvalds 
400*1da177e4SLinus Torvalds static void adi_init_input(struct adi *adi, struct adi_port *port, int half)
401*1da177e4SLinus Torvalds {
402*1da177e4SLinus Torvalds 	int i, t;
403*1da177e4SLinus Torvalds 	char buf[ADI_MAX_NAME_LENGTH];
404*1da177e4SLinus Torvalds 
405*1da177e4SLinus Torvalds 	if (!adi->length) return;
406*1da177e4SLinus Torvalds 
407*1da177e4SLinus Torvalds 	init_input_dev(&adi->dev);
408*1da177e4SLinus Torvalds 
409*1da177e4SLinus Torvalds 	t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
410*1da177e4SLinus Torvalds 
411*1da177e4SLinus Torvalds 	snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id);
412*1da177e4SLinus Torvalds 	snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s", buf);
413*1da177e4SLinus Torvalds 	snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half);
414*1da177e4SLinus Torvalds 
415*1da177e4SLinus Torvalds 	adi->abs = adi_abs[t];
416*1da177e4SLinus Torvalds 	adi->key = adi_key[t];
417*1da177e4SLinus Torvalds 
418*1da177e4SLinus Torvalds 	adi->dev.open = adi_open;
419*1da177e4SLinus Torvalds 	adi->dev.close = adi_close;
420*1da177e4SLinus Torvalds 
421*1da177e4SLinus Torvalds 	adi->dev.name = adi->name;
422*1da177e4SLinus Torvalds 	adi->dev.phys = adi->phys;
423*1da177e4SLinus Torvalds 	adi->dev.id.bustype = BUS_GAMEPORT;
424*1da177e4SLinus Torvalds 	adi->dev.id.vendor = GAMEPORT_ID_VENDOR_LOGITECH;
425*1da177e4SLinus Torvalds 	adi->dev.id.product = adi->id;
426*1da177e4SLinus Torvalds 	adi->dev.id.version = 0x0100;
427*1da177e4SLinus Torvalds 
428*1da177e4SLinus Torvalds 	adi->dev.private = port;
429*1da177e4SLinus Torvalds 	adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
430*1da177e4SLinus Torvalds 
431*1da177e4SLinus Torvalds 	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++)
432*1da177e4SLinus Torvalds 		set_bit(adi->abs[i], adi->dev.absbit);
433*1da177e4SLinus Torvalds 
434*1da177e4SLinus Torvalds 	for (i = 0; i < adi->buttons; i++)
435*1da177e4SLinus Torvalds 		set_bit(adi->key[i], adi->dev.keybit);
436*1da177e4SLinus Torvalds }
437*1da177e4SLinus Torvalds 
438*1da177e4SLinus Torvalds static void adi_init_center(struct adi *adi)
439*1da177e4SLinus Torvalds {
440*1da177e4SLinus Torvalds 	int i, t, x;
441*1da177e4SLinus Torvalds 
442*1da177e4SLinus Torvalds 	if (!adi->length)
443*1da177e4SLinus Torvalds 		return;
444*1da177e4SLinus Torvalds 
445*1da177e4SLinus Torvalds 	for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) {
446*1da177e4SLinus Torvalds 
447*1da177e4SLinus Torvalds 		t = adi->abs[i];
448*1da177e4SLinus Torvalds 		x = adi->dev.abs[t];
449*1da177e4SLinus Torvalds 
450*1da177e4SLinus Torvalds 		if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE)
451*1da177e4SLinus Torvalds 			x = i < adi->axes10 ? 512 : 128;
452*1da177e4SLinus Torvalds 
453*1da177e4SLinus Torvalds 		if (i < adi->axes10)
454*1da177e4SLinus Torvalds 			input_set_abs_params(&adi->dev, t, 64, x * 2 - 64, 2, 16);
455*1da177e4SLinus Torvalds 		else if (i < adi->axes10 + adi->axes8)
456*1da177e4SLinus Torvalds 			input_set_abs_params(&adi->dev, t, 48, x * 2 - 48, 1, 16);
457*1da177e4SLinus Torvalds 		else
458*1da177e4SLinus Torvalds 			input_set_abs_params(&adi->dev, t, -1, 1, 0, 0);
459*1da177e4SLinus Torvalds 	}
460*1da177e4SLinus Torvalds }
461*1da177e4SLinus Torvalds 
462*1da177e4SLinus Torvalds /*
463*1da177e4SLinus Torvalds  * adi_connect() probes for Logitech ADI joysticks.
464*1da177e4SLinus Torvalds  */
465*1da177e4SLinus Torvalds 
466*1da177e4SLinus Torvalds static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
467*1da177e4SLinus Torvalds {
468*1da177e4SLinus Torvalds 	struct adi_port *port;
469*1da177e4SLinus Torvalds 	int i;
470*1da177e4SLinus Torvalds 	int err;
471*1da177e4SLinus Torvalds 
472*1da177e4SLinus Torvalds 	if (!(port = kcalloc(1, sizeof(struct adi_port), GFP_KERNEL)))
473*1da177e4SLinus Torvalds 		return -ENOMEM;
474*1da177e4SLinus Torvalds 
475*1da177e4SLinus Torvalds 	port->gameport = gameport;
476*1da177e4SLinus Torvalds 
477*1da177e4SLinus Torvalds 	gameport_set_drvdata(gameport, port);
478*1da177e4SLinus Torvalds 
479*1da177e4SLinus Torvalds 	err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW);
480*1da177e4SLinus Torvalds 	if (err) {
481*1da177e4SLinus Torvalds 		kfree(port);
482*1da177e4SLinus Torvalds 		return err;
483*1da177e4SLinus Torvalds 	}
484*1da177e4SLinus Torvalds 
485*1da177e4SLinus Torvalds 	adi_init_digital(gameport);
486*1da177e4SLinus Torvalds 	adi_read_packet(port);
487*1da177e4SLinus Torvalds 
488*1da177e4SLinus Torvalds 	if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
489*1da177e4SLinus Torvalds 		adi_move_bits(port, adi_get_bits(port->adi, 10));
490*1da177e4SLinus Torvalds 
491*1da177e4SLinus Torvalds 	for (i = 0; i < 2; i++) {
492*1da177e4SLinus Torvalds 		adi_id_decode(port->adi + i, port);
493*1da177e4SLinus Torvalds 		adi_init_input(port->adi + i, port, i);
494*1da177e4SLinus Torvalds 	}
495*1da177e4SLinus Torvalds 
496*1da177e4SLinus Torvalds 	if (!port->adi[0].length && !port->adi[1].length) {
497*1da177e4SLinus Torvalds 		gameport_close(gameport);
498*1da177e4SLinus Torvalds 		kfree(port);
499*1da177e4SLinus Torvalds 		return -ENODEV;
500*1da177e4SLinus Torvalds 	}
501*1da177e4SLinus Torvalds 
502*1da177e4SLinus Torvalds 	gameport_set_poll_handler(gameport, adi_poll);
503*1da177e4SLinus Torvalds 	gameport_set_poll_interval(gameport, 20);
504*1da177e4SLinus Torvalds 
505*1da177e4SLinus Torvalds 	msleep(ADI_INIT_DELAY);
506*1da177e4SLinus Torvalds 	if (adi_read(port)) {
507*1da177e4SLinus Torvalds 		msleep(ADI_DATA_DELAY);
508*1da177e4SLinus Torvalds 		adi_read(port);
509*1da177e4SLinus Torvalds 	}
510*1da177e4SLinus Torvalds 
511*1da177e4SLinus Torvalds 	for (i = 0; i < 2; i++)
512*1da177e4SLinus Torvalds 		if (port->adi[i].length > 0) {
513*1da177e4SLinus Torvalds 			adi_init_center(port->adi + i);
514*1da177e4SLinus Torvalds 			input_register_device(&port->adi[i].dev);
515*1da177e4SLinus Torvalds 			printk(KERN_INFO "input: %s [%s] on %s\n",
516*1da177e4SLinus Torvalds 				port->adi[i].name, port->adi[i].cname, gameport->phys);
517*1da177e4SLinus Torvalds 		}
518*1da177e4SLinus Torvalds 
519*1da177e4SLinus Torvalds 	return 0;
520*1da177e4SLinus Torvalds }
521*1da177e4SLinus Torvalds 
522*1da177e4SLinus Torvalds static void adi_disconnect(struct gameport *gameport)
523*1da177e4SLinus Torvalds {
524*1da177e4SLinus Torvalds 	int i;
525*1da177e4SLinus Torvalds 	struct adi_port *port = gameport_get_drvdata(gameport);
526*1da177e4SLinus Torvalds 
527*1da177e4SLinus Torvalds 	for (i = 0; i < 2; i++)
528*1da177e4SLinus Torvalds 		if (port->adi[i].length > 0)
529*1da177e4SLinus Torvalds 			input_unregister_device(&port->adi[i].dev);
530*1da177e4SLinus Torvalds 	gameport_close(gameport);
531*1da177e4SLinus Torvalds 	gameport_set_drvdata(gameport, NULL);
532*1da177e4SLinus Torvalds 	kfree(port);
533*1da177e4SLinus Torvalds }
534*1da177e4SLinus Torvalds 
535*1da177e4SLinus Torvalds /*
536*1da177e4SLinus Torvalds  * The gameport device structure.
537*1da177e4SLinus Torvalds  */
538*1da177e4SLinus Torvalds 
539*1da177e4SLinus Torvalds static struct gameport_driver adi_drv = {
540*1da177e4SLinus Torvalds 	.driver		= {
541*1da177e4SLinus Torvalds 		.name	= "adi",
542*1da177e4SLinus Torvalds 	},
543*1da177e4SLinus Torvalds 	.description	= DRIVER_DESC,
544*1da177e4SLinus Torvalds 	.connect	= adi_connect,
545*1da177e4SLinus Torvalds 	.disconnect	= adi_disconnect,
546*1da177e4SLinus Torvalds };
547*1da177e4SLinus Torvalds 
548*1da177e4SLinus Torvalds static int __init adi_init(void)
549*1da177e4SLinus Torvalds {
550*1da177e4SLinus Torvalds 	gameport_register_driver(&adi_drv);
551*1da177e4SLinus Torvalds 	return 0;
552*1da177e4SLinus Torvalds }
553*1da177e4SLinus Torvalds 
554*1da177e4SLinus Torvalds static void __exit adi_exit(void)
555*1da177e4SLinus Torvalds {
556*1da177e4SLinus Torvalds 	gameport_unregister_driver(&adi_drv);
557*1da177e4SLinus Torvalds }
558*1da177e4SLinus Torvalds 
559*1da177e4SLinus Torvalds module_init(adi_init);
560*1da177e4SLinus Torvalds module_exit(adi_exit);
561