2 * joy-gravis.c Version 1.2
4 * Copyright (c) 1998 Vojtech Pavlik
8 * This is a module for the Linux joystick driver, supporting
9 * Gravis GrIP digital joystick family.
13 * This program is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2 of the License, or
16 * (at your option) any later version.
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 * Should you need to contact me, the author, you can do so either by
28 * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
29 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
33 #include <asm/system.h>
34 #include <linux/errno.h>
35 #include <linux/ioport.h>
36 #include <linux/joystick.h>
37 #include <linux/kernel.h>
38 #include <linux/module.h>
39 #include <linux/string.h>
41 #define JS_GR_MODE_GPP 1
42 #define JS_GR_LENGTH_GPP 24
43 #define JS_GR_STROBE_GPP 75
45 #define JS_GR_MODE_XT 2
46 #define JS_GR_MODE_BD 3
47 #define JS_GR_LENGTH_XT 4
48 #define JS_GR_STROBE_XT 30
49 #define JS_GR_MAX_CHUNKS_XT 10
50 #define JS_GR_MAX_BITS_XT 30
52 static int js_gr_port_list
[] __initdata
= {0x201, 0};
53 static struct js_port
* js_gr_port __initdata
= NULL
;
57 unsigned char mode
[2];
61 * js_gr_gpp_read_packet() reads a Gravis GamePad Pro packet.
64 static int js_gr_gpp_read_packet(int io
, int shift
, unsigned int *data
)
71 int strobe
= (js_time_speed
* JS_GR_STROBE_GPP
) >> 10;
82 v
= (inb(io
) >> shift
) & 3;
84 if ((u
^ v
) & u
& 1) {
85 data
[0] |= (v
>> 1) << i
++;
89 } while (i
< JS_GR_LENGTH_GPP
&& js_delta(t1
,t
) < strobe
);
91 __restore_flags(flags
);
93 if (i
< JS_GR_LENGTH_GPP
) return -1;
95 for (i
= 0; i
< JS_GR_LENGTH_GPP
&& (data
[0] & 0xfe4210) ^ 0x7c0000; i
++)
96 data
[0] = data
[0] >> 1 | (data
[0] & 1) << 23;
98 return -(i
== JS_GR_LENGTH_GPP
);
102 * js_gr_xt_read_packet() reads a Gravis Xterminator packet.
105 static int js_gr_xt_read_packet(int io
, int shift
, unsigned int *data
)
108 unsigned char u
, v
, w
;
109 unsigned int i
, j
, buf
, crc
;
113 int strobe
= (js_time_speed
* JS_GR_STROBE_XT
) >> 10;
115 data
[0] = data
[1] = data
[2] = data
[3] = 0;
116 status
= buf
= i
= j
= 0;
121 v
= w
= (inb(io
) >> shift
) & 3;
125 u
= (inb(io
) >> shift
) & 3;
131 buf
= (buf
<< 1) | (u
>> 1);
135 if ((((u
^ v
) & (v
^ w
)) >> 1) & ~(u
| v
| w
) & 1) {
137 crc
= buf
^ (buf
>> 7) ^ (buf
>> 14);
138 if (!((crc
^ (0x25cb9e70 >> ((crc
>> 2) & 0x1c))) & 0xf)) {
139 data
[buf
>> 18] = buf
>> 4;
140 status
|= 1 << (buf
>> 18);
153 } while (status
!= 0xf && i
< JS_GR_MAX_BITS_XT
&& j
< JS_GR_MAX_CHUNKS_XT
&& js_delta(t1
,t
) < strobe
);
155 __restore_flags(flags
);
157 return -(status
!= 0xf);
161 * js_gr_read() reads and analyzes GrIP joystick data.
164 static int js_gr_read(void *xinfo
, int **axes
, int **buttons
)
166 struct js_gr_info
*info
= xinfo
;
167 unsigned int data
[JS_GR_LENGTH_XT
];
170 for (i
= 0; i
< 2; i
++)
171 switch (info
->mode
[i
]) {
175 if (js_gr_gpp_read_packet(info
->io
, (i
<< 1) + 4, data
)) return -1;
177 axes
[i
][0] = ((data
[0] >> 15) & 1) - ((data
[0] >> 16) & 1);
178 axes
[i
][1] = ((data
[0] >> 13) & 1) - ((data
[0] >> 12) & 1);
180 data
[0] = ((data
[0] >> 6) & 0x37) | (data
[0] & 0x08) | ((data
[0] << 1) & 0x40) |
181 ((data
[0] << 5) & 0x80) | ((data
[0] << 8) & 0x300);
183 buttons
[i
][0] = (data
[0] & 0xfc) | ((data
[0] >> 1) & 0x101) | ((data
[0] << 1) & 0x202);
189 if (js_gr_xt_read_packet(info
->io
, (i
<< 1) + 4, data
)) return -1;
191 axes
[i
][0] = (data
[0] >> 2) & 0x3f;
192 axes
[i
][1] = 63 - ((data
[0] >> 8) & 0x3f);
193 axes
[i
][2] = (data
[1] >> 2) & 0x3f;
194 axes
[i
][3] = (data
[1] >> 8) & 0x3f;
195 axes
[i
][4] = (data
[2] >> 8) & 0x3f;
197 axes
[i
][5] = ((data
[2] >> 1) & 1) - ( data
[2] & 1);
198 axes
[i
][6] = ((data
[2] >> 2) & 1) - ((data
[2] >> 3) & 1);
199 axes
[i
][7] = ((data
[2] >> 5) & 1) - ((data
[2] >> 4) & 1);
200 axes
[i
][8] = ((data
[2] >> 6) & 1) - ((data
[2] >> 7) & 1);
202 buttons
[i
][0] = (data
[3] >> 3) & 0x7ff;
208 if (js_gr_xt_read_packet(info
->io
, (i
<< 1) + 4, data
)) return -1;
210 axes
[i
][0] = (data
[0] >> 2) & 0x3f;
211 axes
[i
][1] = 63 - ((data
[0] >> 8) & 0x3f);
212 axes
[i
][2] = (data
[2] >> 8) & 0x3f;
214 axes
[i
][3] = ((data
[2] >> 1) & 1) - ( data
[2] & 1);
215 axes
[i
][4] = ((data
[2] >> 2) & 1) - ((data
[2] >> 3) & 1);
217 buttons
[i
][0] = ((data
[3] >> 6) & 0x01) | ((data
[3] >> 3) & 0x06)
218 | ((data
[3] >> 4) & 0x18);
232 * js_gr_open() is a callback from the file open routine.
235 static int js_gr_open(struct js_dev
*jd
)
242 * js_gr_close() is a callback from the file release routine.
245 static int js_gr_close(struct js_dev
*jd
)
252 * js_gr_init_corr() initializes correction values of
256 static void __init
js_gr_init_corr(int mode
, struct js_corr
*corr
)
264 for (i
= 0; i
< 2; i
++) {
265 corr
[i
].type
= JS_CORR_BROKEN
;
269 corr
[i
].coef
[2] = (1 << 29);
270 corr
[i
].coef
[3] = (1 << 29);
277 for (i
= 0; i
< 5; i
++) {
278 corr
[i
].type
= JS_CORR_BROKEN
;
280 corr
[i
].coef
[0] = 31 - 4;
281 corr
[i
].coef
[1] = 32 + 4;
282 corr
[i
].coef
[2] = (1 << 29) / (32 - 14);
283 corr
[i
].coef
[3] = (1 << 29) / (32 - 14);
286 for (i
= 5; i
< 9; i
++) {
287 corr
[i
].type
= JS_CORR_BROKEN
;
291 corr
[i
].coef
[2] = (1 << 29);
292 corr
[i
].coef
[3] = (1 << 29);
299 for (i
= 0; i
< 3; i
++) {
300 corr
[i
].type
= JS_CORR_BROKEN
;
302 corr
[i
].coef
[0] = 31 - 4;
303 corr
[i
].coef
[1] = 32 + 4;
304 corr
[i
].coef
[2] = (1 << 29) / (32 - 14);
305 corr
[i
].coef
[3] = (1 << 29) / (32 - 14);
308 for (i
= 3; i
< 5; i
++) {
309 corr
[i
].type
= JS_CORR_BROKEN
;
313 corr
[i
].coef
[2] = (1 << 29);
314 corr
[i
].coef
[3] = (1 << 29);
323 * js_gr_probe() probes fro GrIP joysticks.
326 static struct js_port __init
*js_gr_probe(int io
, struct js_port
*port
)
328 struct js_gr_info info
;
329 char *names
[] = { NULL
, "Gravis GamePad Pro", "Gravis Xterminator", "Gravis Blackhawk Digital"};
330 char axes
[] = { 0, 2, 9, 5};
331 char buttons
[] = { 0, 10, 11, 5};
332 unsigned int data
[JS_GR_LENGTH_XT
];
335 if (check_region(io
, 1)) return port
;
337 info
.mode
[0] = info
.mode
[1] = 0;
339 for (i
= 0; i
< 2; i
++) {
340 if (!js_gr_gpp_read_packet(io
, (i
<< 1) + 4, data
)) info
.mode
[i
] = JS_GR_MODE_GPP
;
341 if (!js_gr_xt_read_packet(io
, (i
<< 1) + 4, data
)) {
342 if ((data
[3] & 7) == 7)
343 info
.mode
[i
] = JS_GR_MODE_XT
;
344 if ((data
[3] & 7) == 0)
345 info
.mode
[i
] = JS_GR_MODE_BD
;
349 if (!info
.mode
[0] && !info
.mode
[1]) return port
;
353 request_region(io
, 1, "joystick (gravis)");
354 port
= js_register_port(port
, &info
, 2, sizeof(struct js_gr_info
), js_gr_read
);
356 for (i
= 0; i
< 2; i
++)
358 printk(KERN_INFO
"js%d: %s at %#x\n",
359 js_register_device(port
, i
, axes
[info
.mode
[i
]], buttons
[info
.mode
[i
]],
360 names
[info
.mode
[i
]], js_gr_open
, js_gr_close
),
361 names
[info
.mode
[i
]], io
);
362 js_gr_init_corr(info
.mode
[i
], port
->corr
[i
]);
369 int init_module(void)
371 int __init
js_gr_init(void)
376 for (p
= js_gr_port_list
; *p
; p
++) js_gr_port
= js_gr_probe(*p
, js_gr_port
);
377 if (js_gr_port
) return 0;
380 printk(KERN_WARNING
"joy-gravis: no joysticks found\n");
387 void cleanup_module(void)
390 struct js_gr_info
*info
;
392 while (js_gr_port
!= NULL
) {
393 for (i
= 0; i
< js_gr_port
->ndevs
; i
++)
394 if (js_gr_port
->devs
[i
] != NULL
)
395 js_unregister_device(js_gr_port
->devs
[i
]);
396 info
= js_gr_port
->info
;
397 release_region(info
->io
, 1);
398 js_gr_port
= js_unregister_port(js_gr_port
);