Blame view

drivers/input/joystick/db9.c 20.8 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
2
3
4
   *  Copyright (c) 1999-2001 Vojtech Pavlik
   *
   *  Based on the work of:
96de0e252   Jan Engelhardt   Convert files to ...
5
   *	Andree Borrmann		Mats Sjövall
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
   */
  
  /*
   * Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux
   */
  
  /*
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation; either version 2 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program; if not, write to the Free Software
   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
   *
   * Should you need to contact me, the author, you can do so either by
   * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
   * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
   */
  
  #include <linux/kernel.h>
  #include <linux/module.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
35
36
37
  #include <linux/delay.h>
  #include <linux/init.h>
  #include <linux/parport.h>
  #include <linux/input.h>
72ba9f0ce   Ingo Molnar   Input: joysticks ...
38
  #include <linux/mutex.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
39
40
41
42
  
  MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
  MODULE_DESCRIPTION("Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver");
  MODULE_LICENSE("GPL");
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
43
44
  struct db9_config {
  	int args[2];
78167236e   Dmitry Torokhov   Input: drivers/jo...
45
  	unsigned int nargs;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
46
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47

17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
48
  #define DB9_MAX_PORTS		3
78167236e   Dmitry Torokhov   Input: drivers/jo...
49
  static struct db9_config db9_cfg[DB9_MAX_PORTS] __initdata;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50

78167236e   Dmitry Torokhov   Input: drivers/jo...
51
  module_param_array_named(dev, db9_cfg[0].args, int, &db9_cfg[0].nargs, 0);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
52
  MODULE_PARM_DESC(dev, "Describes first attached device (<parport#>,<type>)");
0e2a4fd2e   Dmitry Torokhov   Input: db9 - do n...
53
  module_param_array_named(dev2, db9_cfg[1].args, int, &db9_cfg[1].nargs, 0);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
54
  MODULE_PARM_DESC(dev2, "Describes second attached device (<parport#>,<type>)");
78167236e   Dmitry Torokhov   Input: drivers/jo...
55
  module_param_array_named(dev3, db9_cfg[2].args, int, &db9_cfg[2].nargs, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
  MODULE_PARM_DESC(dev3, "Describes third attached device (<parport#>,<type>)");
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
57
58
  #define DB9_ARG_PARPORT		0
  #define DB9_ARG_MODE		1
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
  #define DB9_MULTI_STICK		0x01
  #define DB9_MULTI2_STICK	0x02
  #define DB9_GENESIS_PAD		0x03
  #define DB9_GENESIS5_PAD	0x05
  #define DB9_GENESIS6_PAD	0x06
  #define DB9_SATURN_PAD		0x07
  #define DB9_MULTI_0802		0x08
  #define DB9_MULTI_0802_2	0x09
  #define DB9_CD32_PAD		0x0A
  #define DB9_SATURN_DPP		0x0B
  #define DB9_SATURN_DPP_2	0x0C
  #define DB9_MAX_PAD		0x0D
  
  #define DB9_UP			0x01
  #define DB9_DOWN		0x02
  #define DB9_LEFT		0x04
  #define DB9_RIGHT		0x08
  #define DB9_FIRE1		0x10
  #define DB9_FIRE2		0x20
  #define DB9_FIRE3		0x40
  #define DB9_FIRE4		0x80
  
  #define DB9_NORMAL		0x0a
  #define DB9_NOSELECT		0x08
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
83
84
  #define DB9_GENESIS6_DELAY	14
  #define DB9_REFRESH_TIME	HZ/100
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
85
86
87
88
89
90
91
92
93
94
95
  #define DB9_MAX_DEVICES		2
  
  struct db9_mode_data {
  	const char *name;
  	const short *buttons;
  	int n_buttons;
  	int n_pads;
  	int n_axis;
  	int bidirectional;
  	int reverse;
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
  struct db9 {
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
97
  	struct input_dev *dev[DB9_MAX_DEVICES];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
98
99
100
101
  	struct timer_list timer;
  	struct pardevice *pd;
  	int mode;
  	int used;
72ba9f0ce   Ingo Molnar   Input: joysticks ...
102
  	struct mutex mutex;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
103
  	char phys[DB9_MAX_DEVICES][32];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
104
105
106
  };
  
  static struct db9 *db9_base[3];
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
107
108
109
  static const short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
  static const short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
  static const short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
110
  static const short db9_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_RZ, ABS_Z, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
  
  static const struct db9_mode_data db9_modes[] = {
  	{ NULL,					 NULL,		  0,  0,  0,  0,  0 },
  	{ "Multisystem joystick",		 db9_multi_btn,	  1,  1,  2,  1,  1 },
  	{ "Multisystem joystick (2 fire)",	 db9_multi_btn,	  2,  1,  2,  1,  1 },
  	{ "Genesis pad",			 db9_genesis_btn, 4,  1,  2,  1,  1 },
  	{ NULL,					 NULL,		  0,  0,  0,  0,  0 },
  	{ "Genesis 5 pad",			 db9_genesis_btn, 6,  1,  2,  1,  1 },
  	{ "Genesis 6 pad",			 db9_genesis_btn, 8,  1,  2,  1,  1 },
  	{ "Saturn pad",				 db9_cd32_btn,	  9,  6,  7,  0,  1 },
  	{ "Multisystem (0.8.0.2) joystick",	 db9_multi_btn,	  1,  1,  2,  1,  1 },
  	{ "Multisystem (0.8.0.2-dual) joystick", db9_multi_btn,	  1,  2,  2,  1,  1 },
  	{ "Amiga CD-32 pad",			 db9_cd32_btn,	  7,  1,  2,  1,  1 },
  	{ "Saturn dpp",				 db9_cd32_btn,	  9,  6,  7,  0,  0 },
  	{ "Saturn dpp dual",			 db9_cd32_btn,	  9,  12, 7,  0,  0 },
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
  
  /*
   * Saturn controllers
   */
  #define DB9_SATURN_DELAY 300
  static const int db9_saturn_byte[] = { 1, 1, 1, 2, 2, 2, 2, 2, 1 };
  static const unsigned char db9_saturn_mask[] = { 0x04, 0x01, 0x02, 0x40, 0x20, 0x10, 0x08, 0x80, 0x08 };
  
  /*
   * db9_saturn_write_sub() writes 2 bit data.
   */
  static void db9_saturn_write_sub(struct parport *port, int type, unsigned char data, int powered, int pwr_sub)
  {
  	unsigned char c;
  
  	switch (type) {
  	case 1: /* DPP1 */
  		c = 0x80 | 0x30 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | data;
  		parport_write_data(port, c);
  		break;
  	case 2: /* DPP2 */
  		c = 0x40 | data << 4 | (powered ? 0x08 : 0) | (pwr_sub ? 0x04 : 0) | 0x03;
  		parport_write_data(port, c);
  		break;
  	case 0:	/* DB9 */
  		c = ((((data & 2) ? 2 : 0) | ((data & 1) ? 4 : 0)) ^ 0x02) | !powered;
  		parport_write_control(port, c);
  		break;
  	}
  }
  
  /*
   * gc_saturn_read_sub() reads 4 bit data.
   */
  static unsigned char db9_saturn_read_sub(struct parport *port, int type)
  {
  	unsigned char data;
  
  	if (type) {
  		/* DPP */
  		data = parport_read_status(port) ^ 0x80;
  		return (data & 0x80 ? 1 : 0) | (data & 0x40 ? 2 : 0)
  		     | (data & 0x20 ? 4 : 0) | (data & 0x10 ? 8 : 0);
  	} else {
  		/* DB9 */
  		data = parport_read_data(port) & 0x0f;
  		return (data & 0x8 ? 1 : 0) | (data & 0x4 ? 2 : 0)
  		     | (data & 0x2 ? 4 : 0) | (data & 0x1 ? 8 : 0);
  	}
  }
  
  /*
   * db9_saturn_read_analog() sends clock and reads 8 bit data.
   */
  static unsigned char db9_saturn_read_analog(struct parport *port, int type, int powered)
  {
  	unsigned char data;
  
  	db9_saturn_write_sub(port, type, 0, powered, 0);
  	udelay(DB9_SATURN_DELAY);
  	data = db9_saturn_read_sub(port, type) << 4;
  	db9_saturn_write_sub(port, type, 2, powered, 0);
  	udelay(DB9_SATURN_DELAY);
  	data |= db9_saturn_read_sub(port, type);
  	return data;
  }
  
  /*
   * db9_saturn_read_packet() reads whole saturn packet at connector
   * and returns device identifier code.
   */
  static unsigned char db9_saturn_read_packet(struct parport *port, unsigned char *data, int type, int powered)
  {
  	int i, j;
  	unsigned char tmp;
  
  	db9_saturn_write_sub(port, type, 3, powered, 0);
  	data[0] = db9_saturn_read_sub(port, type);
  	switch (data[0] & 0x0f) {
  	case 0xf:
  		/* 1111  no pad */
  		return data[0] = 0xff;
  	case 0x4: case 0x4 | 0x8:
  		/* ?100 : digital controller */
  		db9_saturn_write_sub(port, type, 0, powered, 1);
  		data[2] = db9_saturn_read_sub(port, type) << 4;
  		db9_saturn_write_sub(port, type, 2, powered, 1);
  		data[1] = db9_saturn_read_sub(port, type) << 4;
  		db9_saturn_write_sub(port, type, 1, powered, 1);
  		data[1] |= db9_saturn_read_sub(port, type);
  		db9_saturn_write_sub(port, type, 3, powered, 1);
  		/* data[2] |= db9_saturn_read_sub(port, type); */
  		data[2] |= data[0];
  		return data[0] = 0x02;
  	case 0x1:
  		/* 0001 : analog controller or multitap */
  		db9_saturn_write_sub(port, type, 2, powered, 0);
  		udelay(DB9_SATURN_DELAY);
  		data[0] = db9_saturn_read_analog(port, type, powered);
  		if (data[0] != 0x41) {
  			/* read analog controller */
  			for (i = 0; i < (data[0] & 0x0f); i++)
  				data[i + 1] = db9_saturn_read_analog(port, type, powered);
  			db9_saturn_write_sub(port, type, 3, powered, 0);
  			return data[0];
  		} else {
  			/* read multitap */
  			if (db9_saturn_read_analog(port, type, powered) != 0x60)
  				return data[0] = 0xff;
  			for (i = 0; i < 60; i += 10) {
  				data[i] = db9_saturn_read_analog(port, type, powered);
  				if (data[i] != 0xff)
  					/* read each pad */
  					for (j = 0; j < (data[i] & 0x0f); j++)
  						data[i + j + 1] = db9_saturn_read_analog(port, type, powered);
  			}
  			db9_saturn_write_sub(port, type, 3, powered, 0);
  			return 0x41;
  		}
  	case 0x0:
  		/* 0000 : mouse */
  		db9_saturn_write_sub(port, type, 2, powered, 0);
  		udelay(DB9_SATURN_DELAY);
  		tmp = db9_saturn_read_analog(port, type, powered);
  		if (tmp == 0xff) {
  			for (i = 0; i < 3; i++)
  				data[i + 1] = db9_saturn_read_analog(port, type, powered);
  			db9_saturn_write_sub(port, type, 3, powered, 0);
  			return data[0] = 0xe3;
  		}
  	default:
  		return data[0];
  	}
  }
  
  /*
   * db9_saturn_report() analyzes packet and reports.
   */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
265
  static int db9_saturn_report(unsigned char id, unsigned char data[60], struct input_dev *devs[], int n, int max_pads)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
266
  {
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
267
  	struct input_dev *dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
268
269
270
  	int tmp, i, j;
  
  	tmp = (id == 0x41) ? 60 : 10;
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
271
272
  	for (j = 0; j < tmp && n < max_pads; j += 10, n++) {
  		dev = devs[n];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
273
274
  		switch (data[j]) {
  		case 0x16: /* multi controller (analog 4 axis) */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
275
  			input_report_abs(dev, db9_abs[5], data[j + 6]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
276
  		case 0x15: /* mission stick (analog 3 axis) */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
277
278
  			input_report_abs(dev, db9_abs[3], data[j + 4]);
  			input_report_abs(dev, db9_abs[4], data[j + 5]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
279
  		case 0x13: /* racing controller (analog 1 axis) */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
280
  			input_report_abs(dev, db9_abs[2], data[j + 3]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
281
282
  		case 0x34: /* saturn keyboard (udlr ZXC ASD QE Esc) */
  		case 0x02: /* digital pad (digital 2 axis + buttons) */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
283
284
  			input_report_abs(dev, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
  			input_report_abs(dev, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
285
  			for (i = 0; i < 9; i++)
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
286
  				input_report_key(dev, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
287
288
  			break;
  		case 0x19: /* mission stick x2 (analog 6 axis + buttons) */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
289
290
  			input_report_abs(dev, db9_abs[0], !(data[j + 1] & 128) - !(data[j + 1] & 64));
  			input_report_abs(dev, db9_abs[1], !(data[j + 1] & 32) - !(data[j + 1] & 16));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
291
  			for (i = 0; i < 9; i++)
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
292
293
294
295
  				input_report_key(dev, db9_cd32_btn[i], ~data[j + db9_saturn_byte[i]] & db9_saturn_mask[i]);
  			input_report_abs(dev, db9_abs[2], data[j + 3]);
  			input_report_abs(dev, db9_abs[3], data[j + 4]);
  			input_report_abs(dev, db9_abs[4], data[j + 5]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
296
  			/*
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
297
298
  			input_report_abs(dev, db9_abs[8], (data[j + 6] & 128 ? 0 : 1) - (data[j + 6] & 64 ? 0 : 1));
  			input_report_abs(dev, db9_abs[9], (data[j + 6] & 32 ? 0 : 1) - (data[j + 6] & 16 ? 0 : 1));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
299
  			*/
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
300
301
302
  			input_report_abs(dev, db9_abs[6], data[j + 7]);
  			input_report_abs(dev, db9_abs[7], data[j + 8]);
  			input_report_abs(dev, db9_abs[5], data[j + 9]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
303
304
  			break;
  		case 0xd3: /* sankyo ff (analog 1 axis + stop btn) */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
305
306
  			input_report_key(dev, BTN_A, data[j + 3] & 0x80);
  			input_report_abs(dev, db9_abs[2], data[j + 3] & 0x7f);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
  			break;
  		case 0xe3: /* shuttle mouse (analog 2 axis + buttons. signed value) */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
309
310
311
312
313
314
  			input_report_key(dev, BTN_START, data[j + 1] & 0x08);
  			input_report_key(dev, BTN_A, data[j + 1] & 0x04);
  			input_report_key(dev, BTN_C, data[j + 1] & 0x02);
  			input_report_key(dev, BTN_B, data[j + 1] & 0x01);
  			input_report_abs(dev, db9_abs[2], data[j + 2] ^ 0x80);
  			input_report_abs(dev, db9_abs[3], (0xff-(data[j + 3] ^ 0x80))+1); /* */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
315
316
317
  			break;
  		case 0xff:
  		default: /* no pad */
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
318
319
  			input_report_abs(dev, db9_abs[0], 0);
  			input_report_abs(dev, db9_abs[1], 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
320
  			for (i = 0; i < 9; i++)
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
321
  				input_report_key(dev, db9_cd32_btn[i], 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
326
  			break;
  		}
  	}
  	return n;
  }
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
327
  static int db9_saturn(int mode, struct parport *port, struct input_dev *devs[])
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
  {
  	unsigned char id, data[60];
  	int type, n, max_pads;
  	int tmp, i;
  
  	switch (mode) {
  	case DB9_SATURN_PAD:
  		type = 0;
  		n = 1;
  		break;
  	case DB9_SATURN_DPP:
  		type = 1;
  		n = 1;
  		break;
  	case DB9_SATURN_DPP_2:
  		type = 1;
  		n = 2;
  		break;
  	default:
  		return -1;
  	}
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
349
  	max_pads = min(db9_modes[mode].n_pads, DB9_MAX_DEVICES);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
  	for (tmp = 0, i = 0; i < n; i++) {
  		id = db9_saturn_read_packet(port, data, type + i, 1);
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
352
  		tmp = db9_saturn_report(id, data, devs, tmp, max_pads);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
353
354
355
356
357
358
359
360
  	}
  	return 0;
  }
  
  static void db9_timer(unsigned long private)
  {
  	struct db9 *db9 = (void *) private;
  	struct parport *port = db9->pd->port;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
361
362
  	struct input_dev *dev = db9->dev[0];
  	struct input_dev *dev2 = db9->dev[1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
363
  	int data, i;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
364
  	switch (db9->mode) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
  		case DB9_MULTI_0802_2:
  
  			data = parport_read_data(port) >> 3;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
368
369
370
  			input_report_abs(dev2, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
  			input_report_abs(dev2, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
  			input_report_key(dev2, BTN_TRIGGER, ~data & DB9_FIRE1);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
  
  		case DB9_MULTI_0802:
  
  			data = parport_read_status(port) >> 3;
  
  			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
  			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
  			input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1);
  			break;
  
  		case DB9_MULTI_STICK:
  
  			data = parport_read_data(port);
  
  			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
  			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
  			input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
  			break;
  
  		case DB9_MULTI2_STICK:
  
  			data = parport_read_data(port);
  
  			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
  			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
  			input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
  			input_report_key(dev, BTN_THUMB,   ~data & DB9_FIRE2);
  			break;
  
  		case DB9_GENESIS_PAD:
  
  			parport_write_control(port, DB9_NOSELECT);
  			data = parport_read_data(port);
  
  			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
  			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
  			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
  			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
  
  			parport_write_control(port, DB9_NORMAL);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
411
  			data = parport_read_data(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
412
413
414
415
416
417
418
419
  
  			input_report_key(dev, BTN_A,     ~data & DB9_FIRE1);
  			input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
  			break;
  
  		case DB9_GENESIS5_PAD:
  
  			parport_write_control(port, DB9_NOSELECT);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
420
  			data = parport_read_data(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
421
422
423
424
425
426
427
  
  			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
  			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
  			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
  			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
  
  			parport_write_control(port, DB9_NORMAL);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
428
  			data = parport_read_data(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
429
430
431
432
433
434
435
436
437
438
439
  
  			input_report_key(dev, BTN_A,     ~data & DB9_FIRE1);
  			input_report_key(dev, BTN_X,     ~data & DB9_FIRE2);
  			input_report_key(dev, BTN_Y,     ~data & DB9_LEFT);
  			input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
  			break;
  
  		case DB9_GENESIS6_PAD:
  
  			parport_write_control(port, DB9_NOSELECT); /* 1 */
  			udelay(DB9_GENESIS6_DELAY);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
440
  			data = parport_read_data(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
441
442
443
444
445
446
447
448
  
  			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
  			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
  			input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
  			input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
  
  			parport_write_control(port, DB9_NORMAL);
  			udelay(DB9_GENESIS6_DELAY);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
449
  			data = parport_read_data(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
  
  			input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
  			input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
  
  			parport_write_control(port, DB9_NOSELECT); /* 2 */
  			udelay(DB9_GENESIS6_DELAY);
  			parport_write_control(port, DB9_NORMAL);
  			udelay(DB9_GENESIS6_DELAY);
  			parport_write_control(port, DB9_NOSELECT); /* 3 */
  			udelay(DB9_GENESIS6_DELAY);
  			data=parport_read_data(port);
  
  			input_report_key(dev, BTN_X,    ~data & DB9_LEFT);
  			input_report_key(dev, BTN_Y,    ~data & DB9_DOWN);
  			input_report_key(dev, BTN_Z,    ~data & DB9_UP);
  			input_report_key(dev, BTN_MODE, ~data & DB9_RIGHT);
  
  			parport_write_control(port, DB9_NORMAL);
  			udelay(DB9_GENESIS6_DELAY);
  			parport_write_control(port, DB9_NOSELECT); /* 4 */
  			udelay(DB9_GENESIS6_DELAY);
  			parport_write_control(port, DB9_NORMAL);
  			break;
  
  		case DB9_SATURN_PAD:
  		case DB9_SATURN_DPP:
  		case DB9_SATURN_DPP_2:
84c61896b   Dmitry Torokhov   Input: db9 - fix ...
477
  			db9_saturn(db9->mode, port, db9->dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
478
479
480
  			break;
  
  		case DB9_CD32_PAD:
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
481
  			data = parport_read_data(port);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
482
483
484
485
486
487
488
489
490
491
492
  
  			input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
  			input_report_abs(dev, ABS_Y, (data & DB9_DOWN  ? 0 : 1) - (data & DB9_UP   ? 0 : 1));
  
  			parport_write_control(port, 0x0a);
  
  			for (i = 0; i < 7; i++) {
  				data = parport_read_data(port);
  				parport_write_control(port, 0x02);
  				parport_write_control(port, 0x0a);
  				input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
493
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
494
495
496
497
498
499
500
501
502
503
504
505
  
  			parport_write_control(port, 0x00);
  			break;
  		}
  
  	input_sync(dev);
  
  	mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
  }
  
  static int db9_open(struct input_dev *dev)
  {
8715c1cfa   Dmitry Torokhov   Input: drivers/in...
506
  	struct db9 *db9 = input_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
507
  	struct parport *port = db9->pd->port;
8b1a198bf   Dmitry Torokhov   Input: fix open/c...
508
  	int err;
72ba9f0ce   Ingo Molnar   Input: joysticks ...
509
  	err = mutex_lock_interruptible(&db9->mutex);
8b1a198bf   Dmitry Torokhov   Input: fix open/c...
510
511
  	if (err)
  		return err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
512
513
514
515
  
  	if (!db9->used++) {
  		parport_claim(db9->pd);
  		parport_write_data(port, 0xff);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
516
  		if (db9_modes[db9->mode].reverse) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
518
519
520
521
  			parport_data_reverse(port);
  			parport_write_control(port, DB9_NORMAL);
  		}
  		mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
  	}
72ba9f0ce   Ingo Molnar   Input: joysticks ...
522
  	mutex_unlock(&db9->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
523
524
525
526
527
  	return 0;
  }
  
  static void db9_close(struct input_dev *dev)
  {
8715c1cfa   Dmitry Torokhov   Input: drivers/in...
528
  	struct db9 *db9 = input_get_drvdata(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
  	struct parport *port = db9->pd->port;
72ba9f0ce   Ingo Molnar   Input: joysticks ...
530
  	mutex_lock(&db9->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
531
  	if (!--db9->used) {
8b1a198bf   Dmitry Torokhov   Input: fix open/c...
532
  		del_timer_sync(&db9->timer);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
533
534
535
536
  		parport_write_control(port, 0x00);
  		parport_data_forward(port);
  		parport_release(db9->pd);
  	}
72ba9f0ce   Ingo Molnar   Input: joysticks ...
537
  	mutex_unlock(&db9->mutex);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
  }
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
539
  static struct db9 __init *db9_probe(int parport, int mode)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
540
541
  {
  	struct db9 *db9;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
542
  	const struct db9_mode_data *db9_mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
543
  	struct parport *pp;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
544
545
  	struct pardevice *pd;
  	struct input_dev *input_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
546
  	int i, j;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
547
  	int err;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
548

17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
549
550
551
552
553
  	if (mode < 1 || mode >= DB9_MAX_PAD || !db9_modes[mode].n_buttons) {
  		printk(KERN_ERR "db9.c: Bad device type %d
  ", mode);
  		err = -EINVAL;
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
554
  	}
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
555
  	db9_mode = &db9_modes[mode];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
556

17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
557
  	pp = parport_find_number(parport);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
558
559
560
  	if (!pp) {
  		printk(KERN_ERR "db9.c: no such parport
  ");
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
561
562
  		err = -ENODEV;
  		goto err_out;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
563
  	}
0a3a6d69b   Eric Sesterhenn   Input: db9 - fix ...
564
  	if (db9_mode->bidirectional && !(pp->modes & PARPORT_MODE_TRISTATE)) {
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
565
566
567
568
569
570
571
572
573
574
575
576
  		printk(KERN_ERR "db9.c: specified parport is not bidirectional
  ");
  		err = -EINVAL;
  		goto err_put_pp;
  	}
  
  	pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
  	if (!pd) {
  		printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?
  ");
  		err = -EBUSY;
  		goto err_put_pp;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
577
  	}
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
578
579
580
581
582
583
  	db9 = kzalloc(sizeof(struct db9), GFP_KERNEL);
  	if (!db9) {
  		printk(KERN_ERR "db9.c: Not enough memory
  ");
  		err = -ENOMEM;
  		goto err_unreg_pardev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
584
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
585

72ba9f0ce   Ingo Molnar   Input: joysticks ...
586
  	mutex_init(&db9->mutex);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
587
588
  	db9->pd = pd;
  	db9->mode = mode;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
589
590
591
  	init_timer(&db9->timer);
  	db9->timer.data = (long) db9;
  	db9->timer.function = db9_timer;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
592
  	for (i = 0; i < (min(db9_mode->n_pads, DB9_MAX_DEVICES)); i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
593

17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
594
595
596
597
598
  		db9->dev[i] = input_dev = input_allocate_device();
  		if (!input_dev) {
  			printk(KERN_ERR "db9.c: Not enough memory for input device
  ");
  			err = -ENOMEM;
2e9d675ed   Dmitry Torokhov   Input: db9 - hand...
599
  			goto err_unreg_devs;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
600
  		}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
601

10ca4c0a6   Dmitry Torokhov   Input: fix potent...
602
603
  		snprintf(db9->phys[i], sizeof(db9->phys[i]),
  			 "%s/input%d", db9->pd->port->name, i);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
604

17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
605
606
607
608
609
610
  		input_dev->name = db9_mode->name;
  		input_dev->phys = db9->phys[i];
  		input_dev->id.bustype = BUS_PARPORT;
  		input_dev->id.vendor = 0x0002;
  		input_dev->id.product = mode;
  		input_dev->id.version = 0x0100;
8715c1cfa   Dmitry Torokhov   Input: drivers/in...
611
612
  
  		input_set_drvdata(input_dev, db9);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
613
614
615
  
  		input_dev->open = db9_open;
  		input_dev->close = db9_close;
7b19ada2e   Jiri Slaby   get rid of input ...
616
  		input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
617
618
619
620
621
622
623
  		for (j = 0; j < db9_mode->n_buttons; j++)
  			set_bit(db9_mode->buttons[j], input_dev->keybit);
  		for (j = 0; j < db9_mode->n_axis; j++) {
  			if (j < 2)
  				input_set_abs_params(input_dev, db9_abs[j], -1, 1, 0, 0);
  			else
  				input_set_abs_params(input_dev, db9_abs[j], 1, 255, 0, 0);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
624
  		}
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
625

2e9d675ed   Dmitry Torokhov   Input: db9 - hand...
626
627
628
  		err = input_register_device(input_dev);
  		if (err)
  			goto err_free_dev;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
629
  	}
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
630
  	parport_put_port(pp);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
631
  	return db9;
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
632

2e9d675ed   Dmitry Torokhov   Input: db9 - hand...
633
634
635
   err_free_dev:
  	input_free_device(db9->dev[i]);
   err_unreg_devs:
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
636
637
638
639
640
641
642
643
644
645
  	while (--i >= 0)
  		input_unregister_device(db9->dev[i]);
  	kfree(db9);
   err_unreg_pardev:
  	parport_unregister_device(pd);
   err_put_pp:
  	parport_put_port(pp);
   err_out:
  	return ERR_PTR(err);
  }
2e9d675ed   Dmitry Torokhov   Input: db9 - hand...
646
  static void db9_remove(struct db9 *db9)
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
647
648
649
650
651
652
653
  {
  	int i;
  
  	for (i = 0; i < min(db9_modes[db9->mode].n_pads, DB9_MAX_DEVICES); i++)
  		input_unregister_device(db9->dev[i]);
  	parport_unregister_device(db9->pd);
  	kfree(db9);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
654
655
656
657
  }
  
  static int __init db9_init(void)
  {
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
658
659
660
661
662
  	int i;
  	int have_dev = 0;
  	int err = 0;
  
  	for (i = 0; i < DB9_MAX_PORTS; i++) {
78167236e   Dmitry Torokhov   Input: drivers/jo...
663
  		if (db9_cfg[i].nargs == 0 || db9_cfg[i].args[DB9_ARG_PARPORT] < 0)
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
664
  			continue;
78167236e   Dmitry Torokhov   Input: drivers/jo...
665
  		if (db9_cfg[i].nargs < 2) {
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
666
667
668
669
670
  			printk(KERN_ERR "db9.c: Device type must be specified.
  ");
  			err = -EINVAL;
  			break;
  		}
78167236e   Dmitry Torokhov   Input: drivers/jo...
671
672
  		db9_base[i] = db9_probe(db9_cfg[i].args[DB9_ARG_PARPORT],
  					db9_cfg[i].args[DB9_ARG_MODE]);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
673
674
675
676
677
678
679
  		if (IS_ERR(db9_base[i])) {
  			err = PTR_ERR(db9_base[i]);
  			break;
  		}
  
  		have_dev = 1;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
680

17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
681
682
  	if (err) {
  		while (--i >= 0)
2e9d675ed   Dmitry Torokhov   Input: db9 - hand...
683
684
  			if (db9_base[i])
  				db9_remove(db9_base[i]);
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
685
686
  		return err;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
687

17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
688
  	return have_dev ? 0 : -ENODEV;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
689
690
691
692
  }
  
  static void __exit db9_exit(void)
  {
17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
693
  	int i;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
694

17dd3f0f7   Dmitry Torokhov   [PATCH] drivers/i...
695
696
697
  	for (i = 0; i < DB9_MAX_PORTS; i++)
  		if (db9_base[i])
  			db9_remove(db9_base[i]);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
698
699
700
701
  }
  
  module_init(db9_init);
  module_exit(db9_exit);