2 * joy-console.c Version 0.11V
4 * Copyright (c) 1998 Andree Borrmann
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
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");
51 #define JS_MULTI_STICK 4
52 #define JS_MULTI2_STICK 5
55 #define JS_MAX_PAD JS_PSX_PAD
57 struct js_console_info
{
59 struct pardevice
*port
; /* parport device */
61 int port
; /* hw port */
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 };
84 #define JS_NES_DELAY 6 /* Delay between bits - 6us */
86 #define JS_NES_LENGTH 8 /* The NES pads use 8 bits of data */
90 #define JS_NES_START 2
91 #define JS_NES_SELECT 3
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 */
101 #define JS_SNES_START 2
102 #define JS_SNES_SELECT 3
104 #define JS_SNES_DOWN 5
105 #define JS_SNES_LEFT 6
106 #define JS_SNES_RIGHT 7
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
)
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
)
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
;
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
199 static int js_psx_command(struct js_console_info
*info
, int b
)
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
);
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
)
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);
240 JS_PSX_CTRL_OUT(JS_PSX_SELECT
| JS_PSX_CLOCK
, info
->port
);
241 __restore_flags(flags
);
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
];
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
++) {
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);
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);
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
++) {
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;
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;
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);
337 return -(n
!= info
->pads
);
341 * open callback: claim parport.
344 int js_console_open(struct js_dev
*dev
)
347 struct js_console_info
*info
= dev
->port
->info
;
348 if (!MOD_IN_USE
&& parport_claim(info
->port
)) return -EBUSY
;
355 * close callback: release parport
358 int js_console_close(struct js_dev
*dev
)
361 struct js_console_info
*info
= dev
->port
->info
;
365 if (!MOD_IN_USE
) parport_release(info
->port
);
371 void cleanup_module(void)
373 struct js_console_info
*info
;
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
;
382 parport_unregister_device(info
->port
);
384 release_region(info
->port
, 3);
386 js_console_port
= js_unregister_port(js_console_port
);
392 * js_console_init_corr() initializes correction values of
396 static void __init
js_console_init_corr(int num_axes
, struct js_corr
*corr
)
400 for (i
= 0; i
< num_axes
; i
++) {
401 corr
[i
].type
= JS_CORR_BROKEN
;
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
)
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
;
430 if (config
[0] > 0x10)
431 for (pp
=parport_enumerate(); pp
!= NULL
&& (pp
->base
!=config
[0]); pp
=pp
->next
);
433 for (pp
=parport_enumerate(); pp
!= NULL
&& (config
[0]>0); pp
=pp
->next
) config
[0]--;
436 printk(KERN_ERR
"joy-console: no such parport\n");
440 info
.port
= parport_register_device(pp
, "joystick (console)", NULL
, NULL
, NULL
, PARPORT_DEV_EXCL
, NULL
);
445 if (parport_claim(info
.port
))
447 parport_unregister_device(info
.port
); /* port currently not available ... */
451 info
.port
= config
[0];
452 if (check_region(info
.port
, 3)) return port
;
453 request_region(info
.port
, 3, "joystick (console pad)");
456 for (i
= 0; i
< 5; i
++)
457 switch(config
[i
+1]) {
466 buttons
[info
.pads
] = 8;
467 name
[info
.pads
] = "SNES pad";
468 info
.snes
|= status_bit
[i
];
475 buttons
[info
.pads
] = 4;
476 name
[info
.pads
] = "NES pad";
477 info
.nes
|= status_bit
[i
];
484 buttons
[info
.pads
] = 1;
485 name
[info
.pads
] = "Multisystem joystick";
486 info
.multi
|= status_bit
[i
];
490 case JS_MULTI2_STICK
:
493 buttons
[info
.pads
] = 2;
494 name
[info
.pads
] = "Multisystem joystick (2 fire)";
495 info
.multi
|= status_bit
[i
];
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
];
509 buttons
[info
.pads
] = 10;
510 name
[info
.pads
] = "PSX controller";
511 info
.psx
|= status_bit
[i
];
515 printk(KERN_WARNING
"joy-console: NegCon not yet supported...\n");
518 printk(KERN_WARNING
"joy-console: PSX mouse not supported...\n");
521 printk(KERN_ERR
"joy-console: no PSX controller found...\n");
524 printk(KERN_WARNING
"joy-console: unknown PSX controller 0x%x\n", psx
);
530 printk(KERN_WARNING
"joy-console: pad type %d unknown\n", config
[i
+1]);
535 parport_release(info
.port
);
536 parport_unregister_device(info
.port
);
538 release_region(info
.port
, 3);
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
++) {
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
);
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
),
556 js_console_init_corr(axes
[i
], port
->corr
[i
]);
560 parport_release(info
.port
);
566 void __init
js_console_setup(char *str
, int *ints
)
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];
581 int init_module(void)
583 int __init
js_console_init(void)
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;
593 printk(KERN_WARNING
"joy-console: no joysticks specified\n");