* better
[mascara-docs.git] / i386 / linux-2.3.21 / drivers / char / joystick / joy-console.c
blobad4be30769d7e779dd44d19da3f5aaa1e7db9181
1 /*
2 * joy-console.c Version 0.11V
4 * Copyright (c) 1998 Andree Borrmann
5 */
7 /*
8 * This is a module for the Linux joystick driver, supporting
9 * console (NES, SNES, Multi1, Multi2, PSX) gamepads connected
10 * via parallel port. Up to five such controllers can be
11 * connected to one parallel port.
15 * This program is free software; you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation; either version 2 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program; if not, write to the Free Software
27 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 #include <asm/io.h>
31 #include <asm/system.h>
32 #include <linux/errno.h>
33 #include <linux/ioport.h>
34 #include <linux/joystick.h>
35 #include <linux/kernel.h>
36 #include <linux/module.h>
37 #include <linux/string.h>
38 #include <linux/delay.h>
41 MODULE_AUTHOR("Andree Borrmann <A.Borrmann@tu-bs.de>");
42 MODULE_PARM(js_console, "2-6i");
43 MODULE_PARM(js_console2,"2-6i");
44 MODULE_PARM(js_console3,"2-6i");
47 #define JS_NO_PAD 0
48 #define JS_SNES_PAD 1
49 #define JS_NES_PAD 2
50 #define JS_NES4_PAD 3
51 #define JS_MULTI_STICK 4
52 #define JS_MULTI2_STICK 5
53 #define JS_PSX_PAD 6
55 #define JS_MAX_PAD JS_PSX_PAD
57 struct js_console_info {
58 #ifdef USE_PARPORT
59 struct pardevice *port; /* parport device */
60 #else
61 int port; /* hw port */
62 #endif
63 int pads; /* total number of pads */
64 int snes; /* SNES pads */
65 int nes; /* NES pads */
66 int multi; /* Multi joysticks */
67 int multi2; /* Multi joysticks with 2 buttons */
68 int psx; /* Normal PSX controllers */
69 int negcon; /* PSX NEGCON controllers */
72 static struct js_port* js_console_port = NULL;
74 static int js_console[] __initdata = { -1, 0, 0, 0, 0, 0 };
75 static int js_console2[] __initdata = { -1, 0, 0, 0, 0, 0 };
76 static int js_console3[] __initdata = { -1, 0, 0, 0, 0, 0 };
78 static int status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
81 * NES/SNES support.
84 #define JS_NES_DELAY 6 /* Delay between bits - 6us */
86 #define JS_NES_LENGTH 8 /* The NES pads use 8 bits of data */
88 #define JS_NES_A 0
89 #define JS_NES_B 1
90 #define JS_NES_START 2
91 #define JS_NES_SELECT 3
92 #define JS_NES_UP 4
93 #define JS_NES_DOWN 5
94 #define JS_NES_LEFT 6
95 #define JS_NES_RIGHT 7
97 #define JS_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */
99 #define JS_SNES_B 0
100 #define JS_SNES_Y 1
101 #define JS_SNES_START 2
102 #define JS_SNES_SELECT 3
103 #define JS_SNES_UP 4
104 #define JS_SNES_DOWN 5
105 #define JS_SNES_LEFT 6
106 #define JS_SNES_RIGHT 7
107 #define JS_SNES_A 8
108 #define JS_SNES_X 9
109 #define JS_SNES_L 10
110 #define JS_SNES_R 11
112 #define JS_NES_POWER 0xf8
113 #define JS_NES_CLOCK 0x01
114 #define JS_NES_LATCH 0x02
117 * js_nes_read_packet() reads a NES/SNES packet.
118 * Each pad uses one bit per byte. So all pads connected to
119 * this port are read in parallel.
122 static void js_nes_read_packet(struct js_console_info *info, int length, unsigned char *data)
124 int i;
126 JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK + JS_NES_LATCH, info->port);
127 udelay(JS_NES_DELAY * 2);
128 JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK, info->port);
130 for (i = 0; i < length; i++) {
131 udelay(JS_NES_DELAY);
132 JS_PAR_DATA_OUT(JS_NES_POWER, info->port);
133 data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
134 udelay(JS_NES_DELAY);
135 JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK, info->port);
140 * Multisystem joystick support
143 #define JS_MULTI_LENGTH 5 /* Multi system joystick packet lenght is 5 */
144 #define JS_MULTI2_LENGTH 6 /* One more bit for one more button */
146 #define JS_MULTI_UP 0
147 #define JS_MULTI_DOWN 1
148 #define JS_MULTI_LEFT 2
149 #define JS_MULTI_RIGHT 3
150 #define JS_MULTI_BUTTON 4
151 #define JS_MULTI_BUTTON2 5
154 * js_multi_read_packet() reads a Multisystem joystick packet.
157 static void js_multi_read_packet(struct js_console_info *info, int length, unsigned char *data)
159 int i;
161 for (i = 0; i < length; i++) {
162 JS_PAR_DATA_OUT(~(1 << i), info->port);
163 data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
168 * PSX support
171 #define JS_PSX_DELAY 10
173 #define JS_PSX_LENGTH 8
175 #define JS_PSX_NORMAL 0x41
176 #define JS_PSX_NEGCON 0x23
177 #define JS_PSX_MOUSE 0x12
179 #define JS_PSX_SELBUT 0x01
180 #define JS_PSX_START 0x08
181 #define JS_PSX_UP 0x10
182 #define JS_PSX_RIGHT 0x20
183 #define JS_PSX_DOWN 0x40
184 #define JS_PSX_LEFT 0x80
186 #define JS_PSX_CLOCK 0x01
187 #define JS_PSX_COMMAND 0x02
188 #define JS_PSX_POWER 0xf8
189 #define JS_PSX_NOPOWER 0x04
190 #define JS_PSX_SELECT 0x08
192 #define JS_PSX_CTRL_OUT(X,Y) JS_PAR_CTRL_OUT((X)^0x0f, Y)
195 * js_psx_command() writes 8bit command and reads 8bit data from
196 * the psx pad.
199 static int js_psx_command(struct js_console_info *info, int b)
201 int i, cmd, ret=0;
203 cmd = (b&1)?JS_PSX_COMMAND:0;
204 for (i=0; i<8; i++) {
205 JS_PSX_CTRL_OUT(cmd, info->port);
206 udelay(JS_PSX_DELAY);
207 ret |= ((JS_PAR_STATUS(info->port) ^ JS_PAR_STATUS_INVERT ) & info->psx) ? (1<<i) : 0;
208 cmd = (b&1)?JS_PSX_COMMAND:0;
209 JS_PSX_CTRL_OUT(JS_PSX_CLOCK | cmd, info->port);
210 udelay(JS_PSX_DELAY);
211 b >>= 1;
213 return ret;
217 * js_psx_read_packet() reads a whole psx packet and returns
218 * device identifier code.
221 static int js_psx_read_packet(struct js_console_info *info, int length, unsigned char *data)
223 int i, ret;
224 unsigned long flags;
226 __save_flags(flags);
227 __cli();
229 JS_PAR_DATA_OUT(JS_PSX_POWER, info->port);
231 JS_PSX_CTRL_OUT(JS_PSX_CLOCK | JS_PSX_SELECT, info->port); /* Select pad */
232 udelay(JS_PSX_DELAY*2);
233 js_psx_command(info, 0x01); /* Access pad */
234 ret = js_psx_command(info, 0x42); /* Get device id */
235 if (js_psx_command(info, 0)=='Z') /* okay? */
236 for (i=0; i<length; i++)
237 data[i]=js_psx_command(info, 0);
238 else ret = -1;
240 JS_PSX_CTRL_OUT(JS_PSX_SELECT | JS_PSX_CLOCK, info->port);
241 __restore_flags(flags);
243 return ret;
248 * js_console_read() reads and analyzes console pads data.
251 #define JS_MAX_LENGTH JS_SNES_LENGTH
253 static int js_console_read(void *xinfo, int **axes, int **buttons)
255 struct js_console_info *info = xinfo;
256 unsigned char data[JS_MAX_LENGTH];
258 int i, s;
259 int n = 0;
262 * NES and SNES pads
265 if (info->nes || info->snes) {
267 js_nes_read_packet(info, info->snes ? JS_SNES_LENGTH : JS_NES_LENGTH, data);
269 for (i = 0; i < 5; i++) {
270 s = status_bit[i];
271 if (info->nes & s) {
272 axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
273 axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0);
275 buttons[n][0] = ((data[JS_NES_A] &s)?1:0) | ((data[JS_NES_B] &s)?2:0)
276 | ((data[JS_NES_START]&s)?4:0) | ((data[JS_NES_SELECT]&s)?8:0);
278 n++;
279 } else
280 if (info->snes & s) {
281 axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
282 axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0);
284 buttons[n][0] = ((data[JS_SNES_A] &s)?0x01:0) | ((data[JS_SNES_B] &s)?0x02:0)
285 | ((data[JS_SNES_X] &s)?0x04:0) | ((data[JS_SNES_Y] &s)?0x08:0)
286 | ((data[JS_SNES_L] &s)?0x10:0) | ((data[JS_SNES_R] &s)?0x20:0)
287 | ((data[JS_SNES_START]&s)?0x40:0) | ((data[JS_SNES_SELECT]&s)?0x80:0);
288 n++;
294 * Multi and Multi2 joysticks
297 if (info->multi || info->multi2) {
299 js_multi_read_packet(info, info->multi2 ? JS_MULTI2_LENGTH : JS_MULTI_LENGTH, data);
301 for (i = 0; i < 5; i++) {
302 s = status_bit[i];
303 if (info->multi & s) {
304 axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
305 axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0);
307 buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0;
309 n++;
310 } else
311 if (info->multi2 & s) {
312 axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
313 axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0);
315 buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0 | (data[JS_MULTI_BUTTON2]&s)?2:0;
317 n++;
323 * PSX controllers
326 if (info->psx && (js_psx_read_packet(info, 2, data) == JS_PSX_NORMAL)) { /* FIXME? >1 PSX pads? */
328 axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1);
329 axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP ?0:1);
331 buttons[n][0] = ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) |
332 (data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100);
334 n++;
337 return -(n != info->pads);
341 * open callback: claim parport.
344 int js_console_open(struct js_dev *dev)
346 #ifdef USE_PARPORT
347 struct js_console_info *info = dev->port->info;
348 if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY;
349 #endif
350 MOD_INC_USE_COUNT;
351 return 0;
355 * close callback: release parport
358 int js_console_close(struct js_dev *dev)
360 #ifdef USE_PARPORT
361 struct js_console_info *info = dev->port->info;
362 #endif
363 MOD_DEC_USE_COUNT;
364 #ifdef USE_PARPORT
365 if (!MOD_IN_USE) parport_release(info->port);
366 #endif
367 return 0;
370 #ifdef MODULE
371 void cleanup_module(void)
373 struct js_console_info *info;
374 int i;
376 while (js_console_port != NULL) {
377 for (i = 0; i < js_console_port->ndevs; i++)
378 if (js_console_port->devs[i] != NULL)
379 js_unregister_device(js_console_port->devs[i]);
380 info = js_console_port->info;
381 #ifdef USE_PARPORT
382 parport_unregister_device(info->port);
383 #else
384 release_region(info->port, 3);
385 #endif
386 js_console_port = js_unregister_port(js_console_port);
389 #endif
392 * js_console_init_corr() initializes correction values of
393 * console gamepads.
396 static void __init js_console_init_corr(int num_axes, struct js_corr *corr)
398 int i;
400 for (i = 0; i < num_axes; i++) {
401 corr[i].type = JS_CORR_BROKEN;
402 corr[i].prec = 0;
403 corr[i].coef[0] = 0;
404 corr[i].coef[1] = 0;
405 corr[i].coef[2] = (1 << 29);
406 corr[i].coef[3] = (1 << 29);
411 * js_console_probe() probes for console gamepads.
412 * Only PSX pads can really be probed for.
415 static struct js_port __init *js_console_probe(int *config, struct js_port *port)
417 char *name[5];
418 int i, psx, axes[5], buttons[5];
419 unsigned char data[2]; /* used for PSX probe */
420 struct js_console_info info;
422 memset(&info, 0, sizeof(struct js_console_info));
424 if (config[0] < 0) return port;
426 #ifdef USE_PARPORT
428 struct parport *pp;
430 if (config[0] > 0x10)
431 for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
432 else
433 for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
435 if (pp == NULL) {
436 printk(KERN_ERR "joy-console: no such parport\n");
437 return port;
440 info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
441 if (!info.port)
442 return port;
445 if (parport_claim(info.port))
447 parport_unregister_device(info.port); /* port currently not available ... */
448 return port;
450 #else
451 info.port = config[0];
452 if (check_region(info.port, 3)) return port;
453 request_region(info.port, 3, "joystick (console pad)");
454 #endif
456 for (i = 0; i < 5; i++)
457 switch(config[i+1]) {
459 case JS_NO_PAD:
461 break;
463 case JS_SNES_PAD:
465 axes[info.pads] = 2;
466 buttons[info.pads] = 8;
467 name[info.pads] = "SNES pad";
468 info.snes |= status_bit[i];
469 info.pads++;
470 break;
472 case JS_NES_PAD:
474 axes[info.pads] = 2;
475 buttons[info.pads] = 4;
476 name[info.pads] = "NES pad";
477 info.nes |= status_bit[i];
478 info.pads++;
479 break;
481 case JS_MULTI_STICK:
483 axes[info.pads] = 2;
484 buttons[info.pads] = 1;
485 name[info.pads] = "Multisystem joystick";
486 info.multi |= status_bit[i];
487 info.pads++;
488 break;
490 case JS_MULTI2_STICK:
492 axes[info.pads] = 2;
493 buttons[info.pads] = 2;
494 name[info.pads] = "Multisystem joystick (2 fire)";
495 info.multi |= status_bit[i];
496 info.pads++;
497 break;
499 case JS_PSX_PAD:
501 info.psx |= status_bit[i];
502 psx = js_psx_read_packet(&info, 2, data);
503 psx = js_psx_read_packet(&info, 2, data);
504 info.psx &= ~status_bit[i];
506 switch(psx) {
507 case JS_PSX_NORMAL:
508 axes[info.pads] = 2;
509 buttons[info.pads] = 10;
510 name[info.pads] = "PSX controller";
511 info.psx |= status_bit[i];
512 info.pads++;
513 break;
514 case JS_PSX_NEGCON:
515 printk(KERN_WARNING "joy-console: NegCon not yet supported...\n");
516 break;
517 case JS_PSX_MOUSE:
518 printk(KERN_WARNING "joy-console: PSX mouse not supported...\n");
519 break;
520 case -1:
521 printk(KERN_ERR "joy-console: no PSX controller found...\n");
522 break;
523 default:
524 printk(KERN_WARNING "joy-console: unknown PSX controller 0x%x\n", psx);
526 break;
528 default:
530 printk(KERN_WARNING "joy-console: pad type %d unknown\n", config[i+1]);
533 if (!info.pads) {
534 #ifdef USE_PARPORT
535 parport_release(info.port);
536 parport_unregister_device(info.port);
537 #else
538 release_region(info.port, 3);
539 #endif
540 return port;
543 port = js_register_port(port, &info, info.pads, sizeof(struct js_console_info), js_console_read);
545 for (i = 0; i < info.pads; i++) {
546 #ifdef USE_PARPORT
547 printk(KERN_INFO "js%d: %s on %s\n",
548 js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close),
549 name[i], info.port->port->name);
550 #else
551 printk(KERN_INFO "js%d: %s at %#x\n",
552 js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close),
553 name[i], info.port);
554 #endif
556 js_console_init_corr(axes[i], port->corr[i]);
559 #ifdef USE_PARPORT
560 parport_release(info.port);
561 #endif
562 return port;
565 #ifndef MODULE
566 void __init js_console_setup(char *str, int *ints)
568 int i;
570 if (!strcmp(str,"js_console"))
571 for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1];
572 if (!strcmp(str,"js_console2"))
573 for (i = 0; i <= ints[0] && i < 6; i++) js_console2[i] = ints[i+1];
574 if (!strcmp(str,"js_console3"))
575 for (i = 0; i <= ints[0] && i < 6; i++) js_console3[i] = ints[i+1];
578 #endif
580 #ifdef MODULE
581 int init_module(void)
582 #else
583 int __init js_console_init(void)
584 #endif
586 js_console_port = js_console_probe(js_console, js_console_port);
587 js_console_port = js_console_probe(js_console2, js_console_port);
588 js_console_port = js_console_probe(js_console3, js_console_port);
590 if (js_console_port) return 0;
592 #ifdef MODULE
593 printk(KERN_WARNING "joy-console: no joysticks specified\n");
594 #endif
595 return -ENODEV;