2 * joy-sidewinder.c Version 1.2
4 * Copyright (c) 1998-1999 Vojtech Pavlik
10 * This is a module for the Linux joystick driver, supporting
11 * Microsoft SideWinder digital joystick family.
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
29 * Should you need to contact me, the author, you can do so either by
30 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
31 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
35 #include <asm/system.h>
36 #include <linux/delay.h>
37 #include <linux/errno.h>
38 #include <linux/ioport.h>
39 #include <linux/joystick.h>
40 #include <linux/kernel.h>
41 #include <linux/module.h>
42 #include <linux/string.h>
43 #include <linux/init.h>
46 * These are really magic values. Changing them can make a problem go away,
47 * as well as break everything.
52 #define JS_SW_START 400 /* The time we wait for the first bit [400 us] */
53 #define JS_SW_STROBE 45 /* Max time per bit [45 us] */
54 #define JS_SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */
55 #define JS_SW_KICK 45 /* Wait after A0 fall till kick [45 us] */
56 #define JS_SW_END 8 /* Number of bits before end of packet to kick */
57 #define JS_SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */
58 #define JS_SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */
59 #define JS_SW_OK 64 /* Number of packet read successes to switch optimization back on */
60 #define JS_SW_LENGTH 512 /* Max number of bits in a packet */
63 * SideWinder joystick types ...
66 #define JS_SW_TYPE_3DP 1
67 #define JS_SW_TYPE_F23 2
68 #define JS_SW_TYPE_GP 3
69 #define JS_SW_TYPE_PP 4
70 #define JS_SW_TYPE_FFP 5
71 #define JS_SW_TYPE_FSP 6
72 #define JS_SW_TYPE_FFW 7
74 static int js_sw_port_list
[] __initdata
= {0x201, 0};
75 static struct js_port
* js_sw_port __initdata
= NULL
;
80 } js_sw_hat_to_axis
[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
97 unsigned int js_sw_io_speed
= 0;
100 * js_sw_measure_speed() measures the gameport i/o speed.
103 static int __init
js_sw_measure_speed(int io
)
107 #define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
108 #define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
110 unsigned int i
, t
, t1
, t2
, t3
, tx
;
115 for(i
= 0; i
< 50; i
++) {
116 save_flags(flags
); /* Yes, all CPUs */
119 for(t
= 0; t
< 50; t
++) inb(io
);
122 restore_flags(flags
);
124 if ((t
= DELTA(t2
,t1
) - DELTA(t3
,t2
)) < tx
) tx
= t
;
131 unsigned int j
, t
= 0;
133 j
= jiffies
; while (j
== jiffies
);
134 j
= jiffies
; while (j
== jiffies
) { t
++; inb(0x201); }
136 return t
* HZ
/ 1000;
142 * js_sw_read_packet() is a function which reads either a data packet, or an
143 * identification packet from a SideWinder joystick. Better don't try to
144 * understand this, since all the ugliness of the Microsoft Digital
145 * Overdrive protocol is concentrated in this function. If you really want
146 * to know how this works, first go watch a couple horror movies, so that
147 * you are well prepared, read US patent #5628686 and then e-mail me,
148 * and I'll send you an explanation.
149 * Vojtech <vojtech@suse.cz>
152 static int js_sw_read_packet(int io
, int speed
, unsigned char *buf
, int length
, int id
)
155 int timeout
, bitout
, sched
, i
, kick
, start
, strobe
;
156 unsigned char pending
, u
, v
;
158 i
= -id
; /* Don't care about data, only want ID */
159 timeout
= id
? (JS_SW_TIMEOUT
* speed
) >> 10 : 0; /* Set up global timeout for ID packet */
160 kick
= id
? (JS_SW_KICK
* speed
) >> 10 : 0; /* Set up kick timeout for ID packet */
161 start
= (JS_SW_START
* speed
) >> 10;
162 strobe
= (JS_SW_STROBE
* speed
) >> 10;
167 __save_flags(flags
); /* Quiet, please */
170 outb(0xff, io
); /* Trigger */
177 } while (!(~v
& u
& 0x10) && (bitout
> 0)); /* Wait for first falling edge on clock */
179 if (bitout
> 0) bitout
= strobe
; /* Extend time if not timed out */
181 while ((timeout
> 0 || bitout
> 0) && (i
< length
)) {
184 bitout
--; /* Decrement timers */
190 if ((~u
& v
& 0x10) && (bitout
> 0)) { /* Rising edge on clock - data bit */
191 if (i
>= 0) /* Want this data */
192 buf
[i
] = v
>> 5; /* Store it */
193 i
++; /* Advance index */
194 bitout
= strobe
; /* Extend timeout for next bit */
197 if (kick
&& (~v
& u
& 0x01)) { /* Falling edge on axis 0 */
198 sched
= kick
; /* Schedule second trigger */
199 kick
= 0; /* Don't schedule next time on falling edge */
200 pending
= 1; /* Mark schedule */
203 if (pending
&& sched
< 0 && (i
> -JS_SW_END
)) { /* Second trigger time */
204 outb(0xff, io
); /* Trigger */
205 bitout
= start
; /* Long bit timeout */
206 pending
= 0; /* Unmark schedule */
207 timeout
= 0; /* Switch from global to bit timeouts */
211 __restore_flags(flags
); /* Done - relax */
216 printk(KERN_DEBUG
"joy-sidewinder: Read %d triplets. [", i
);
217 for (j
= 0; j
< i
; j
++) printk("%d", buf
[j
]);
226 * js_sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
227 * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
228 * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
229 * is number of bits per triplet.
232 #define GB(pos,num,shift) js_sw_get_bits(buf, pos, num, shift, info->bits)
234 static __u64
js_sw_get_bits(unsigned char *buf
, int pos
, int num
, char shift
, char bits
)
237 int tri
= pos
% bits
; /* Start position */
242 data
|= (__u64
)((buf
[i
] >> tri
++) & 1) << bit
++; /* Transfer bit */
244 i
++; /* Next triplet */
253 * js_sw_init_digital() initializes a SideWinder 3D Pro joystick
257 static void js_sw_init_digital(int io
, int speed
)
259 int seq
[] = { 140, 140+725, 140+300, 0 };
268 outb(0xff, io
); /* Trigger */
269 t
= (JS_SW_TIMEOUT
* speed
) >> 10;
270 while ((inb(io
) & 1) && t
) t
--; /* Wait for axis to fall back to 0 */
271 udelay(seq
[i
]); /* Delay magic time */
274 outb(0xff, io
); /* Last trigger */
276 __restore_flags(flags
);
280 * js_sw_parity() computes parity of __u64
283 static int js_sw_parity(__u64 t
)
285 int x
= t
^ (t
>> 32);
295 * js_sw_ccheck() checks synchronization bits and computes checksum of nibbles.
298 static int js_sw_check(__u64 t
)
302 if ((t
& 0x8080808080808080ULL
) ^ 0x80) /* Sync */
305 while (t
) { /* Sum */
314 * js_sw_parse() analyzes SideWinder joystick data, and writes the results into
315 * the axes and buttons arrays.
318 static int js_sw_parse(unsigned char *buf
, struct js_sw_info
*info
, int **axes
, int **buttons
)
322 switch (info
->type
) {
327 if (js_sw_check(GB(0,64,0)) || (hat
= GB(6,1,3) | GB(60,3,0)) > 8) return -1;
329 axes
[0][0] = GB( 3,3,7) | GB(16,7,0);
330 axes
[0][1] = GB( 0,3,7) | GB(24,7,0);
331 axes
[0][2] = GB(35,2,7) | GB(40,7,0);
332 axes
[0][3] = GB(32,3,7) | GB(48,7,0);
333 axes
[0][4] = js_sw_hat_to_axis
[hat
].x
;
334 axes
[0][5] = js_sw_hat_to_axis
[hat
].y
;
335 buttons
[0][0] = ~(GB(37,1,8) | GB(38,1,7) | GB(8,7,0));
341 for (i
= 0; i
< info
->number
* 15; i
+= 15) {
343 if (js_sw_parity(GB(i
,15,0))) return -1;
345 axes
[i
][0] = GB(i
+3,1,0) - GB(i
+2,1,0);
346 axes
[i
][1] = GB(i
+0,1,0) - GB(i
+1,1,0);
347 buttons
[i
][0] = ~GB(i
+4,10,0);
356 if (!js_sw_parity(GB(0,48,0)) || (hat
= GB(42,4,0)) > 8) return -1;
358 axes
[0][0] = GB( 9,10,0);
359 axes
[0][1] = GB(19,10,0);
360 axes
[0][2] = GB(36, 6,0);
361 axes
[0][3] = GB(29, 7,0);
362 axes
[0][4] = js_sw_hat_to_axis
[hat
].x
;
363 axes
[0][5] = js_sw_hat_to_axis
[hat
].y
;
364 buttons
[0][0] = ~GB(0,9,0);
370 if (!js_sw_parity(GB(0,43,0)) || (hat
= GB(28,4,0)) > 8) return -1;
372 axes
[0][0] = GB( 0,10,0);
373 axes
[0][1] = GB(16,10,0);
374 axes
[0][2] = GB(32, 6,0);
375 axes
[0][3] = js_sw_hat_to_axis
[hat
].x
;
376 axes
[0][4] = js_sw_hat_to_axis
[hat
].y
;
377 buttons
[0][0] = ~(GB(10,6,0) | GB(26,2,6) | GB(38,2,8));
383 if (!js_sw_parity(GB(0,33,0))) return -1;
385 axes
[0][0] = GB( 0,10,0);
386 axes
[0][1] = GB(10, 6,0);
387 axes
[0][2] = GB(16, 6,0);
388 buttons
[0][0] = ~GB(22,8,0);
397 * js_sw_read() reads SideWinder joystick data, and reinitializes
398 * the joystick in case of persistent problems. This is the function that is
399 * called from the generic code to poll the joystick.
402 static int js_sw_read(void *xinfo
, int **axes
, int **buttons
)
404 struct js_sw_info
*info
= xinfo
;
405 unsigned char buf
[JS_SW_LENGTH
];
408 i
= js_sw_read_packet(info
->io
, info
->speed
, buf
, info
->length
, 0);
410 if (info
->type
<= JS_SW_TYPE_F23
&& info
->length
== 66 && i
!= 66) { /* Broken packet, try to fix */
412 if (i
== 64 && !js_sw_check(js_sw_get_bits(buf
,0,64,0,1))) { /* Last init failed, 1 bit mode */
413 printk(KERN_WARNING
"joy-sidewinder: Joystick in wrong mode on %#x"
414 " - going to reinitialize.\n", info
->io
);
415 info
->fail
= JS_SW_FAIL
; /* Reinitialize */
416 i
= 128; /* Bogus value */
419 if (i
< 66 && GB(0,64,0) == GB(i
*3-66,64,0)) /* 1 == 3 */
420 i
= 66; /* Everything is fine */
422 if (i
< 66 && GB(0,64,0) == GB(66,64,0)) /* 1 == 2 */
423 i
= 66; /* Everything is fine */
425 if (i
< 66 && GB(i
*3-132,64,0) == GB(i
*3-66,64,0)) { /* 2 == 3 */
426 memmove(buf
, buf
+ i
- 22, 22); /* Move data */
427 i
= 66; /* Carry on */
431 if (i
== info
->length
&& !js_sw_parse(buf
, info
, axes
, buttons
)) { /* Parse data */
436 if (info
->type
<= JS_SW_TYPE_F23
&& info
->length
== 66 /* Many packets OK */
437 && info
->ok
> JS_SW_OK
) {
439 printk(KERN_INFO
"joy-sidewinder: No more trouble on %#x"
440 " - enabling optimization again.\n", info
->io
);
450 if (info
->type
<= JS_SW_TYPE_F23
&& info
->length
== 22 /* Consecutive bad packets */
451 && info
->fail
> JS_SW_BAD
) {
453 printk(KERN_INFO
"joy-sidewinder: Many bit errors on %#x"
454 " - disabling optimization.\n", info
->io
);
458 if (info
->fail
< JS_SW_FAIL
) return -1; /* Not enough, don't reinitialize yet */
460 printk(KERN_WARNING
"joy-sidewinder: Too many bit errors on %#x"
461 " - reinitializing joystick.\n", info
->io
);
463 if (!i
&& info
->type
<= JS_SW_TYPE_F23
) { /* 3D Pro can be in analog mode */
464 udelay(3 * JS_SW_TIMEOUT
);
465 js_sw_init_digital(info
->io
, info
->speed
);
468 udelay(JS_SW_TIMEOUT
);
469 i
= js_sw_read_packet(info
->io
, info
->speed
, buf
, JS_SW_LENGTH
, 0); /* Read normal data packet */
470 udelay(JS_SW_TIMEOUT
);
471 js_sw_read_packet(info
->io
, info
->speed
, buf
, JS_SW_LENGTH
, i
); /* Read ID packet, this initializes the stick */
473 info
->fail
= JS_SW_FAIL
;
479 * js_sw_init_corr() initializes the correction values for
483 static void __init
js_sw_init_corr(int num_axes
, int type
, int number
, struct js_corr
**corr
)
487 for (i
= 0; i
< number
; i
++) {
489 for (j
= 0; j
< num_axes
; j
++) {
490 corr
[i
][j
].type
= JS_CORR_BROKEN
;
492 corr
[i
][j
].coef
[0] = 511 - 32;
493 corr
[i
][j
].coef
[1] = 512 + 32;
494 corr
[i
][j
].coef
[2] = (1 << 29) / (511 - 32);
495 corr
[i
][j
].coef
[3] = (1 << 29) / (511 - 32);
503 corr
[i
][2].type
= JS_CORR_BROKEN
;
505 corr
[i
][2].coef
[0] = 255 - 16;
506 corr
[i
][2].coef
[1] = 256 + 16;
507 corr
[i
][2].coef
[2] = (1 << 29) / (255 - 16);
508 corr
[i
][2].coef
[3] = (1 << 29) / (255 - 16);
517 corr
[i
][2].type
= JS_CORR_BROKEN
;
519 corr
[i
][2].coef
[0] = 31 - 2;
520 corr
[i
][2].coef
[1] = 32 + 2;
521 corr
[i
][2].coef
[2] = (1 << 29) / (31 - 2);
522 corr
[i
][2].coef
[3] = (1 << 29) / (31 - 2);
524 corr
[i
][3].type
= JS_CORR_BROKEN
;
526 corr
[i
][3].coef
[0] = 63 - 4;
527 corr
[i
][3].coef
[1] = 64 + 4;
528 corr
[i
][3].coef
[2] = (1 << 29) / (63 - 4);
529 corr
[i
][3].coef
[3] = (1 << 29) / (63 - 4);
537 corr
[i
][0].type
= JS_CORR_BROKEN
;
539 corr
[i
][0].coef
[0] = 511 - 8;
540 corr
[i
][0].coef
[1] = 512 + 8;
541 corr
[i
][0].coef
[2] = (1 << 29) / (511 - 8);
542 corr
[i
][0].coef
[3] = (1 << 29) / (511 - 8);
544 corr
[i
][1].type
= JS_CORR_BROKEN
;
546 corr
[i
][1].coef
[0] = 63;
547 corr
[i
][1].coef
[1] = 63;
548 corr
[i
][1].coef
[2] = (1 << 29) / -63;
549 corr
[i
][1].coef
[3] = (1 << 29) / -63;
551 corr
[i
][2].type
= JS_CORR_BROKEN
;
553 corr
[i
][2].coef
[0] = 63;
554 corr
[i
][2].coef
[1] = 63;
555 corr
[i
][2].coef
[2] = (1 << 29) / -63;
556 corr
[i
][2].coef
[3] = (1 << 29) / -63;
564 corr
[i
][2].type
= JS_CORR_BROKEN
;
566 corr
[i
][2].coef
[0] = 31 - 2;
567 corr
[i
][2].coef
[1] = 32 + 2;
568 corr
[i
][2].coef
[2] = (1 << 29) / (31 - 2);
569 corr
[i
][2].coef
[3] = (1 << 29) / (31 - 2);
580 for (; j
< num_axes
; j
++) { /* Hats & other binary axes */
581 corr
[i
][j
].type
= JS_CORR_BROKEN
;
583 corr
[i
][j
].coef
[0] = 0;
584 corr
[i
][j
].coef
[1] = 0;
585 corr
[i
][j
].coef
[2] = (1 << 29);
586 corr
[i
][j
].coef
[3] = (1 << 29);
592 * js_sw_print_packet() prints the contents of a SideWinder packet.
595 static void js_sw_print_packet(char *name
, int length
, unsigned char *buf
, char bits
)
599 printk("joy-sidewinder: %s packet, %d bits. [", name
, length
);
600 for (i
= (((length
+ 3) >> 2) - 1); i
>= 0; i
--)
601 printk("%x", (int)js_sw_get_bits(buf
, i
<< 2, 4, 0, bits
));
606 * js_sw_3dp_id() translates the 3DP id into a human legible string.
607 * Unfortunately I don't know how to do this for the other SW types.
610 static void js_sw_3dp_id(unsigned char *buf
, char *comment
)
615 for (i
= 0; i
< 7; i
++) /* ASCII PnP ID */
616 pnp
[i
] = js_sw_get_bits(buf
, 24+8*i
, 8, 0, 1);
618 for (i
= 0; i
< 8; i
++) /* ASCII firmware revision */
619 rev
[i
] = js_sw_get_bits(buf
, 88+8*i
, 8, 0, 1);
623 sprintf(comment
, " [PnP %d.%02d id %s rev %s]",
624 (int) (js_sw_get_bits(buf
, 8, 6, 6, 1) | /* Two 6-bit values */
625 js_sw_get_bits(buf
, 16, 6, 0, 1)) / 100,
626 (int) (js_sw_get_bits(buf
, 8, 6, 6, 1) |
627 js_sw_get_bits(buf
, 16, 6, 0, 1)) % 100,
632 * js_sw_guess_mode() checks the upper two button bits for toggling -
633 * indication of that the joystick is in 3-bit mode. This is documented
634 * behavior for 3DP ID packet, and for example the FSP does this in
635 * normal packets instead. Fun ...
638 static int js_sw_guess_mode(unsigned char *buf
, int len
)
641 unsigned char xor = 0;
642 for (i
= 1; i
< len
; i
++) xor |= (buf
[i
- 1] ^ buf
[i
]) & 6;
643 return !!xor * 2 + 1;
647 * js_sw_probe() probes for SideWinder type joysticks.
650 static struct js_port __init
*js_sw_probe(int io
, struct js_port
*port
)
652 struct js_sw_info info
;
653 char *names
[] = {NULL
, "SideWinder 3D Pro", "Flight2000 F-23", "SideWinder GamePad", "SideWinder Precision Pro",
654 "SideWinder Force Feedback Pro", "SideWinder FreeStyle Pro", "SideWinder Force Feedback Wheel" };
655 char axes
[] = { 0, 6, 6, 2, 6, 6, 5, 3 };
656 char buttons
[] = { 0, 9, 9, 10, 9, 9, 10, 8 };
657 int i
, j
, k
, l
, speed
;
658 unsigned char buf
[JS_SW_LENGTH
];
659 unsigned char idbuf
[JS_SW_LENGTH
];
665 if (check_region(io
, 1)) return port
;
667 speed
= js_sw_measure_speed(io
);
669 i
= js_sw_read_packet(io
, speed
, buf
, JS_SW_LENGTH
, 0); /* Read normal packet */
670 m
|= js_sw_guess_mode(buf
, i
); /* Data packet (1-bit) can carry mode info [FSP] */
671 udelay(JS_SW_TIMEOUT
);
674 printk(KERN_DEBUG
"joy-sidewinder: Init 1: Mode %d. Length %d.\n", m
, i
);
677 if (!i
) { /* No data. 3d Pro analog mode? */
678 js_sw_init_digital(io
, speed
); /* Switch to digital */
679 udelay(JS_SW_TIMEOUT
);
680 i
= js_sw_read_packet(io
, speed
, buf
, JS_SW_LENGTH
, 0); /* Retry reading packet */
681 udelay(JS_SW_TIMEOUT
);
683 printk(KERN_DEBUG
"joy-sidewinder: Init 1b: Length %d.\n", i
);
685 if (!i
) return port
; /* No data -> FAIL */
688 j
= js_sw_read_packet(io
, speed
, idbuf
, JS_SW_LENGTH
, i
); /* Read ID. This initializes the stick */
689 m
|= js_sw_guess_mode(idbuf
, j
); /* ID packet should carry mode info [3DP] */
692 printk(KERN_DEBUG
"joy-sidewinder: Init 2: Mode %d. ID Length %d.\n", m
, j
);
695 if (!j
) { /* Read ID failed. Happens in 1-bit mode on PP */
696 udelay(JS_SW_TIMEOUT
);
697 i
= js_sw_read_packet(io
, speed
, buf
, JS_SW_LENGTH
, 0); /* Retry reading packet */
699 printk(KERN_DEBUG
"joy-sidewinder: Init 2b: Mode %d. Length %d.\n", m
, i
);
702 udelay(JS_SW_TIMEOUT
);
703 j
= js_sw_read_packet(io
, speed
, idbuf
, JS_SW_LENGTH
, i
);/* Retry reading ID */
705 printk(KERN_DEBUG
"joy-sidewinder: Init 2c: ID Length %d.\n", j
);
710 k
= JS_SW_FAIL
; /* Try JS_SW_FAIL times */
715 udelay(JS_SW_TIMEOUT
);
716 i
= js_sw_read_packet(io
, speed
, buf
, JS_SW_LENGTH
, 0); /* Read data packet */
718 printk(KERN_DEBUG
"joy-sidewinder: Init 3: Length %d.\n", i
);
721 if (i
> l
) { /* Longer? As we can only lose bits, it makes */
722 /* no sense to try detection for a packet shorter */
723 l
= i
; /* than the previous one */
737 case 45: /* Ambiguous packet length */
738 if (j
<= 40) { /* ID length less or eq 40 -> FSP */
740 info
.type
= JS_SW_TYPE_FSP
;
747 info
.type
= JS_SW_TYPE_GP
;
751 info
.type
= JS_SW_TYPE_FFW
;
753 case 48: /* Ambiguous */
754 if (j
== 14) { /* ID lenght 14*3 -> FFP */
755 info
.type
= JS_SW_TYPE_FFP
;
756 sprintf(comment
, " [AC %s]", js_sw_get_bits(idbuf
,38,1,0,3) ? "off" : "on");
758 info
.type
= JS_SW_TYPE_PP
;
763 info
.type
= JS_SW_TYPE_3DP
;
764 if (j
== 160) js_sw_3dp_id(idbuf
, comment
);
769 } while (k
&& !info
.type
);
772 printk(KERN_WARNING
"joy-sidewinder: unknown joystick device detected "
773 "(io=%#x), contact <vojtech@suse.cz>\n", io
);
774 js_sw_print_packet("ID", j
* 3, idbuf
, 3);
775 js_sw_print_packet("Data", i
* m
, buf
, m
);
780 js_sw_print_packet("ID", j
* 3, idbuf
, 3);
781 js_sw_print_packet("Data", i
* m
, buf
, m
);
786 request_region(io
, 1, "joystick (sidewinder)");
788 port
= js_register_port(port
, &info
, info
.number
, sizeof(struct js_sw_info
), js_sw_read
);
790 for (i
= 0; i
< info
.number
; i
++)
791 printk(KERN_INFO
"js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n",
792 js_register_device(port
, i
, axes
[info
.type
], buttons
[info
.type
],
793 names
[info
.type
], THIS_MODULE
, NULL
, NULL
), names
[info
.type
], comment
, io
,
794 1000000 / speed
, m
, j
, k
);
796 js_sw_init_corr(axes
[info
.type
], info
.type
, info
.number
, port
->corr
);
802 int init_module(void)
804 int __init
js_sw_init(void)
809 for (p
= js_sw_port_list
; *p
; p
++) js_sw_port
= js_sw_probe(*p
, js_sw_port
);
810 if (js_sw_port
) return 0;
813 printk(KERN_WARNING
"joy-sidewinder: no joysticks found\n");
820 void cleanup_module(void)
823 struct js_sw_info
*info
;
826 for (i
= 0; i
< js_sw_port
->ndevs
; i
++)
827 if (js_sw_port
->devs
[i
])
828 js_unregister_device(js_sw_port
->devs
[i
]);
829 info
= js_sw_port
->info
;
830 release_region(info
->io
, 1);
831 js_sw_port
= js_unregister_port(js_sw_port
);