]>
Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * NES, SNES, N64, MultiSystem, PSX gamepad driver for Linux | |
3 | * | |
ab0c3443 DT |
4 | * Copyright (c) 1999-2004 Vojtech Pavlik <vojtech@suse.cz> |
5 | * Copyright (c) 2004 Peter Nelson <rufus-kernel@hackish.org> | |
1da177e4 LT |
6 | * |
7 | * Based on the work of: | |
ab0c3443 DT |
8 | * Andree Borrmann John Dahlstrom |
9 | * David Kuder Nathan Hand | |
b157d55e | 10 | * Raphael Assenat |
1da177e4 LT |
11 | */ |
12 | ||
13 | /* | |
14 | * This program is free software; you can redistribute it and/or modify | |
15 | * it under the terms of the GNU General Public License as published by | |
16 | * the Free Software Foundation; either version 2 of the License, or | |
17 | * (at your option) any later version. | |
18 | * | |
19 | * This program is distributed in the hope that it will be useful, | |
20 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
21 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
22 | * GNU General Public License for more details. | |
23 | * | |
24 | * You should have received a copy of the GNU General Public License | |
25 | * along with this program; if not, write to the Free Software | |
26 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
27 | * | |
28 | * Should you need to contact me, the author, you can do so either by | |
29 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
30 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
31 | */ | |
32 | ||
33 | #include <linux/kernel.h> | |
34 | #include <linux/delay.h> | |
35 | #include <linux/module.h> | |
1da177e4 LT |
36 | #include <linux/init.h> |
37 | #include <linux/parport.h> | |
38 | #include <linux/input.h> | |
72ba9f0c | 39 | #include <linux/mutex.h> |
1da177e4 LT |
40 | |
41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
42 | MODULE_DESCRIPTION("NES, SNES, N64, MultiSystem, PSX gamepad driver"); | |
43 | MODULE_LICENSE("GPL"); | |
44 | ||
17dd3f0f DT |
45 | #define GC_MAX_PORTS 3 |
46 | #define GC_MAX_DEVICES 5 | |
1da177e4 | 47 | |
17dd3f0f DT |
48 | struct gc_config { |
49 | int args[GC_MAX_DEVICES + 1]; | |
78167236 | 50 | unsigned int nargs; |
17dd3f0f DT |
51 | }; |
52 | ||
78167236 | 53 | static struct gc_config gc_cfg[GC_MAX_PORTS] __initdata; |
1da177e4 | 54 | |
78167236 | 55 | module_param_array_named(map, gc_cfg[0].args, int, &gc_cfg[0].nargs, 0); |
17dd3f0f | 56 | MODULE_PARM_DESC(map, "Describes first set of devices (<parport#>,<pad1>,<pad2>,..<pad5>)"); |
78167236 | 57 | module_param_array_named(map2, gc_cfg[1].args, int, &gc_cfg[1].nargs, 0); |
17dd3f0f | 58 | MODULE_PARM_DESC(map2, "Describes second set of devices"); |
78167236 | 59 | module_param_array_named(map3, gc_cfg[2].args, int, &gc_cfg[2].nargs, 0); |
17dd3f0f | 60 | MODULE_PARM_DESC(map3, "Describes third set of devices"); |
1da177e4 | 61 | |
1da177e4 LT |
62 | /* see also gs_psx_delay parameter in PSX support section */ |
63 | ||
64 | #define GC_SNES 1 | |
65 | #define GC_NES 2 | |
66 | #define GC_NES4 3 | |
67 | #define GC_MULTI 4 | |
68 | #define GC_MULTI2 5 | |
69 | #define GC_N64 6 | |
70 | #define GC_PSX 7 | |
71 | #define GC_DDR 8 | |
b157d55e | 72 | #define GC_SNESMOUSE 9 |
1da177e4 | 73 | |
b157d55e | 74 | #define GC_MAX 9 |
1da177e4 LT |
75 | |
76 | #define GC_REFRESH_TIME HZ/100 | |
77 | ||
78 | struct gc { | |
79 | struct pardevice *pd; | |
17dd3f0f | 80 | struct input_dev *dev[GC_MAX_DEVICES]; |
1da177e4 LT |
81 | struct timer_list timer; |
82 | unsigned char pads[GC_MAX + 1]; | |
83 | int used; | |
72ba9f0c | 84 | struct mutex mutex; |
17dd3f0f | 85 | char phys[GC_MAX_DEVICES][32]; |
1da177e4 LT |
86 | }; |
87 | ||
7aa9e0e8 SM |
88 | struct gc_subdev { |
89 | unsigned int idx; | |
90 | }; | |
91 | ||
1da177e4 LT |
92 | static struct gc *gc_base[3]; |
93 | ||
94 | static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 }; | |
95 | ||
d38fcb96 DT |
96 | static char *gc_names[] = { |
97 | NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick", | |
98 | "Multisystem 2-button joystick", "N64 controller", "PSX controller", | |
99 | "PSX DDR controller", "SNES mouse" | |
100 | }; | |
101 | ||
1da177e4 LT |
102 | /* |
103 | * N64 support. | |
104 | */ | |
105 | ||
106 | static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 }; | |
d38fcb96 DT |
107 | static short gc_n64_btn[] = { |
108 | BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, | |
109 | BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START | |
110 | }; | |
1da177e4 LT |
111 | |
112 | #define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */ | |
7aa9e0e8 SM |
113 | #define GC_N64_STOP_LENGTH 5 /* Length of encoded stop bit */ |
114 | #define GC_N64_CMD_00 0x11111111UL | |
115 | #define GC_N64_CMD_01 0xd1111111UL | |
116 | #define GC_N64_CMD_03 0xdd111111UL | |
117 | #define GC_N64_CMD_1b 0xdd1dd111UL | |
118 | #define GC_N64_CMD_c0 0x111111ddUL | |
119 | #define GC_N64_CMD_80 0x1111111dUL | |
120 | #define GC_N64_STOP_BIT 0x1d /* Encoded stop bit */ | |
121 | #define GC_N64_REQUEST_DATA GC_N64_CMD_01 /* the request data command */ | |
1da177e4 | 122 | #define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */ |
1da177e4 LT |
123 | #define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */ |
124 | /* GC_N64_DWS > 24 is known to fail */ | |
125 | #define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */ | |
126 | #define GC_N64_POWER_R 0xfd /* power during read */ | |
127 | #define GC_N64_OUT 0x1d /* output bits to the 4 pads */ | |
128 | /* Reading the main axes of any N64 pad is known to fail if the corresponding bit */ | |
129 | /* in GC_N64_OUT is pulled low on the output port (by any routine) for more */ | |
130 | /* than 123 us */ | |
131 | #define GC_N64_CLOCK 0x02 /* clock bits for read */ | |
132 | ||
7aa9e0e8 SM |
133 | /* |
134 | * Used for rumble code. | |
135 | */ | |
136 | ||
137 | /* Send encoded command */ | |
138 | static void gc_n64_send_command(struct gc *gc, unsigned long cmd, | |
139 | unsigned char target) | |
140 | { | |
141 | struct parport *port = gc->pd->port; | |
142 | int i; | |
143 | ||
144 | for (i = 0; i < GC_N64_LENGTH; i++) { | |
145 | unsigned char data = (cmd >> i) & 1 ? target : 0; | |
146 | parport_write_data(port, GC_N64_POWER_W | data); | |
147 | udelay(GC_N64_DWS); | |
148 | } | |
149 | } | |
150 | ||
151 | /* Send stop bit */ | |
152 | static void gc_n64_send_stop_bit(struct gc *gc, unsigned char target) | |
153 | { | |
154 | struct parport *port = gc->pd->port; | |
155 | int i; | |
156 | ||
157 | for (i = 0; i < GC_N64_STOP_LENGTH; i++) { | |
158 | unsigned char data = (GC_N64_STOP_BIT >> i) & 1 ? target : 0; | |
159 | parport_write_data(port, GC_N64_POWER_W | data); | |
160 | udelay(GC_N64_DWS); | |
161 | } | |
162 | } | |
163 | ||
1da177e4 LT |
164 | /* |
165 | * gc_n64_read_packet() reads an N64 packet. | |
d38fcb96 DT |
166 | * Each pad uses one bit per byte. So all pads connected to this port |
167 | * are read in parallel. | |
1da177e4 LT |
168 | */ |
169 | ||
170 | static void gc_n64_read_packet(struct gc *gc, unsigned char *data) | |
171 | { | |
172 | int i; | |
173 | unsigned long flags; | |
174 | ||
175 | /* | |
176 | * Request the pad to transmit data | |
177 | */ | |
178 | ||
179 | local_irq_save(flags); | |
7aa9e0e8 SM |
180 | gc_n64_send_command(gc, GC_N64_REQUEST_DATA, GC_N64_OUT); |
181 | gc_n64_send_stop_bit(gc, GC_N64_OUT); | |
1da177e4 LT |
182 | local_irq_restore(flags); |
183 | ||
184 | /* | |
d38fcb96 DT |
185 | * Wait for the pad response to be loaded into the 33-bit register |
186 | * of the adapter. | |
1da177e4 LT |
187 | */ |
188 | ||
189 | udelay(GC_N64_DELAY); | |
190 | ||
191 | /* | |
192 | * Grab data (ignoring the last bit, which is a stop bit) | |
193 | */ | |
194 | ||
195 | for (i = 0; i < GC_N64_LENGTH; i++) { | |
196 | parport_write_data(gc->pd->port, GC_N64_POWER_R); | |
7aa9e0e8 | 197 | udelay(2); |
1da177e4 LT |
198 | data[i] = parport_read_status(gc->pd->port); |
199 | parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK); | |
200 | } | |
201 | ||
202 | /* | |
d38fcb96 DT |
203 | * We must wait 200 ms here for the controller to reinitialize before |
204 | * the next read request. No worries as long as gc_read is polled less | |
205 | * frequently than this. | |
1da177e4 LT |
206 | */ |
207 | ||
208 | } | |
209 | ||
c7fd018d DT |
210 | static void gc_n64_process_packet(struct gc *gc) |
211 | { | |
212 | unsigned char data[GC_N64_LENGTH]; | |
c7fd018d DT |
213 | struct input_dev *dev; |
214 | int i, j, s; | |
d38fcb96 | 215 | signed char x, y; |
c7fd018d DT |
216 | |
217 | gc_n64_read_packet(gc, data); | |
218 | ||
219 | for (i = 0; i < GC_MAX_DEVICES; i++) { | |
220 | ||
221 | dev = gc->dev[i]; | |
222 | if (!dev) | |
223 | continue; | |
224 | ||
225 | s = gc_status_bit[i]; | |
226 | ||
227 | if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) { | |
228 | ||
d38fcb96 | 229 | x = y = 0; |
c7fd018d DT |
230 | |
231 | for (j = 0; j < 8; j++) { | |
232 | if (data[23 - j] & s) | |
d38fcb96 | 233 | x |= 1 << j; |
c7fd018d | 234 | if (data[31 - j] & s) |
d38fcb96 | 235 | y |= 1 << j; |
c7fd018d DT |
236 | } |
237 | ||
d38fcb96 DT |
238 | input_report_abs(dev, ABS_X, x); |
239 | input_report_abs(dev, ABS_Y, -y); | |
c7fd018d | 240 | |
d38fcb96 DT |
241 | input_report_abs(dev, ABS_HAT0X, |
242 | !(s & data[6]) - !(s & data[7])); | |
243 | input_report_abs(dev, ABS_HAT0Y, | |
244 | !(s & data[4]) - !(s & data[5])); | |
c7fd018d DT |
245 | |
246 | for (j = 0; j < 10; j++) | |
d38fcb96 DT |
247 | input_report_key(dev, gc_n64_btn[j], |
248 | s & data[gc_n64_bytes[j]]); | |
c7fd018d DT |
249 | |
250 | input_sync(dev); | |
251 | } | |
252 | } | |
253 | } | |
254 | ||
7aa9e0e8 SM |
255 | static int gc_n64_play_effect(struct input_dev *dev, void *data, |
256 | struct ff_effect *effect) | |
257 | { | |
258 | int i; | |
259 | unsigned long flags; | |
260 | struct gc *gc = input_get_drvdata(dev); | |
261 | struct gc_subdev *sdev = data; | |
262 | unsigned char target = 1 << sdev->idx; /* select desired pin */ | |
263 | ||
264 | if (effect->type == FF_RUMBLE) { | |
265 | struct ff_rumble_effect *rumble = &effect->u.rumble; | |
266 | unsigned int cmd = | |
267 | rumble->strong_magnitude || rumble->weak_magnitude ? | |
268 | GC_N64_CMD_01 : GC_N64_CMD_00; | |
269 | ||
270 | local_irq_save(flags); | |
271 | ||
272 | /* Init Rumble - 0x03, 0x80, 0x01, (34)0x80 */ | |
273 | gc_n64_send_command(gc, GC_N64_CMD_03, target); | |
274 | gc_n64_send_command(gc, GC_N64_CMD_80, target); | |
275 | gc_n64_send_command(gc, GC_N64_CMD_01, target); | |
276 | for (i = 0; i < 32; i++) | |
277 | gc_n64_send_command(gc, GC_N64_CMD_80, target); | |
278 | gc_n64_send_stop_bit(gc, target); | |
279 | ||
280 | udelay(GC_N64_DELAY); | |
281 | ||
282 | /* Now start or stop it - 0x03, 0xc0, 0zx1b, (32)0x01/0x00 */ | |
283 | gc_n64_send_command(gc, GC_N64_CMD_03, target); | |
284 | gc_n64_send_command(gc, GC_N64_CMD_c0, target); | |
285 | gc_n64_send_command(gc, GC_N64_CMD_1b, target); | |
286 | for (i = 0; i < 32; i++) | |
287 | gc_n64_send_command(gc, cmd, target); | |
288 | gc_n64_send_stop_bit(gc, target); | |
289 | ||
290 | local_irq_restore(flags); | |
291 | ||
292 | } | |
293 | ||
294 | return 0; | |
295 | } | |
296 | ||
297 | static int __init gc_n64_init_ff(struct input_dev *dev, int i) | |
298 | { | |
299 | struct gc_subdev *sdev; | |
300 | int err; | |
301 | ||
302 | sdev = kmalloc(sizeof(*sdev), GFP_KERNEL); | |
303 | if (!sdev) | |
304 | return -ENOMEM; | |
305 | ||
306 | sdev->idx = i; | |
307 | ||
308 | input_set_capability(dev, EV_FF, FF_RUMBLE); | |
309 | ||
310 | err = input_ff_create_memless(dev, sdev, gc_n64_play_effect); | |
311 | if (err) { | |
312 | kfree(sdev); | |
313 | return err; | |
314 | } | |
315 | ||
316 | return 0; | |
317 | } | |
318 | ||
1da177e4 LT |
319 | /* |
320 | * NES/SNES support. | |
321 | */ | |
322 | ||
b157d55e RA |
323 | #define GC_NES_DELAY 6 /* Delay between bits - 6us */ |
324 | #define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */ | |
325 | #define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the | |
326 | last 4 bits are unused */ | |
327 | #define GC_SNESMOUSE_LENGTH 32 /* The SNES mouse uses 32 bits, the first | |
328 | 16 bits are equivalent to a gamepad */ | |
1da177e4 LT |
329 | |
330 | #define GC_NES_POWER 0xfc | |
331 | #define GC_NES_CLOCK 0x01 | |
332 | #define GC_NES_LATCH 0x02 | |
333 | ||
334 | static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 }; | |
335 | static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 }; | |
d38fcb96 DT |
336 | static short gc_snes_btn[] = { |
337 | BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR | |
338 | }; | |
1da177e4 LT |
339 | |
340 | /* | |
341 | * gc_nes_read_packet() reads a NES/SNES packet. | |
342 | * Each pad uses one bit per byte. So all pads connected to | |
343 | * this port are read in parallel. | |
344 | */ | |
345 | ||
346 | static void gc_nes_read_packet(struct gc *gc, int length, unsigned char *data) | |
347 | { | |
348 | int i; | |
349 | ||
350 | parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH); | |
351 | udelay(GC_NES_DELAY * 2); | |
352 | parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK); | |
353 | ||
354 | for (i = 0; i < length; i++) { | |
355 | udelay(GC_NES_DELAY); | |
356 | parport_write_data(gc->pd->port, GC_NES_POWER); | |
357 | data[i] = parport_read_status(gc->pd->port) ^ 0x7f; | |
358 | udelay(GC_NES_DELAY); | |
359 | parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK); | |
360 | } | |
361 | } | |
362 | ||
c7fd018d DT |
363 | static void gc_nes_process_packet(struct gc *gc) |
364 | { | |
b157d55e | 365 | unsigned char data[GC_SNESMOUSE_LENGTH]; |
c7fd018d | 366 | struct input_dev *dev; |
b157d55e RA |
367 | int i, j, s, len; |
368 | char x_rel, y_rel; | |
369 | ||
370 | len = gc->pads[GC_SNESMOUSE] ? GC_SNESMOUSE_LENGTH : | |
371 | (gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH); | |
c7fd018d | 372 | |
b157d55e | 373 | gc_nes_read_packet(gc, len, data); |
c7fd018d DT |
374 | |
375 | for (i = 0; i < GC_MAX_DEVICES; i++) { | |
376 | ||
377 | dev = gc->dev[i]; | |
378 | if (!dev) | |
379 | continue; | |
380 | ||
381 | s = gc_status_bit[i]; | |
382 | ||
383 | if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) { | |
384 | input_report_abs(dev, ABS_X, !(s & data[6]) - !(s & data[7])); | |
385 | input_report_abs(dev, ABS_Y, !(s & data[4]) - !(s & data[5])); | |
386 | } | |
387 | ||
388 | if (s & gc->pads[GC_NES]) | |
389 | for (j = 0; j < 4; j++) | |
d38fcb96 DT |
390 | input_report_key(dev, gc_snes_btn[j], |
391 | s & data[gc_nes_bytes[j]]); | |
c7fd018d DT |
392 | |
393 | if (s & gc->pads[GC_SNES]) | |
394 | for (j = 0; j < 8; j++) | |
d38fcb96 DT |
395 | input_report_key(dev, gc_snes_btn[j], |
396 | s & data[gc_snes_bytes[j]]); | |
c7fd018d | 397 | |
b157d55e RA |
398 | if (s & gc->pads[GC_SNESMOUSE]) { |
399 | /* | |
d38fcb96 DT |
400 | * The 4 unused bits from SNES controllers appear |
401 | * to be ID bits so use them to make sure we are | |
402 | * dealing with a mouse. | |
b157d55e RA |
403 | * gamepad is connected. This is important since |
404 | * my SNES gamepad sends 1's for bits 16-31, which | |
405 | * cause the mouse pointer to quickly move to the | |
406 | * upper left corner of the screen. | |
407 | */ | |
408 | if (!(s & data[12]) && !(s & data[13]) && | |
409 | !(s & data[14]) && (s & data[15])) { | |
410 | input_report_key(dev, BTN_LEFT, s & data[9]); | |
411 | input_report_key(dev, BTN_RIGHT, s & data[8]); | |
412 | ||
413 | x_rel = y_rel = 0; | |
414 | for (j = 0; j < 7; j++) { | |
415 | x_rel <<= 1; | |
416 | if (data[25 + j] & s) | |
417 | x_rel |= 1; | |
418 | ||
419 | y_rel <<= 1; | |
420 | if (data[17 + j] & s) | |
421 | y_rel |= 1; | |
422 | } | |
423 | ||
424 | if (x_rel) { | |
425 | if (data[24] & s) | |
426 | x_rel = -x_rel; | |
427 | input_report_rel(dev, REL_X, x_rel); | |
428 | } | |
429 | ||
430 | if (y_rel) { | |
431 | if (data[16] & s) | |
432 | y_rel = -y_rel; | |
433 | input_report_rel(dev, REL_Y, y_rel); | |
434 | } | |
435 | } | |
436 | } | |
c7fd018d DT |
437 | input_sync(dev); |
438 | } | |
439 | } | |
440 | ||
1da177e4 LT |
441 | /* |
442 | * Multisystem joystick support | |
443 | */ | |
444 | ||
445 | #define GC_MULTI_LENGTH 5 /* Multi system joystick packet length is 5 */ | |
446 | #define GC_MULTI2_LENGTH 6 /* One more bit for one more button */ | |
447 | ||
448 | /* | |
449 | * gc_multi_read_packet() reads a Multisystem joystick packet. | |
450 | */ | |
451 | ||
452 | static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data) | |
453 | { | |
454 | int i; | |
455 | ||
456 | for (i = 0; i < length; i++) { | |
457 | parport_write_data(gc->pd->port, ~(1 << i)); | |
458 | data[i] = parport_read_status(gc->pd->port) ^ 0x7f; | |
459 | } | |
460 | } | |
461 | ||
c7fd018d DT |
462 | static void gc_multi_process_packet(struct gc *gc) |
463 | { | |
464 | unsigned char data[GC_MULTI2_LENGTH]; | |
d38fcb96 | 465 | int data_len = gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH; |
c7fd018d DT |
466 | struct input_dev *dev; |
467 | int i, s; | |
468 | ||
d38fcb96 | 469 | gc_multi_read_packet(gc, data_len, data); |
c7fd018d DT |
470 | |
471 | for (i = 0; i < GC_MAX_DEVICES; i++) { | |
472 | ||
473 | dev = gc->dev[i]; | |
474 | if (!dev) | |
475 | continue; | |
476 | ||
477 | s = gc_status_bit[i]; | |
478 | ||
479 | if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) { | |
d38fcb96 DT |
480 | input_report_abs(dev, ABS_X, |
481 | !(s & data[2]) - !(s & data[3])); | |
482 | input_report_abs(dev, ABS_Y, | |
483 | !(s & data[0]) - !(s & data[1])); | |
c7fd018d DT |
484 | input_report_key(dev, BTN_TRIGGER, s & data[4]); |
485 | } | |
486 | ||
487 | if (s & gc->pads[GC_MULTI2]) | |
488 | input_report_key(dev, BTN_THUMB, s & data[5]); | |
489 | ||
490 | input_sync(dev); | |
491 | } | |
492 | } | |
493 | ||
1da177e4 LT |
494 | /* |
495 | * PSX support | |
496 | * | |
497 | * See documentation at: | |
498 | * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt | |
499 | * http://www.gamesx.com/controldata/psxcont/psxcont.htm | |
500 | * ftp://milano.usal.es/pablo/ | |
501 | * | |
502 | */ | |
503 | ||
504 | #define GC_PSX_DELAY 25 /* 25 usec */ | |
505 | #define GC_PSX_LENGTH 8 /* talk to the controller in bits */ | |
506 | #define GC_PSX_BYTES 6 /* the maximum number of bytes to read off the controller */ | |
507 | ||
508 | #define GC_PSX_MOUSE 1 /* Mouse */ | |
509 | #define GC_PSX_NEGCON 2 /* NegCon */ | |
510 | #define GC_PSX_NORMAL 4 /* Digital / Analog or Rumble in Digital mode */ | |
511 | #define GC_PSX_ANALOG 5 /* Analog in Analog mode / Rumble in Green mode */ | |
512 | #define GC_PSX_RUMBLE 7 /* Rumble in Red mode */ | |
513 | ||
514 | #define GC_PSX_CLOCK 0x04 /* Pin 4 */ | |
515 | #define GC_PSX_COMMAND 0x01 /* Pin 2 */ | |
516 | #define GC_PSX_POWER 0xf8 /* Pins 5-9 */ | |
517 | #define GC_PSX_SELECT 0x02 /* Pin 3 */ | |
518 | ||
519 | #define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */ | |
520 | #define GC_PSX_LEN(x) (((x) & 0xf) << 1) /* Low nibble is length in bytes/2 */ | |
521 | ||
522 | static int gc_psx_delay = GC_PSX_DELAY; | |
523 | module_param_named(psx_delay, gc_psx_delay, uint, 0); | |
524 | MODULE_PARM_DESC(psx_delay, "Delay when accessing Sony PSX controller (usecs)"); | |
525 | ||
d38fcb96 DT |
526 | static short gc_psx_abs[] = { |
527 | ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y | |
528 | }; | |
529 | static short gc_psx_btn[] = { | |
530 | BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y, | |
531 | BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR | |
532 | }; | |
1da177e4 LT |
533 | static short gc_psx_ddr_btn[] = { BTN_0, BTN_1, BTN_2, BTN_3 }; |
534 | ||
535 | /* | |
536 | * gc_psx_command() writes 8bit command and reads 8bit data from | |
537 | * the psx pad. | |
538 | */ | |
539 | ||
d38fcb96 | 540 | static void gc_psx_command(struct gc *gc, int b, unsigned char *data) |
1da177e4 | 541 | { |
d38fcb96 | 542 | struct parport *port = gc->pd->port; |
1da177e4 | 543 | int i, j, cmd, read; |
c7fd018d | 544 | |
d38fcb96 | 545 | memset(data, 0, GC_MAX_DEVICES); |
1da177e4 LT |
546 | |
547 | for (i = 0; i < GC_PSX_LENGTH; i++, b >>= 1) { | |
548 | cmd = (b & 1) ? GC_PSX_COMMAND : 0; | |
d38fcb96 | 549 | parport_write_data(port, cmd | GC_PSX_POWER); |
1da177e4 | 550 | udelay(gc_psx_delay); |
d38fcb96 | 551 | read = parport_read_status(port) ^ 0x80; |
c7fd018d | 552 | for (j = 0; j < GC_MAX_DEVICES; j++) |
1da177e4 LT |
553 | data[j] |= (read & gc_status_bit[j] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) ? (1 << i) : 0; |
554 | parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER); | |
555 | udelay(gc_psx_delay); | |
556 | } | |
557 | } | |
558 | ||
559 | /* | |
560 | * gc_psx_read_packet() reads a whole psx packet and returns | |
561 | * device identifier code. | |
562 | */ | |
563 | ||
c7fd018d DT |
564 | static void gc_psx_read_packet(struct gc *gc, unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES], |
565 | unsigned char id[GC_MAX_DEVICES]) | |
1da177e4 LT |
566 | { |
567 | int i, j, max_len = 0; | |
568 | unsigned long flags; | |
c7fd018d | 569 | unsigned char data2[GC_MAX_DEVICES]; |
1da177e4 | 570 | |
d38fcb96 DT |
571 | /* Select pad */ |
572 | parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); | |
1da177e4 | 573 | udelay(gc_psx_delay); |
d38fcb96 DT |
574 | /* Deselect, begin command */ |
575 | parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); | |
1da177e4 LT |
576 | udelay(gc_psx_delay); |
577 | ||
578 | local_irq_save(flags); | |
579 | ||
d38fcb96 DT |
580 | gc_psx_command(gc, 0x01, data2); /* Access pad */ |
581 | gc_psx_command(gc, 0x42, id); /* Get device ids */ | |
582 | gc_psx_command(gc, 0, data2); /* Dump status */ | |
1da177e4 | 583 | |
d38fcb96 DT |
584 | /* Find the longest pad */ |
585 | for (i = 0; i < GC_MAX_DEVICES; i++) | |
586 | if ((gc_status_bit[i] & (gc->pads[GC_PSX] | gc->pads[GC_DDR])) && | |
587 | GC_PSX_LEN(id[i]) > max_len && | |
588 | GC_PSX_LEN(id[i]) <= GC_PSX_BYTES) { | |
1da177e4 | 589 | max_len = GC_PSX_LEN(id[i]); |
d38fcb96 | 590 | } |
1da177e4 | 591 | |
d38fcb96 DT |
592 | /* Read in all the data */ |
593 | for (i = 0; i < max_len; i++) { | |
1da177e4 | 594 | gc_psx_command(gc, 0, data2); |
c7fd018d | 595 | for (j = 0; j < GC_MAX_DEVICES; j++) |
1da177e4 LT |
596 | data[j][i] = data2[j]; |
597 | } | |
598 | ||
599 | local_irq_restore(flags); | |
600 | ||
601 | parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); | |
602 | ||
d38fcb96 DT |
603 | /* Set id's to the real value */ |
604 | for (i = 0; i < GC_MAX_DEVICES; i++) | |
1da177e4 LT |
605 | id[i] = GC_PSX_ID(id[i]); |
606 | } | |
607 | ||
d38fcb96 DT |
608 | static void gc_psx_report_one(struct gc *gc, struct input_dev *dev, |
609 | unsigned char pad_type, unsigned char status_bit, | |
610 | unsigned char *data) | |
c7fd018d | 611 | { |
d38fcb96 | 612 | int i; |
1da177e4 | 613 | |
d38fcb96 | 614 | switch (pad_type) { |
1da177e4 | 615 | |
d38fcb96 | 616 | case GC_PSX_RUMBLE: |
1da177e4 | 617 | |
d38fcb96 DT |
618 | input_report_key(dev, BTN_THUMBL, ~data[0] & 0x04); |
619 | input_report_key(dev, BTN_THUMBR, ~data[0] & 0x02); | |
1da177e4 | 620 | |
d38fcb96 DT |
621 | case GC_PSX_NEGCON: |
622 | case GC_PSX_ANALOG: | |
1da177e4 | 623 | |
d38fcb96 DT |
624 | if (gc->pads[GC_DDR] & status_bit) { |
625 | for (i = 0; i < 4; i++) | |
626 | input_report_key(dev, gc_psx_ddr_btn[i], | |
627 | ~data[0] & (0x10 << i)); | |
628 | } else { | |
629 | for (i = 0; i < 4; i++) | |
630 | input_report_abs(dev, gc_psx_abs[i + 2], | |
631 | data[i + 2]); | |
1da177e4 | 632 | |
d38fcb96 DT |
633 | input_report_abs(dev, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); |
634 | input_report_abs(dev, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); | |
635 | } | |
1da177e4 | 636 | |
d38fcb96 DT |
637 | for (i = 0; i < 8; i++) |
638 | input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i)); | |
1da177e4 | 639 | |
d38fcb96 DT |
640 | input_report_key(dev, BTN_START, ~data[0] & 0x08); |
641 | input_report_key(dev, BTN_SELECT, ~data[0] & 0x01); | |
1da177e4 | 642 | |
d38fcb96 | 643 | input_sync(dev); |
1da177e4 | 644 | |
d38fcb96 | 645 | break; |
c7fd018d | 646 | |
d38fcb96 DT |
647 | case GC_PSX_NORMAL: |
648 | if (gc->pads[GC_DDR] & status_bit) { | |
649 | for (i = 0; i < 4; i++) | |
650 | input_report_key(dev, gc_psx_ddr_btn[i], | |
651 | ~data[0] & (0x10 << i)); | |
652 | } else { | |
653 | input_report_abs(dev, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128); | |
654 | input_report_abs(dev, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128); | |
c7fd018d | 655 | |
d38fcb96 DT |
656 | /* |
657 | * For some reason if the extra axes are left unset | |
658 | * they drift. | |
659 | * for (i = 0; i < 4; i++) | |
660 | input_report_abs(dev, gc_psx_abs[i + 2], 128); | |
661 | * This needs to be debugged properly, | |
662 | * maybe fuzz processing needs to be done | |
663 | * in input_sync() | |
664 | * --vojtech | |
665 | */ | |
666 | } | |
c7fd018d | 667 | |
d38fcb96 DT |
668 | for (i = 0; i < 8; i++) |
669 | input_report_key(dev, gc_psx_btn[i], ~data[1] & (1 << i)); | |
c7fd018d | 670 | |
d38fcb96 DT |
671 | input_report_key(dev, BTN_START, ~data[0] & 0x08); |
672 | input_report_key(dev, BTN_SELECT, ~data[0] & 0x01); | |
c7fd018d | 673 | |
d38fcb96 | 674 | input_sync(dev); |
1da177e4 | 675 | |
d38fcb96 | 676 | break; |
1da177e4 | 677 | |
d38fcb96 DT |
678 | case 0: /* not a pad, ignore */ |
679 | break; | |
680 | } | |
681 | } | |
1da177e4 | 682 | |
d38fcb96 DT |
683 | static void gc_psx_process_packet(struct gc *gc) |
684 | { | |
685 | unsigned char data[GC_MAX_DEVICES][GC_PSX_BYTES]; | |
686 | unsigned char id[GC_MAX_DEVICES]; | |
687 | int i; | |
1da177e4 | 688 | |
d38fcb96 | 689 | gc_psx_read_packet(gc, data, id); |
c7fd018d | 690 | |
d38fcb96 DT |
691 | for (i = 0; i < GC_MAX_DEVICES; i++) { |
692 | ||
693 | if (gc->dev[i]) | |
694 | gc_psx_report_one(gc, gc->dev[i], | |
695 | id[i], gc_status_bit[i], data[i]); | |
1da177e4 | 696 | } |
c7fd018d | 697 | } |
1da177e4 LT |
698 | |
699 | /* | |
c7fd018d | 700 | * gc_timer() initiates reads of console pads data. |
1da177e4 LT |
701 | */ |
702 | ||
c7fd018d DT |
703 | static void gc_timer(unsigned long private) |
704 | { | |
705 | struct gc *gc = (void *) private; | |
1da177e4 | 706 | |
c7fd018d DT |
707 | /* |
708 | * N64 pads - must be read first, any read confuses them for 200 us | |
709 | */ | |
1da177e4 | 710 | |
c7fd018d DT |
711 | if (gc->pads[GC_N64]) |
712 | gc_n64_process_packet(gc); | |
1da177e4 | 713 | |
c7fd018d | 714 | /* |
b157d55e | 715 | * NES and SNES pads or mouse |
c7fd018d | 716 | */ |
1da177e4 | 717 | |
b157d55e | 718 | if (gc->pads[GC_NES] || gc->pads[GC_SNES] || gc->pads[GC_SNESMOUSE]) |
c7fd018d | 719 | gc_nes_process_packet(gc); |
1da177e4 LT |
720 | |
721 | /* | |
722 | * Multi and Multi2 joysticks | |
723 | */ | |
724 | ||
c7fd018d DT |
725 | if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) |
726 | gc_multi_process_packet(gc); | |
1da177e4 LT |
727 | |
728 | /* | |
729 | * PSX controllers | |
730 | */ | |
731 | ||
c7fd018d DT |
732 | if (gc->pads[GC_PSX] || gc->pads[GC_DDR]) |
733 | gc_psx_process_packet(gc); | |
1da177e4 LT |
734 | |
735 | mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); | |
736 | } | |
737 | ||
738 | static int gc_open(struct input_dev *dev) | |
739 | { | |
8715c1cf | 740 | struct gc *gc = input_get_drvdata(dev); |
8b1a198b DT |
741 | int err; |
742 | ||
72ba9f0c | 743 | err = mutex_lock_interruptible(&gc->mutex); |
8b1a198b DT |
744 | if (err) |
745 | return err; | |
746 | ||
1da177e4 LT |
747 | if (!gc->used++) { |
748 | parport_claim(gc->pd); | |
749 | parport_write_control(gc->pd->port, 0x04); | |
750 | mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME); | |
751 | } | |
8b1a198b | 752 | |
72ba9f0c | 753 | mutex_unlock(&gc->mutex); |
1da177e4 LT |
754 | return 0; |
755 | } | |
756 | ||
757 | static void gc_close(struct input_dev *dev) | |
758 | { | |
8715c1cf | 759 | struct gc *gc = input_get_drvdata(dev); |
8b1a198b | 760 | |
72ba9f0c | 761 | mutex_lock(&gc->mutex); |
1da177e4 | 762 | if (!--gc->used) { |
8b1a198b | 763 | del_timer_sync(&gc->timer); |
1da177e4 LT |
764 | parport_write_control(gc->pd->port, 0x00); |
765 | parport_release(gc->pd); | |
766 | } | |
72ba9f0c | 767 | mutex_unlock(&gc->mutex); |
1da177e4 LT |
768 | } |
769 | ||
17dd3f0f | 770 | static int __init gc_setup_pad(struct gc *gc, int idx, int pad_type) |
1da177e4 | 771 | { |
17dd3f0f DT |
772 | struct input_dev *input_dev; |
773 | int i; | |
7aa9e0e8 | 774 | int err; |
1da177e4 | 775 | |
17dd3f0f DT |
776 | if (!pad_type) |
777 | return 0; | |
1da177e4 | 778 | |
17dd3f0f DT |
779 | if (pad_type < 1 || pad_type > GC_MAX) { |
780 | printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", pad_type); | |
781 | return -EINVAL; | |
1da177e4 LT |
782 | } |
783 | ||
17dd3f0f DT |
784 | gc->dev[idx] = input_dev = input_allocate_device(); |
785 | if (!input_dev) { | |
786 | printk(KERN_ERR "gamecon.c: Not enough memory for input device\n"); | |
787 | return -ENOMEM; | |
1da177e4 LT |
788 | } |
789 | ||
17dd3f0f DT |
790 | input_dev->name = gc_names[pad_type]; |
791 | input_dev->phys = gc->phys[idx]; | |
792 | input_dev->id.bustype = BUS_PARPORT; | |
793 | input_dev->id.vendor = 0x0001; | |
794 | input_dev->id.product = pad_type; | |
795 | input_dev->id.version = 0x0100; | |
8715c1cf DT |
796 | |
797 | input_set_drvdata(input_dev, gc); | |
17dd3f0f DT |
798 | |
799 | input_dev->open = gc_open; | |
800 | input_dev->close = gc_close; | |
801 | ||
b157d55e | 802 | if (pad_type != GC_SNESMOUSE) { |
7b19ada2 | 803 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
17dd3f0f | 804 | |
b157d55e RA |
805 | for (i = 0; i < 2; i++) |
806 | input_set_abs_params(input_dev, ABS_X + i, -1, 1, 0, 0); | |
807 | } else | |
7b19ada2 | 808 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); |
17dd3f0f DT |
809 | |
810 | gc->pads[0] |= gc_status_bit[idx]; | |
811 | gc->pads[pad_type] |= gc_status_bit[idx]; | |
812 | ||
813 | switch (pad_type) { | |
814 | ||
d38fcb96 DT |
815 | case GC_N64: |
816 | for (i = 0; i < 10; i++) | |
817 | __set_bit(gc_n64_btn[i], input_dev->keybit); | |
b157d55e | 818 | |
d38fcb96 DT |
819 | for (i = 0; i < 2; i++) { |
820 | input_set_abs_params(input_dev, ABS_X + i, -127, 126, 0, 2); | |
821 | input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); | |
822 | } | |
17dd3f0f | 823 | |
d38fcb96 DT |
824 | err = gc_n64_init_ff(input_dev, idx); |
825 | if (err) { | |
826 | printk(KERN_WARNING "gamecon.c: Failed to initiate rumble for N64 device %d\n", idx); | |
827 | input_free_device(input_dev); | |
828 | return err; | |
829 | } | |
17dd3f0f | 830 | |
d38fcb96 DT |
831 | break; |
832 | ||
833 | case GC_SNESMOUSE: | |
834 | __set_bit(BTN_LEFT, input_dev->keybit); | |
835 | __set_bit(BTN_RIGHT, input_dev->keybit); | |
836 | __set_bit(REL_X, input_dev->relbit); | |
837 | __set_bit(REL_Y, input_dev->relbit); | |
838 | break; | |
839 | ||
840 | case GC_SNES: | |
841 | for (i = 4; i < 8; i++) | |
842 | __set_bit(gc_snes_btn[i], input_dev->keybit); | |
843 | case GC_NES: | |
844 | for (i = 0; i < 4; i++) | |
845 | __set_bit(gc_snes_btn[i], input_dev->keybit); | |
846 | break; | |
847 | ||
848 | case GC_MULTI2: | |
849 | __set_bit(BTN_THUMB, input_dev->keybit); | |
850 | case GC_MULTI: | |
851 | __set_bit(BTN_TRIGGER, input_dev->keybit); | |
852 | break; | |
853 | ||
854 | case GC_PSX: | |
855 | for (i = 0; i < 6; i++) | |
856 | input_set_abs_params(input_dev, | |
857 | gc_psx_abs[i], 4, 252, 0, 2); | |
858 | for (i = 0; i < 12; i++) | |
859 | __set_bit(gc_psx_btn[i], input_dev->keybit); | |
860 | ||
861 | break; | |
862 | ||
863 | case GC_DDR: | |
864 | for (i = 0; i < 4; i++) | |
865 | __set_bit(gc_psx_ddr_btn[i], input_dev->keybit); | |
866 | for (i = 0; i < 12; i++) | |
867 | __set_bit(gc_psx_btn[i], input_dev->keybit); | |
868 | ||
869 | break; | |
1da177e4 | 870 | } |
8b1a198b | 871 | |
17dd3f0f DT |
872 | return 0; |
873 | } | |
1da177e4 | 874 | |
17dd3f0f DT |
875 | static struct gc __init *gc_probe(int parport, int *pads, int n_pads) |
876 | { | |
877 | struct gc *gc; | |
878 | struct parport *pp; | |
879 | struct pardevice *pd; | |
880 | int i; | |
881 | int err; | |
1da177e4 | 882 | |
17dd3f0f DT |
883 | pp = parport_find_number(parport); |
884 | if (!pp) { | |
885 | printk(KERN_ERR "gamecon.c: no such parport\n"); | |
886 | err = -EINVAL; | |
887 | goto err_out; | |
888 | } | |
1da177e4 | 889 | |
17dd3f0f DT |
890 | pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL); |
891 | if (!pd) { | |
1da177e4 | 892 | printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n"); |
17dd3f0f DT |
893 | err = -EBUSY; |
894 | goto err_put_pp; | |
1da177e4 LT |
895 | } |
896 | ||
17dd3f0f DT |
897 | gc = kzalloc(sizeof(struct gc), GFP_KERNEL); |
898 | if (!gc) { | |
899 | printk(KERN_ERR "gamecon.c: Not enough memory\n"); | |
900 | err = -ENOMEM; | |
901 | goto err_unreg_pardev; | |
902 | } | |
1da177e4 | 903 | |
72ba9f0c | 904 | mutex_init(&gc->mutex); |
17dd3f0f | 905 | gc->pd = pd; |
d38fcb96 | 906 | setup_timer(&gc->timer, gc_timer, (long) gc); |
1da177e4 | 907 | |
c7fd018d | 908 | for (i = 0; i < n_pads && i < GC_MAX_DEVICES; i++) { |
17dd3f0f | 909 | if (!pads[i]) |
1da177e4 LT |
910 | continue; |
911 | ||
10ca4c0a DT |
912 | snprintf(gc->phys[i], sizeof(gc->phys[i]), |
913 | "%s/input%d", gc->pd->port->name, i); | |
17dd3f0f DT |
914 | err = gc_setup_pad(gc, i, pads[i]); |
915 | if (err) | |
77fc46ca | 916 | goto err_unreg_devs; |
1da177e4 | 917 | |
77fc46ca DT |
918 | err = input_register_device(gc->dev[i]); |
919 | if (err) | |
920 | goto err_free_dev; | |
17dd3f0f | 921 | } |
1da177e4 | 922 | |
17dd3f0f DT |
923 | if (!gc->pads[0]) { |
924 | printk(KERN_ERR "gamecon.c: No valid devices specified\n"); | |
925 | err = -EINVAL; | |
926 | goto err_free_gc; | |
927 | } | |
1da177e4 | 928 | |
17dd3f0f DT |
929 | parport_put_port(pp); |
930 | return gc; | |
1da177e4 | 931 | |
77fc46ca DT |
932 | err_free_dev: |
933 | input_free_device(gc->dev[i]); | |
934 | err_unreg_devs: | |
17dd3f0f | 935 | while (--i >= 0) |
77fc46ca DT |
936 | if (gc->dev[i]) |
937 | input_unregister_device(gc->dev[i]); | |
17dd3f0f DT |
938 | err_free_gc: |
939 | kfree(gc); | |
940 | err_unreg_pardev: | |
941 | parport_unregister_device(pd); | |
942 | err_put_pp: | |
943 | parport_put_port(pp); | |
944 | err_out: | |
945 | return ERR_PTR(err); | |
946 | } | |
1da177e4 | 947 | |
77fc46ca | 948 | static void gc_remove(struct gc *gc) |
17dd3f0f DT |
949 | { |
950 | int i; | |
1da177e4 | 951 | |
17dd3f0f DT |
952 | for (i = 0; i < GC_MAX_DEVICES; i++) |
953 | if (gc->dev[i]) | |
954 | input_unregister_device(gc->dev[i]); | |
955 | parport_unregister_device(gc->pd); | |
956 | kfree(gc); | |
957 | } | |
1da177e4 | 958 | |
17dd3f0f DT |
959 | static int __init gc_init(void) |
960 | { | |
961 | int i; | |
962 | int have_dev = 0; | |
963 | int err = 0; | |
1da177e4 | 964 | |
17dd3f0f | 965 | for (i = 0; i < GC_MAX_PORTS; i++) { |
78167236 | 966 | if (gc_cfg[i].nargs == 0 || gc_cfg[i].args[0] < 0) |
17dd3f0f | 967 | continue; |
1da177e4 | 968 | |
78167236 | 969 | if (gc_cfg[i].nargs < 2) { |
17dd3f0f DT |
970 | printk(KERN_ERR "gamecon.c: at least one device must be specified\n"); |
971 | err = -EINVAL; | |
972 | break; | |
1da177e4 LT |
973 | } |
974 | ||
78167236 DT |
975 | gc_base[i] = gc_probe(gc_cfg[i].args[0], |
976 | gc_cfg[i].args + 1, gc_cfg[i].nargs - 1); | |
17dd3f0f DT |
977 | if (IS_ERR(gc_base[i])) { |
978 | err = PTR_ERR(gc_base[i]); | |
979 | break; | |
980 | } | |
1da177e4 | 981 | |
17dd3f0f | 982 | have_dev = 1; |
1da177e4 LT |
983 | } |
984 | ||
17dd3f0f DT |
985 | if (err) { |
986 | while (--i >= 0) | |
77fc46ca DT |
987 | if (gc_base[i]) |
988 | gc_remove(gc_base[i]); | |
17dd3f0f | 989 | return err; |
1da177e4 LT |
990 | } |
991 | ||
17dd3f0f | 992 | return have_dev ? 0 : -ENODEV; |
1da177e4 LT |
993 | } |
994 | ||
995 | static void __exit gc_exit(void) | |
996 | { | |
17dd3f0f DT |
997 | int i; |
998 | ||
999 | for (i = 0; i < GC_MAX_PORTS; i++) | |
1000 | if (gc_base[i]) | |
1001 | gc_remove(gc_base[i]); | |
1da177e4 LT |
1002 | } |
1003 | ||
1004 | module_init(gc_init); | |
1005 | module_exit(gc_exit); |