Commit 98a84131926ebafe868c65631b69d4912922211e
Committed by
Dmitry Torokhov
1 parent
45b2604eaa
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
Input: gameport - use module_gameport_driver
This patch converts the drivers in drivers/input/* to use module_gameport_driver() macro which makes the code smaller and a bit simpler. Signed-off-by: Axel Lin <axel.lin@gmail.com> Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
Showing 11 changed files with 11 additions and 136 deletions Inline Diff
- drivers/input/joystick/a3d.c
- drivers/input/joystick/adi.c
- drivers/input/joystick/cobra.c
- drivers/input/joystick/gf2k.c
- drivers/input/joystick/grip.c
- drivers/input/joystick/grip_mp.c
- drivers/input/joystick/guillemot.c
- drivers/input/joystick/interact.c
- drivers/input/joystick/joydump.c
- drivers/input/joystick/sidewinder.c
- drivers/input/joystick/tmdc.c
drivers/input/joystick/a3d.c
1 | /* | 1 | /* |
2 | * Copyright (c) 1998-2001 Vojtech Pavlik | 2 | * Copyright (c) 1998-2001 Vojtech Pavlik |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
6 | * FP-Gaming Assassin 3D joystick driver for Linux | 6 | * FP-Gaming Assassin 3D joystick driver for Linux |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Should you need to contact me, the author, you can do so either by | 24 | * Should you need to contact me, the author, you can do so either by |
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
33 | #include <linux/gameport.h> | 33 | #include <linux/gameport.h> |
34 | #include <linux/input.h> | 34 | #include <linux/input.h> |
35 | #include <linux/jiffies.h> | 35 | #include <linux/jiffies.h> |
36 | 36 | ||
37 | #define DRIVER_DESC "FP-Gaming Assassin 3D joystick driver" | 37 | #define DRIVER_DESC "FP-Gaming Assassin 3D joystick driver" |
38 | 38 | ||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
40 | MODULE_DESCRIPTION(DRIVER_DESC); | 40 | MODULE_DESCRIPTION(DRIVER_DESC); |
41 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
42 | 42 | ||
43 | #define A3D_MAX_START 600 /* 600 us */ | 43 | #define A3D_MAX_START 600 /* 600 us */ |
44 | #define A3D_MAX_STROBE 80 /* 80 us */ | 44 | #define A3D_MAX_STROBE 80 /* 80 us */ |
45 | #define A3D_MAX_LENGTH 40 /* 40*3 bits */ | 45 | #define A3D_MAX_LENGTH 40 /* 40*3 bits */ |
46 | 46 | ||
47 | #define A3D_MODE_A3D 1 /* Assassin 3D */ | 47 | #define A3D_MODE_A3D 1 /* Assassin 3D */ |
48 | #define A3D_MODE_PAN 2 /* Panther */ | 48 | #define A3D_MODE_PAN 2 /* Panther */ |
49 | #define A3D_MODE_OEM 3 /* Panther OEM version */ | 49 | #define A3D_MODE_OEM 3 /* Panther OEM version */ |
50 | #define A3D_MODE_PXL 4 /* Panther XL */ | 50 | #define A3D_MODE_PXL 4 /* Panther XL */ |
51 | 51 | ||
52 | static char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther", | 52 | static char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther", |
53 | "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" }; | 53 | "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" }; |
54 | 54 | ||
55 | struct a3d { | 55 | struct a3d { |
56 | struct gameport *gameport; | 56 | struct gameport *gameport; |
57 | struct gameport *adc; | 57 | struct gameport *adc; |
58 | struct input_dev *dev; | 58 | struct input_dev *dev; |
59 | int axes[4]; | 59 | int axes[4]; |
60 | int buttons; | 60 | int buttons; |
61 | int mode; | 61 | int mode; |
62 | int length; | 62 | int length; |
63 | int reads; | 63 | int reads; |
64 | int bads; | 64 | int bads; |
65 | char phys[32]; | 65 | char phys[32]; |
66 | }; | 66 | }; |
67 | 67 | ||
68 | /* | 68 | /* |
69 | * a3d_read_packet() reads an Assassin 3D packet. | 69 | * a3d_read_packet() reads an Assassin 3D packet. |
70 | */ | 70 | */ |
71 | 71 | ||
72 | static int a3d_read_packet(struct gameport *gameport, int length, char *data) | 72 | static int a3d_read_packet(struct gameport *gameport, int length, char *data) |
73 | { | 73 | { |
74 | unsigned long flags; | 74 | unsigned long flags; |
75 | unsigned char u, v; | 75 | unsigned char u, v; |
76 | unsigned int t, s; | 76 | unsigned int t, s; |
77 | int i; | 77 | int i; |
78 | 78 | ||
79 | i = 0; | 79 | i = 0; |
80 | t = gameport_time(gameport, A3D_MAX_START); | 80 | t = gameport_time(gameport, A3D_MAX_START); |
81 | s = gameport_time(gameport, A3D_MAX_STROBE); | 81 | s = gameport_time(gameport, A3D_MAX_STROBE); |
82 | 82 | ||
83 | local_irq_save(flags); | 83 | local_irq_save(flags); |
84 | gameport_trigger(gameport); | 84 | gameport_trigger(gameport); |
85 | v = gameport_read(gameport); | 85 | v = gameport_read(gameport); |
86 | 86 | ||
87 | while (t > 0 && i < length) { | 87 | while (t > 0 && i < length) { |
88 | t--; | 88 | t--; |
89 | u = v; v = gameport_read(gameport); | 89 | u = v; v = gameport_read(gameport); |
90 | if (~v & u & 0x10) { | 90 | if (~v & u & 0x10) { |
91 | data[i++] = v >> 5; | 91 | data[i++] = v >> 5; |
92 | t = s; | 92 | t = s; |
93 | } | 93 | } |
94 | } | 94 | } |
95 | 95 | ||
96 | local_irq_restore(flags); | 96 | local_irq_restore(flags); |
97 | 97 | ||
98 | return i; | 98 | return i; |
99 | } | 99 | } |
100 | 100 | ||
101 | /* | 101 | /* |
102 | * a3d_csum() computes checksum of triplet packet | 102 | * a3d_csum() computes checksum of triplet packet |
103 | */ | 103 | */ |
104 | 104 | ||
105 | static int a3d_csum(char *data, int count) | 105 | static int a3d_csum(char *data, int count) |
106 | { | 106 | { |
107 | int i, csum = 0; | 107 | int i, csum = 0; |
108 | 108 | ||
109 | for (i = 0; i < count - 2; i++) | 109 | for (i = 0; i < count - 2; i++) |
110 | csum += data[i]; | 110 | csum += data[i]; |
111 | return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]); | 111 | return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]); |
112 | } | 112 | } |
113 | 113 | ||
114 | static void a3d_read(struct a3d *a3d, unsigned char *data) | 114 | static void a3d_read(struct a3d *a3d, unsigned char *data) |
115 | { | 115 | { |
116 | struct input_dev *dev = a3d->dev; | 116 | struct input_dev *dev = a3d->dev; |
117 | 117 | ||
118 | switch (a3d->mode) { | 118 | switch (a3d->mode) { |
119 | 119 | ||
120 | case A3D_MODE_A3D: | 120 | case A3D_MODE_A3D: |
121 | case A3D_MODE_OEM: | 121 | case A3D_MODE_OEM: |
122 | case A3D_MODE_PAN: | 122 | case A3D_MODE_PAN: |
123 | 123 | ||
124 | input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7)); | 124 | input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7)); |
125 | input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7)); | 125 | input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7)); |
126 | 126 | ||
127 | input_report_key(dev, BTN_RIGHT, data[2] & 1); | 127 | input_report_key(dev, BTN_RIGHT, data[2] & 1); |
128 | input_report_key(dev, BTN_LEFT, data[3] & 2); | 128 | input_report_key(dev, BTN_LEFT, data[3] & 2); |
129 | input_report_key(dev, BTN_MIDDLE, data[3] & 4); | 129 | input_report_key(dev, BTN_MIDDLE, data[3] & 4); |
130 | 130 | ||
131 | input_sync(dev); | 131 | input_sync(dev); |
132 | 132 | ||
133 | a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128; | 133 | a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128; |
134 | a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128; | 134 | a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128; |
135 | a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128; | 135 | a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128; |
136 | a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128; | 136 | a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128; |
137 | 137 | ||
138 | a3d->buttons = ((data[3] << 3) | data[4]) & 0xf; | 138 | a3d->buttons = ((data[3] << 3) | data[4]) & 0xf; |
139 | 139 | ||
140 | break; | 140 | break; |
141 | 141 | ||
142 | case A3D_MODE_PXL: | 142 | case A3D_MODE_PXL: |
143 | 143 | ||
144 | input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7)); | 144 | input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7)); |
145 | input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7)); | 145 | input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7)); |
146 | 146 | ||
147 | input_report_key(dev, BTN_RIGHT, data[2] & 1); | 147 | input_report_key(dev, BTN_RIGHT, data[2] & 1); |
148 | input_report_key(dev, BTN_LEFT, data[3] & 2); | 148 | input_report_key(dev, BTN_LEFT, data[3] & 2); |
149 | input_report_key(dev, BTN_MIDDLE, data[3] & 4); | 149 | input_report_key(dev, BTN_MIDDLE, data[3] & 4); |
150 | input_report_key(dev, BTN_SIDE, data[7] & 2); | 150 | input_report_key(dev, BTN_SIDE, data[7] & 2); |
151 | input_report_key(dev, BTN_EXTRA, data[7] & 4); | 151 | input_report_key(dev, BTN_EXTRA, data[7] & 4); |
152 | 152 | ||
153 | input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128); | 153 | input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128); |
154 | input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128); | 154 | input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128); |
155 | input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128); | 155 | input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128); |
156 | input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128); | 156 | input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128); |
157 | 157 | ||
158 | input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1)); | 158 | input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1)); |
159 | input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1)); | 159 | input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1)); |
160 | input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1)); | 160 | input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1)); |
161 | input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1)); | 161 | input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1)); |
162 | 162 | ||
163 | input_report_key(dev, BTN_TRIGGER, data[8] & 1); | 163 | input_report_key(dev, BTN_TRIGGER, data[8] & 1); |
164 | input_report_key(dev, BTN_THUMB, data[8] & 2); | 164 | input_report_key(dev, BTN_THUMB, data[8] & 2); |
165 | input_report_key(dev, BTN_TOP, data[8] & 4); | 165 | input_report_key(dev, BTN_TOP, data[8] & 4); |
166 | input_report_key(dev, BTN_PINKIE, data[7] & 1); | 166 | input_report_key(dev, BTN_PINKIE, data[7] & 1); |
167 | 167 | ||
168 | input_sync(dev); | 168 | input_sync(dev); |
169 | 169 | ||
170 | break; | 170 | break; |
171 | } | 171 | } |
172 | } | 172 | } |
173 | 173 | ||
174 | 174 | ||
175 | /* | 175 | /* |
176 | * a3d_poll() reads and analyzes A3D joystick data. | 176 | * a3d_poll() reads and analyzes A3D joystick data. |
177 | */ | 177 | */ |
178 | 178 | ||
179 | static void a3d_poll(struct gameport *gameport) | 179 | static void a3d_poll(struct gameport *gameport) |
180 | { | 180 | { |
181 | struct a3d *a3d = gameport_get_drvdata(gameport); | 181 | struct a3d *a3d = gameport_get_drvdata(gameport); |
182 | unsigned char data[A3D_MAX_LENGTH]; | 182 | unsigned char data[A3D_MAX_LENGTH]; |
183 | 183 | ||
184 | a3d->reads++; | 184 | a3d->reads++; |
185 | if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length || | 185 | if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length || |
186 | data[0] != a3d->mode || a3d_csum(data, a3d->length)) | 186 | data[0] != a3d->mode || a3d_csum(data, a3d->length)) |
187 | a3d->bads++; | 187 | a3d->bads++; |
188 | else | 188 | else |
189 | a3d_read(a3d, data); | 189 | a3d_read(a3d, data); |
190 | } | 190 | } |
191 | 191 | ||
192 | /* | 192 | /* |
193 | * a3d_adc_cooked_read() copies the acis and button data to the | 193 | * a3d_adc_cooked_read() copies the acis and button data to the |
194 | * callers arrays. It could do the read itself, but the caller could | 194 | * callers arrays. It could do the read itself, but the caller could |
195 | * call this more than 50 times a second, which would use too much CPU. | 195 | * call this more than 50 times a second, which would use too much CPU. |
196 | */ | 196 | */ |
197 | 197 | ||
198 | static int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons) | 198 | static int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons) |
199 | { | 199 | { |
200 | struct a3d *a3d = gameport->port_data; | 200 | struct a3d *a3d = gameport->port_data; |
201 | int i; | 201 | int i; |
202 | 202 | ||
203 | for (i = 0; i < 4; i++) | 203 | for (i = 0; i < 4; i++) |
204 | axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1; | 204 | axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1; |
205 | *buttons = a3d->buttons; | 205 | *buttons = a3d->buttons; |
206 | return 0; | 206 | return 0; |
207 | } | 207 | } |
208 | 208 | ||
209 | /* | 209 | /* |
210 | * a3d_adc_open() is the gameport open routine. It refuses to serve | 210 | * a3d_adc_open() is the gameport open routine. It refuses to serve |
211 | * any but cooked data. | 211 | * any but cooked data. |
212 | */ | 212 | */ |
213 | 213 | ||
214 | static int a3d_adc_open(struct gameport *gameport, int mode) | 214 | static int a3d_adc_open(struct gameport *gameport, int mode) |
215 | { | 215 | { |
216 | struct a3d *a3d = gameport->port_data; | 216 | struct a3d *a3d = gameport->port_data; |
217 | 217 | ||
218 | if (mode != GAMEPORT_MODE_COOKED) | 218 | if (mode != GAMEPORT_MODE_COOKED) |
219 | return -1; | 219 | return -1; |
220 | 220 | ||
221 | gameport_start_polling(a3d->gameport); | 221 | gameport_start_polling(a3d->gameport); |
222 | return 0; | 222 | return 0; |
223 | } | 223 | } |
224 | 224 | ||
225 | /* | 225 | /* |
226 | * a3d_adc_close() is a callback from the input close routine. | 226 | * a3d_adc_close() is a callback from the input close routine. |
227 | */ | 227 | */ |
228 | 228 | ||
229 | static void a3d_adc_close(struct gameport *gameport) | 229 | static void a3d_adc_close(struct gameport *gameport) |
230 | { | 230 | { |
231 | struct a3d *a3d = gameport->port_data; | 231 | struct a3d *a3d = gameport->port_data; |
232 | 232 | ||
233 | gameport_stop_polling(a3d->gameport); | 233 | gameport_stop_polling(a3d->gameport); |
234 | } | 234 | } |
235 | 235 | ||
236 | /* | 236 | /* |
237 | * a3d_open() is a callback from the input open routine. | 237 | * a3d_open() is a callback from the input open routine. |
238 | */ | 238 | */ |
239 | 239 | ||
240 | static int a3d_open(struct input_dev *dev) | 240 | static int a3d_open(struct input_dev *dev) |
241 | { | 241 | { |
242 | struct a3d *a3d = input_get_drvdata(dev); | 242 | struct a3d *a3d = input_get_drvdata(dev); |
243 | 243 | ||
244 | gameport_start_polling(a3d->gameport); | 244 | gameport_start_polling(a3d->gameport); |
245 | return 0; | 245 | return 0; |
246 | } | 246 | } |
247 | 247 | ||
248 | /* | 248 | /* |
249 | * a3d_close() is a callback from the input close routine. | 249 | * a3d_close() is a callback from the input close routine. |
250 | */ | 250 | */ |
251 | 251 | ||
252 | static void a3d_close(struct input_dev *dev) | 252 | static void a3d_close(struct input_dev *dev) |
253 | { | 253 | { |
254 | struct a3d *a3d = input_get_drvdata(dev); | 254 | struct a3d *a3d = input_get_drvdata(dev); |
255 | 255 | ||
256 | gameport_stop_polling(a3d->gameport); | 256 | gameport_stop_polling(a3d->gameport); |
257 | } | 257 | } |
258 | 258 | ||
259 | /* | 259 | /* |
260 | * a3d_connect() probes for A3D joysticks. | 260 | * a3d_connect() probes for A3D joysticks. |
261 | */ | 261 | */ |
262 | 262 | ||
263 | static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv) | 263 | static int a3d_connect(struct gameport *gameport, struct gameport_driver *drv) |
264 | { | 264 | { |
265 | struct a3d *a3d; | 265 | struct a3d *a3d; |
266 | struct input_dev *input_dev; | 266 | struct input_dev *input_dev; |
267 | struct gameport *adc; | 267 | struct gameport *adc; |
268 | unsigned char data[A3D_MAX_LENGTH]; | 268 | unsigned char data[A3D_MAX_LENGTH]; |
269 | int i; | 269 | int i; |
270 | int err; | 270 | int err; |
271 | 271 | ||
272 | a3d = kzalloc(sizeof(struct a3d), GFP_KERNEL); | 272 | a3d = kzalloc(sizeof(struct a3d), GFP_KERNEL); |
273 | input_dev = input_allocate_device(); | 273 | input_dev = input_allocate_device(); |
274 | if (!a3d || !input_dev) { | 274 | if (!a3d || !input_dev) { |
275 | err = -ENOMEM; | 275 | err = -ENOMEM; |
276 | goto fail1; | 276 | goto fail1; |
277 | } | 277 | } |
278 | 278 | ||
279 | a3d->dev = input_dev; | 279 | a3d->dev = input_dev; |
280 | a3d->gameport = gameport; | 280 | a3d->gameport = gameport; |
281 | 281 | ||
282 | gameport_set_drvdata(gameport, a3d); | 282 | gameport_set_drvdata(gameport, a3d); |
283 | 283 | ||
284 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 284 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
285 | if (err) | 285 | if (err) |
286 | goto fail1; | 286 | goto fail1; |
287 | 287 | ||
288 | i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data); | 288 | i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data); |
289 | 289 | ||
290 | if (!i || a3d_csum(data, i)) { | 290 | if (!i || a3d_csum(data, i)) { |
291 | err = -ENODEV; | 291 | err = -ENODEV; |
292 | goto fail2; | 292 | goto fail2; |
293 | } | 293 | } |
294 | 294 | ||
295 | a3d->mode = data[0]; | 295 | a3d->mode = data[0]; |
296 | 296 | ||
297 | if (!a3d->mode || a3d->mode > 5) { | 297 | if (!a3d->mode || a3d->mode > 5) { |
298 | printk(KERN_WARNING "a3d.c: Unknown A3D device detected " | 298 | printk(KERN_WARNING "a3d.c: Unknown A3D device detected " |
299 | "(%s, id=%d), contact <vojtech@ucw.cz>\n", gameport->phys, a3d->mode); | 299 | "(%s, id=%d), contact <vojtech@ucw.cz>\n", gameport->phys, a3d->mode); |
300 | err = -ENODEV; | 300 | err = -ENODEV; |
301 | goto fail2; | 301 | goto fail2; |
302 | } | 302 | } |
303 | 303 | ||
304 | gameport_set_poll_handler(gameport, a3d_poll); | 304 | gameport_set_poll_handler(gameport, a3d_poll); |
305 | gameport_set_poll_interval(gameport, 20); | 305 | gameport_set_poll_interval(gameport, 20); |
306 | 306 | ||
307 | snprintf(a3d->phys, sizeof(a3d->phys), "%s/input0", gameport->phys); | 307 | snprintf(a3d->phys, sizeof(a3d->phys), "%s/input0", gameport->phys); |
308 | 308 | ||
309 | input_dev->name = a3d_names[a3d->mode]; | 309 | input_dev->name = a3d_names[a3d->mode]; |
310 | input_dev->phys = a3d->phys; | 310 | input_dev->phys = a3d->phys; |
311 | input_dev->id.bustype = BUS_GAMEPORT; | 311 | input_dev->id.bustype = BUS_GAMEPORT; |
312 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_MADCATZ; | 312 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_MADCATZ; |
313 | input_dev->id.product = a3d->mode; | 313 | input_dev->id.product = a3d->mode; |
314 | input_dev->id.version = 0x0100; | 314 | input_dev->id.version = 0x0100; |
315 | input_dev->dev.parent = &gameport->dev; | 315 | input_dev->dev.parent = &gameport->dev; |
316 | input_dev->open = a3d_open; | 316 | input_dev->open = a3d_open; |
317 | input_dev->close = a3d_close; | 317 | input_dev->close = a3d_close; |
318 | 318 | ||
319 | input_set_drvdata(input_dev, a3d); | 319 | input_set_drvdata(input_dev, a3d); |
320 | 320 | ||
321 | if (a3d->mode == A3D_MODE_PXL) { | 321 | if (a3d->mode == A3D_MODE_PXL) { |
322 | 322 | ||
323 | int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER }; | 323 | int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER }; |
324 | 324 | ||
325 | a3d->length = 33; | 325 | a3d->length = 33; |
326 | 326 | ||
327 | input_dev->evbit[0] |= BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY) | | 327 | input_dev->evbit[0] |= BIT_MASK(EV_ABS) | BIT_MASK(EV_KEY) | |
328 | BIT_MASK(EV_REL); | 328 | BIT_MASK(EV_REL); |
329 | input_dev->relbit[0] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); | 329 | input_dev->relbit[0] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); |
330 | input_dev->absbit[0] |= BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | | 330 | input_dev->absbit[0] |= BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | |
331 | BIT_MASK(ABS_THROTTLE) | BIT_MASK(ABS_RUDDER) | | 331 | BIT_MASK(ABS_THROTTLE) | BIT_MASK(ABS_RUDDER) | |
332 | BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) | | 332 | BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) | |
333 | BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y); | 333 | BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y); |
334 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_RIGHT) | | 334 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_RIGHT) | |
335 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | | 335 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | |
336 | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); | 336 | BIT_MASK(BTN_SIDE) | BIT_MASK(BTN_EXTRA); |
337 | input_dev->keybit[BIT_WORD(BTN_JOYSTICK)] |= | 337 | input_dev->keybit[BIT_WORD(BTN_JOYSTICK)] |= |
338 | BIT_MASK(BTN_TRIGGER) | BIT_MASK(BTN_THUMB) | | 338 | BIT_MASK(BTN_TRIGGER) | BIT_MASK(BTN_THUMB) | |
339 | BIT_MASK(BTN_TOP) | BIT_MASK(BTN_PINKIE); | 339 | BIT_MASK(BTN_TOP) | BIT_MASK(BTN_PINKIE); |
340 | 340 | ||
341 | a3d_read(a3d, data); | 341 | a3d_read(a3d, data); |
342 | 342 | ||
343 | for (i = 0; i < 4; i++) { | 343 | for (i = 0; i < 4; i++) { |
344 | if (i < 2) | 344 | if (i < 2) |
345 | input_set_abs_params(input_dev, axes[i], | 345 | input_set_abs_params(input_dev, axes[i], |
346 | 48, input_abs_get_val(input_dev, axes[i]) * 2 - 48, 0, 8); | 346 | 48, input_abs_get_val(input_dev, axes[i]) * 2 - 48, 0, 8); |
347 | else | 347 | else |
348 | input_set_abs_params(input_dev, axes[i], 2, 253, 0, 0); | 348 | input_set_abs_params(input_dev, axes[i], 2, 253, 0, 0); |
349 | input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); | 349 | input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); |
350 | } | 350 | } |
351 | 351 | ||
352 | } else { | 352 | } else { |
353 | a3d->length = 29; | 353 | a3d->length = 29; |
354 | 354 | ||
355 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); | 355 | input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_REL); |
356 | input_dev->relbit[0] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); | 356 | input_dev->relbit[0] |= BIT_MASK(REL_X) | BIT_MASK(REL_Y); |
357 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_RIGHT) | | 357 | input_dev->keybit[BIT_WORD(BTN_MOUSE)] |= BIT_MASK(BTN_RIGHT) | |
358 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE); | 358 | BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE); |
359 | 359 | ||
360 | a3d_read(a3d, data); | 360 | a3d_read(a3d, data); |
361 | 361 | ||
362 | if (!(a3d->adc = adc = gameport_allocate_port())) | 362 | if (!(a3d->adc = adc = gameport_allocate_port())) |
363 | printk(KERN_ERR "a3d: Not enough memory for ADC port\n"); | 363 | printk(KERN_ERR "a3d: Not enough memory for ADC port\n"); |
364 | else { | 364 | else { |
365 | adc->port_data = a3d; | 365 | adc->port_data = a3d; |
366 | adc->open = a3d_adc_open; | 366 | adc->open = a3d_adc_open; |
367 | adc->close = a3d_adc_close; | 367 | adc->close = a3d_adc_close; |
368 | adc->cooked_read = a3d_adc_cooked_read; | 368 | adc->cooked_read = a3d_adc_cooked_read; |
369 | adc->fuzz = 1; | 369 | adc->fuzz = 1; |
370 | 370 | ||
371 | gameport_set_name(adc, a3d_names[a3d->mode]); | 371 | gameport_set_name(adc, a3d_names[a3d->mode]); |
372 | gameport_set_phys(adc, "%s/gameport0", gameport->phys); | 372 | gameport_set_phys(adc, "%s/gameport0", gameport->phys); |
373 | adc->dev.parent = &gameport->dev; | 373 | adc->dev.parent = &gameport->dev; |
374 | 374 | ||
375 | gameport_register_port(adc); | 375 | gameport_register_port(adc); |
376 | } | 376 | } |
377 | } | 377 | } |
378 | 378 | ||
379 | err = input_register_device(a3d->dev); | 379 | err = input_register_device(a3d->dev); |
380 | if (err) | 380 | if (err) |
381 | goto fail3; | 381 | goto fail3; |
382 | 382 | ||
383 | return 0; | 383 | return 0; |
384 | 384 | ||
385 | fail3: if (a3d->adc) | 385 | fail3: if (a3d->adc) |
386 | gameport_unregister_port(a3d->adc); | 386 | gameport_unregister_port(a3d->adc); |
387 | fail2: gameport_close(gameport); | 387 | fail2: gameport_close(gameport); |
388 | fail1: gameport_set_drvdata(gameport, NULL); | 388 | fail1: gameport_set_drvdata(gameport, NULL); |
389 | input_free_device(input_dev); | 389 | input_free_device(input_dev); |
390 | kfree(a3d); | 390 | kfree(a3d); |
391 | return err; | 391 | return err; |
392 | } | 392 | } |
393 | 393 | ||
394 | static void a3d_disconnect(struct gameport *gameport) | 394 | static void a3d_disconnect(struct gameport *gameport) |
395 | { | 395 | { |
396 | struct a3d *a3d = gameport_get_drvdata(gameport); | 396 | struct a3d *a3d = gameport_get_drvdata(gameport); |
397 | 397 | ||
398 | input_unregister_device(a3d->dev); | 398 | input_unregister_device(a3d->dev); |
399 | if (a3d->adc) | 399 | if (a3d->adc) |
400 | gameport_unregister_port(a3d->adc); | 400 | gameport_unregister_port(a3d->adc); |
401 | gameport_close(gameport); | 401 | gameport_close(gameport); |
402 | gameport_set_drvdata(gameport, NULL); | 402 | gameport_set_drvdata(gameport, NULL); |
403 | kfree(a3d); | 403 | kfree(a3d); |
404 | } | 404 | } |
405 | 405 | ||
406 | static struct gameport_driver a3d_drv = { | 406 | static struct gameport_driver a3d_drv = { |
407 | .driver = { | 407 | .driver = { |
408 | .name = "adc", | 408 | .name = "adc", |
409 | .owner = THIS_MODULE, | 409 | .owner = THIS_MODULE, |
410 | }, | 410 | }, |
411 | .description = DRIVER_DESC, | 411 | .description = DRIVER_DESC, |
412 | .connect = a3d_connect, | 412 | .connect = a3d_connect, |
413 | .disconnect = a3d_disconnect, | 413 | .disconnect = a3d_disconnect, |
414 | }; | 414 | }; |
415 | 415 | ||
416 | static int __init a3d_init(void) | 416 | module_gameport_driver(a3d_drv); |
417 | { | ||
418 | return gameport_register_driver(&a3d_drv); | ||
419 | } | ||
420 | |||
421 | static void __exit a3d_exit(void) | ||
422 | { | ||
423 | gameport_unregister_driver(&a3d_drv); | ||
424 | } | ||
425 | |||
426 | module_init(a3d_init); | ||
427 | module_exit(a3d_exit); | ||
428 | 417 |
drivers/input/joystick/adi.c
1 | /* | 1 | /* |
2 | * Copyright (c) 1998-2005 Vojtech Pavlik | 2 | * Copyright (c) 1998-2005 Vojtech Pavlik |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
6 | * Logitech ADI joystick family driver for Linux | 6 | * Logitech ADI joystick family driver for Linux |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Should you need to contact me, the author, you can do so either by | 24 | * Should you need to contact me, the author, you can do so either by |
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/string.h> | 32 | #include <linux/string.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/input.h> | 34 | #include <linux/input.h> |
35 | #include <linux/gameport.h> | 35 | #include <linux/gameport.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/jiffies.h> | 37 | #include <linux/jiffies.h> |
38 | 38 | ||
39 | #define DRIVER_DESC "Logitech ADI joystick family driver" | 39 | #define DRIVER_DESC "Logitech ADI joystick family driver" |
40 | 40 | ||
41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 41 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
42 | MODULE_DESCRIPTION(DRIVER_DESC); | 42 | MODULE_DESCRIPTION(DRIVER_DESC); |
43 | MODULE_LICENSE("GPL"); | 43 | MODULE_LICENSE("GPL"); |
44 | 44 | ||
45 | /* | 45 | /* |
46 | * Times, array sizes, flags, ids. | 46 | * Times, array sizes, flags, ids. |
47 | */ | 47 | */ |
48 | 48 | ||
49 | #define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */ | 49 | #define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */ |
50 | #define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */ | 50 | #define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */ |
51 | #define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */ | 51 | #define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */ |
52 | #define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */ | 52 | #define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */ |
53 | 53 | ||
54 | #define ADI_MAX_LENGTH 256 | 54 | #define ADI_MAX_LENGTH 256 |
55 | #define ADI_MIN_LENGTH 8 | 55 | #define ADI_MIN_LENGTH 8 |
56 | #define ADI_MIN_LEN_LENGTH 10 | 56 | #define ADI_MIN_LEN_LENGTH 10 |
57 | #define ADI_MIN_ID_LENGTH 66 | 57 | #define ADI_MIN_ID_LENGTH 66 |
58 | #define ADI_MAX_NAME_LENGTH 64 | 58 | #define ADI_MAX_NAME_LENGTH 64 |
59 | #define ADI_MAX_CNAME_LENGTH 16 | 59 | #define ADI_MAX_CNAME_LENGTH 16 |
60 | #define ADI_MAX_PHYS_LENGTH 64 | 60 | #define ADI_MAX_PHYS_LENGTH 64 |
61 | 61 | ||
62 | #define ADI_FLAG_HAT 0x04 | 62 | #define ADI_FLAG_HAT 0x04 |
63 | #define ADI_FLAG_10BIT 0x08 | 63 | #define ADI_FLAG_10BIT 0x08 |
64 | 64 | ||
65 | #define ADI_ID_TPD 0x01 | 65 | #define ADI_ID_TPD 0x01 |
66 | #define ADI_ID_WGP 0x06 | 66 | #define ADI_ID_WGP 0x06 |
67 | #define ADI_ID_WGPE 0x08 | 67 | #define ADI_ID_WGPE 0x08 |
68 | #define ADI_ID_MAX 0x0a | 68 | #define ADI_ID_MAX 0x0a |
69 | 69 | ||
70 | /* | 70 | /* |
71 | * Names, buttons, axes ... | 71 | * Names, buttons, axes ... |
72 | */ | 72 | */ |
73 | 73 | ||
74 | static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2", | 74 | static char *adi_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2", |
75 | "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", | 75 | "WingMan Interceptor", "WingMan Formula", "WingMan GamePad", |
76 | "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", | 76 | "WingMan Extreme Digital 3D", "WingMan GamePad Extreme", |
77 | "WingMan GamePad USB", "Unknown Device %#x" }; | 77 | "WingMan GamePad USB", "Unknown Device %#x" }; |
78 | 78 | ||
79 | static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y }; | 79 | static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y }; |
80 | static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; | 80 | static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; |
81 | static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y }; | 81 | static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y }; |
82 | static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; | 82 | static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ }; |
83 | static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; | 83 | static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y }; |
84 | 84 | ||
85 | static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }; | 85 | static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }; |
86 | static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA }; | 86 | static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA }; |
87 | static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 }; | 87 | static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 }; |
88 | static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; | 88 | static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 }; |
89 | 89 | ||
90 | static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs, | 90 | static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs, |
91 | adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs }; | 91 | adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs }; |
92 | 92 | ||
93 | static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key, | 93 | static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key, |
94 | adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key }; | 94 | adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key }; |
95 | 95 | ||
96 | /* | 96 | /* |
97 | * Hat to axis conversion arrays. | 97 | * Hat to axis conversion arrays. |
98 | */ | 98 | */ |
99 | 99 | ||
100 | static struct { | 100 | static struct { |
101 | int x; | 101 | int x; |
102 | int y; | 102 | int y; |
103 | } adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | 103 | } adi_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; |
104 | 104 | ||
105 | /* | 105 | /* |
106 | * Per-port information. | 106 | * Per-port information. |
107 | */ | 107 | */ |
108 | 108 | ||
109 | struct adi { | 109 | struct adi { |
110 | struct input_dev *dev; | 110 | struct input_dev *dev; |
111 | int length; | 111 | int length; |
112 | int ret; | 112 | int ret; |
113 | int idx; | 113 | int idx; |
114 | unsigned char id; | 114 | unsigned char id; |
115 | char buttons; | 115 | char buttons; |
116 | char axes10; | 116 | char axes10; |
117 | char axes8; | 117 | char axes8; |
118 | signed char pad; | 118 | signed char pad; |
119 | char hats; | 119 | char hats; |
120 | char *abs; | 120 | char *abs; |
121 | short *key; | 121 | short *key; |
122 | char name[ADI_MAX_NAME_LENGTH]; | 122 | char name[ADI_MAX_NAME_LENGTH]; |
123 | char cname[ADI_MAX_CNAME_LENGTH]; | 123 | char cname[ADI_MAX_CNAME_LENGTH]; |
124 | char phys[ADI_MAX_PHYS_LENGTH]; | 124 | char phys[ADI_MAX_PHYS_LENGTH]; |
125 | unsigned char data[ADI_MAX_LENGTH]; | 125 | unsigned char data[ADI_MAX_LENGTH]; |
126 | }; | 126 | }; |
127 | 127 | ||
128 | struct adi_port { | 128 | struct adi_port { |
129 | struct gameport *gameport; | 129 | struct gameport *gameport; |
130 | struct adi adi[2]; | 130 | struct adi adi[2]; |
131 | int bad; | 131 | int bad; |
132 | int reads; | 132 | int reads; |
133 | }; | 133 | }; |
134 | 134 | ||
135 | /* | 135 | /* |
136 | * adi_read_packet() reads a Logitech ADI packet. | 136 | * adi_read_packet() reads a Logitech ADI packet. |
137 | */ | 137 | */ |
138 | 138 | ||
139 | static void adi_read_packet(struct adi_port *port) | 139 | static void adi_read_packet(struct adi_port *port) |
140 | { | 140 | { |
141 | struct adi *adi = port->adi; | 141 | struct adi *adi = port->adi; |
142 | struct gameport *gameport = port->gameport; | 142 | struct gameport *gameport = port->gameport; |
143 | unsigned char u, v, w, x, z; | 143 | unsigned char u, v, w, x, z; |
144 | int t[2], s[2], i; | 144 | int t[2], s[2], i; |
145 | unsigned long flags; | 145 | unsigned long flags; |
146 | 146 | ||
147 | for (i = 0; i < 2; i++) { | 147 | for (i = 0; i < 2; i++) { |
148 | adi[i].ret = -1; | 148 | adi[i].ret = -1; |
149 | t[i] = gameport_time(gameport, ADI_MAX_START); | 149 | t[i] = gameport_time(gameport, ADI_MAX_START); |
150 | s[i] = 0; | 150 | s[i] = 0; |
151 | } | 151 | } |
152 | 152 | ||
153 | local_irq_save(flags); | 153 | local_irq_save(flags); |
154 | 154 | ||
155 | gameport_trigger(gameport); | 155 | gameport_trigger(gameport); |
156 | v = z = gameport_read(gameport); | 156 | v = z = gameport_read(gameport); |
157 | 157 | ||
158 | do { | 158 | do { |
159 | u = v; | 159 | u = v; |
160 | w = u ^ (v = x = gameport_read(gameport)); | 160 | w = u ^ (v = x = gameport_read(gameport)); |
161 | for (i = 0; i < 2; i++, w >>= 2, x >>= 2) { | 161 | for (i = 0; i < 2; i++, w >>= 2, x >>= 2) { |
162 | t[i]--; | 162 | t[i]--; |
163 | if ((w & 0x30) && s[i]) { | 163 | if ((w & 0x30) && s[i]) { |
164 | if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) { | 164 | if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) { |
165 | adi[i].data[++adi[i].ret] = w; | 165 | adi[i].data[++adi[i].ret] = w; |
166 | t[i] = gameport_time(gameport, ADI_MAX_STROBE); | 166 | t[i] = gameport_time(gameport, ADI_MAX_STROBE); |
167 | } else t[i] = 0; | 167 | } else t[i] = 0; |
168 | } else if (!(x & 0x30)) s[i] = 1; | 168 | } else if (!(x & 0x30)) s[i] = 1; |
169 | } | 169 | } |
170 | } while (t[0] > 0 || t[1] > 0); | 170 | } while (t[0] > 0 || t[1] > 0); |
171 | 171 | ||
172 | local_irq_restore(flags); | 172 | local_irq_restore(flags); |
173 | 173 | ||
174 | return; | 174 | return; |
175 | } | 175 | } |
176 | 176 | ||
177 | /* | 177 | /* |
178 | * adi_move_bits() detects a possible 2-stream mode, and moves | 178 | * adi_move_bits() detects a possible 2-stream mode, and moves |
179 | * the bits accordingly. | 179 | * the bits accordingly. |
180 | */ | 180 | */ |
181 | 181 | ||
182 | static void adi_move_bits(struct adi_port *port, int length) | 182 | static void adi_move_bits(struct adi_port *port, int length) |
183 | { | 183 | { |
184 | int i; | 184 | int i; |
185 | struct adi *adi = port->adi; | 185 | struct adi *adi = port->adi; |
186 | 186 | ||
187 | adi[0].idx = adi[1].idx = 0; | 187 | adi[0].idx = adi[1].idx = 0; |
188 | 188 | ||
189 | if (adi[0].ret <= 0 || adi[1].ret <= 0) return; | 189 | if (adi[0].ret <= 0 || adi[1].ret <= 0) return; |
190 | if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return; | 190 | if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return; |
191 | 191 | ||
192 | for (i = 1; i <= adi[1].ret; i++) | 192 | for (i = 1; i <= adi[1].ret; i++) |
193 | adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i]; | 193 | adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i]; |
194 | 194 | ||
195 | adi[0].ret += adi[1].ret; | 195 | adi[0].ret += adi[1].ret; |
196 | adi[1].ret = -1; | 196 | adi[1].ret = -1; |
197 | } | 197 | } |
198 | 198 | ||
199 | /* | 199 | /* |
200 | * adi_get_bits() gathers bits from the data packet. | 200 | * adi_get_bits() gathers bits from the data packet. |
201 | */ | 201 | */ |
202 | 202 | ||
203 | static inline int adi_get_bits(struct adi *adi, int count) | 203 | static inline int adi_get_bits(struct adi *adi, int count) |
204 | { | 204 | { |
205 | int bits = 0; | 205 | int bits = 0; |
206 | int i; | 206 | int i; |
207 | if ((adi->idx += count) > adi->ret) return 0; | 207 | if ((adi->idx += count) > adi->ret) return 0; |
208 | for (i = 0; i < count; i++) | 208 | for (i = 0; i < count; i++) |
209 | bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; | 209 | bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i; |
210 | return bits; | 210 | return bits; |
211 | } | 211 | } |
212 | 212 | ||
213 | /* | 213 | /* |
214 | * adi_decode() decodes Logitech joystick data into input events. | 214 | * adi_decode() decodes Logitech joystick data into input events. |
215 | */ | 215 | */ |
216 | 216 | ||
217 | static int adi_decode(struct adi *adi) | 217 | static int adi_decode(struct adi *adi) |
218 | { | 218 | { |
219 | struct input_dev *dev = adi->dev; | 219 | struct input_dev *dev = adi->dev; |
220 | char *abs = adi->abs; | 220 | char *abs = adi->abs; |
221 | short *key = adi->key; | 221 | short *key = adi->key; |
222 | int i, t; | 222 | int i, t; |
223 | 223 | ||
224 | if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4))) | 224 | if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4))) |
225 | return -1; | 225 | return -1; |
226 | 226 | ||
227 | for (i = 0; i < adi->axes10; i++) | 227 | for (i = 0; i < adi->axes10; i++) |
228 | input_report_abs(dev, *abs++, adi_get_bits(adi, 10)); | 228 | input_report_abs(dev, *abs++, adi_get_bits(adi, 10)); |
229 | 229 | ||
230 | for (i = 0; i < adi->axes8; i++) | 230 | for (i = 0; i < adi->axes8; i++) |
231 | input_report_abs(dev, *abs++, adi_get_bits(adi, 8)); | 231 | input_report_abs(dev, *abs++, adi_get_bits(adi, 8)); |
232 | 232 | ||
233 | for (i = 0; i < adi->buttons && i < 63; i++) { | 233 | for (i = 0; i < adi->buttons && i < 63; i++) { |
234 | if (i == adi->pad) { | 234 | if (i == adi->pad) { |
235 | t = adi_get_bits(adi, 4); | 235 | t = adi_get_bits(adi, 4); |
236 | input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1)); | 236 | input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1)); |
237 | input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1)); | 237 | input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1)); |
238 | } | 238 | } |
239 | input_report_key(dev, *key++, adi_get_bits(adi, 1)); | 239 | input_report_key(dev, *key++, adi_get_bits(adi, 1)); |
240 | } | 240 | } |
241 | 241 | ||
242 | for (i = 0; i < adi->hats; i++) { | 242 | for (i = 0; i < adi->hats; i++) { |
243 | if ((t = adi_get_bits(adi, 4)) > 8) t = 0; | 243 | if ((t = adi_get_bits(adi, 4)) > 8) t = 0; |
244 | input_report_abs(dev, *abs++, adi_hat_to_axis[t].x); | 244 | input_report_abs(dev, *abs++, adi_hat_to_axis[t].x); |
245 | input_report_abs(dev, *abs++, adi_hat_to_axis[t].y); | 245 | input_report_abs(dev, *abs++, adi_hat_to_axis[t].y); |
246 | } | 246 | } |
247 | 247 | ||
248 | for (i = 63; i < adi->buttons; i++) | 248 | for (i = 63; i < adi->buttons; i++) |
249 | input_report_key(dev, *key++, adi_get_bits(adi, 1)); | 249 | input_report_key(dev, *key++, adi_get_bits(adi, 1)); |
250 | 250 | ||
251 | input_sync(dev); | 251 | input_sync(dev); |
252 | 252 | ||
253 | return 0; | 253 | return 0; |
254 | } | 254 | } |
255 | 255 | ||
256 | /* | 256 | /* |
257 | * adi_read() reads the data packet and decodes it. | 257 | * adi_read() reads the data packet and decodes it. |
258 | */ | 258 | */ |
259 | 259 | ||
260 | static int adi_read(struct adi_port *port) | 260 | static int adi_read(struct adi_port *port) |
261 | { | 261 | { |
262 | int i; | 262 | int i; |
263 | int result = 0; | 263 | int result = 0; |
264 | 264 | ||
265 | adi_read_packet(port); | 265 | adi_read_packet(port); |
266 | adi_move_bits(port, port->adi[0].length); | 266 | adi_move_bits(port, port->adi[0].length); |
267 | 267 | ||
268 | for (i = 0; i < 2; i++) | 268 | for (i = 0; i < 2; i++) |
269 | if (port->adi[i].length) | 269 | if (port->adi[i].length) |
270 | result |= adi_decode(port->adi + i); | 270 | result |= adi_decode(port->adi + i); |
271 | 271 | ||
272 | return result; | 272 | return result; |
273 | } | 273 | } |
274 | 274 | ||
275 | /* | 275 | /* |
276 | * adi_poll() repeatedly polls the Logitech joysticks. | 276 | * adi_poll() repeatedly polls the Logitech joysticks. |
277 | */ | 277 | */ |
278 | 278 | ||
279 | static void adi_poll(struct gameport *gameport) | 279 | static void adi_poll(struct gameport *gameport) |
280 | { | 280 | { |
281 | struct adi_port *port = gameport_get_drvdata(gameport); | 281 | struct adi_port *port = gameport_get_drvdata(gameport); |
282 | 282 | ||
283 | port->bad -= adi_read(port); | 283 | port->bad -= adi_read(port); |
284 | port->reads++; | 284 | port->reads++; |
285 | } | 285 | } |
286 | 286 | ||
287 | /* | 287 | /* |
288 | * adi_open() is a callback from the input open routine. | 288 | * adi_open() is a callback from the input open routine. |
289 | */ | 289 | */ |
290 | 290 | ||
291 | static int adi_open(struct input_dev *dev) | 291 | static int adi_open(struct input_dev *dev) |
292 | { | 292 | { |
293 | struct adi_port *port = input_get_drvdata(dev); | 293 | struct adi_port *port = input_get_drvdata(dev); |
294 | 294 | ||
295 | gameport_start_polling(port->gameport); | 295 | gameport_start_polling(port->gameport); |
296 | return 0; | 296 | return 0; |
297 | } | 297 | } |
298 | 298 | ||
299 | /* | 299 | /* |
300 | * adi_close() is a callback from the input close routine. | 300 | * adi_close() is a callback from the input close routine. |
301 | */ | 301 | */ |
302 | 302 | ||
303 | static void adi_close(struct input_dev *dev) | 303 | static void adi_close(struct input_dev *dev) |
304 | { | 304 | { |
305 | struct adi_port *port = input_get_drvdata(dev); | 305 | struct adi_port *port = input_get_drvdata(dev); |
306 | 306 | ||
307 | gameport_stop_polling(port->gameport); | 307 | gameport_stop_polling(port->gameport); |
308 | } | 308 | } |
309 | 309 | ||
310 | /* | 310 | /* |
311 | * adi_init_digital() sends a trigger & delay sequence | 311 | * adi_init_digital() sends a trigger & delay sequence |
312 | * to reset and initialize a Logitech joystick into digital mode. | 312 | * to reset and initialize a Logitech joystick into digital mode. |
313 | */ | 313 | */ |
314 | 314 | ||
315 | static void adi_init_digital(struct gameport *gameport) | 315 | static void adi_init_digital(struct gameport *gameport) |
316 | { | 316 | { |
317 | int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 }; | 317 | int seq[] = { 4, -2, -3, 10, -6, -11, -7, -9, 11, 0 }; |
318 | int i; | 318 | int i; |
319 | 319 | ||
320 | for (i = 0; seq[i]; i++) { | 320 | for (i = 0; seq[i]; i++) { |
321 | gameport_trigger(gameport); | 321 | gameport_trigger(gameport); |
322 | if (seq[i] > 0) | 322 | if (seq[i] > 0) |
323 | msleep(seq[i]); | 323 | msleep(seq[i]); |
324 | if (seq[i] < 0) { | 324 | if (seq[i] < 0) { |
325 | mdelay(-seq[i]); | 325 | mdelay(-seq[i]); |
326 | udelay(-seq[i]*14); /* It looks like mdelay() is off by approx 1.4% */ | 326 | udelay(-seq[i]*14); /* It looks like mdelay() is off by approx 1.4% */ |
327 | } | 327 | } |
328 | } | 328 | } |
329 | } | 329 | } |
330 | 330 | ||
331 | static void adi_id_decode(struct adi *adi, struct adi_port *port) | 331 | static void adi_id_decode(struct adi *adi, struct adi_port *port) |
332 | { | 332 | { |
333 | int i, t; | 333 | int i, t; |
334 | 334 | ||
335 | if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */ | 335 | if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */ |
336 | return; | 336 | return; |
337 | 337 | ||
338 | if (adi->ret < (t = adi_get_bits(adi, 10))) { | 338 | if (adi->ret < (t = adi_get_bits(adi, 10))) { |
339 | printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); | 339 | printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret); |
340 | return; | 340 | return; |
341 | } | 341 | } |
342 | 342 | ||
343 | adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4); | 343 | adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4); |
344 | 344 | ||
345 | if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++; | 345 | if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++; |
346 | 346 | ||
347 | adi->length = adi_get_bits(adi, 10); | 347 | adi->length = adi_get_bits(adi, 10); |
348 | 348 | ||
349 | if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) { | 349 | if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) { |
350 | printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length); | 350 | printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length); |
351 | adi->length = 0; | 351 | adi->length = 0; |
352 | return; | 352 | return; |
353 | } | 353 | } |
354 | 354 | ||
355 | adi->axes8 = adi_get_bits(adi, 4); | 355 | adi->axes8 = adi_get_bits(adi, 4); |
356 | adi->buttons = adi_get_bits(adi, 6); | 356 | adi->buttons = adi_get_bits(adi, 6); |
357 | 357 | ||
358 | if (adi_get_bits(adi, 6) != 8 && adi->hats) { | 358 | if (adi_get_bits(adi, 6) != 8 && adi->hats) { |
359 | printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n"); | 359 | printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n"); |
360 | adi->length = 0; | 360 | adi->length = 0; |
361 | return; | 361 | return; |
362 | } | 362 | } |
363 | 363 | ||
364 | adi->buttons += adi_get_bits(adi, 6); | 364 | adi->buttons += adi_get_bits(adi, 6); |
365 | adi->hats += adi_get_bits(adi, 4); | 365 | adi->hats += adi_get_bits(adi, 4); |
366 | 366 | ||
367 | i = adi_get_bits(adi, 4); | 367 | i = adi_get_bits(adi, 4); |
368 | 368 | ||
369 | if (t & ADI_FLAG_10BIT) { | 369 | if (t & ADI_FLAG_10BIT) { |
370 | adi->axes10 = adi->axes8 - i; | 370 | adi->axes10 = adi->axes8 - i; |
371 | adi->axes8 = i; | 371 | adi->axes8 = i; |
372 | } | 372 | } |
373 | 373 | ||
374 | t = adi_get_bits(adi, 4); | 374 | t = adi_get_bits(adi, 4); |
375 | 375 | ||
376 | for (i = 0; i < t; i++) | 376 | for (i = 0; i < t; i++) |
377 | adi->cname[i] = adi_get_bits(adi, 8); | 377 | adi->cname[i] = adi_get_bits(adi, 8); |
378 | adi->cname[i] = 0; | 378 | adi->cname[i] = 0; |
379 | 379 | ||
380 | t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4; | 380 | t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4; |
381 | if (adi->length != t && adi->length != t + (t & 1)) { | 381 | if (adi->length != t && adi->length != t + (t & 1)) { |
382 | printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length); | 382 | printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length); |
383 | adi->length = 0; | 383 | adi->length = 0; |
384 | return; | 384 | return; |
385 | } | 385 | } |
386 | 386 | ||
387 | switch (adi->id) { | 387 | switch (adi->id) { |
388 | case ADI_ID_TPD: | 388 | case ADI_ID_TPD: |
389 | adi->pad = 4; | 389 | adi->pad = 4; |
390 | adi->buttons -= 4; | 390 | adi->buttons -= 4; |
391 | break; | 391 | break; |
392 | case ADI_ID_WGP: | 392 | case ADI_ID_WGP: |
393 | adi->pad = 0; | 393 | adi->pad = 0; |
394 | adi->buttons -= 4; | 394 | adi->buttons -= 4; |
395 | break; | 395 | break; |
396 | default: | 396 | default: |
397 | adi->pad = -1; | 397 | adi->pad = -1; |
398 | break; | 398 | break; |
399 | } | 399 | } |
400 | } | 400 | } |
401 | 401 | ||
402 | static int adi_init_input(struct adi *adi, struct adi_port *port, int half) | 402 | static int adi_init_input(struct adi *adi, struct adi_port *port, int half) |
403 | { | 403 | { |
404 | struct input_dev *input_dev; | 404 | struct input_dev *input_dev; |
405 | char buf[ADI_MAX_NAME_LENGTH]; | 405 | char buf[ADI_MAX_NAME_LENGTH]; |
406 | int i, t; | 406 | int i, t; |
407 | 407 | ||
408 | adi->dev = input_dev = input_allocate_device(); | 408 | adi->dev = input_dev = input_allocate_device(); |
409 | if (!input_dev) | 409 | if (!input_dev) |
410 | return -ENOMEM; | 410 | return -ENOMEM; |
411 | 411 | ||
412 | t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX; | 412 | t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX; |
413 | 413 | ||
414 | snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id); | 414 | snprintf(buf, ADI_MAX_PHYS_LENGTH, adi_names[t], adi->id); |
415 | snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s [%s]", buf, adi->cname); | 415 | snprintf(adi->name, ADI_MAX_NAME_LENGTH, "Logitech %s [%s]", buf, adi->cname); |
416 | snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half); | 416 | snprintf(adi->phys, ADI_MAX_PHYS_LENGTH, "%s/input%d", port->gameport->phys, half); |
417 | 417 | ||
418 | adi->abs = adi_abs[t]; | 418 | adi->abs = adi_abs[t]; |
419 | adi->key = adi_key[t]; | 419 | adi->key = adi_key[t]; |
420 | 420 | ||
421 | input_dev->name = adi->name; | 421 | input_dev->name = adi->name; |
422 | input_dev->phys = adi->phys; | 422 | input_dev->phys = adi->phys; |
423 | input_dev->id.bustype = BUS_GAMEPORT; | 423 | input_dev->id.bustype = BUS_GAMEPORT; |
424 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; | 424 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_LOGITECH; |
425 | input_dev->id.product = adi->id; | 425 | input_dev->id.product = adi->id; |
426 | input_dev->id.version = 0x0100; | 426 | input_dev->id.version = 0x0100; |
427 | input_dev->dev.parent = &port->gameport->dev; | 427 | input_dev->dev.parent = &port->gameport->dev; |
428 | 428 | ||
429 | input_set_drvdata(input_dev, port); | 429 | input_set_drvdata(input_dev, port); |
430 | 430 | ||
431 | input_dev->open = adi_open; | 431 | input_dev->open = adi_open; |
432 | input_dev->close = adi_close; | 432 | input_dev->close = adi_close; |
433 | 433 | ||
434 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 434 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
435 | 435 | ||
436 | for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) | 436 | for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) |
437 | set_bit(adi->abs[i], input_dev->absbit); | 437 | set_bit(adi->abs[i], input_dev->absbit); |
438 | 438 | ||
439 | for (i = 0; i < adi->buttons; i++) | 439 | for (i = 0; i < adi->buttons; i++) |
440 | set_bit(adi->key[i], input_dev->keybit); | 440 | set_bit(adi->key[i], input_dev->keybit); |
441 | 441 | ||
442 | return 0; | 442 | return 0; |
443 | } | 443 | } |
444 | 444 | ||
445 | static void adi_init_center(struct adi *adi) | 445 | static void adi_init_center(struct adi *adi) |
446 | { | 446 | { |
447 | int i, t, x; | 447 | int i, t, x; |
448 | 448 | ||
449 | if (!adi->length) | 449 | if (!adi->length) |
450 | return; | 450 | return; |
451 | 451 | ||
452 | for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) { | 452 | for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad != -1)) * 2; i++) { |
453 | 453 | ||
454 | t = adi->abs[i]; | 454 | t = adi->abs[i]; |
455 | x = input_abs_get_val(adi->dev, t); | 455 | x = input_abs_get_val(adi->dev, t); |
456 | 456 | ||
457 | if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) | 457 | if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) |
458 | x = i < adi->axes10 ? 512 : 128; | 458 | x = i < adi->axes10 ? 512 : 128; |
459 | 459 | ||
460 | if (i < adi->axes10) | 460 | if (i < adi->axes10) |
461 | input_set_abs_params(adi->dev, t, 64, x * 2 - 64, 2, 16); | 461 | input_set_abs_params(adi->dev, t, 64, x * 2 - 64, 2, 16); |
462 | else if (i < adi->axes10 + adi->axes8) | 462 | else if (i < adi->axes10 + adi->axes8) |
463 | input_set_abs_params(adi->dev, t, 48, x * 2 - 48, 1, 16); | 463 | input_set_abs_params(adi->dev, t, 48, x * 2 - 48, 1, 16); |
464 | else | 464 | else |
465 | input_set_abs_params(adi->dev, t, -1, 1, 0, 0); | 465 | input_set_abs_params(adi->dev, t, -1, 1, 0, 0); |
466 | } | 466 | } |
467 | } | 467 | } |
468 | 468 | ||
469 | /* | 469 | /* |
470 | * adi_connect() probes for Logitech ADI joysticks. | 470 | * adi_connect() probes for Logitech ADI joysticks. |
471 | */ | 471 | */ |
472 | 472 | ||
473 | static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) | 473 | static int adi_connect(struct gameport *gameport, struct gameport_driver *drv) |
474 | { | 474 | { |
475 | struct adi_port *port; | 475 | struct adi_port *port; |
476 | int i; | 476 | int i; |
477 | int err; | 477 | int err; |
478 | 478 | ||
479 | port = kzalloc(sizeof(struct adi_port), GFP_KERNEL); | 479 | port = kzalloc(sizeof(struct adi_port), GFP_KERNEL); |
480 | if (!port) | 480 | if (!port) |
481 | return -ENOMEM; | 481 | return -ENOMEM; |
482 | 482 | ||
483 | port->gameport = gameport; | 483 | port->gameport = gameport; |
484 | 484 | ||
485 | gameport_set_drvdata(gameport, port); | 485 | gameport_set_drvdata(gameport, port); |
486 | 486 | ||
487 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 487 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
488 | if (err) | 488 | if (err) |
489 | goto fail1; | 489 | goto fail1; |
490 | 490 | ||
491 | adi_init_digital(gameport); | 491 | adi_init_digital(gameport); |
492 | adi_read_packet(port); | 492 | adi_read_packet(port); |
493 | 493 | ||
494 | if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH) | 494 | if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH) |
495 | adi_move_bits(port, adi_get_bits(port->adi, 10)); | 495 | adi_move_bits(port, adi_get_bits(port->adi, 10)); |
496 | 496 | ||
497 | for (i = 0; i < 2; i++) { | 497 | for (i = 0; i < 2; i++) { |
498 | adi_id_decode(port->adi + i, port); | 498 | adi_id_decode(port->adi + i, port); |
499 | 499 | ||
500 | if (!port->adi[i].length) | 500 | if (!port->adi[i].length) |
501 | continue; | 501 | continue; |
502 | 502 | ||
503 | err = adi_init_input(port->adi + i, port, i); | 503 | err = adi_init_input(port->adi + i, port, i); |
504 | if (err) | 504 | if (err) |
505 | goto fail2; | 505 | goto fail2; |
506 | } | 506 | } |
507 | 507 | ||
508 | if (!port->adi[0].length && !port->adi[1].length) { | 508 | if (!port->adi[0].length && !port->adi[1].length) { |
509 | err = -ENODEV; | 509 | err = -ENODEV; |
510 | goto fail2; | 510 | goto fail2; |
511 | } | 511 | } |
512 | 512 | ||
513 | gameport_set_poll_handler(gameport, adi_poll); | 513 | gameport_set_poll_handler(gameport, adi_poll); |
514 | gameport_set_poll_interval(gameport, 20); | 514 | gameport_set_poll_interval(gameport, 20); |
515 | 515 | ||
516 | msleep(ADI_INIT_DELAY); | 516 | msleep(ADI_INIT_DELAY); |
517 | if (adi_read(port)) { | 517 | if (adi_read(port)) { |
518 | msleep(ADI_DATA_DELAY); | 518 | msleep(ADI_DATA_DELAY); |
519 | adi_read(port); | 519 | adi_read(port); |
520 | } | 520 | } |
521 | 521 | ||
522 | for (i = 0; i < 2; i++) | 522 | for (i = 0; i < 2; i++) |
523 | if (port->adi[i].length > 0) { | 523 | if (port->adi[i].length > 0) { |
524 | adi_init_center(port->adi + i); | 524 | adi_init_center(port->adi + i); |
525 | err = input_register_device(port->adi[i].dev); | 525 | err = input_register_device(port->adi[i].dev); |
526 | if (err) | 526 | if (err) |
527 | goto fail3; | 527 | goto fail3; |
528 | } | 528 | } |
529 | 529 | ||
530 | return 0; | 530 | return 0; |
531 | 531 | ||
532 | fail3: while (--i >= 0) { | 532 | fail3: while (--i >= 0) { |
533 | if (port->adi[i].length > 0) { | 533 | if (port->adi[i].length > 0) { |
534 | input_unregister_device(port->adi[i].dev); | 534 | input_unregister_device(port->adi[i].dev); |
535 | port->adi[i].dev = NULL; | 535 | port->adi[i].dev = NULL; |
536 | } | 536 | } |
537 | } | 537 | } |
538 | fail2: for (i = 0; i < 2; i++) | 538 | fail2: for (i = 0; i < 2; i++) |
539 | if (port->adi[i].dev) | 539 | if (port->adi[i].dev) |
540 | input_free_device(port->adi[i].dev); | 540 | input_free_device(port->adi[i].dev); |
541 | gameport_close(gameport); | 541 | gameport_close(gameport); |
542 | fail1: gameport_set_drvdata(gameport, NULL); | 542 | fail1: gameport_set_drvdata(gameport, NULL); |
543 | kfree(port); | 543 | kfree(port); |
544 | return err; | 544 | return err; |
545 | } | 545 | } |
546 | 546 | ||
547 | static void adi_disconnect(struct gameport *gameport) | 547 | static void adi_disconnect(struct gameport *gameport) |
548 | { | 548 | { |
549 | int i; | 549 | int i; |
550 | struct adi_port *port = gameport_get_drvdata(gameport); | 550 | struct adi_port *port = gameport_get_drvdata(gameport); |
551 | 551 | ||
552 | for (i = 0; i < 2; i++) | 552 | for (i = 0; i < 2; i++) |
553 | if (port->adi[i].length > 0) | 553 | if (port->adi[i].length > 0) |
554 | input_unregister_device(port->adi[i].dev); | 554 | input_unregister_device(port->adi[i].dev); |
555 | gameport_close(gameport); | 555 | gameport_close(gameport); |
556 | gameport_set_drvdata(gameport, NULL); | 556 | gameport_set_drvdata(gameport, NULL); |
557 | kfree(port); | 557 | kfree(port); |
558 | } | 558 | } |
559 | 559 | ||
560 | /* | ||
561 | * The gameport device structure. | ||
562 | */ | ||
563 | |||
564 | static struct gameport_driver adi_drv = { | 560 | static struct gameport_driver adi_drv = { |
565 | .driver = { | 561 | .driver = { |
566 | .name = "adi", | 562 | .name = "adi", |
567 | }, | 563 | }, |
568 | .description = DRIVER_DESC, | 564 | .description = DRIVER_DESC, |
569 | .connect = adi_connect, | 565 | .connect = adi_connect, |
570 | .disconnect = adi_disconnect, | 566 | .disconnect = adi_disconnect, |
571 | }; | 567 | }; |
572 | 568 | ||
573 | static int __init adi_init(void) | 569 | module_gameport_driver(adi_drv); |
574 | { | ||
575 | return gameport_register_driver(&adi_drv); | ||
576 | } | ||
577 | |||
578 | static void __exit adi_exit(void) | ||
579 | { | ||
580 | gameport_unregister_driver(&adi_drv); | ||
581 | } | ||
582 | |||
583 | module_init(adi_init); | ||
584 | module_exit(adi_exit); | ||
585 | 570 |
drivers/input/joystick/cobra.c
1 | /* | 1 | /* |
2 | * Copyright (c) 1999-2001 Vojtech Pavlik | 2 | * Copyright (c) 1999-2001 Vojtech Pavlik |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
6 | * Creative Labs Blaster GamePad Cobra driver for Linux | 6 | * Creative Labs Blaster GamePad Cobra driver for Linux |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Should you need to contact me, the author, you can do so either by | 24 | * Should you need to contact me, the author, you can do so either by |
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/init.h> | 32 | #include <linux/init.h> |
33 | #include <linux/gameport.h> | 33 | #include <linux/gameport.h> |
34 | #include <linux/input.h> | 34 | #include <linux/input.h> |
35 | #include <linux/jiffies.h> | 35 | #include <linux/jiffies.h> |
36 | 36 | ||
37 | #define DRIVER_DESC "Creative Labs Blaster GamePad Cobra driver" | 37 | #define DRIVER_DESC "Creative Labs Blaster GamePad Cobra driver" |
38 | 38 | ||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
40 | MODULE_DESCRIPTION(DRIVER_DESC); | 40 | MODULE_DESCRIPTION(DRIVER_DESC); |
41 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
42 | 42 | ||
43 | #define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */ | 43 | #define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */ |
44 | #define COBRA_LENGTH 36 | 44 | #define COBRA_LENGTH 36 |
45 | 45 | ||
46 | static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 }; | 46 | static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 }; |
47 | 47 | ||
48 | struct cobra { | 48 | struct cobra { |
49 | struct gameport *gameport; | 49 | struct gameport *gameport; |
50 | struct input_dev *dev[2]; | 50 | struct input_dev *dev[2]; |
51 | int reads; | 51 | int reads; |
52 | int bads; | 52 | int bads; |
53 | unsigned char exists; | 53 | unsigned char exists; |
54 | char phys[2][32]; | 54 | char phys[2][32]; |
55 | }; | 55 | }; |
56 | 56 | ||
57 | static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data) | 57 | static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data) |
58 | { | 58 | { |
59 | unsigned long flags; | 59 | unsigned long flags; |
60 | unsigned char u, v, w; | 60 | unsigned char u, v, w; |
61 | __u64 buf[2]; | 61 | __u64 buf[2]; |
62 | int r[2], t[2]; | 62 | int r[2], t[2]; |
63 | int i, j, ret; | 63 | int i, j, ret; |
64 | 64 | ||
65 | int strobe = gameport_time(gameport, COBRA_MAX_STROBE); | 65 | int strobe = gameport_time(gameport, COBRA_MAX_STROBE); |
66 | 66 | ||
67 | for (i = 0; i < 2; i++) { | 67 | for (i = 0; i < 2; i++) { |
68 | r[i] = buf[i] = 0; | 68 | r[i] = buf[i] = 0; |
69 | t[i] = COBRA_MAX_STROBE; | 69 | t[i] = COBRA_MAX_STROBE; |
70 | } | 70 | } |
71 | 71 | ||
72 | local_irq_save(flags); | 72 | local_irq_save(flags); |
73 | 73 | ||
74 | u = gameport_read(gameport); | 74 | u = gameport_read(gameport); |
75 | 75 | ||
76 | do { | 76 | do { |
77 | t[0]--; t[1]--; | 77 | t[0]--; t[1]--; |
78 | v = gameport_read(gameport); | 78 | v = gameport_read(gameport); |
79 | for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2) | 79 | for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2) |
80 | if (w & 0x30) { | 80 | if (w & 0x30) { |
81 | if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) { | 81 | if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) { |
82 | buf[i] |= (__u64)((w >> 5) & 1) << r[i]++; | 82 | buf[i] |= (__u64)((w >> 5) & 1) << r[i]++; |
83 | t[i] = strobe; | 83 | t[i] = strobe; |
84 | u = v; | 84 | u = v; |
85 | } else t[i] = 0; | 85 | } else t[i] = 0; |
86 | } | 86 | } |
87 | } while (t[0] > 0 || t[1] > 0); | 87 | } while (t[0] > 0 || t[1] > 0); |
88 | 88 | ||
89 | local_irq_restore(flags); | 89 | local_irq_restore(flags); |
90 | 90 | ||
91 | ret = 0; | 91 | ret = 0; |
92 | 92 | ||
93 | for (i = 0; i < 2; i++) { | 93 | for (i = 0; i < 2; i++) { |
94 | 94 | ||
95 | if (r[i] != COBRA_LENGTH) continue; | 95 | if (r[i] != COBRA_LENGTH) continue; |
96 | 96 | ||
97 | for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++) | 97 | for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++) |
98 | buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1)); | 98 | buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1)); |
99 | 99 | ||
100 | if (j < COBRA_LENGTH) ret |= (1 << i); | 100 | if (j < COBRA_LENGTH) ret |= (1 << i); |
101 | 101 | ||
102 | data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0) | 102 | data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0) |
103 | | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000) | 103 | | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000) |
104 | | ((buf[i] >> 11) & 0x1f00000); | 104 | | ((buf[i] >> 11) & 0x1f00000); |
105 | 105 | ||
106 | } | 106 | } |
107 | 107 | ||
108 | return ret; | 108 | return ret; |
109 | } | 109 | } |
110 | 110 | ||
111 | static void cobra_poll(struct gameport *gameport) | 111 | static void cobra_poll(struct gameport *gameport) |
112 | { | 112 | { |
113 | struct cobra *cobra = gameport_get_drvdata(gameport); | 113 | struct cobra *cobra = gameport_get_drvdata(gameport); |
114 | struct input_dev *dev; | 114 | struct input_dev *dev; |
115 | unsigned int data[2]; | 115 | unsigned int data[2]; |
116 | int i, j, r; | 116 | int i, j, r; |
117 | 117 | ||
118 | cobra->reads++; | 118 | cobra->reads++; |
119 | 119 | ||
120 | if ((r = cobra_read_packet(gameport, data)) != cobra->exists) { | 120 | if ((r = cobra_read_packet(gameport, data)) != cobra->exists) { |
121 | cobra->bads++; | 121 | cobra->bads++; |
122 | return; | 122 | return; |
123 | } | 123 | } |
124 | 124 | ||
125 | for (i = 0; i < 2; i++) | 125 | for (i = 0; i < 2; i++) |
126 | if (cobra->exists & r & (1 << i)) { | 126 | if (cobra->exists & r & (1 << i)) { |
127 | 127 | ||
128 | dev = cobra->dev[i]; | 128 | dev = cobra->dev[i]; |
129 | 129 | ||
130 | input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1)); | 130 | input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1)); |
131 | input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); | 131 | input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1)); |
132 | 132 | ||
133 | for (j = 0; cobra_btn[j]; j++) | 133 | for (j = 0; cobra_btn[j]; j++) |
134 | input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j)); | 134 | input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j)); |
135 | 135 | ||
136 | input_sync(dev); | 136 | input_sync(dev); |
137 | 137 | ||
138 | } | 138 | } |
139 | } | 139 | } |
140 | 140 | ||
141 | static int cobra_open(struct input_dev *dev) | 141 | static int cobra_open(struct input_dev *dev) |
142 | { | 142 | { |
143 | struct cobra *cobra = input_get_drvdata(dev); | 143 | struct cobra *cobra = input_get_drvdata(dev); |
144 | 144 | ||
145 | gameport_start_polling(cobra->gameport); | 145 | gameport_start_polling(cobra->gameport); |
146 | return 0; | 146 | return 0; |
147 | } | 147 | } |
148 | 148 | ||
149 | static void cobra_close(struct input_dev *dev) | 149 | static void cobra_close(struct input_dev *dev) |
150 | { | 150 | { |
151 | struct cobra *cobra = input_get_drvdata(dev); | 151 | struct cobra *cobra = input_get_drvdata(dev); |
152 | 152 | ||
153 | gameport_stop_polling(cobra->gameport); | 153 | gameport_stop_polling(cobra->gameport); |
154 | } | 154 | } |
155 | 155 | ||
156 | static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) | 156 | static int cobra_connect(struct gameport *gameport, struct gameport_driver *drv) |
157 | { | 157 | { |
158 | struct cobra *cobra; | 158 | struct cobra *cobra; |
159 | struct input_dev *input_dev; | 159 | struct input_dev *input_dev; |
160 | unsigned int data[2]; | 160 | unsigned int data[2]; |
161 | int i, j; | 161 | int i, j; |
162 | int err; | 162 | int err; |
163 | 163 | ||
164 | cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL); | 164 | cobra = kzalloc(sizeof(struct cobra), GFP_KERNEL); |
165 | if (!cobra) | 165 | if (!cobra) |
166 | return -ENOMEM; | 166 | return -ENOMEM; |
167 | 167 | ||
168 | cobra->gameport = gameport; | 168 | cobra->gameport = gameport; |
169 | 169 | ||
170 | gameport_set_drvdata(gameport, cobra); | 170 | gameport_set_drvdata(gameport, cobra); |
171 | 171 | ||
172 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 172 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
173 | if (err) | 173 | if (err) |
174 | goto fail1; | 174 | goto fail1; |
175 | 175 | ||
176 | cobra->exists = cobra_read_packet(gameport, data); | 176 | cobra->exists = cobra_read_packet(gameport, data); |
177 | 177 | ||
178 | for (i = 0; i < 2; i++) | 178 | for (i = 0; i < 2; i++) |
179 | if ((cobra->exists >> i) & data[i] & 1) { | 179 | if ((cobra->exists >> i) & data[i] & 1) { |
180 | printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d" | 180 | printk(KERN_WARNING "cobra.c: Device %d on %s has the Ext bit set. ID is: %d" |
181 | " Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7); | 181 | " Contact vojtech@ucw.cz\n", i, gameport->phys, (data[i] >> 2) & 7); |
182 | cobra->exists &= ~(1 << i); | 182 | cobra->exists &= ~(1 << i); |
183 | } | 183 | } |
184 | 184 | ||
185 | if (!cobra->exists) { | 185 | if (!cobra->exists) { |
186 | err = -ENODEV; | 186 | err = -ENODEV; |
187 | goto fail2; | 187 | goto fail2; |
188 | } | 188 | } |
189 | 189 | ||
190 | gameport_set_poll_handler(gameport, cobra_poll); | 190 | gameport_set_poll_handler(gameport, cobra_poll); |
191 | gameport_set_poll_interval(gameport, 20); | 191 | gameport_set_poll_interval(gameport, 20); |
192 | 192 | ||
193 | for (i = 0; i < 2; i++) { | 193 | for (i = 0; i < 2; i++) { |
194 | if (~(cobra->exists >> i) & 1) | 194 | if (~(cobra->exists >> i) & 1) |
195 | continue; | 195 | continue; |
196 | 196 | ||
197 | cobra->dev[i] = input_dev = input_allocate_device(); | 197 | cobra->dev[i] = input_dev = input_allocate_device(); |
198 | if (!input_dev) { | 198 | if (!input_dev) { |
199 | err = -ENOMEM; | 199 | err = -ENOMEM; |
200 | goto fail3; | 200 | goto fail3; |
201 | } | 201 | } |
202 | 202 | ||
203 | snprintf(cobra->phys[i], sizeof(cobra->phys[i]), | 203 | snprintf(cobra->phys[i], sizeof(cobra->phys[i]), |
204 | "%s/input%d", gameport->phys, i); | 204 | "%s/input%d", gameport->phys, i); |
205 | 205 | ||
206 | input_dev->name = "Creative Labs Blaster GamePad Cobra"; | 206 | input_dev->name = "Creative Labs Blaster GamePad Cobra"; |
207 | input_dev->phys = cobra->phys[i]; | 207 | input_dev->phys = cobra->phys[i]; |
208 | input_dev->id.bustype = BUS_GAMEPORT; | 208 | input_dev->id.bustype = BUS_GAMEPORT; |
209 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; | 209 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_CREATIVE; |
210 | input_dev->id.product = 0x0008; | 210 | input_dev->id.product = 0x0008; |
211 | input_dev->id.version = 0x0100; | 211 | input_dev->id.version = 0x0100; |
212 | input_dev->dev.parent = &gameport->dev; | 212 | input_dev->dev.parent = &gameport->dev; |
213 | 213 | ||
214 | input_set_drvdata(input_dev, cobra); | 214 | input_set_drvdata(input_dev, cobra); |
215 | 215 | ||
216 | input_dev->open = cobra_open; | 216 | input_dev->open = cobra_open; |
217 | input_dev->close = cobra_close; | 217 | input_dev->close = cobra_close; |
218 | 218 | ||
219 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 219 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
220 | input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); | 220 | input_set_abs_params(input_dev, ABS_X, -1, 1, 0, 0); |
221 | input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); | 221 | input_set_abs_params(input_dev, ABS_Y, -1, 1, 0, 0); |
222 | for (j = 0; cobra_btn[j]; j++) | 222 | for (j = 0; cobra_btn[j]; j++) |
223 | set_bit(cobra_btn[j], input_dev->keybit); | 223 | set_bit(cobra_btn[j], input_dev->keybit); |
224 | 224 | ||
225 | err = input_register_device(cobra->dev[i]); | 225 | err = input_register_device(cobra->dev[i]); |
226 | if (err) | 226 | if (err) |
227 | goto fail4; | 227 | goto fail4; |
228 | } | 228 | } |
229 | 229 | ||
230 | return 0; | 230 | return 0; |
231 | 231 | ||
232 | fail4: input_free_device(cobra->dev[i]); | 232 | fail4: input_free_device(cobra->dev[i]); |
233 | fail3: while (--i >= 0) | 233 | fail3: while (--i >= 0) |
234 | if (cobra->dev[i]) | 234 | if (cobra->dev[i]) |
235 | input_unregister_device(cobra->dev[i]); | 235 | input_unregister_device(cobra->dev[i]); |
236 | fail2: gameport_close(gameport); | 236 | fail2: gameport_close(gameport); |
237 | fail1: gameport_set_drvdata(gameport, NULL); | 237 | fail1: gameport_set_drvdata(gameport, NULL); |
238 | kfree(cobra); | 238 | kfree(cobra); |
239 | return err; | 239 | return err; |
240 | } | 240 | } |
241 | 241 | ||
242 | static void cobra_disconnect(struct gameport *gameport) | 242 | static void cobra_disconnect(struct gameport *gameport) |
243 | { | 243 | { |
244 | struct cobra *cobra = gameport_get_drvdata(gameport); | 244 | struct cobra *cobra = gameport_get_drvdata(gameport); |
245 | int i; | 245 | int i; |
246 | 246 | ||
247 | for (i = 0; i < 2; i++) | 247 | for (i = 0; i < 2; i++) |
248 | if ((cobra->exists >> i) & 1) | 248 | if ((cobra->exists >> i) & 1) |
249 | input_unregister_device(cobra->dev[i]); | 249 | input_unregister_device(cobra->dev[i]); |
250 | gameport_close(gameport); | 250 | gameport_close(gameport); |
251 | gameport_set_drvdata(gameport, NULL); | 251 | gameport_set_drvdata(gameport, NULL); |
252 | kfree(cobra); | 252 | kfree(cobra); |
253 | } | 253 | } |
254 | 254 | ||
255 | static struct gameport_driver cobra_drv = { | 255 | static struct gameport_driver cobra_drv = { |
256 | .driver = { | 256 | .driver = { |
257 | .name = "cobra", | 257 | .name = "cobra", |
258 | }, | 258 | }, |
259 | .description = DRIVER_DESC, | 259 | .description = DRIVER_DESC, |
260 | .connect = cobra_connect, | 260 | .connect = cobra_connect, |
261 | .disconnect = cobra_disconnect, | 261 | .disconnect = cobra_disconnect, |
262 | }; | 262 | }; |
263 | 263 | ||
264 | static int __init cobra_init(void) | 264 | module_gameport_driver(cobra_drv); |
265 | { | ||
266 | return gameport_register_driver(&cobra_drv); | ||
267 | } | ||
268 | |||
269 | static void __exit cobra_exit(void) | ||
270 | { | ||
271 | gameport_unregister_driver(&cobra_drv); | ||
272 | } | ||
273 | |||
274 | module_init(cobra_init); | ||
275 | module_exit(cobra_exit); | ||
276 | 265 |
drivers/input/joystick/gf2k.c
1 | /* | 1 | /* |
2 | * Copyright (c) 1998-2001 Vojtech Pavlik | 2 | * Copyright (c) 1998-2001 Vojtech Pavlik |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
6 | * Genius Flight 2000 joystick driver for Linux | 6 | * Genius Flight 2000 joystick driver for Linux |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Should you need to contact me, the author, you can do so either by | 24 | * Should you need to contact me, the author, you can do so either by |
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/slab.h> | 31 | #include <linux/slab.h> |
32 | #include <linux/module.h> | 32 | #include <linux/module.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/input.h> | 34 | #include <linux/input.h> |
35 | #include <linux/gameport.h> | 35 | #include <linux/gameport.h> |
36 | #include <linux/jiffies.h> | 36 | #include <linux/jiffies.h> |
37 | 37 | ||
38 | #define DRIVER_DESC "Genius Flight 2000 joystick driver" | 38 | #define DRIVER_DESC "Genius Flight 2000 joystick driver" |
39 | 39 | ||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
41 | MODULE_DESCRIPTION(DRIVER_DESC); | 41 | MODULE_DESCRIPTION(DRIVER_DESC); |
42 | MODULE_LICENSE("GPL"); | 42 | MODULE_LICENSE("GPL"); |
43 | 43 | ||
44 | #define GF2K_START 400 /* The time we wait for the first bit [400 us] */ | 44 | #define GF2K_START 400 /* The time we wait for the first bit [400 us] */ |
45 | #define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */ | 45 | #define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */ |
46 | #define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */ | 46 | #define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */ |
47 | #define GF2K_LENGTH 80 /* Max number of triplets in a packet */ | 47 | #define GF2K_LENGTH 80 /* Max number of triplets in a packet */ |
48 | 48 | ||
49 | /* | 49 | /* |
50 | * Genius joystick ids ... | 50 | * Genius joystick ids ... |
51 | */ | 51 | */ |
52 | 52 | ||
53 | #define GF2K_ID_G09 1 | 53 | #define GF2K_ID_G09 1 |
54 | #define GF2K_ID_F30D 2 | 54 | #define GF2K_ID_F30D 2 |
55 | #define GF2K_ID_F30 3 | 55 | #define GF2K_ID_F30 3 |
56 | #define GF2K_ID_F31D 4 | 56 | #define GF2K_ID_F31D 4 |
57 | #define GF2K_ID_F305 5 | 57 | #define GF2K_ID_F305 5 |
58 | #define GF2K_ID_F23P 6 | 58 | #define GF2K_ID_F23P 6 |
59 | #define GF2K_ID_F31 7 | 59 | #define GF2K_ID_F31 7 |
60 | #define GF2K_ID_MAX 7 | 60 | #define GF2K_ID_MAX 7 |
61 | 61 | ||
62 | static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 }; | 62 | static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 }; |
63 | static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | 63 | static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; |
64 | 64 | ||
65 | static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D", | 65 | static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D", |
66 | "Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"}; | 66 | "Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"}; |
67 | static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 }; | 67 | static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 }; |
68 | static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 }; | 68 | static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 }; |
69 | static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 }; | 69 | static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 }; |
70 | static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 }; | 70 | static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 }; |
71 | static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 }; | 71 | static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 }; |
72 | 72 | ||
73 | static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE }; | 73 | static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE }; |
74 | static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }; | 74 | static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }; |
75 | static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT }; | 75 | static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT }; |
76 | 76 | ||
77 | 77 | ||
78 | static short gf2k_seq_reset[] = { 240, 340, 0 }; | 78 | static short gf2k_seq_reset[] = { 240, 340, 0 }; |
79 | static short gf2k_seq_digital[] = { 590, 320, 860, 0 }; | 79 | static short gf2k_seq_digital[] = { 590, 320, 860, 0 }; |
80 | 80 | ||
81 | struct gf2k { | 81 | struct gf2k { |
82 | struct gameport *gameport; | 82 | struct gameport *gameport; |
83 | struct input_dev *dev; | 83 | struct input_dev *dev; |
84 | int reads; | 84 | int reads; |
85 | int bads; | 85 | int bads; |
86 | unsigned char id; | 86 | unsigned char id; |
87 | unsigned char length; | 87 | unsigned char length; |
88 | char phys[32]; | 88 | char phys[32]; |
89 | }; | 89 | }; |
90 | 90 | ||
91 | /* | 91 | /* |
92 | * gf2k_read_packet() reads a Genius Flight2000 packet. | 92 | * gf2k_read_packet() reads a Genius Flight2000 packet. |
93 | */ | 93 | */ |
94 | 94 | ||
95 | static int gf2k_read_packet(struct gameport *gameport, int length, char *data) | 95 | static int gf2k_read_packet(struct gameport *gameport, int length, char *data) |
96 | { | 96 | { |
97 | unsigned char u, v; | 97 | unsigned char u, v; |
98 | int i; | 98 | int i; |
99 | unsigned int t, p; | 99 | unsigned int t, p; |
100 | unsigned long flags; | 100 | unsigned long flags; |
101 | 101 | ||
102 | t = gameport_time(gameport, GF2K_START); | 102 | t = gameport_time(gameport, GF2K_START); |
103 | p = gameport_time(gameport, GF2K_STROBE); | 103 | p = gameport_time(gameport, GF2K_STROBE); |
104 | 104 | ||
105 | i = 0; | 105 | i = 0; |
106 | 106 | ||
107 | local_irq_save(flags); | 107 | local_irq_save(flags); |
108 | 108 | ||
109 | gameport_trigger(gameport); | 109 | gameport_trigger(gameport); |
110 | v = gameport_read(gameport); | 110 | v = gameport_read(gameport); |
111 | 111 | ||
112 | while (t > 0 && i < length) { | 112 | while (t > 0 && i < length) { |
113 | t--; u = v; | 113 | t--; u = v; |
114 | v = gameport_read(gameport); | 114 | v = gameport_read(gameport); |
115 | if (v & ~u & 0x10) { | 115 | if (v & ~u & 0x10) { |
116 | data[i++] = v >> 5; | 116 | data[i++] = v >> 5; |
117 | t = p; | 117 | t = p; |
118 | } | 118 | } |
119 | } | 119 | } |
120 | 120 | ||
121 | local_irq_restore(flags); | 121 | local_irq_restore(flags); |
122 | 122 | ||
123 | return i; | 123 | return i; |
124 | } | 124 | } |
125 | 125 | ||
126 | /* | 126 | /* |
127 | * gf2k_trigger_seq() initializes a Genius Flight2000 joystick | 127 | * gf2k_trigger_seq() initializes a Genius Flight2000 joystick |
128 | * into digital mode. | 128 | * into digital mode. |
129 | */ | 129 | */ |
130 | 130 | ||
131 | static void gf2k_trigger_seq(struct gameport *gameport, short *seq) | 131 | static void gf2k_trigger_seq(struct gameport *gameport, short *seq) |
132 | { | 132 | { |
133 | 133 | ||
134 | unsigned long flags; | 134 | unsigned long flags; |
135 | int i, t; | 135 | int i, t; |
136 | 136 | ||
137 | local_irq_save(flags); | 137 | local_irq_save(flags); |
138 | 138 | ||
139 | i = 0; | 139 | i = 0; |
140 | do { | 140 | do { |
141 | gameport_trigger(gameport); | 141 | gameport_trigger(gameport); |
142 | t = gameport_time(gameport, GF2K_TIMEOUT * 1000); | 142 | t = gameport_time(gameport, GF2K_TIMEOUT * 1000); |
143 | while ((gameport_read(gameport) & 1) && t) t--; | 143 | while ((gameport_read(gameport) & 1) && t) t--; |
144 | udelay(seq[i]); | 144 | udelay(seq[i]); |
145 | } while (seq[++i]); | 145 | } while (seq[++i]); |
146 | 146 | ||
147 | gameport_trigger(gameport); | 147 | gameport_trigger(gameport); |
148 | 148 | ||
149 | local_irq_restore(flags); | 149 | local_irq_restore(flags); |
150 | } | 150 | } |
151 | 151 | ||
152 | /* | 152 | /* |
153 | * js_sw_get_bits() composes bits from the triplet buffer into a __u64. | 153 | * js_sw_get_bits() composes bits from the triplet buffer into a __u64. |
154 | * Parameter 'pos' is bit number inside packet where to start at, 'num' is number | 154 | * Parameter 'pos' is bit number inside packet where to start at, 'num' is number |
155 | * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits | 155 | * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits |
156 | * is number of bits per triplet. | 156 | * is number of bits per triplet. |
157 | */ | 157 | */ |
158 | 158 | ||
159 | #define GB(p,n,s) gf2k_get_bits(data, p, n, s) | 159 | #define GB(p,n,s) gf2k_get_bits(data, p, n, s) |
160 | 160 | ||
161 | static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift) | 161 | static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift) |
162 | { | 162 | { |
163 | __u64 data = 0; | 163 | __u64 data = 0; |
164 | int i; | 164 | int i; |
165 | 165 | ||
166 | for (i = 0; i < num / 3 + 2; i++) | 166 | for (i = 0; i < num / 3 + 2; i++) |
167 | data |= buf[pos / 3 + i] << (i * 3); | 167 | data |= buf[pos / 3 + i] << (i * 3); |
168 | data >>= pos % 3; | 168 | data >>= pos % 3; |
169 | data &= (1 << num) - 1; | 169 | data &= (1 << num) - 1; |
170 | data <<= shift; | 170 | data <<= shift; |
171 | 171 | ||
172 | return data; | 172 | return data; |
173 | } | 173 | } |
174 | 174 | ||
175 | static void gf2k_read(struct gf2k *gf2k, unsigned char *data) | 175 | static void gf2k_read(struct gf2k *gf2k, unsigned char *data) |
176 | { | 176 | { |
177 | struct input_dev *dev = gf2k->dev; | 177 | struct input_dev *dev = gf2k->dev; |
178 | int i, t; | 178 | int i, t; |
179 | 179 | ||
180 | for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++) | 180 | for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++) |
181 | input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9)); | 181 | input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9)); |
182 | 182 | ||
183 | for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++) | 183 | for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++) |
184 | input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9)); | 184 | input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9)); |
185 | 185 | ||
186 | t = GB(40,4,0); | 186 | t = GB(40,4,0); |
187 | 187 | ||
188 | for (i = 0; i < gf2k_hats[gf2k->id]; i++) | 188 | for (i = 0; i < gf2k_hats[gf2k->id]; i++) |
189 | input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]); | 189 | input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]); |
190 | 190 | ||
191 | t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10); | 191 | t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10); |
192 | 192 | ||
193 | for (i = 0; i < gf2k_joys[gf2k->id]; i++) | 193 | for (i = 0; i < gf2k_joys[gf2k->id]; i++) |
194 | input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1); | 194 | input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1); |
195 | 195 | ||
196 | for (i = 0; i < gf2k_pads[gf2k->id]; i++) | 196 | for (i = 0; i < gf2k_pads[gf2k->id]; i++) |
197 | input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1); | 197 | input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1); |
198 | 198 | ||
199 | input_sync(dev); | 199 | input_sync(dev); |
200 | } | 200 | } |
201 | 201 | ||
202 | /* | 202 | /* |
203 | * gf2k_poll() reads and analyzes Genius joystick data. | 203 | * gf2k_poll() reads and analyzes Genius joystick data. |
204 | */ | 204 | */ |
205 | 205 | ||
206 | static void gf2k_poll(struct gameport *gameport) | 206 | static void gf2k_poll(struct gameport *gameport) |
207 | { | 207 | { |
208 | struct gf2k *gf2k = gameport_get_drvdata(gameport); | 208 | struct gf2k *gf2k = gameport_get_drvdata(gameport); |
209 | unsigned char data[GF2K_LENGTH]; | 209 | unsigned char data[GF2K_LENGTH]; |
210 | 210 | ||
211 | gf2k->reads++; | 211 | gf2k->reads++; |
212 | 212 | ||
213 | if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) | 213 | if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) |
214 | gf2k->bads++; | 214 | gf2k->bads++; |
215 | else | 215 | else |
216 | gf2k_read(gf2k, data); | 216 | gf2k_read(gf2k, data); |
217 | } | 217 | } |
218 | 218 | ||
219 | static int gf2k_open(struct input_dev *dev) | 219 | static int gf2k_open(struct input_dev *dev) |
220 | { | 220 | { |
221 | struct gf2k *gf2k = input_get_drvdata(dev); | 221 | struct gf2k *gf2k = input_get_drvdata(dev); |
222 | 222 | ||
223 | gameport_start_polling(gf2k->gameport); | 223 | gameport_start_polling(gf2k->gameport); |
224 | return 0; | 224 | return 0; |
225 | } | 225 | } |
226 | 226 | ||
227 | static void gf2k_close(struct input_dev *dev) | 227 | static void gf2k_close(struct input_dev *dev) |
228 | { | 228 | { |
229 | struct gf2k *gf2k = input_get_drvdata(dev); | 229 | struct gf2k *gf2k = input_get_drvdata(dev); |
230 | 230 | ||
231 | gameport_stop_polling(gf2k->gameport); | 231 | gameport_stop_polling(gf2k->gameport); |
232 | } | 232 | } |
233 | 233 | ||
234 | /* | 234 | /* |
235 | * gf2k_connect() probes for Genius id joysticks. | 235 | * gf2k_connect() probes for Genius id joysticks. |
236 | */ | 236 | */ |
237 | 237 | ||
238 | static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) | 238 | static int gf2k_connect(struct gameport *gameport, struct gameport_driver *drv) |
239 | { | 239 | { |
240 | struct gf2k *gf2k; | 240 | struct gf2k *gf2k; |
241 | struct input_dev *input_dev; | 241 | struct input_dev *input_dev; |
242 | unsigned char data[GF2K_LENGTH]; | 242 | unsigned char data[GF2K_LENGTH]; |
243 | int i, err; | 243 | int i, err; |
244 | 244 | ||
245 | gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL); | 245 | gf2k = kzalloc(sizeof(struct gf2k), GFP_KERNEL); |
246 | input_dev = input_allocate_device(); | 246 | input_dev = input_allocate_device(); |
247 | if (!gf2k || !input_dev) { | 247 | if (!gf2k || !input_dev) { |
248 | err = -ENOMEM; | 248 | err = -ENOMEM; |
249 | goto fail1; | 249 | goto fail1; |
250 | } | 250 | } |
251 | 251 | ||
252 | gf2k->gameport = gameport; | 252 | gf2k->gameport = gameport; |
253 | gf2k->dev = input_dev; | 253 | gf2k->dev = input_dev; |
254 | 254 | ||
255 | gameport_set_drvdata(gameport, gf2k); | 255 | gameport_set_drvdata(gameport, gf2k); |
256 | 256 | ||
257 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 257 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
258 | if (err) | 258 | if (err) |
259 | goto fail1; | 259 | goto fail1; |
260 | 260 | ||
261 | gf2k_trigger_seq(gameport, gf2k_seq_reset); | 261 | gf2k_trigger_seq(gameport, gf2k_seq_reset); |
262 | 262 | ||
263 | msleep(GF2K_TIMEOUT); | 263 | msleep(GF2K_TIMEOUT); |
264 | 264 | ||
265 | gf2k_trigger_seq(gameport, gf2k_seq_digital); | 265 | gf2k_trigger_seq(gameport, gf2k_seq_digital); |
266 | 266 | ||
267 | msleep(GF2K_TIMEOUT); | 267 | msleep(GF2K_TIMEOUT); |
268 | 268 | ||
269 | if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12) { | 269 | if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12) { |
270 | err = -ENODEV; | 270 | err = -ENODEV; |
271 | goto fail2; | 271 | goto fail2; |
272 | } | 272 | } |
273 | 273 | ||
274 | if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5))) { | 274 | if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5))) { |
275 | err = -ENODEV; | 275 | err = -ENODEV; |
276 | goto fail2; | 276 | goto fail2; |
277 | } | 277 | } |
278 | 278 | ||
279 | #ifdef RESET_WORKS | 279 | #ifdef RESET_WORKS |
280 | if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) && | 280 | if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) && |
281 | (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) { | 281 | (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5)))) { |
282 | err = -ENODEV; | 282 | err = -ENODEV; |
283 | goto fail2; | 283 | goto fail2; |
284 | } | 284 | } |
285 | #else | 285 | #else |
286 | gf2k->id = 6; | 286 | gf2k->id = 6; |
287 | #endif | 287 | #endif |
288 | 288 | ||
289 | if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) { | 289 | if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) { |
290 | printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n", | 290 | printk(KERN_WARNING "gf2k.c: Not yet supported joystick on %s. [id: %d type:%s]\n", |
291 | gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]); | 291 | gameport->phys, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]); |
292 | err = -ENODEV; | 292 | err = -ENODEV; |
293 | goto fail2; | 293 | goto fail2; |
294 | } | 294 | } |
295 | 295 | ||
296 | gameport_set_poll_handler(gameport, gf2k_poll); | 296 | gameport_set_poll_handler(gameport, gf2k_poll); |
297 | gameport_set_poll_interval(gameport, 20); | 297 | gameport_set_poll_interval(gameport, 20); |
298 | 298 | ||
299 | snprintf(gf2k->phys, sizeof(gf2k->phys), "%s/input0", gameport->phys); | 299 | snprintf(gf2k->phys, sizeof(gf2k->phys), "%s/input0", gameport->phys); |
300 | 300 | ||
301 | gf2k->length = gf2k_lens[gf2k->id]; | 301 | gf2k->length = gf2k_lens[gf2k->id]; |
302 | 302 | ||
303 | input_dev->name = gf2k_names[gf2k->id]; | 303 | input_dev->name = gf2k_names[gf2k->id]; |
304 | input_dev->phys = gf2k->phys; | 304 | input_dev->phys = gf2k->phys; |
305 | input_dev->id.bustype = BUS_GAMEPORT; | 305 | input_dev->id.bustype = BUS_GAMEPORT; |
306 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS; | 306 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_GENIUS; |
307 | input_dev->id.product = gf2k->id; | 307 | input_dev->id.product = gf2k->id; |
308 | input_dev->id.version = 0x0100; | 308 | input_dev->id.version = 0x0100; |
309 | input_dev->dev.parent = &gameport->dev; | 309 | input_dev->dev.parent = &gameport->dev; |
310 | 310 | ||
311 | input_set_drvdata(input_dev, gf2k); | 311 | input_set_drvdata(input_dev, gf2k); |
312 | 312 | ||
313 | input_dev->open = gf2k_open; | 313 | input_dev->open = gf2k_open; |
314 | input_dev->close = gf2k_close; | 314 | input_dev->close = gf2k_close; |
315 | 315 | ||
316 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 316 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
317 | 317 | ||
318 | for (i = 0; i < gf2k_axes[gf2k->id]; i++) | 318 | for (i = 0; i < gf2k_axes[gf2k->id]; i++) |
319 | set_bit(gf2k_abs[i], input_dev->absbit); | 319 | set_bit(gf2k_abs[i], input_dev->absbit); |
320 | 320 | ||
321 | for (i = 0; i < gf2k_hats[gf2k->id]; i++) | 321 | for (i = 0; i < gf2k_hats[gf2k->id]; i++) |
322 | input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); | 322 | input_set_abs_params(input_dev, ABS_HAT0X + i, -1, 1, 0, 0); |
323 | 323 | ||
324 | for (i = 0; i < gf2k_joys[gf2k->id]; i++) | 324 | for (i = 0; i < gf2k_joys[gf2k->id]; i++) |
325 | set_bit(gf2k_btn_joy[i], input_dev->keybit); | 325 | set_bit(gf2k_btn_joy[i], input_dev->keybit); |
326 | 326 | ||
327 | for (i = 0; i < gf2k_pads[gf2k->id]; i++) | 327 | for (i = 0; i < gf2k_pads[gf2k->id]; i++) |
328 | set_bit(gf2k_btn_pad[i], input_dev->keybit); | 328 | set_bit(gf2k_btn_pad[i], input_dev->keybit); |
329 | 329 | ||
330 | gf2k_read_packet(gameport, gf2k->length, data); | 330 | gf2k_read_packet(gameport, gf2k->length, data); |
331 | gf2k_read(gf2k, data); | 331 | gf2k_read(gf2k, data); |
332 | 332 | ||
333 | for (i = 0; i < gf2k_axes[gf2k->id]; i++) { | 333 | for (i = 0; i < gf2k_axes[gf2k->id]; i++) { |
334 | int max = i < 2 ? | 334 | int max = i < 2 ? |
335 | input_abs_get_val(input_dev, gf2k_abs[i]) * 2 : | 335 | input_abs_get_val(input_dev, gf2k_abs[i]) * 2 : |
336 | input_abs_get_val(input_dev, gf2k_abs[0]) + | 336 | input_abs_get_val(input_dev, gf2k_abs[0]) + |
337 | input_abs_get_val(input_dev, gf2k_abs[1]); | 337 | input_abs_get_val(input_dev, gf2k_abs[1]); |
338 | int flat = i < 2 ? 24 : 0; | 338 | int flat = i < 2 ? 24 : 0; |
339 | 339 | ||
340 | input_set_abs_params(input_dev, gf2k_abs[i], | 340 | input_set_abs_params(input_dev, gf2k_abs[i], |
341 | 32, max - 32, 8, flat); | 341 | 32, max - 32, 8, flat); |
342 | } | 342 | } |
343 | 343 | ||
344 | err = input_register_device(gf2k->dev); | 344 | err = input_register_device(gf2k->dev); |
345 | if (err) | 345 | if (err) |
346 | goto fail2; | 346 | goto fail2; |
347 | 347 | ||
348 | return 0; | 348 | return 0; |
349 | 349 | ||
350 | fail2: gameport_close(gameport); | 350 | fail2: gameport_close(gameport); |
351 | fail1: gameport_set_drvdata(gameport, NULL); | 351 | fail1: gameport_set_drvdata(gameport, NULL); |
352 | input_free_device(input_dev); | 352 | input_free_device(input_dev); |
353 | kfree(gf2k); | 353 | kfree(gf2k); |
354 | return err; | 354 | return err; |
355 | } | 355 | } |
356 | 356 | ||
357 | static void gf2k_disconnect(struct gameport *gameport) | 357 | static void gf2k_disconnect(struct gameport *gameport) |
358 | { | 358 | { |
359 | struct gf2k *gf2k = gameport_get_drvdata(gameport); | 359 | struct gf2k *gf2k = gameport_get_drvdata(gameport); |
360 | 360 | ||
361 | input_unregister_device(gf2k->dev); | 361 | input_unregister_device(gf2k->dev); |
362 | gameport_close(gameport); | 362 | gameport_close(gameport); |
363 | gameport_set_drvdata(gameport, NULL); | 363 | gameport_set_drvdata(gameport, NULL); |
364 | kfree(gf2k); | 364 | kfree(gf2k); |
365 | } | 365 | } |
366 | 366 | ||
367 | static struct gameport_driver gf2k_drv = { | 367 | static struct gameport_driver gf2k_drv = { |
368 | .driver = { | 368 | .driver = { |
369 | .name = "gf2k", | 369 | .name = "gf2k", |
370 | }, | 370 | }, |
371 | .description = DRIVER_DESC, | 371 | .description = DRIVER_DESC, |
372 | .connect = gf2k_connect, | 372 | .connect = gf2k_connect, |
373 | .disconnect = gf2k_disconnect, | 373 | .disconnect = gf2k_disconnect, |
374 | }; | 374 | }; |
375 | 375 | ||
376 | static int __init gf2k_init(void) | 376 | module_gameport_driver(gf2k_drv); |
377 | { | ||
378 | return gameport_register_driver(&gf2k_drv); | ||
379 | } | ||
380 | |||
381 | static void __exit gf2k_exit(void) | ||
382 | { | ||
383 | gameport_unregister_driver(&gf2k_drv); | ||
384 | } | ||
385 | |||
386 | module_init(gf2k_init); | ||
387 | module_exit(gf2k_exit); | ||
388 | 377 |
drivers/input/joystick/grip.c
1 | /* | 1 | /* |
2 | * Copyright (c) 1998-2001 Vojtech Pavlik | 2 | * Copyright (c) 1998-2001 Vojtech Pavlik |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
6 | * Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux | 6 | * Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Should you need to contact me, the author, you can do so either by | 24 | * Should you need to contact me, the author, you can do so either by |
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/init.h> | 31 | #include <linux/init.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/gameport.h> | 33 | #include <linux/gameport.h> |
34 | #include <linux/input.h> | 34 | #include <linux/input.h> |
35 | #include <linux/jiffies.h> | 35 | #include <linux/jiffies.h> |
36 | 36 | ||
37 | #define DRIVER_DESC "Gravis GrIP protocol joystick driver" | 37 | #define DRIVER_DESC "Gravis GrIP protocol joystick driver" |
38 | 38 | ||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
40 | MODULE_DESCRIPTION(DRIVER_DESC); | 40 | MODULE_DESCRIPTION(DRIVER_DESC); |
41 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
42 | 42 | ||
43 | #define GRIP_MODE_GPP 1 | 43 | #define GRIP_MODE_GPP 1 |
44 | #define GRIP_MODE_BD 2 | 44 | #define GRIP_MODE_BD 2 |
45 | #define GRIP_MODE_XT 3 | 45 | #define GRIP_MODE_XT 3 |
46 | #define GRIP_MODE_DC 4 | 46 | #define GRIP_MODE_DC 4 |
47 | 47 | ||
48 | #define GRIP_LENGTH_GPP 24 | 48 | #define GRIP_LENGTH_GPP 24 |
49 | #define GRIP_STROBE_GPP 200 /* 200 us */ | 49 | #define GRIP_STROBE_GPP 200 /* 200 us */ |
50 | #define GRIP_LENGTH_XT 4 | 50 | #define GRIP_LENGTH_XT 4 |
51 | #define GRIP_STROBE_XT 64 /* 64 us */ | 51 | #define GRIP_STROBE_XT 64 /* 64 us */ |
52 | #define GRIP_MAX_CHUNKS_XT 10 | 52 | #define GRIP_MAX_CHUNKS_XT 10 |
53 | #define GRIP_MAX_BITS_XT 30 | 53 | #define GRIP_MAX_BITS_XT 30 |
54 | 54 | ||
55 | struct grip { | 55 | struct grip { |
56 | struct gameport *gameport; | 56 | struct gameport *gameport; |
57 | struct input_dev *dev[2]; | 57 | struct input_dev *dev[2]; |
58 | unsigned char mode[2]; | 58 | unsigned char mode[2]; |
59 | int reads; | 59 | int reads; |
60 | int bads; | 60 | int bads; |
61 | char phys[2][32]; | 61 | char phys[2][32]; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 }; | 64 | static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 }; |
65 | static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 }; | 65 | static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 }; |
66 | static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 }; | 66 | static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 }; |
67 | static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 }; | 67 | static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 }; |
68 | 68 | ||
69 | static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 }; | 69 | static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 }; |
70 | static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; | 70 | static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; |
71 | static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 }; | 71 | static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 }; |
72 | static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; | 72 | static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; |
73 | 73 | ||
74 | static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital", | 74 | static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital", |
75 | "Gravis Xterminator Digital", "Gravis Xterminator DualControl" }; | 75 | "Gravis Xterminator Digital", "Gravis Xterminator DualControl" }; |
76 | static int *grip_abs[] = { NULL, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc }; | 76 | static int *grip_abs[] = { NULL, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc }; |
77 | static int *grip_btn[] = { NULL, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc }; | 77 | static int *grip_btn[] = { NULL, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc }; |
78 | static char grip_anx[] = { 0, 0, 3, 5, 5 }; | 78 | static char grip_anx[] = { 0, 0, 3, 5, 5 }; |
79 | static char grip_cen[] = { 0, 0, 2, 2, 4 }; | 79 | static char grip_cen[] = { 0, 0, 2, 2, 4 }; |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * grip_gpp_read_packet() reads a Gravis GamePad Pro packet. | 82 | * grip_gpp_read_packet() reads a Gravis GamePad Pro packet. |
83 | */ | 83 | */ |
84 | 84 | ||
85 | static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data) | 85 | static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data) |
86 | { | 86 | { |
87 | unsigned long flags; | 87 | unsigned long flags; |
88 | unsigned char u, v; | 88 | unsigned char u, v; |
89 | unsigned int t; | 89 | unsigned int t; |
90 | int i; | 90 | int i; |
91 | 91 | ||
92 | int strobe = gameport_time(gameport, GRIP_STROBE_GPP); | 92 | int strobe = gameport_time(gameport, GRIP_STROBE_GPP); |
93 | 93 | ||
94 | data[0] = 0; | 94 | data[0] = 0; |
95 | t = strobe; | 95 | t = strobe; |
96 | i = 0; | 96 | i = 0; |
97 | 97 | ||
98 | local_irq_save(flags); | 98 | local_irq_save(flags); |
99 | 99 | ||
100 | v = gameport_read(gameport) >> shift; | 100 | v = gameport_read(gameport) >> shift; |
101 | 101 | ||
102 | do { | 102 | do { |
103 | t--; | 103 | t--; |
104 | u = v; v = (gameport_read(gameport) >> shift) & 3; | 104 | u = v; v = (gameport_read(gameport) >> shift) & 3; |
105 | if (~v & u & 1) { | 105 | if (~v & u & 1) { |
106 | data[0] |= (v >> 1) << i++; | 106 | data[0] |= (v >> 1) << i++; |
107 | t = strobe; | 107 | t = strobe; |
108 | } | 108 | } |
109 | } while (i < GRIP_LENGTH_GPP && t > 0); | 109 | } while (i < GRIP_LENGTH_GPP && t > 0); |
110 | 110 | ||
111 | local_irq_restore(flags); | 111 | local_irq_restore(flags); |
112 | 112 | ||
113 | if (i < GRIP_LENGTH_GPP) return -1; | 113 | if (i < GRIP_LENGTH_GPP) return -1; |
114 | 114 | ||
115 | for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++) | 115 | for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++) |
116 | data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1); | 116 | data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1); |
117 | 117 | ||
118 | return -(i == GRIP_LENGTH_GPP); | 118 | return -(i == GRIP_LENGTH_GPP); |
119 | } | 119 | } |
120 | 120 | ||
121 | /* | 121 | /* |
122 | * grip_xt_read_packet() reads a Gravis Xterminator packet. | 122 | * grip_xt_read_packet() reads a Gravis Xterminator packet. |
123 | */ | 123 | */ |
124 | 124 | ||
125 | static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data) | 125 | static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data) |
126 | { | 126 | { |
127 | unsigned int i, j, buf, crc; | 127 | unsigned int i, j, buf, crc; |
128 | unsigned char u, v, w; | 128 | unsigned char u, v, w; |
129 | unsigned long flags; | 129 | unsigned long flags; |
130 | unsigned int t; | 130 | unsigned int t; |
131 | char status; | 131 | char status; |
132 | 132 | ||
133 | int strobe = gameport_time(gameport, GRIP_STROBE_XT); | 133 | int strobe = gameport_time(gameport, GRIP_STROBE_XT); |
134 | 134 | ||
135 | data[0] = data[1] = data[2] = data[3] = 0; | 135 | data[0] = data[1] = data[2] = data[3] = 0; |
136 | status = buf = i = j = 0; | 136 | status = buf = i = j = 0; |
137 | t = strobe; | 137 | t = strobe; |
138 | 138 | ||
139 | local_irq_save(flags); | 139 | local_irq_save(flags); |
140 | 140 | ||
141 | v = w = (gameport_read(gameport) >> shift) & 3; | 141 | v = w = (gameport_read(gameport) >> shift) & 3; |
142 | 142 | ||
143 | do { | 143 | do { |
144 | t--; | 144 | t--; |
145 | u = (gameport_read(gameport) >> shift) & 3; | 145 | u = (gameport_read(gameport) >> shift) & 3; |
146 | 146 | ||
147 | if (u ^ v) { | 147 | if (u ^ v) { |
148 | 148 | ||
149 | if ((u ^ v) & 1) { | 149 | if ((u ^ v) & 1) { |
150 | buf = (buf << 1) | (u >> 1); | 150 | buf = (buf << 1) | (u >> 1); |
151 | t = strobe; | 151 | t = strobe; |
152 | i++; | 152 | i++; |
153 | } else | 153 | } else |
154 | 154 | ||
155 | if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) { | 155 | if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) { |
156 | if (i == 20) { | 156 | if (i == 20) { |
157 | crc = buf ^ (buf >> 7) ^ (buf >> 14); | 157 | crc = buf ^ (buf >> 7) ^ (buf >> 14); |
158 | if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) { | 158 | if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) { |
159 | data[buf >> 18] = buf >> 4; | 159 | data[buf >> 18] = buf >> 4; |
160 | status |= 1 << (buf >> 18); | 160 | status |= 1 << (buf >> 18); |
161 | } | 161 | } |
162 | j++; | 162 | j++; |
163 | } | 163 | } |
164 | t = strobe; | 164 | t = strobe; |
165 | buf = 0; | 165 | buf = 0; |
166 | i = 0; | 166 | i = 0; |
167 | } | 167 | } |
168 | w = v; | 168 | w = v; |
169 | v = u; | 169 | v = u; |
170 | } | 170 | } |
171 | 171 | ||
172 | } while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0); | 172 | } while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0); |
173 | 173 | ||
174 | local_irq_restore(flags); | 174 | local_irq_restore(flags); |
175 | 175 | ||
176 | return -(status != 0xf); | 176 | return -(status != 0xf); |
177 | } | 177 | } |
178 | 178 | ||
179 | /* | 179 | /* |
180 | * grip_timer() repeatedly polls the joysticks and generates events. | 180 | * grip_timer() repeatedly polls the joysticks and generates events. |
181 | */ | 181 | */ |
182 | 182 | ||
183 | static void grip_poll(struct gameport *gameport) | 183 | static void grip_poll(struct gameport *gameport) |
184 | { | 184 | { |
185 | struct grip *grip = gameport_get_drvdata(gameport); | 185 | struct grip *grip = gameport_get_drvdata(gameport); |
186 | unsigned int data[GRIP_LENGTH_XT]; | 186 | unsigned int data[GRIP_LENGTH_XT]; |
187 | struct input_dev *dev; | 187 | struct input_dev *dev; |
188 | int i, j; | 188 | int i, j; |
189 | 189 | ||
190 | for (i = 0; i < 2; i++) { | 190 | for (i = 0; i < 2; i++) { |
191 | 191 | ||
192 | dev = grip->dev[i]; | 192 | dev = grip->dev[i]; |
193 | if (!dev) | 193 | if (!dev) |
194 | continue; | 194 | continue; |
195 | 195 | ||
196 | grip->reads++; | 196 | grip->reads++; |
197 | 197 | ||
198 | switch (grip->mode[i]) { | 198 | switch (grip->mode[i]) { |
199 | 199 | ||
200 | case GRIP_MODE_GPP: | 200 | case GRIP_MODE_GPP: |
201 | 201 | ||
202 | if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) { | 202 | if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) { |
203 | grip->bads++; | 203 | grip->bads++; |
204 | break; | 204 | break; |
205 | } | 205 | } |
206 | 206 | ||
207 | input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1)); | 207 | input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1)); |
208 | input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1)); | 208 | input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1)); |
209 | 209 | ||
210 | for (j = 0; j < 12; j++) | 210 | for (j = 0; j < 12; j++) |
211 | if (grip_btn_gpp[j]) | 211 | if (grip_btn_gpp[j]) |
212 | input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1); | 212 | input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1); |
213 | 213 | ||
214 | break; | 214 | break; |
215 | 215 | ||
216 | case GRIP_MODE_BD: | 216 | case GRIP_MODE_BD: |
217 | 217 | ||
218 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { | 218 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { |
219 | grip->bads++; | 219 | grip->bads++; |
220 | break; | 220 | break; |
221 | } | 221 | } |
222 | 222 | ||
223 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); | 223 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); |
224 | input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f)); | 224 | input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f)); |
225 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); | 225 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); |
226 | 226 | ||
227 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); | 227 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); |
228 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); | 228 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); |
229 | 229 | ||
230 | for (j = 0; j < 5; j++) | 230 | for (j = 0; j < 5; j++) |
231 | input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1); | 231 | input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1); |
232 | 232 | ||
233 | break; | 233 | break; |
234 | 234 | ||
235 | case GRIP_MODE_XT: | 235 | case GRIP_MODE_XT: |
236 | 236 | ||
237 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { | 237 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { |
238 | grip->bads++; | 238 | grip->bads++; |
239 | break; | 239 | break; |
240 | } | 240 | } |
241 | 241 | ||
242 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); | 242 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); |
243 | input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f)); | 243 | input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f)); |
244 | input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f); | 244 | input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f); |
245 | input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f); | 245 | input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f); |
246 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); | 246 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); |
247 | 247 | ||
248 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); | 248 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); |
249 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); | 249 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); |
250 | input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1)); | 250 | input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1)); |
251 | input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1)); | 251 | input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1)); |
252 | 252 | ||
253 | for (j = 0; j < 11; j++) | 253 | for (j = 0; j < 11; j++) |
254 | input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1); | 254 | input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1); |
255 | break; | 255 | break; |
256 | 256 | ||
257 | case GRIP_MODE_DC: | 257 | case GRIP_MODE_DC: |
258 | 258 | ||
259 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { | 259 | if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) { |
260 | grip->bads++; | 260 | grip->bads++; |
261 | break; | 261 | break; |
262 | } | 262 | } |
263 | 263 | ||
264 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); | 264 | input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f); |
265 | input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f); | 265 | input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f); |
266 | input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f); | 266 | input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f); |
267 | input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f); | 267 | input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f); |
268 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); | 268 | input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f); |
269 | 269 | ||
270 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); | 270 | input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1)); |
271 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); | 271 | input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1)); |
272 | 272 | ||
273 | for (j = 0; j < 9; j++) | 273 | for (j = 0; j < 9; j++) |
274 | input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1); | 274 | input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1); |
275 | break; | 275 | break; |
276 | 276 | ||
277 | 277 | ||
278 | } | 278 | } |
279 | 279 | ||
280 | input_sync(dev); | 280 | input_sync(dev); |
281 | } | 281 | } |
282 | } | 282 | } |
283 | 283 | ||
284 | static int grip_open(struct input_dev *dev) | 284 | static int grip_open(struct input_dev *dev) |
285 | { | 285 | { |
286 | struct grip *grip = input_get_drvdata(dev); | 286 | struct grip *grip = input_get_drvdata(dev); |
287 | 287 | ||
288 | gameport_start_polling(grip->gameport); | 288 | gameport_start_polling(grip->gameport); |
289 | return 0; | 289 | return 0; |
290 | } | 290 | } |
291 | 291 | ||
292 | static void grip_close(struct input_dev *dev) | 292 | static void grip_close(struct input_dev *dev) |
293 | { | 293 | { |
294 | struct grip *grip = input_get_drvdata(dev); | 294 | struct grip *grip = input_get_drvdata(dev); |
295 | 295 | ||
296 | gameport_stop_polling(grip->gameport); | 296 | gameport_stop_polling(grip->gameport); |
297 | } | 297 | } |
298 | 298 | ||
299 | static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) | 299 | static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) |
300 | { | 300 | { |
301 | struct grip *grip; | 301 | struct grip *grip; |
302 | struct input_dev *input_dev; | 302 | struct input_dev *input_dev; |
303 | unsigned int data[GRIP_LENGTH_XT]; | 303 | unsigned int data[GRIP_LENGTH_XT]; |
304 | int i, j, t; | 304 | int i, j, t; |
305 | int err; | 305 | int err; |
306 | 306 | ||
307 | if (!(grip = kzalloc(sizeof(struct grip), GFP_KERNEL))) | 307 | if (!(grip = kzalloc(sizeof(struct grip), GFP_KERNEL))) |
308 | return -ENOMEM; | 308 | return -ENOMEM; |
309 | 309 | ||
310 | grip->gameport = gameport; | 310 | grip->gameport = gameport; |
311 | 311 | ||
312 | gameport_set_drvdata(gameport, grip); | 312 | gameport_set_drvdata(gameport, grip); |
313 | 313 | ||
314 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 314 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
315 | if (err) | 315 | if (err) |
316 | goto fail1; | 316 | goto fail1; |
317 | 317 | ||
318 | for (i = 0; i < 2; i++) { | 318 | for (i = 0; i < 2; i++) { |
319 | if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) { | 319 | if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) { |
320 | grip->mode[i] = GRIP_MODE_GPP; | 320 | grip->mode[i] = GRIP_MODE_GPP; |
321 | continue; | 321 | continue; |
322 | } | 322 | } |
323 | if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) { | 323 | if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) { |
324 | if (!(data[3] & 7)) { | 324 | if (!(data[3] & 7)) { |
325 | grip->mode[i] = GRIP_MODE_BD; | 325 | grip->mode[i] = GRIP_MODE_BD; |
326 | continue; | 326 | continue; |
327 | } | 327 | } |
328 | if (!(data[2] & 0xf0)) { | 328 | if (!(data[2] & 0xf0)) { |
329 | grip->mode[i] = GRIP_MODE_XT; | 329 | grip->mode[i] = GRIP_MODE_XT; |
330 | continue; | 330 | continue; |
331 | } | 331 | } |
332 | grip->mode[i] = GRIP_MODE_DC; | 332 | grip->mode[i] = GRIP_MODE_DC; |
333 | continue; | 333 | continue; |
334 | } | 334 | } |
335 | } | 335 | } |
336 | 336 | ||
337 | if (!grip->mode[0] && !grip->mode[1]) { | 337 | if (!grip->mode[0] && !grip->mode[1]) { |
338 | err = -ENODEV; | 338 | err = -ENODEV; |
339 | goto fail2; | 339 | goto fail2; |
340 | } | 340 | } |
341 | 341 | ||
342 | gameport_set_poll_handler(gameport, grip_poll); | 342 | gameport_set_poll_handler(gameport, grip_poll); |
343 | gameport_set_poll_interval(gameport, 20); | 343 | gameport_set_poll_interval(gameport, 20); |
344 | 344 | ||
345 | for (i = 0; i < 2; i++) { | 345 | for (i = 0; i < 2; i++) { |
346 | if (!grip->mode[i]) | 346 | if (!grip->mode[i]) |
347 | continue; | 347 | continue; |
348 | 348 | ||
349 | grip->dev[i] = input_dev = input_allocate_device(); | 349 | grip->dev[i] = input_dev = input_allocate_device(); |
350 | if (!input_dev) { | 350 | if (!input_dev) { |
351 | err = -ENOMEM; | 351 | err = -ENOMEM; |
352 | goto fail3; | 352 | goto fail3; |
353 | } | 353 | } |
354 | 354 | ||
355 | snprintf(grip->phys[i], sizeof(grip->phys[i]), | 355 | snprintf(grip->phys[i], sizeof(grip->phys[i]), |
356 | "%s/input%d", gameport->phys, i); | 356 | "%s/input%d", gameport->phys, i); |
357 | 357 | ||
358 | input_dev->name = grip_name[grip->mode[i]]; | 358 | input_dev->name = grip_name[grip->mode[i]]; |
359 | input_dev->phys = grip->phys[i]; | 359 | input_dev->phys = grip->phys[i]; |
360 | input_dev->id.bustype = BUS_GAMEPORT; | 360 | input_dev->id.bustype = BUS_GAMEPORT; |
361 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; | 361 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; |
362 | input_dev->id.product = grip->mode[i]; | 362 | input_dev->id.product = grip->mode[i]; |
363 | input_dev->id.version = 0x0100; | 363 | input_dev->id.version = 0x0100; |
364 | input_dev->dev.parent = &gameport->dev; | 364 | input_dev->dev.parent = &gameport->dev; |
365 | 365 | ||
366 | input_set_drvdata(input_dev, grip); | 366 | input_set_drvdata(input_dev, grip); |
367 | 367 | ||
368 | input_dev->open = grip_open; | 368 | input_dev->open = grip_open; |
369 | input_dev->close = grip_close; | 369 | input_dev->close = grip_close; |
370 | 370 | ||
371 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 371 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
372 | 372 | ||
373 | for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) { | 373 | for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) { |
374 | 374 | ||
375 | if (j < grip_cen[grip->mode[i]]) | 375 | if (j < grip_cen[grip->mode[i]]) |
376 | input_set_abs_params(input_dev, t, 14, 52, 1, 2); | 376 | input_set_abs_params(input_dev, t, 14, 52, 1, 2); |
377 | else if (j < grip_anx[grip->mode[i]]) | 377 | else if (j < grip_anx[grip->mode[i]]) |
378 | input_set_abs_params(input_dev, t, 3, 57, 1, 0); | 378 | input_set_abs_params(input_dev, t, 3, 57, 1, 0); |
379 | else | 379 | else |
380 | input_set_abs_params(input_dev, t, -1, 1, 0, 0); | 380 | input_set_abs_params(input_dev, t, -1, 1, 0, 0); |
381 | } | 381 | } |
382 | 382 | ||
383 | for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++) | 383 | for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++) |
384 | if (t > 0) | 384 | if (t > 0) |
385 | set_bit(t, input_dev->keybit); | 385 | set_bit(t, input_dev->keybit); |
386 | 386 | ||
387 | err = input_register_device(grip->dev[i]); | 387 | err = input_register_device(grip->dev[i]); |
388 | if (err) | 388 | if (err) |
389 | goto fail4; | 389 | goto fail4; |
390 | } | 390 | } |
391 | 391 | ||
392 | return 0; | 392 | return 0; |
393 | 393 | ||
394 | fail4: input_free_device(grip->dev[i]); | 394 | fail4: input_free_device(grip->dev[i]); |
395 | fail3: while (--i >= 0) | 395 | fail3: while (--i >= 0) |
396 | if (grip->dev[i]) | 396 | if (grip->dev[i]) |
397 | input_unregister_device(grip->dev[i]); | 397 | input_unregister_device(grip->dev[i]); |
398 | fail2: gameport_close(gameport); | 398 | fail2: gameport_close(gameport); |
399 | fail1: gameport_set_drvdata(gameport, NULL); | 399 | fail1: gameport_set_drvdata(gameport, NULL); |
400 | kfree(grip); | 400 | kfree(grip); |
401 | return err; | 401 | return err; |
402 | } | 402 | } |
403 | 403 | ||
404 | static void grip_disconnect(struct gameport *gameport) | 404 | static void grip_disconnect(struct gameport *gameport) |
405 | { | 405 | { |
406 | struct grip *grip = gameport_get_drvdata(gameport); | 406 | struct grip *grip = gameport_get_drvdata(gameport); |
407 | int i; | 407 | int i; |
408 | 408 | ||
409 | for (i = 0; i < 2; i++) | 409 | for (i = 0; i < 2; i++) |
410 | if (grip->dev[i]) | 410 | if (grip->dev[i]) |
411 | input_unregister_device(grip->dev[i]); | 411 | input_unregister_device(grip->dev[i]); |
412 | gameport_close(gameport); | 412 | gameport_close(gameport); |
413 | gameport_set_drvdata(gameport, NULL); | 413 | gameport_set_drvdata(gameport, NULL); |
414 | kfree(grip); | 414 | kfree(grip); |
415 | } | 415 | } |
416 | 416 | ||
417 | static struct gameport_driver grip_drv = { | 417 | static struct gameport_driver grip_drv = { |
418 | .driver = { | 418 | .driver = { |
419 | .name = "grip", | 419 | .name = "grip", |
420 | .owner = THIS_MODULE, | 420 | .owner = THIS_MODULE, |
421 | }, | 421 | }, |
422 | .description = DRIVER_DESC, | 422 | .description = DRIVER_DESC, |
423 | .connect = grip_connect, | 423 | .connect = grip_connect, |
424 | .disconnect = grip_disconnect, | 424 | .disconnect = grip_disconnect, |
425 | }; | 425 | }; |
426 | 426 | ||
427 | static int __init grip_init(void) | 427 | module_gameport_driver(grip_drv); |
428 | { | ||
429 | return gameport_register_driver(&grip_drv); | ||
430 | } | ||
431 | |||
432 | static void __exit grip_exit(void) | ||
433 | { | ||
434 | gameport_unregister_driver(&grip_drv); | ||
435 | } | ||
436 | |||
437 | module_init(grip_init); | ||
438 | module_exit(grip_exit); | ||
439 | 428 |
drivers/input/joystick/grip_mp.c
1 | /* | 1 | /* |
2 | * Driver for the Gravis Grip Multiport, a gamepad "hub" that | 2 | * Driver for the Gravis Grip Multiport, a gamepad "hub" that |
3 | * connects up to four 9-pin digital gamepads/joysticks. | 3 | * connects up to four 9-pin digital gamepads/joysticks. |
4 | * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5. | 4 | * Driver tested on SMP and UP kernel versions 2.4.18-4 and 2.4.18-5. |
5 | * | 5 | * |
6 | * Thanks to Chris Gassib for helpful advice. | 6 | * Thanks to Chris Gassib for helpful advice. |
7 | * | 7 | * |
8 | * Copyright (c) 2002 Brian Bonnlander, Bill Soudan | 8 | * Copyright (c) 2002 Brian Bonnlander, Bill Soudan |
9 | * Copyright (c) 1998-2000 Vojtech Pavlik | 9 | * Copyright (c) 1998-2000 Vojtech Pavlik |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/kernel.h> | 12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | 13 | #include <linux/module.h> |
14 | #include <linux/init.h> | 14 | #include <linux/init.h> |
15 | #include <linux/slab.h> | 15 | #include <linux/slab.h> |
16 | #include <linux/gameport.h> | 16 | #include <linux/gameport.h> |
17 | #include <linux/input.h> | 17 | #include <linux/input.h> |
18 | #include <linux/delay.h> | 18 | #include <linux/delay.h> |
19 | #include <linux/proc_fs.h> | 19 | #include <linux/proc_fs.h> |
20 | #include <linux/jiffies.h> | 20 | #include <linux/jiffies.h> |
21 | 21 | ||
22 | #define DRIVER_DESC "Gravis Grip Multiport driver" | 22 | #define DRIVER_DESC "Gravis Grip Multiport driver" |
23 | 23 | ||
24 | MODULE_AUTHOR("Brian Bonnlander"); | 24 | MODULE_AUTHOR("Brian Bonnlander"); |
25 | MODULE_DESCRIPTION(DRIVER_DESC); | 25 | MODULE_DESCRIPTION(DRIVER_DESC); |
26 | MODULE_LICENSE("GPL"); | 26 | MODULE_LICENSE("GPL"); |
27 | 27 | ||
28 | #ifdef GRIP_DEBUG | 28 | #ifdef GRIP_DEBUG |
29 | #define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) | 29 | #define dbg(format, arg...) printk(KERN_ERR __FILE__ ": " format "\n" , ## arg) |
30 | #else | 30 | #else |
31 | #define dbg(format, arg...) do {} while (0) | 31 | #define dbg(format, arg...) do {} while (0) |
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | #define GRIP_MAX_PORTS 4 | 34 | #define GRIP_MAX_PORTS 4 |
35 | /* | 35 | /* |
36 | * Grip multiport state | 36 | * Grip multiport state |
37 | */ | 37 | */ |
38 | 38 | ||
39 | struct grip_port { | 39 | struct grip_port { |
40 | struct input_dev *dev; | 40 | struct input_dev *dev; |
41 | int mode; | 41 | int mode; |
42 | int registered; | 42 | int registered; |
43 | 43 | ||
44 | /* individual gamepad states */ | 44 | /* individual gamepad states */ |
45 | int buttons; | 45 | int buttons; |
46 | int xaxes; | 46 | int xaxes; |
47 | int yaxes; | 47 | int yaxes; |
48 | int dirty; /* has the state been updated? */ | 48 | int dirty; /* has the state been updated? */ |
49 | }; | 49 | }; |
50 | 50 | ||
51 | struct grip_mp { | 51 | struct grip_mp { |
52 | struct gameport *gameport; | 52 | struct gameport *gameport; |
53 | struct grip_port *port[GRIP_MAX_PORTS]; | 53 | struct grip_port *port[GRIP_MAX_PORTS]; |
54 | int reads; | 54 | int reads; |
55 | int bads; | 55 | int bads; |
56 | }; | 56 | }; |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * Multiport packet interpretation | 59 | * Multiport packet interpretation |
60 | */ | 60 | */ |
61 | 61 | ||
62 | #define PACKET_FULL 0x80000000 /* packet is full */ | 62 | #define PACKET_FULL 0x80000000 /* packet is full */ |
63 | #define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */ | 63 | #define PACKET_IO_FAST 0x40000000 /* 3 bits per gameport read */ |
64 | #define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */ | 64 | #define PACKET_IO_SLOW 0x20000000 /* 1 bit per gameport read */ |
65 | #define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */ | 65 | #define PACKET_MP_MORE 0x04000000 /* multiport wants to send more */ |
66 | #define PACKET_MP_DONE 0x02000000 /* multiport done sending */ | 66 | #define PACKET_MP_DONE 0x02000000 /* multiport done sending */ |
67 | 67 | ||
68 | /* | 68 | /* |
69 | * Packet status code interpretation | 69 | * Packet status code interpretation |
70 | */ | 70 | */ |
71 | 71 | ||
72 | #define IO_GOT_PACKET 0x0100 /* Got a packet */ | 72 | #define IO_GOT_PACKET 0x0100 /* Got a packet */ |
73 | #define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */ | 73 | #define IO_MODE_FAST 0x0200 /* Used 3 data bits per gameport read */ |
74 | #define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */ | 74 | #define IO_SLOT_CHANGE 0x0800 /* Multiport physical slot status changed */ |
75 | #define IO_DONE 0x1000 /* Multiport is done sending packets */ | 75 | #define IO_DONE 0x1000 /* Multiport is done sending packets */ |
76 | #define IO_RETRY 0x4000 /* Try again later to get packet */ | 76 | #define IO_RETRY 0x4000 /* Try again later to get packet */ |
77 | #define IO_RESET 0x8000 /* Force multiport to resend all packets */ | 77 | #define IO_RESET 0x8000 /* Force multiport to resend all packets */ |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * Gamepad configuration data. Other 9-pin digital joystick devices | 80 | * Gamepad configuration data. Other 9-pin digital joystick devices |
81 | * may work with the multiport, so this may not be an exhaustive list! | 81 | * may work with the multiport, so this may not be an exhaustive list! |
82 | * Commodore 64 joystick remains untested. | 82 | * Commodore 64 joystick remains untested. |
83 | */ | 83 | */ |
84 | 84 | ||
85 | #define GRIP_INIT_DELAY 2000 /* 2 ms */ | 85 | #define GRIP_INIT_DELAY 2000 /* 2 ms */ |
86 | 86 | ||
87 | #define GRIP_MODE_NONE 0 | 87 | #define GRIP_MODE_NONE 0 |
88 | #define GRIP_MODE_RESET 1 | 88 | #define GRIP_MODE_RESET 1 |
89 | #define GRIP_MODE_GP 2 | 89 | #define GRIP_MODE_GP 2 |
90 | #define GRIP_MODE_C64 3 | 90 | #define GRIP_MODE_C64 3 |
91 | 91 | ||
92 | static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; | 92 | static const int grip_btn_gp[] = { BTN_TR, BTN_TL, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, -1 }; |
93 | static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; | 93 | static const int grip_btn_c64[] = { BTN_JOYSTICK, -1 }; |
94 | 94 | ||
95 | static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; | 95 | static const int grip_abs_gp[] = { ABS_X, ABS_Y, -1 }; |
96 | static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; | 96 | static const int grip_abs_c64[] = { ABS_X, ABS_Y, -1 }; |
97 | 97 | ||
98 | static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; | 98 | static const int *grip_abs[] = { NULL, NULL, grip_abs_gp, grip_abs_c64 }; |
99 | static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; | 99 | static const int *grip_btn[] = { NULL, NULL, grip_btn_gp, grip_btn_c64 }; |
100 | 100 | ||
101 | static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; | 101 | static const char *grip_name[] = { NULL, NULL, "Gravis Grip Pad", "Commodore 64 Joystick" }; |
102 | 102 | ||
103 | static const int init_seq[] = { | 103 | static const int init_seq[] = { |
104 | 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, | 104 | 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, |
105 | 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, | 105 | 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, |
106 | 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, | 106 | 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, |
107 | 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 }; | 107 | 0, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1 }; |
108 | 108 | ||
109 | /* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */ | 109 | /* Maps multiport directional values to X,Y axis values (each axis encoded in 3 bits) */ |
110 | 110 | ||
111 | static const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; | 111 | static const int axis_map[] = { 5, 9, 1, 5, 6, 10, 2, 6, 4, 8, 0, 4, 5, 9, 1, 5 }; |
112 | 112 | ||
113 | static int register_slot(int i, struct grip_mp *grip); | 113 | static int register_slot(int i, struct grip_mp *grip); |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * Returns whether an odd or even number of bits are on in pkt. | 116 | * Returns whether an odd or even number of bits are on in pkt. |
117 | */ | 117 | */ |
118 | 118 | ||
119 | static int bit_parity(u32 pkt) | 119 | static int bit_parity(u32 pkt) |
120 | { | 120 | { |
121 | int x = pkt ^ (pkt >> 16); | 121 | int x = pkt ^ (pkt >> 16); |
122 | x ^= x >> 8; | 122 | x ^= x >> 8; |
123 | x ^= x >> 4; | 123 | x ^= x >> 4; |
124 | x ^= x >> 2; | 124 | x ^= x >> 2; |
125 | x ^= x >> 1; | 125 | x ^= x >> 1; |
126 | return x & 1; | 126 | return x & 1; |
127 | } | 127 | } |
128 | 128 | ||
129 | /* | 129 | /* |
130 | * Poll gameport; return true if all bits set in 'onbits' are on and | 130 | * Poll gameport; return true if all bits set in 'onbits' are on and |
131 | * all bits set in 'offbits' are off. | 131 | * all bits set in 'offbits' are off. |
132 | */ | 132 | */ |
133 | 133 | ||
134 | static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data) | 134 | static inline int poll_until(u8 onbits, u8 offbits, int u_sec, struct gameport* gp, u8 *data) |
135 | { | 135 | { |
136 | int i, nloops; | 136 | int i, nloops; |
137 | 137 | ||
138 | nloops = gameport_time(gp, u_sec); | 138 | nloops = gameport_time(gp, u_sec); |
139 | for (i = 0; i < nloops; i++) { | 139 | for (i = 0; i < nloops; i++) { |
140 | *data = gameport_read(gp); | 140 | *data = gameport_read(gp); |
141 | if ((*data & onbits) == onbits && | 141 | if ((*data & onbits) == onbits && |
142 | (~(*data) & offbits) == offbits) | 142 | (~(*data) & offbits) == offbits) |
143 | return 1; | 143 | return 1; |
144 | } | 144 | } |
145 | dbg("gameport timed out after %d microseconds.\n", u_sec); | 145 | dbg("gameport timed out after %d microseconds.\n", u_sec); |
146 | return 0; | 146 | return 0; |
147 | } | 147 | } |
148 | 148 | ||
149 | /* | 149 | /* |
150 | * Gets a 28-bit packet from the multiport. | 150 | * Gets a 28-bit packet from the multiport. |
151 | * | 151 | * |
152 | * After getting a packet successfully, commands encoded by sendcode may | 152 | * After getting a packet successfully, commands encoded by sendcode may |
153 | * be sent to the multiport. | 153 | * be sent to the multiport. |
154 | * | 154 | * |
155 | * The multiport clock value is reflected in gameport bit B4. | 155 | * The multiport clock value is reflected in gameport bit B4. |
156 | * | 156 | * |
157 | * Returns a packet status code indicating whether packet is valid, the transfer | 157 | * Returns a packet status code indicating whether packet is valid, the transfer |
158 | * mode, and any error conditions. | 158 | * mode, and any error conditions. |
159 | * | 159 | * |
160 | * sendflags: current I/O status | 160 | * sendflags: current I/O status |
161 | * sendcode: data to send to the multiport if sendflags is nonzero | 161 | * sendcode: data to send to the multiport if sendflags is nonzero |
162 | */ | 162 | */ |
163 | 163 | ||
164 | static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) | 164 | static int mp_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) |
165 | { | 165 | { |
166 | u8 raw_data; /* raw data from gameport */ | 166 | u8 raw_data; /* raw data from gameport */ |
167 | u8 data_mask; /* packet data bits from raw_data */ | 167 | u8 data_mask; /* packet data bits from raw_data */ |
168 | u32 pkt; /* packet temporary storage */ | 168 | u32 pkt; /* packet temporary storage */ |
169 | int bits_per_read; /* num packet bits per gameport read */ | 169 | int bits_per_read; /* num packet bits per gameport read */ |
170 | int portvals = 0; /* used for port value sanity check */ | 170 | int portvals = 0; /* used for port value sanity check */ |
171 | int i; | 171 | int i; |
172 | 172 | ||
173 | /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */ | 173 | /* Gameport bits B0, B4, B5 should first be off, then B4 should come on. */ |
174 | 174 | ||
175 | *packet = 0; | 175 | *packet = 0; |
176 | raw_data = gameport_read(gameport); | 176 | raw_data = gameport_read(gameport); |
177 | if (raw_data & 1) | 177 | if (raw_data & 1) |
178 | return IO_RETRY; | 178 | return IO_RETRY; |
179 | 179 | ||
180 | for (i = 0; i < 64; i++) { | 180 | for (i = 0; i < 64; i++) { |
181 | raw_data = gameport_read(gameport); | 181 | raw_data = gameport_read(gameport); |
182 | portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */ | 182 | portvals |= 1 << ((raw_data >> 4) & 3); /* Demux B4, B5 */ |
183 | } | 183 | } |
184 | 184 | ||
185 | if (portvals == 1) { /* B4, B5 off */ | 185 | if (portvals == 1) { /* B4, B5 off */ |
186 | raw_data = gameport_read(gameport); | 186 | raw_data = gameport_read(gameport); |
187 | portvals = raw_data & 0xf0; | 187 | portvals = raw_data & 0xf0; |
188 | 188 | ||
189 | if (raw_data & 0x31) | 189 | if (raw_data & 0x31) |
190 | return IO_RESET; | 190 | return IO_RESET; |
191 | gameport_trigger(gameport); | 191 | gameport_trigger(gameport); |
192 | 192 | ||
193 | if (!poll_until(0x10, 0, 308, gameport, &raw_data)) | 193 | if (!poll_until(0x10, 0, 308, gameport, &raw_data)) |
194 | return IO_RESET; | 194 | return IO_RESET; |
195 | } else | 195 | } else |
196 | return IO_RETRY; | 196 | return IO_RETRY; |
197 | 197 | ||
198 | /* Determine packet transfer mode and prepare for packet construction. */ | 198 | /* Determine packet transfer mode and prepare for packet construction. */ |
199 | 199 | ||
200 | if (raw_data & 0x20) { /* 3 data bits/read */ | 200 | if (raw_data & 0x20) { /* 3 data bits/read */ |
201 | portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */ | 201 | portvals |= raw_data >> 4; /* Compare B4-B7 before & after trigger */ |
202 | 202 | ||
203 | if (portvals != 0xb) | 203 | if (portvals != 0xb) |
204 | return 0; | 204 | return 0; |
205 | data_mask = 7; | 205 | data_mask = 7; |
206 | bits_per_read = 3; | 206 | bits_per_read = 3; |
207 | pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28; | 207 | pkt = (PACKET_FULL | PACKET_IO_FAST) >> 28; |
208 | } else { /* 1 data bit/read */ | 208 | } else { /* 1 data bit/read */ |
209 | data_mask = 1; | 209 | data_mask = 1; |
210 | bits_per_read = 1; | 210 | bits_per_read = 1; |
211 | pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28; | 211 | pkt = (PACKET_FULL | PACKET_IO_SLOW) >> 28; |
212 | } | 212 | } |
213 | 213 | ||
214 | /* Construct a packet. Final data bits must be zero. */ | 214 | /* Construct a packet. Final data bits must be zero. */ |
215 | 215 | ||
216 | while (1) { | 216 | while (1) { |
217 | if (!poll_until(0, 0x10, 77, gameport, &raw_data)) | 217 | if (!poll_until(0, 0x10, 77, gameport, &raw_data)) |
218 | return IO_RESET; | 218 | return IO_RESET; |
219 | raw_data = (raw_data >> 5) & data_mask; | 219 | raw_data = (raw_data >> 5) & data_mask; |
220 | 220 | ||
221 | if (pkt & PACKET_FULL) | 221 | if (pkt & PACKET_FULL) |
222 | break; | 222 | break; |
223 | pkt = (pkt << bits_per_read) | raw_data; | 223 | pkt = (pkt << bits_per_read) | raw_data; |
224 | 224 | ||
225 | if (!poll_until(0x10, 0, 77, gameport, &raw_data)) | 225 | if (!poll_until(0x10, 0, 77, gameport, &raw_data)) |
226 | return IO_RESET; | 226 | return IO_RESET; |
227 | } | 227 | } |
228 | 228 | ||
229 | if (raw_data) | 229 | if (raw_data) |
230 | return IO_RESET; | 230 | return IO_RESET; |
231 | 231 | ||
232 | /* If 3 bits/read used, drop from 30 bits to 28. */ | 232 | /* If 3 bits/read used, drop from 30 bits to 28. */ |
233 | 233 | ||
234 | if (bits_per_read == 3) { | 234 | if (bits_per_read == 3) { |
235 | pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff); | 235 | pkt = (pkt & 0xffff0000) | ((pkt << 1) & 0xffff); |
236 | pkt = (pkt >> 2) | 0xf0000000; | 236 | pkt = (pkt >> 2) | 0xf0000000; |
237 | } | 237 | } |
238 | 238 | ||
239 | if (bit_parity(pkt) == 1) | 239 | if (bit_parity(pkt) == 1) |
240 | return IO_RESET; | 240 | return IO_RESET; |
241 | 241 | ||
242 | /* Acknowledge packet receipt */ | 242 | /* Acknowledge packet receipt */ |
243 | 243 | ||
244 | if (!poll_until(0x30, 0, 77, gameport, &raw_data)) | 244 | if (!poll_until(0x30, 0, 77, gameport, &raw_data)) |
245 | return IO_RESET; | 245 | return IO_RESET; |
246 | 246 | ||
247 | raw_data = gameport_read(gameport); | 247 | raw_data = gameport_read(gameport); |
248 | 248 | ||
249 | if (raw_data & 1) | 249 | if (raw_data & 1) |
250 | return IO_RESET; | 250 | return IO_RESET; |
251 | 251 | ||
252 | gameport_trigger(gameport); | 252 | gameport_trigger(gameport); |
253 | 253 | ||
254 | if (!poll_until(0, 0x20, 77, gameport, &raw_data)) | 254 | if (!poll_until(0, 0x20, 77, gameport, &raw_data)) |
255 | return IO_RESET; | 255 | return IO_RESET; |
256 | 256 | ||
257 | /* Return if we just wanted the packet or multiport wants to send more */ | 257 | /* Return if we just wanted the packet or multiport wants to send more */ |
258 | 258 | ||
259 | *packet = pkt; | 259 | *packet = pkt; |
260 | if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE))) | 260 | if ((sendflags == 0) || ((sendflags & IO_RETRY) && !(pkt & PACKET_MP_DONE))) |
261 | return IO_GOT_PACKET; | 261 | return IO_GOT_PACKET; |
262 | 262 | ||
263 | if (pkt & PACKET_MP_MORE) | 263 | if (pkt & PACKET_MP_MORE) |
264 | return IO_GOT_PACKET | IO_RETRY; | 264 | return IO_GOT_PACKET | IO_RETRY; |
265 | 265 | ||
266 | /* Multiport is done sending packets and is ready to receive data */ | 266 | /* Multiport is done sending packets and is ready to receive data */ |
267 | 267 | ||
268 | if (!poll_until(0x20, 0, 77, gameport, &raw_data)) | 268 | if (!poll_until(0x20, 0, 77, gameport, &raw_data)) |
269 | return IO_GOT_PACKET | IO_RESET; | 269 | return IO_GOT_PACKET | IO_RESET; |
270 | 270 | ||
271 | raw_data = gameport_read(gameport); | 271 | raw_data = gameport_read(gameport); |
272 | if (raw_data & 1) | 272 | if (raw_data & 1) |
273 | return IO_GOT_PACKET | IO_RESET; | 273 | return IO_GOT_PACKET | IO_RESET; |
274 | 274 | ||
275 | /* Trigger gameport based on bits in sendcode */ | 275 | /* Trigger gameport based on bits in sendcode */ |
276 | 276 | ||
277 | gameport_trigger(gameport); | 277 | gameport_trigger(gameport); |
278 | do { | 278 | do { |
279 | if (!poll_until(0x20, 0x10, 116, gameport, &raw_data)) | 279 | if (!poll_until(0x20, 0x10, 116, gameport, &raw_data)) |
280 | return IO_GOT_PACKET | IO_RESET; | 280 | return IO_GOT_PACKET | IO_RESET; |
281 | 281 | ||
282 | if (!poll_until(0x30, 0, 193, gameport, &raw_data)) | 282 | if (!poll_until(0x30, 0, 193, gameport, &raw_data)) |
283 | return IO_GOT_PACKET | IO_RESET; | 283 | return IO_GOT_PACKET | IO_RESET; |
284 | 284 | ||
285 | if (raw_data & 1) | 285 | if (raw_data & 1) |
286 | return IO_GOT_PACKET | IO_RESET; | 286 | return IO_GOT_PACKET | IO_RESET; |
287 | 287 | ||
288 | if (sendcode & 1) | 288 | if (sendcode & 1) |
289 | gameport_trigger(gameport); | 289 | gameport_trigger(gameport); |
290 | 290 | ||
291 | sendcode >>= 1; | 291 | sendcode >>= 1; |
292 | } while (sendcode); | 292 | } while (sendcode); |
293 | 293 | ||
294 | return IO_GOT_PACKET | IO_MODE_FAST; | 294 | return IO_GOT_PACKET | IO_MODE_FAST; |
295 | } | 295 | } |
296 | 296 | ||
297 | /* | 297 | /* |
298 | * Disables and restores interrupts for mp_io(), which does the actual I/O. | 298 | * Disables and restores interrupts for mp_io(), which does the actual I/O. |
299 | */ | 299 | */ |
300 | 300 | ||
301 | static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) | 301 | static int multiport_io(struct gameport* gameport, int sendflags, int sendcode, u32 *packet) |
302 | { | 302 | { |
303 | int status; | 303 | int status; |
304 | unsigned long flags; | 304 | unsigned long flags; |
305 | 305 | ||
306 | local_irq_save(flags); | 306 | local_irq_save(flags); |
307 | status = mp_io(gameport, sendflags, sendcode, packet); | 307 | status = mp_io(gameport, sendflags, sendcode, packet); |
308 | local_irq_restore(flags); | 308 | local_irq_restore(flags); |
309 | 309 | ||
310 | return status; | 310 | return status; |
311 | } | 311 | } |
312 | 312 | ||
313 | /* | 313 | /* |
314 | * Puts multiport into digital mode. Multiport LED turns green. | 314 | * Puts multiport into digital mode. Multiport LED turns green. |
315 | * | 315 | * |
316 | * Returns true if a valid digital packet was received, false otherwise. | 316 | * Returns true if a valid digital packet was received, false otherwise. |
317 | */ | 317 | */ |
318 | 318 | ||
319 | static int dig_mode_start(struct gameport *gameport, u32 *packet) | 319 | static int dig_mode_start(struct gameport *gameport, u32 *packet) |
320 | { | 320 | { |
321 | int i; | 321 | int i; |
322 | int flags, tries = 0, bads = 0; | 322 | int flags, tries = 0, bads = 0; |
323 | 323 | ||
324 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { /* Send magic sequence */ | 324 | for (i = 0; i < ARRAY_SIZE(init_seq); i++) { /* Send magic sequence */ |
325 | if (init_seq[i]) | 325 | if (init_seq[i]) |
326 | gameport_trigger(gameport); | 326 | gameport_trigger(gameport); |
327 | udelay(GRIP_INIT_DELAY); | 327 | udelay(GRIP_INIT_DELAY); |
328 | } | 328 | } |
329 | 329 | ||
330 | for (i = 0; i < 16; i++) /* Wait for multiport to settle */ | 330 | for (i = 0; i < 16; i++) /* Wait for multiport to settle */ |
331 | udelay(GRIP_INIT_DELAY); | 331 | udelay(GRIP_INIT_DELAY); |
332 | 332 | ||
333 | while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */ | 333 | while (tries < 64 && bads < 8) { /* Reset multiport and try getting a packet */ |
334 | 334 | ||
335 | flags = multiport_io(gameport, IO_RESET, 0x27, packet); | 335 | flags = multiport_io(gameport, IO_RESET, 0x27, packet); |
336 | 336 | ||
337 | if (flags & IO_MODE_FAST) | 337 | if (flags & IO_MODE_FAST) |
338 | return 1; | 338 | return 1; |
339 | 339 | ||
340 | if (flags & IO_RETRY) | 340 | if (flags & IO_RETRY) |
341 | tries++; | 341 | tries++; |
342 | else | 342 | else |
343 | bads++; | 343 | bads++; |
344 | } | 344 | } |
345 | return 0; | 345 | return 0; |
346 | } | 346 | } |
347 | 347 | ||
348 | /* | 348 | /* |
349 | * Packet structure: B0-B15 => gamepad state | 349 | * Packet structure: B0-B15 => gamepad state |
350 | * B16-B20 => gamepad device type | 350 | * B16-B20 => gamepad device type |
351 | * B21-B24 => multiport slot index (1-4) | 351 | * B21-B24 => multiport slot index (1-4) |
352 | * | 352 | * |
353 | * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist. | 353 | * Known device types: 0x1f (grip pad), 0x0 (no device). Others may exist. |
354 | * | 354 | * |
355 | * Returns the packet status. | 355 | * Returns the packet status. |
356 | */ | 356 | */ |
357 | 357 | ||
358 | static int get_and_decode_packet(struct grip_mp *grip, int flags) | 358 | static int get_and_decode_packet(struct grip_mp *grip, int flags) |
359 | { | 359 | { |
360 | struct grip_port *port; | 360 | struct grip_port *port; |
361 | u32 packet; | 361 | u32 packet; |
362 | int joytype = 0; | 362 | int joytype = 0; |
363 | int slot; | 363 | int slot; |
364 | 364 | ||
365 | /* Get a packet and check for validity */ | 365 | /* Get a packet and check for validity */ |
366 | 366 | ||
367 | flags &= IO_RESET | IO_RETRY; | 367 | flags &= IO_RESET | IO_RETRY; |
368 | flags = multiport_io(grip->gameport, flags, 0, &packet); | 368 | flags = multiport_io(grip->gameport, flags, 0, &packet); |
369 | grip->reads++; | 369 | grip->reads++; |
370 | 370 | ||
371 | if (packet & PACKET_MP_DONE) | 371 | if (packet & PACKET_MP_DONE) |
372 | flags |= IO_DONE; | 372 | flags |= IO_DONE; |
373 | 373 | ||
374 | if (flags && !(flags & IO_GOT_PACKET)) { | 374 | if (flags && !(flags & IO_GOT_PACKET)) { |
375 | grip->bads++; | 375 | grip->bads++; |
376 | return flags; | 376 | return flags; |
377 | } | 377 | } |
378 | 378 | ||
379 | /* Ignore non-gamepad packets, e.g. multiport hardware version */ | 379 | /* Ignore non-gamepad packets, e.g. multiport hardware version */ |
380 | 380 | ||
381 | slot = ((packet >> 21) & 0xf) - 1; | 381 | slot = ((packet >> 21) & 0xf) - 1; |
382 | if ((slot < 0) || (slot > 3)) | 382 | if ((slot < 0) || (slot > 3)) |
383 | return flags; | 383 | return flags; |
384 | 384 | ||
385 | port = grip->port[slot]; | 385 | port = grip->port[slot]; |
386 | 386 | ||
387 | /* | 387 | /* |
388 | * Handle "reset" packets, which occur at startup, and when gamepads | 388 | * Handle "reset" packets, which occur at startup, and when gamepads |
389 | * are removed or plugged in. May contain configuration of a new gamepad. | 389 | * are removed or plugged in. May contain configuration of a new gamepad. |
390 | */ | 390 | */ |
391 | 391 | ||
392 | joytype = (packet >> 16) & 0x1f; | 392 | joytype = (packet >> 16) & 0x1f; |
393 | if (!joytype) { | 393 | if (!joytype) { |
394 | 394 | ||
395 | if (port->registered) { | 395 | if (port->registered) { |
396 | printk(KERN_INFO "grip_mp: removing %s, slot %d\n", | 396 | printk(KERN_INFO "grip_mp: removing %s, slot %d\n", |
397 | grip_name[port->mode], slot); | 397 | grip_name[port->mode], slot); |
398 | input_unregister_device(port->dev); | 398 | input_unregister_device(port->dev); |
399 | port->registered = 0; | 399 | port->registered = 0; |
400 | } | 400 | } |
401 | dbg("Reset: grip multiport slot %d\n", slot); | 401 | dbg("Reset: grip multiport slot %d\n", slot); |
402 | port->mode = GRIP_MODE_RESET; | 402 | port->mode = GRIP_MODE_RESET; |
403 | flags |= IO_SLOT_CHANGE; | 403 | flags |= IO_SLOT_CHANGE; |
404 | return flags; | 404 | return flags; |
405 | } | 405 | } |
406 | 406 | ||
407 | /* Interpret a grip pad packet */ | 407 | /* Interpret a grip pad packet */ |
408 | 408 | ||
409 | if (joytype == 0x1f) { | 409 | if (joytype == 0x1f) { |
410 | 410 | ||
411 | int dir = (packet >> 8) & 0xf; /* eight way directional value */ | 411 | int dir = (packet >> 8) & 0xf; /* eight way directional value */ |
412 | port->buttons = (~packet) & 0xff; | 412 | port->buttons = (~packet) & 0xff; |
413 | port->yaxes = ((axis_map[dir] >> 2) & 3) - 1; | 413 | port->yaxes = ((axis_map[dir] >> 2) & 3) - 1; |
414 | port->xaxes = (axis_map[dir] & 3) - 1; | 414 | port->xaxes = (axis_map[dir] & 3) - 1; |
415 | port->dirty = 1; | 415 | port->dirty = 1; |
416 | 416 | ||
417 | if (port->mode == GRIP_MODE_RESET) | 417 | if (port->mode == GRIP_MODE_RESET) |
418 | flags |= IO_SLOT_CHANGE; | 418 | flags |= IO_SLOT_CHANGE; |
419 | 419 | ||
420 | port->mode = GRIP_MODE_GP; | 420 | port->mode = GRIP_MODE_GP; |
421 | 421 | ||
422 | if (!port->registered) { | 422 | if (!port->registered) { |
423 | dbg("New Grip pad in multiport slot %d.\n", slot); | 423 | dbg("New Grip pad in multiport slot %d.\n", slot); |
424 | if (register_slot(slot, grip)) { | 424 | if (register_slot(slot, grip)) { |
425 | port->mode = GRIP_MODE_RESET; | 425 | port->mode = GRIP_MODE_RESET; |
426 | port->dirty = 0; | 426 | port->dirty = 0; |
427 | } | 427 | } |
428 | } | 428 | } |
429 | return flags; | 429 | return flags; |
430 | } | 430 | } |
431 | 431 | ||
432 | /* Handle non-grip device codes. For now, just print diagnostics. */ | 432 | /* Handle non-grip device codes. For now, just print diagnostics. */ |
433 | 433 | ||
434 | { | 434 | { |
435 | static int strange_code = 0; | 435 | static int strange_code = 0; |
436 | if (strange_code != joytype) { | 436 | if (strange_code != joytype) { |
437 | printk(KERN_INFO "Possible non-grip pad/joystick detected.\n"); | 437 | printk(KERN_INFO "Possible non-grip pad/joystick detected.\n"); |
438 | printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet); | 438 | printk(KERN_INFO "Got joy type 0x%x and packet 0x%x.\n", joytype, packet); |
439 | strange_code = joytype; | 439 | strange_code = joytype; |
440 | } | 440 | } |
441 | } | 441 | } |
442 | return flags; | 442 | return flags; |
443 | } | 443 | } |
444 | 444 | ||
445 | /* | 445 | /* |
446 | * Returns true if all multiport slot states appear valid. | 446 | * Returns true if all multiport slot states appear valid. |
447 | */ | 447 | */ |
448 | 448 | ||
449 | static int slots_valid(struct grip_mp *grip) | 449 | static int slots_valid(struct grip_mp *grip) |
450 | { | 450 | { |
451 | int flags, slot, invalid = 0, active = 0; | 451 | int flags, slot, invalid = 0, active = 0; |
452 | 452 | ||
453 | flags = get_and_decode_packet(grip, 0); | 453 | flags = get_and_decode_packet(grip, 0); |
454 | if (!(flags & IO_GOT_PACKET)) | 454 | if (!(flags & IO_GOT_PACKET)) |
455 | return 0; | 455 | return 0; |
456 | 456 | ||
457 | for (slot = 0; slot < 4; slot++) { | 457 | for (slot = 0; slot < 4; slot++) { |
458 | if (grip->port[slot]->mode == GRIP_MODE_RESET) | 458 | if (grip->port[slot]->mode == GRIP_MODE_RESET) |
459 | invalid = 1; | 459 | invalid = 1; |
460 | if (grip->port[slot]->mode != GRIP_MODE_NONE) | 460 | if (grip->port[slot]->mode != GRIP_MODE_NONE) |
461 | active = 1; | 461 | active = 1; |
462 | } | 462 | } |
463 | 463 | ||
464 | /* Return true if no active slot but multiport sent all its data */ | 464 | /* Return true if no active slot but multiport sent all its data */ |
465 | if (!active) | 465 | if (!active) |
466 | return (flags & IO_DONE) ? 1 : 0; | 466 | return (flags & IO_DONE) ? 1 : 0; |
467 | 467 | ||
468 | /* Return false if invalid device code received */ | 468 | /* Return false if invalid device code received */ |
469 | return invalid ? 0 : 1; | 469 | return invalid ? 0 : 1; |
470 | } | 470 | } |
471 | 471 | ||
472 | /* | 472 | /* |
473 | * Returns whether the multiport was placed into digital mode and | 473 | * Returns whether the multiport was placed into digital mode and |
474 | * able to communicate its state successfully. | 474 | * able to communicate its state successfully. |
475 | */ | 475 | */ |
476 | 476 | ||
477 | static int multiport_init(struct grip_mp *grip) | 477 | static int multiport_init(struct grip_mp *grip) |
478 | { | 478 | { |
479 | int dig_mode, initialized = 0, tries = 0; | 479 | int dig_mode, initialized = 0, tries = 0; |
480 | u32 packet; | 480 | u32 packet; |
481 | 481 | ||
482 | dig_mode = dig_mode_start(grip->gameport, &packet); | 482 | dig_mode = dig_mode_start(grip->gameport, &packet); |
483 | while (!dig_mode && tries < 4) { | 483 | while (!dig_mode && tries < 4) { |
484 | dig_mode = dig_mode_start(grip->gameport, &packet); | 484 | dig_mode = dig_mode_start(grip->gameport, &packet); |
485 | tries++; | 485 | tries++; |
486 | } | 486 | } |
487 | 487 | ||
488 | if (dig_mode) | 488 | if (dig_mode) |
489 | dbg("multiport_init(): digital mode activated.\n"); | 489 | dbg("multiport_init(): digital mode activated.\n"); |
490 | else { | 490 | else { |
491 | dbg("multiport_init(): unable to activate digital mode.\n"); | 491 | dbg("multiport_init(): unable to activate digital mode.\n"); |
492 | return 0; | 492 | return 0; |
493 | } | 493 | } |
494 | 494 | ||
495 | /* Get packets, store multiport state, and check state's validity */ | 495 | /* Get packets, store multiport state, and check state's validity */ |
496 | for (tries = 0; tries < 4096; tries++) { | 496 | for (tries = 0; tries < 4096; tries++) { |
497 | if (slots_valid(grip)) { | 497 | if (slots_valid(grip)) { |
498 | initialized = 1; | 498 | initialized = 1; |
499 | break; | 499 | break; |
500 | } | 500 | } |
501 | } | 501 | } |
502 | dbg("multiport_init(): initialized == %d\n", initialized); | 502 | dbg("multiport_init(): initialized == %d\n", initialized); |
503 | return initialized; | 503 | return initialized; |
504 | } | 504 | } |
505 | 505 | ||
506 | /* | 506 | /* |
507 | * Reports joystick state to the linux input layer. | 507 | * Reports joystick state to the linux input layer. |
508 | */ | 508 | */ |
509 | 509 | ||
510 | static void report_slot(struct grip_mp *grip, int slot) | 510 | static void report_slot(struct grip_mp *grip, int slot) |
511 | { | 511 | { |
512 | struct grip_port *port = grip->port[slot]; | 512 | struct grip_port *port = grip->port[slot]; |
513 | int i; | 513 | int i; |
514 | 514 | ||
515 | /* Store button states with linux input driver */ | 515 | /* Store button states with linux input driver */ |
516 | 516 | ||
517 | for (i = 0; i < 8; i++) | 517 | for (i = 0; i < 8; i++) |
518 | input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1); | 518 | input_report_key(port->dev, grip_btn_gp[i], (port->buttons >> i) & 1); |
519 | 519 | ||
520 | /* Store axis states with linux driver */ | 520 | /* Store axis states with linux driver */ |
521 | 521 | ||
522 | input_report_abs(port->dev, ABS_X, port->xaxes); | 522 | input_report_abs(port->dev, ABS_X, port->xaxes); |
523 | input_report_abs(port->dev, ABS_Y, port->yaxes); | 523 | input_report_abs(port->dev, ABS_Y, port->yaxes); |
524 | 524 | ||
525 | /* Tell the receiver of the events to process them */ | 525 | /* Tell the receiver of the events to process them */ |
526 | 526 | ||
527 | input_sync(port->dev); | 527 | input_sync(port->dev); |
528 | 528 | ||
529 | port->dirty = 0; | 529 | port->dirty = 0; |
530 | } | 530 | } |
531 | 531 | ||
532 | /* | 532 | /* |
533 | * Get the multiport state. | 533 | * Get the multiport state. |
534 | */ | 534 | */ |
535 | 535 | ||
536 | static void grip_poll(struct gameport *gameport) | 536 | static void grip_poll(struct gameport *gameport) |
537 | { | 537 | { |
538 | struct grip_mp *grip = gameport_get_drvdata(gameport); | 538 | struct grip_mp *grip = gameport_get_drvdata(gameport); |
539 | int i, npkts, flags; | 539 | int i, npkts, flags; |
540 | 540 | ||
541 | for (npkts = 0; npkts < 4; npkts++) { | 541 | for (npkts = 0; npkts < 4; npkts++) { |
542 | flags = IO_RETRY; | 542 | flags = IO_RETRY; |
543 | for (i = 0; i < 32; i++) { | 543 | for (i = 0; i < 32; i++) { |
544 | flags = get_and_decode_packet(grip, flags); | 544 | flags = get_and_decode_packet(grip, flags); |
545 | if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY)) | 545 | if ((flags & IO_GOT_PACKET) || !(flags & IO_RETRY)) |
546 | break; | 546 | break; |
547 | } | 547 | } |
548 | if (flags & IO_DONE) | 548 | if (flags & IO_DONE) |
549 | break; | 549 | break; |
550 | } | 550 | } |
551 | 551 | ||
552 | for (i = 0; i < 4; i++) | 552 | for (i = 0; i < 4; i++) |
553 | if (grip->port[i]->dirty) | 553 | if (grip->port[i]->dirty) |
554 | report_slot(grip, i); | 554 | report_slot(grip, i); |
555 | } | 555 | } |
556 | 556 | ||
557 | /* | 557 | /* |
558 | * Called when a joystick device file is opened | 558 | * Called when a joystick device file is opened |
559 | */ | 559 | */ |
560 | 560 | ||
561 | static int grip_open(struct input_dev *dev) | 561 | static int grip_open(struct input_dev *dev) |
562 | { | 562 | { |
563 | struct grip_mp *grip = input_get_drvdata(dev); | 563 | struct grip_mp *grip = input_get_drvdata(dev); |
564 | 564 | ||
565 | gameport_start_polling(grip->gameport); | 565 | gameport_start_polling(grip->gameport); |
566 | return 0; | 566 | return 0; |
567 | } | 567 | } |
568 | 568 | ||
569 | /* | 569 | /* |
570 | * Called when a joystick device file is closed | 570 | * Called when a joystick device file is closed |
571 | */ | 571 | */ |
572 | 572 | ||
573 | static void grip_close(struct input_dev *dev) | 573 | static void grip_close(struct input_dev *dev) |
574 | { | 574 | { |
575 | struct grip_mp *grip = input_get_drvdata(dev); | 575 | struct grip_mp *grip = input_get_drvdata(dev); |
576 | 576 | ||
577 | gameport_stop_polling(grip->gameport); | 577 | gameport_stop_polling(grip->gameport); |
578 | } | 578 | } |
579 | 579 | ||
580 | /* | 580 | /* |
581 | * Tell the linux input layer about a newly plugged-in gamepad. | 581 | * Tell the linux input layer about a newly plugged-in gamepad. |
582 | */ | 582 | */ |
583 | 583 | ||
584 | static int register_slot(int slot, struct grip_mp *grip) | 584 | static int register_slot(int slot, struct grip_mp *grip) |
585 | { | 585 | { |
586 | struct grip_port *port = grip->port[slot]; | 586 | struct grip_port *port = grip->port[slot]; |
587 | struct input_dev *input_dev; | 587 | struct input_dev *input_dev; |
588 | int j, t; | 588 | int j, t; |
589 | int err; | 589 | int err; |
590 | 590 | ||
591 | port->dev = input_dev = input_allocate_device(); | 591 | port->dev = input_dev = input_allocate_device(); |
592 | if (!input_dev) | 592 | if (!input_dev) |
593 | return -ENOMEM; | 593 | return -ENOMEM; |
594 | 594 | ||
595 | input_dev->name = grip_name[port->mode]; | 595 | input_dev->name = grip_name[port->mode]; |
596 | input_dev->id.bustype = BUS_GAMEPORT; | 596 | input_dev->id.bustype = BUS_GAMEPORT; |
597 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; | 597 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_GRAVIS; |
598 | input_dev->id.product = 0x0100 + port->mode; | 598 | input_dev->id.product = 0x0100 + port->mode; |
599 | input_dev->id.version = 0x0100; | 599 | input_dev->id.version = 0x0100; |
600 | input_dev->dev.parent = &grip->gameport->dev; | 600 | input_dev->dev.parent = &grip->gameport->dev; |
601 | 601 | ||
602 | input_set_drvdata(input_dev, grip); | 602 | input_set_drvdata(input_dev, grip); |
603 | 603 | ||
604 | input_dev->open = grip_open; | 604 | input_dev->open = grip_open; |
605 | input_dev->close = grip_close; | 605 | input_dev->close = grip_close; |
606 | 606 | ||
607 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 607 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
608 | 608 | ||
609 | for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++) | 609 | for (j = 0; (t = grip_abs[port->mode][j]) >= 0; j++) |
610 | input_set_abs_params(input_dev, t, -1, 1, 0, 0); | 610 | input_set_abs_params(input_dev, t, -1, 1, 0, 0); |
611 | 611 | ||
612 | for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++) | 612 | for (j = 0; (t = grip_btn[port->mode][j]) >= 0; j++) |
613 | if (t > 0) | 613 | if (t > 0) |
614 | set_bit(t, input_dev->keybit); | 614 | set_bit(t, input_dev->keybit); |
615 | 615 | ||
616 | err = input_register_device(port->dev); | 616 | err = input_register_device(port->dev); |
617 | if (err) { | 617 | if (err) { |
618 | input_free_device(port->dev); | 618 | input_free_device(port->dev); |
619 | return err; | 619 | return err; |
620 | } | 620 | } |
621 | 621 | ||
622 | port->registered = 1; | 622 | port->registered = 1; |
623 | 623 | ||
624 | if (port->dirty) /* report initial state, if any */ | 624 | if (port->dirty) /* report initial state, if any */ |
625 | report_slot(grip, slot); | 625 | report_slot(grip, slot); |
626 | 626 | ||
627 | return 0; | 627 | return 0; |
628 | } | 628 | } |
629 | 629 | ||
630 | static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) | 630 | static int grip_connect(struct gameport *gameport, struct gameport_driver *drv) |
631 | { | 631 | { |
632 | struct grip_mp *grip; | 632 | struct grip_mp *grip; |
633 | int err; | 633 | int err; |
634 | 634 | ||
635 | if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL))) | 635 | if (!(grip = kzalloc(sizeof(struct grip_mp), GFP_KERNEL))) |
636 | return -ENOMEM; | 636 | return -ENOMEM; |
637 | 637 | ||
638 | grip->gameport = gameport; | 638 | grip->gameport = gameport; |
639 | 639 | ||
640 | gameport_set_drvdata(gameport, grip); | 640 | gameport_set_drvdata(gameport, grip); |
641 | 641 | ||
642 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 642 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
643 | if (err) | 643 | if (err) |
644 | goto fail1; | 644 | goto fail1; |
645 | 645 | ||
646 | gameport_set_poll_handler(gameport, grip_poll); | 646 | gameport_set_poll_handler(gameport, grip_poll); |
647 | gameport_set_poll_interval(gameport, 20); | 647 | gameport_set_poll_interval(gameport, 20); |
648 | 648 | ||
649 | if (!multiport_init(grip)) { | 649 | if (!multiport_init(grip)) { |
650 | err = -ENODEV; | 650 | err = -ENODEV; |
651 | goto fail2; | 651 | goto fail2; |
652 | } | 652 | } |
653 | 653 | ||
654 | if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) { | 654 | if (!grip->port[0]->mode && !grip->port[1]->mode && !grip->port[2]->mode && !grip->port[3]->mode) { |
655 | /* nothing plugged in */ | 655 | /* nothing plugged in */ |
656 | err = -ENODEV; | 656 | err = -ENODEV; |
657 | goto fail2; | 657 | goto fail2; |
658 | } | 658 | } |
659 | 659 | ||
660 | return 0; | 660 | return 0; |
661 | 661 | ||
662 | fail2: gameport_close(gameport); | 662 | fail2: gameport_close(gameport); |
663 | fail1: gameport_set_drvdata(gameport, NULL); | 663 | fail1: gameport_set_drvdata(gameport, NULL); |
664 | kfree(grip); | 664 | kfree(grip); |
665 | return err; | 665 | return err; |
666 | } | 666 | } |
667 | 667 | ||
668 | static void grip_disconnect(struct gameport *gameport) | 668 | static void grip_disconnect(struct gameport *gameport) |
669 | { | 669 | { |
670 | struct grip_mp *grip = gameport_get_drvdata(gameport); | 670 | struct grip_mp *grip = gameport_get_drvdata(gameport); |
671 | int i; | 671 | int i; |
672 | 672 | ||
673 | for (i = 0; i < 4; i++) | 673 | for (i = 0; i < 4; i++) |
674 | if (grip->port[i]->registered) | 674 | if (grip->port[i]->registered) |
675 | input_unregister_device(grip->port[i]->dev); | 675 | input_unregister_device(grip->port[i]->dev); |
676 | gameport_close(gameport); | 676 | gameport_close(gameport); |
677 | gameport_set_drvdata(gameport, NULL); | 677 | gameport_set_drvdata(gameport, NULL); |
678 | kfree(grip); | 678 | kfree(grip); |
679 | } | 679 | } |
680 | 680 | ||
681 | static struct gameport_driver grip_drv = { | 681 | static struct gameport_driver grip_drv = { |
682 | .driver = { | 682 | .driver = { |
683 | .name = "grip_mp", | 683 | .name = "grip_mp", |
684 | }, | 684 | }, |
685 | .description = DRIVER_DESC, | 685 | .description = DRIVER_DESC, |
686 | .connect = grip_connect, | 686 | .connect = grip_connect, |
687 | .disconnect = grip_disconnect, | 687 | .disconnect = grip_disconnect, |
688 | }; | 688 | }; |
689 | 689 | ||
690 | static int __init grip_init(void) | 690 | module_gameport_driver(grip_drv); |
691 | { | ||
692 | return gameport_register_driver(&grip_drv); | ||
693 | } | ||
694 | |||
695 | static void __exit grip_exit(void) | ||
696 | { | ||
697 | gameport_unregister_driver(&grip_drv); | ||
698 | } | ||
699 | |||
700 | module_init(grip_init); | ||
701 | module_exit(grip_exit); | ||
702 | 691 |
drivers/input/joystick/guillemot.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2001 Vojtech Pavlik | 2 | * Copyright (c) 2001 Vojtech Pavlik |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
6 | * Guillemot Digital Interface Protocol driver for Linux | 6 | * Guillemot Digital Interface Protocol driver for Linux |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Should you need to contact me, the author, you can do so either by | 24 | * Should you need to contact me, the author, you can do so either by |
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/kernel.h> | 29 | #include <linux/kernel.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/gameport.h> | 34 | #include <linux/gameport.h> |
35 | #include <linux/input.h> | 35 | #include <linux/input.h> |
36 | #include <linux/jiffies.h> | 36 | #include <linux/jiffies.h> |
37 | 37 | ||
38 | #define DRIVER_DESC "Guillemot Digital joystick driver" | 38 | #define DRIVER_DESC "Guillemot Digital joystick driver" |
39 | 39 | ||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
41 | MODULE_DESCRIPTION(DRIVER_DESC); | 41 | MODULE_DESCRIPTION(DRIVER_DESC); |
42 | MODULE_LICENSE("GPL"); | 42 | MODULE_LICENSE("GPL"); |
43 | 43 | ||
44 | #define GUILLEMOT_MAX_START 600 /* 600 us */ | 44 | #define GUILLEMOT_MAX_START 600 /* 600 us */ |
45 | #define GUILLEMOT_MAX_STROBE 60 /* 60 us */ | 45 | #define GUILLEMOT_MAX_STROBE 60 /* 60 us */ |
46 | #define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */ | 46 | #define GUILLEMOT_MAX_LENGTH 17 /* 17 bytes */ |
47 | 47 | ||
48 | static short guillemot_abs_pad[] = | 48 | static short guillemot_abs_pad[] = |
49 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 }; | 49 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, -1 }; |
50 | 50 | ||
51 | static short guillemot_btn_pad[] = | 51 | static short guillemot_btn_pad[] = |
52 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 }; | 52 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_MODE, BTN_SELECT, -1 }; |
53 | 53 | ||
54 | static struct { | 54 | static struct { |
55 | int x; | 55 | int x; |
56 | int y; | 56 | int y; |
57 | } guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | 57 | } guillemot_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; |
58 | 58 | ||
59 | struct guillemot_type { | 59 | struct guillemot_type { |
60 | unsigned char id; | 60 | unsigned char id; |
61 | short *abs; | 61 | short *abs; |
62 | short *btn; | 62 | short *btn; |
63 | int hat; | 63 | int hat; |
64 | char *name; | 64 | char *name; |
65 | }; | 65 | }; |
66 | 66 | ||
67 | struct guillemot { | 67 | struct guillemot { |
68 | struct gameport *gameport; | 68 | struct gameport *gameport; |
69 | struct input_dev *dev; | 69 | struct input_dev *dev; |
70 | int bads; | 70 | int bads; |
71 | int reads; | 71 | int reads; |
72 | struct guillemot_type *type; | 72 | struct guillemot_type *type; |
73 | unsigned char length; | 73 | unsigned char length; |
74 | char phys[32]; | 74 | char phys[32]; |
75 | }; | 75 | }; |
76 | 76 | ||
77 | static struct guillemot_type guillemot_type[] = { | 77 | static struct guillemot_type guillemot_type[] = { |
78 | { 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" }, | 78 | { 0x00, guillemot_abs_pad, guillemot_btn_pad, 1, "Guillemot Pad" }, |
79 | { 0 }}; | 79 | { 0 }}; |
80 | 80 | ||
81 | /* | 81 | /* |
82 | * guillemot_read_packet() reads Guillemot joystick data. | 82 | * guillemot_read_packet() reads Guillemot joystick data. |
83 | */ | 83 | */ |
84 | 84 | ||
85 | static int guillemot_read_packet(struct gameport *gameport, u8 *data) | 85 | static int guillemot_read_packet(struct gameport *gameport, u8 *data) |
86 | { | 86 | { |
87 | unsigned long flags; | 87 | unsigned long flags; |
88 | unsigned char u, v; | 88 | unsigned char u, v; |
89 | unsigned int t, s; | 89 | unsigned int t, s; |
90 | int i; | 90 | int i; |
91 | 91 | ||
92 | for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++) | 92 | for (i = 0; i < GUILLEMOT_MAX_LENGTH; i++) |
93 | data[i] = 0; | 93 | data[i] = 0; |
94 | 94 | ||
95 | i = 0; | 95 | i = 0; |
96 | t = gameport_time(gameport, GUILLEMOT_MAX_START); | 96 | t = gameport_time(gameport, GUILLEMOT_MAX_START); |
97 | s = gameport_time(gameport, GUILLEMOT_MAX_STROBE); | 97 | s = gameport_time(gameport, GUILLEMOT_MAX_STROBE); |
98 | 98 | ||
99 | local_irq_save(flags); | 99 | local_irq_save(flags); |
100 | gameport_trigger(gameport); | 100 | gameport_trigger(gameport); |
101 | v = gameport_read(gameport); | 101 | v = gameport_read(gameport); |
102 | 102 | ||
103 | while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) { | 103 | while (t > 0 && i < GUILLEMOT_MAX_LENGTH * 8) { |
104 | t--; | 104 | t--; |
105 | u = v; v = gameport_read(gameport); | 105 | u = v; v = gameport_read(gameport); |
106 | if (v & ~u & 0x10) { | 106 | if (v & ~u & 0x10) { |
107 | data[i >> 3] |= ((v >> 5) & 1) << (i & 7); | 107 | data[i >> 3] |= ((v >> 5) & 1) << (i & 7); |
108 | i++; | 108 | i++; |
109 | t = s; | 109 | t = s; |
110 | } | 110 | } |
111 | } | 111 | } |
112 | 112 | ||
113 | local_irq_restore(flags); | 113 | local_irq_restore(flags); |
114 | 114 | ||
115 | return i; | 115 | return i; |
116 | } | 116 | } |
117 | 117 | ||
118 | /* | 118 | /* |
119 | * guillemot_poll() reads and analyzes Guillemot joystick data. | 119 | * guillemot_poll() reads and analyzes Guillemot joystick data. |
120 | */ | 120 | */ |
121 | 121 | ||
122 | static void guillemot_poll(struct gameport *gameport) | 122 | static void guillemot_poll(struct gameport *gameport) |
123 | { | 123 | { |
124 | struct guillemot *guillemot = gameport_get_drvdata(gameport); | 124 | struct guillemot *guillemot = gameport_get_drvdata(gameport); |
125 | struct input_dev *dev = guillemot->dev; | 125 | struct input_dev *dev = guillemot->dev; |
126 | u8 data[GUILLEMOT_MAX_LENGTH]; | 126 | u8 data[GUILLEMOT_MAX_LENGTH]; |
127 | int i; | 127 | int i; |
128 | 128 | ||
129 | guillemot->reads++; | 129 | guillemot->reads++; |
130 | 130 | ||
131 | if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 || | 131 | if (guillemot_read_packet(guillemot->gameport, data) != GUILLEMOT_MAX_LENGTH * 8 || |
132 | data[0] != 0x55 || data[16] != 0xaa) { | 132 | data[0] != 0x55 || data[16] != 0xaa) { |
133 | guillemot->bads++; | 133 | guillemot->bads++; |
134 | } else { | 134 | } else { |
135 | 135 | ||
136 | for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++) | 136 | for (i = 0; i < 6 && guillemot->type->abs[i] >= 0; i++) |
137 | input_report_abs(dev, guillemot->type->abs[i], data[i + 5]); | 137 | input_report_abs(dev, guillemot->type->abs[i], data[i + 5]); |
138 | 138 | ||
139 | if (guillemot->type->hat) { | 139 | if (guillemot->type->hat) { |
140 | input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x); | 140 | input_report_abs(dev, ABS_HAT0X, guillemot_hat_to_axis[data[4] >> 4].x); |
141 | input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y); | 141 | input_report_abs(dev, ABS_HAT0Y, guillemot_hat_to_axis[data[4] >> 4].y); |
142 | } | 142 | } |
143 | 143 | ||
144 | for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++) | 144 | for (i = 0; i < 16 && guillemot->type->btn[i] >= 0; i++) |
145 | input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1); | 145 | input_report_key(dev, guillemot->type->btn[i], (data[2 + (i >> 3)] >> (i & 7)) & 1); |
146 | } | 146 | } |
147 | 147 | ||
148 | input_sync(dev); | 148 | input_sync(dev); |
149 | } | 149 | } |
150 | 150 | ||
151 | /* | 151 | /* |
152 | * guillemot_open() is a callback from the input open routine. | 152 | * guillemot_open() is a callback from the input open routine. |
153 | */ | 153 | */ |
154 | 154 | ||
155 | static int guillemot_open(struct input_dev *dev) | 155 | static int guillemot_open(struct input_dev *dev) |
156 | { | 156 | { |
157 | struct guillemot *guillemot = input_get_drvdata(dev); | 157 | struct guillemot *guillemot = input_get_drvdata(dev); |
158 | 158 | ||
159 | gameport_start_polling(guillemot->gameport); | 159 | gameport_start_polling(guillemot->gameport); |
160 | return 0; | 160 | return 0; |
161 | } | 161 | } |
162 | 162 | ||
163 | /* | 163 | /* |
164 | * guillemot_close() is a callback from the input close routine. | 164 | * guillemot_close() is a callback from the input close routine. |
165 | */ | 165 | */ |
166 | 166 | ||
167 | static void guillemot_close(struct input_dev *dev) | 167 | static void guillemot_close(struct input_dev *dev) |
168 | { | 168 | { |
169 | struct guillemot *guillemot = input_get_drvdata(dev); | 169 | struct guillemot *guillemot = input_get_drvdata(dev); |
170 | 170 | ||
171 | gameport_stop_polling(guillemot->gameport); | 171 | gameport_stop_polling(guillemot->gameport); |
172 | } | 172 | } |
173 | 173 | ||
174 | /* | 174 | /* |
175 | * guillemot_connect() probes for Guillemot joysticks. | 175 | * guillemot_connect() probes for Guillemot joysticks. |
176 | */ | 176 | */ |
177 | 177 | ||
178 | static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv) | 178 | static int guillemot_connect(struct gameport *gameport, struct gameport_driver *drv) |
179 | { | 179 | { |
180 | struct guillemot *guillemot; | 180 | struct guillemot *guillemot; |
181 | struct input_dev *input_dev; | 181 | struct input_dev *input_dev; |
182 | u8 data[GUILLEMOT_MAX_LENGTH]; | 182 | u8 data[GUILLEMOT_MAX_LENGTH]; |
183 | int i, t; | 183 | int i, t; |
184 | int err; | 184 | int err; |
185 | 185 | ||
186 | guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL); | 186 | guillemot = kzalloc(sizeof(struct guillemot), GFP_KERNEL); |
187 | input_dev = input_allocate_device(); | 187 | input_dev = input_allocate_device(); |
188 | if (!guillemot || !input_dev) { | 188 | if (!guillemot || !input_dev) { |
189 | err = -ENOMEM; | 189 | err = -ENOMEM; |
190 | goto fail1; | 190 | goto fail1; |
191 | } | 191 | } |
192 | 192 | ||
193 | guillemot->gameport = gameport; | 193 | guillemot->gameport = gameport; |
194 | guillemot->dev = input_dev; | 194 | guillemot->dev = input_dev; |
195 | 195 | ||
196 | gameport_set_drvdata(gameport, guillemot); | 196 | gameport_set_drvdata(gameport, guillemot); |
197 | 197 | ||
198 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 198 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
199 | if (err) | 199 | if (err) |
200 | goto fail1; | 200 | goto fail1; |
201 | 201 | ||
202 | i = guillemot_read_packet(gameport, data); | 202 | i = guillemot_read_packet(gameport, data); |
203 | 203 | ||
204 | if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) { | 204 | if (i != GUILLEMOT_MAX_LENGTH * 8 || data[0] != 0x55 || data[16] != 0xaa) { |
205 | err = -ENODEV; | 205 | err = -ENODEV; |
206 | goto fail2; | 206 | goto fail2; |
207 | } | 207 | } |
208 | 208 | ||
209 | for (i = 0; guillemot_type[i].name; i++) | 209 | for (i = 0; guillemot_type[i].name; i++) |
210 | if (guillemot_type[i].id == data[11]) | 210 | if (guillemot_type[i].id == data[11]) |
211 | break; | 211 | break; |
212 | 212 | ||
213 | if (!guillemot_type[i].name) { | 213 | if (!guillemot_type[i].name) { |
214 | printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n", | 214 | printk(KERN_WARNING "guillemot.c: Unknown joystick on %s. [ %02x%02x:%04x, ver %d.%02d ]\n", |
215 | gameport->phys, data[12], data[13], data[11], data[14], data[15]); | 215 | gameport->phys, data[12], data[13], data[11], data[14], data[15]); |
216 | err = -ENODEV; | 216 | err = -ENODEV; |
217 | goto fail2; | 217 | goto fail2; |
218 | } | 218 | } |
219 | 219 | ||
220 | gameport_set_poll_handler(gameport, guillemot_poll); | 220 | gameport_set_poll_handler(gameport, guillemot_poll); |
221 | gameport_set_poll_interval(gameport, 20); | 221 | gameport_set_poll_interval(gameport, 20); |
222 | 222 | ||
223 | snprintf(guillemot->phys, sizeof(guillemot->phys), "%s/input0", gameport->phys); | 223 | snprintf(guillemot->phys, sizeof(guillemot->phys), "%s/input0", gameport->phys); |
224 | guillemot->type = guillemot_type + i; | 224 | guillemot->type = guillemot_type + i; |
225 | 225 | ||
226 | input_dev->name = guillemot_type[i].name; | 226 | input_dev->name = guillemot_type[i].name; |
227 | input_dev->phys = guillemot->phys; | 227 | input_dev->phys = guillemot->phys; |
228 | input_dev->id.bustype = BUS_GAMEPORT; | 228 | input_dev->id.bustype = BUS_GAMEPORT; |
229 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; | 229 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_GUILLEMOT; |
230 | input_dev->id.product = guillemot_type[i].id; | 230 | input_dev->id.product = guillemot_type[i].id; |
231 | input_dev->id.version = (int)data[14] << 8 | data[15]; | 231 | input_dev->id.version = (int)data[14] << 8 | data[15]; |
232 | input_dev->dev.parent = &gameport->dev; | 232 | input_dev->dev.parent = &gameport->dev; |
233 | 233 | ||
234 | input_set_drvdata(input_dev, guillemot); | 234 | input_set_drvdata(input_dev, guillemot); |
235 | 235 | ||
236 | input_dev->open = guillemot_open; | 236 | input_dev->open = guillemot_open; |
237 | input_dev->close = guillemot_close; | 237 | input_dev->close = guillemot_close; |
238 | 238 | ||
239 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 239 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
240 | 240 | ||
241 | for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) | 241 | for (i = 0; (t = guillemot->type->abs[i]) >= 0; i++) |
242 | input_set_abs_params(input_dev, t, 0, 255, 0, 0); | 242 | input_set_abs_params(input_dev, t, 0, 255, 0, 0); |
243 | 243 | ||
244 | if (guillemot->type->hat) { | 244 | if (guillemot->type->hat) { |
245 | input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); | 245 | input_set_abs_params(input_dev, ABS_HAT0X, -1, 1, 0, 0); |
246 | input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0); | 246 | input_set_abs_params(input_dev, ABS_HAT0Y, -1, 1, 0, 0); |
247 | } | 247 | } |
248 | 248 | ||
249 | for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++) | 249 | for (i = 0; (t = guillemot->type->btn[i]) >= 0; i++) |
250 | set_bit(t, input_dev->keybit); | 250 | set_bit(t, input_dev->keybit); |
251 | 251 | ||
252 | err = input_register_device(guillemot->dev); | 252 | err = input_register_device(guillemot->dev); |
253 | if (err) | 253 | if (err) |
254 | goto fail2; | 254 | goto fail2; |
255 | 255 | ||
256 | return 0; | 256 | return 0; |
257 | 257 | ||
258 | fail2: gameport_close(gameport); | 258 | fail2: gameport_close(gameport); |
259 | fail1: gameport_set_drvdata(gameport, NULL); | 259 | fail1: gameport_set_drvdata(gameport, NULL); |
260 | input_free_device(input_dev); | 260 | input_free_device(input_dev); |
261 | kfree(guillemot); | 261 | kfree(guillemot); |
262 | return err; | 262 | return err; |
263 | } | 263 | } |
264 | 264 | ||
265 | static void guillemot_disconnect(struct gameport *gameport) | 265 | static void guillemot_disconnect(struct gameport *gameport) |
266 | { | 266 | { |
267 | struct guillemot *guillemot = gameport_get_drvdata(gameport); | 267 | struct guillemot *guillemot = gameport_get_drvdata(gameport); |
268 | 268 | ||
269 | printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys); | 269 | printk(KERN_INFO "guillemot.c: Failed %d reads out of %d on %s\n", guillemot->reads, guillemot->bads, guillemot->phys); |
270 | input_unregister_device(guillemot->dev); | 270 | input_unregister_device(guillemot->dev); |
271 | gameport_close(gameport); | 271 | gameport_close(gameport); |
272 | kfree(guillemot); | 272 | kfree(guillemot); |
273 | } | 273 | } |
274 | 274 | ||
275 | static struct gameport_driver guillemot_drv = { | 275 | static struct gameport_driver guillemot_drv = { |
276 | .driver = { | 276 | .driver = { |
277 | .name = "guillemot", | 277 | .name = "guillemot", |
278 | }, | 278 | }, |
279 | .description = DRIVER_DESC, | 279 | .description = DRIVER_DESC, |
280 | .connect = guillemot_connect, | 280 | .connect = guillemot_connect, |
281 | .disconnect = guillemot_disconnect, | 281 | .disconnect = guillemot_disconnect, |
282 | }; | 282 | }; |
283 | 283 | ||
284 | static int __init guillemot_init(void) | 284 | module_gameport_driver(guillemot_drv); |
285 | { | ||
286 | return gameport_register_driver(&guillemot_drv); | ||
287 | } | ||
288 | |||
289 | static void __exit guillemot_exit(void) | ||
290 | { | ||
291 | gameport_unregister_driver(&guillemot_drv); | ||
292 | } | ||
293 | |||
294 | module_init(guillemot_init); | ||
295 | module_exit(guillemot_exit); | ||
296 | 285 |
drivers/input/joystick/interact.c
1 | /* | 1 | /* |
2 | * Copyright (c) 2001 Vojtech Pavlik | 2 | * Copyright (c) 2001 Vojtech Pavlik |
3 | * | 3 | * |
4 | * Based on the work of: | 4 | * Based on the work of: |
5 | * Toby Deshane | 5 | * Toby Deshane |
6 | */ | 6 | */ |
7 | 7 | ||
8 | /* | 8 | /* |
9 | * InterAct digital gamepad/joystick driver for Linux | 9 | * InterAct digital gamepad/joystick driver for Linux |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | 12 | /* |
13 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 15 | * the Free Software Foundation; either version 2 of the License, or |
16 | * (at your option) any later version. | 16 | * (at your option) any later version. |
17 | * | 17 | * |
18 | * This program is distributed in the hope that it will be useful, | 18 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 21 | * GNU General Public License for more details. |
22 | * | 22 | * |
23 | * You should have received a copy of the GNU General Public License | 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 | 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 | 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
26 | * | 26 | * |
27 | * Should you need to contact me, the author, you can do so either by | 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: | 28 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/slab.h> | 33 | #include <linux/slab.h> |
34 | #include <linux/module.h> | 34 | #include <linux/module.h> |
35 | #include <linux/delay.h> | 35 | #include <linux/delay.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/gameport.h> | 37 | #include <linux/gameport.h> |
38 | #include <linux/input.h> | 38 | #include <linux/input.h> |
39 | #include <linux/jiffies.h> | 39 | #include <linux/jiffies.h> |
40 | 40 | ||
41 | #define DRIVER_DESC "InterAct digital joystick driver" | 41 | #define DRIVER_DESC "InterAct digital joystick driver" |
42 | 42 | ||
43 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 43 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
44 | MODULE_DESCRIPTION(DRIVER_DESC); | 44 | MODULE_DESCRIPTION(DRIVER_DESC); |
45 | MODULE_LICENSE("GPL"); | 45 | MODULE_LICENSE("GPL"); |
46 | 46 | ||
47 | #define INTERACT_MAX_START 600 /* 400 us */ | 47 | #define INTERACT_MAX_START 600 /* 400 us */ |
48 | #define INTERACT_MAX_STROBE 60 /* 40 us */ | 48 | #define INTERACT_MAX_STROBE 60 /* 40 us */ |
49 | #define INTERACT_MAX_LENGTH 32 /* 32 bits */ | 49 | #define INTERACT_MAX_LENGTH 32 /* 32 bits */ |
50 | 50 | ||
51 | #define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */ | 51 | #define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */ |
52 | #define INTERACT_TYPE_PP8D 1 /* ProPad 8 */ | 52 | #define INTERACT_TYPE_PP8D 1 /* ProPad 8 */ |
53 | 53 | ||
54 | struct interact { | 54 | struct interact { |
55 | struct gameport *gameport; | 55 | struct gameport *gameport; |
56 | struct input_dev *dev; | 56 | struct input_dev *dev; |
57 | int bads; | 57 | int bads; |
58 | int reads; | 58 | int reads; |
59 | unsigned char type; | 59 | unsigned char type; |
60 | unsigned char length; | 60 | unsigned char length; |
61 | char phys[32]; | 61 | char phys[32]; |
62 | }; | 62 | }; |
63 | 63 | ||
64 | static short interact_abs_hhfx[] = | 64 | static short interact_abs_hhfx[] = |
65 | { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 }; | 65 | { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 }; |
66 | static short interact_abs_pp8d[] = | 66 | static short interact_abs_pp8d[] = |
67 | { ABS_X, ABS_Y, -1 }; | 67 | { ABS_X, ABS_Y, -1 }; |
68 | 68 | ||
69 | static short interact_btn_hhfx[] = | 69 | static short interact_btn_hhfx[] = |
70 | { BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 }; | 70 | { BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 }; |
71 | static short interact_btn_pp8d[] = | 71 | static short interact_btn_pp8d[] = |
72 | { BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 }; | 72 | { BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 }; |
73 | 73 | ||
74 | struct interact_type { | 74 | struct interact_type { |
75 | int id; | 75 | int id; |
76 | short *abs; | 76 | short *abs; |
77 | short *btn; | 77 | short *btn; |
78 | char *name; | 78 | char *name; |
79 | unsigned char length; | 79 | unsigned char length; |
80 | unsigned char b8; | 80 | unsigned char b8; |
81 | }; | 81 | }; |
82 | 82 | ||
83 | static struct interact_type interact_type[] = { | 83 | static struct interact_type interact_type[] = { |
84 | { 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 }, | 84 | { 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 }, |
85 | { 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 }, | 85 | { 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 }, |
86 | { 0 }}; | 86 | { 0 }}; |
87 | 87 | ||
88 | /* | 88 | /* |
89 | * interact_read_packet() reads and InterAct joystick data. | 89 | * interact_read_packet() reads and InterAct joystick data. |
90 | */ | 90 | */ |
91 | 91 | ||
92 | static int interact_read_packet(struct gameport *gameport, int length, u32 *data) | 92 | static int interact_read_packet(struct gameport *gameport, int length, u32 *data) |
93 | { | 93 | { |
94 | unsigned long flags; | 94 | unsigned long flags; |
95 | unsigned char u, v; | 95 | unsigned char u, v; |
96 | unsigned int t, s; | 96 | unsigned int t, s; |
97 | int i; | 97 | int i; |
98 | 98 | ||
99 | i = 0; | 99 | i = 0; |
100 | data[0] = data[1] = data[2] = 0; | 100 | data[0] = data[1] = data[2] = 0; |
101 | t = gameport_time(gameport, INTERACT_MAX_START); | 101 | t = gameport_time(gameport, INTERACT_MAX_START); |
102 | s = gameport_time(gameport, INTERACT_MAX_STROBE); | 102 | s = gameport_time(gameport, INTERACT_MAX_STROBE); |
103 | 103 | ||
104 | local_irq_save(flags); | 104 | local_irq_save(flags); |
105 | gameport_trigger(gameport); | 105 | gameport_trigger(gameport); |
106 | v = gameport_read(gameport); | 106 | v = gameport_read(gameport); |
107 | 107 | ||
108 | while (t > 0 && i < length) { | 108 | while (t > 0 && i < length) { |
109 | t--; | 109 | t--; |
110 | u = v; v = gameport_read(gameport); | 110 | u = v; v = gameport_read(gameport); |
111 | if (v & ~u & 0x40) { | 111 | if (v & ~u & 0x40) { |
112 | data[0] = (data[0] << 1) | ((v >> 4) & 1); | 112 | data[0] = (data[0] << 1) | ((v >> 4) & 1); |
113 | data[1] = (data[1] << 1) | ((v >> 5) & 1); | 113 | data[1] = (data[1] << 1) | ((v >> 5) & 1); |
114 | data[2] = (data[2] << 1) | ((v >> 7) & 1); | 114 | data[2] = (data[2] << 1) | ((v >> 7) & 1); |
115 | i++; | 115 | i++; |
116 | t = s; | 116 | t = s; |
117 | } | 117 | } |
118 | } | 118 | } |
119 | 119 | ||
120 | local_irq_restore(flags); | 120 | local_irq_restore(flags); |
121 | 121 | ||
122 | return i; | 122 | return i; |
123 | } | 123 | } |
124 | 124 | ||
125 | /* | 125 | /* |
126 | * interact_poll() reads and analyzes InterAct joystick data. | 126 | * interact_poll() reads and analyzes InterAct joystick data. |
127 | */ | 127 | */ |
128 | 128 | ||
129 | static void interact_poll(struct gameport *gameport) | 129 | static void interact_poll(struct gameport *gameport) |
130 | { | 130 | { |
131 | struct interact *interact = gameport_get_drvdata(gameport); | 131 | struct interact *interact = gameport_get_drvdata(gameport); |
132 | struct input_dev *dev = interact->dev; | 132 | struct input_dev *dev = interact->dev; |
133 | u32 data[3]; | 133 | u32 data[3]; |
134 | int i; | 134 | int i; |
135 | 135 | ||
136 | interact->reads++; | 136 | interact->reads++; |
137 | 137 | ||
138 | if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) { | 138 | if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) { |
139 | interact->bads++; | 139 | interact->bads++; |
140 | } else { | 140 | } else { |
141 | 141 | ||
142 | for (i = 0; i < 3; i++) | 142 | for (i = 0; i < 3; i++) |
143 | data[i] <<= INTERACT_MAX_LENGTH - interact->length; | 143 | data[i] <<= INTERACT_MAX_LENGTH - interact->length; |
144 | 144 | ||
145 | switch (interact->type) { | 145 | switch (interact->type) { |
146 | 146 | ||
147 | case INTERACT_TYPE_HHFX: | 147 | case INTERACT_TYPE_HHFX: |
148 | 148 | ||
149 | for (i = 0; i < 4; i++) | 149 | for (i = 0; i < 4; i++) |
150 | input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff); | 150 | input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff); |
151 | 151 | ||
152 | for (i = 0; i < 2; i++) | 152 | for (i = 0; i < 2; i++) |
153 | input_report_abs(dev, ABS_HAT0Y - i, | 153 | input_report_abs(dev, ABS_HAT0Y - i, |
154 | ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1)); | 154 | ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1)); |
155 | 155 | ||
156 | for (i = 0; i < 8; i++) | 156 | for (i = 0; i < 8; i++) |
157 | input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1); | 157 | input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1); |
158 | 158 | ||
159 | for (i = 0; i < 4; i++) | 159 | for (i = 0; i < 4; i++) |
160 | input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1); | 160 | input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1); |
161 | 161 | ||
162 | break; | 162 | break; |
163 | 163 | ||
164 | case INTERACT_TYPE_PP8D: | 164 | case INTERACT_TYPE_PP8D: |
165 | 165 | ||
166 | for (i = 0; i < 2; i++) | 166 | for (i = 0; i < 2; i++) |
167 | input_report_abs(dev, interact_abs_pp8d[i], | 167 | input_report_abs(dev, interact_abs_pp8d[i], |
168 | ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); | 168 | ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1)); |
169 | 169 | ||
170 | for (i = 0; i < 8; i++) | 170 | for (i = 0; i < 8; i++) |
171 | input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1); | 171 | input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1); |
172 | 172 | ||
173 | break; | 173 | break; |
174 | } | 174 | } |
175 | } | 175 | } |
176 | 176 | ||
177 | input_sync(dev); | 177 | input_sync(dev); |
178 | } | 178 | } |
179 | 179 | ||
180 | /* | 180 | /* |
181 | * interact_open() is a callback from the input open routine. | 181 | * interact_open() is a callback from the input open routine. |
182 | */ | 182 | */ |
183 | 183 | ||
184 | static int interact_open(struct input_dev *dev) | 184 | static int interact_open(struct input_dev *dev) |
185 | { | 185 | { |
186 | struct interact *interact = input_get_drvdata(dev); | 186 | struct interact *interact = input_get_drvdata(dev); |
187 | 187 | ||
188 | gameport_start_polling(interact->gameport); | 188 | gameport_start_polling(interact->gameport); |
189 | return 0; | 189 | return 0; |
190 | } | 190 | } |
191 | 191 | ||
192 | /* | 192 | /* |
193 | * interact_close() is a callback from the input close routine. | 193 | * interact_close() is a callback from the input close routine. |
194 | */ | 194 | */ |
195 | 195 | ||
196 | static void interact_close(struct input_dev *dev) | 196 | static void interact_close(struct input_dev *dev) |
197 | { | 197 | { |
198 | struct interact *interact = input_get_drvdata(dev); | 198 | struct interact *interact = input_get_drvdata(dev); |
199 | 199 | ||
200 | gameport_stop_polling(interact->gameport); | 200 | gameport_stop_polling(interact->gameport); |
201 | } | 201 | } |
202 | 202 | ||
203 | /* | 203 | /* |
204 | * interact_connect() probes for InterAct joysticks. | 204 | * interact_connect() probes for InterAct joysticks. |
205 | */ | 205 | */ |
206 | 206 | ||
207 | static int interact_connect(struct gameport *gameport, struct gameport_driver *drv) | 207 | static int interact_connect(struct gameport *gameport, struct gameport_driver *drv) |
208 | { | 208 | { |
209 | struct interact *interact; | 209 | struct interact *interact; |
210 | struct input_dev *input_dev; | 210 | struct input_dev *input_dev; |
211 | __u32 data[3]; | 211 | __u32 data[3]; |
212 | int i, t; | 212 | int i, t; |
213 | int err; | 213 | int err; |
214 | 214 | ||
215 | interact = kzalloc(sizeof(struct interact), GFP_KERNEL); | 215 | interact = kzalloc(sizeof(struct interact), GFP_KERNEL); |
216 | input_dev = input_allocate_device(); | 216 | input_dev = input_allocate_device(); |
217 | if (!interact || !input_dev) { | 217 | if (!interact || !input_dev) { |
218 | err = -ENOMEM; | 218 | err = -ENOMEM; |
219 | goto fail1; | 219 | goto fail1; |
220 | } | 220 | } |
221 | 221 | ||
222 | interact->gameport = gameport; | 222 | interact->gameport = gameport; |
223 | interact->dev = input_dev; | 223 | interact->dev = input_dev; |
224 | 224 | ||
225 | gameport_set_drvdata(gameport, interact); | 225 | gameport_set_drvdata(gameport, interact); |
226 | 226 | ||
227 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 227 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
228 | if (err) | 228 | if (err) |
229 | goto fail1; | 229 | goto fail1; |
230 | 230 | ||
231 | i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data); | 231 | i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data); |
232 | 232 | ||
233 | if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) { | 233 | if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) { |
234 | err = -ENODEV; | 234 | err = -ENODEV; |
235 | goto fail2; | 235 | goto fail2; |
236 | } | 236 | } |
237 | 237 | ||
238 | for (i = 0; interact_type[i].length; i++) | 238 | for (i = 0; interact_type[i].length; i++) |
239 | if (interact_type[i].id == (data[2] >> 16)) | 239 | if (interact_type[i].id == (data[2] >> 16)) |
240 | break; | 240 | break; |
241 | 241 | ||
242 | if (!interact_type[i].length) { | 242 | if (!interact_type[i].length) { |
243 | printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n", | 243 | printk(KERN_WARNING "interact.c: Unknown joystick on %s. [len %d d0 %08x d1 %08x i2 %08x]\n", |
244 | gameport->phys, i, data[0], data[1], data[2]); | 244 | gameport->phys, i, data[0], data[1], data[2]); |
245 | err = -ENODEV; | 245 | err = -ENODEV; |
246 | goto fail2; | 246 | goto fail2; |
247 | } | 247 | } |
248 | 248 | ||
249 | gameport_set_poll_handler(gameport, interact_poll); | 249 | gameport_set_poll_handler(gameport, interact_poll); |
250 | gameport_set_poll_interval(gameport, 20); | 250 | gameport_set_poll_interval(gameport, 20); |
251 | 251 | ||
252 | snprintf(interact->phys, sizeof(interact->phys), "%s/input0", gameport->phys); | 252 | snprintf(interact->phys, sizeof(interact->phys), "%s/input0", gameport->phys); |
253 | 253 | ||
254 | interact->type = i; | 254 | interact->type = i; |
255 | interact->length = interact_type[i].length; | 255 | interact->length = interact_type[i].length; |
256 | 256 | ||
257 | input_dev->name = interact_type[i].name; | 257 | input_dev->name = interact_type[i].name; |
258 | input_dev->phys = interact->phys; | 258 | input_dev->phys = interact->phys; |
259 | input_dev->id.bustype = BUS_GAMEPORT; | 259 | input_dev->id.bustype = BUS_GAMEPORT; |
260 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT; | 260 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_INTERACT; |
261 | input_dev->id.product = interact_type[i].id; | 261 | input_dev->id.product = interact_type[i].id; |
262 | input_dev->id.version = 0x0100; | 262 | input_dev->id.version = 0x0100; |
263 | input_dev->dev.parent = &gameport->dev; | 263 | input_dev->dev.parent = &gameport->dev; |
264 | 264 | ||
265 | input_set_drvdata(input_dev, interact); | 265 | input_set_drvdata(input_dev, interact); |
266 | 266 | ||
267 | input_dev->open = interact_open; | 267 | input_dev->open = interact_open; |
268 | input_dev->close = interact_close; | 268 | input_dev->close = interact_close; |
269 | 269 | ||
270 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 270 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
271 | 271 | ||
272 | for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) { | 272 | for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) { |
273 | if (i < interact_type[interact->type].b8) | 273 | if (i < interact_type[interact->type].b8) |
274 | input_set_abs_params(input_dev, t, 0, 255, 0, 0); | 274 | input_set_abs_params(input_dev, t, 0, 255, 0, 0); |
275 | else | 275 | else |
276 | input_set_abs_params(input_dev, t, -1, 1, 0, 0); | 276 | input_set_abs_params(input_dev, t, -1, 1, 0, 0); |
277 | } | 277 | } |
278 | 278 | ||
279 | for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++) | 279 | for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++) |
280 | __set_bit(t, input_dev->keybit); | 280 | __set_bit(t, input_dev->keybit); |
281 | 281 | ||
282 | err = input_register_device(interact->dev); | 282 | err = input_register_device(interact->dev); |
283 | if (err) | 283 | if (err) |
284 | goto fail2; | 284 | goto fail2; |
285 | 285 | ||
286 | return 0; | 286 | return 0; |
287 | 287 | ||
288 | fail2: gameport_close(gameport); | 288 | fail2: gameport_close(gameport); |
289 | fail1: gameport_set_drvdata(gameport, NULL); | 289 | fail1: gameport_set_drvdata(gameport, NULL); |
290 | input_free_device(input_dev); | 290 | input_free_device(input_dev); |
291 | kfree(interact); | 291 | kfree(interact); |
292 | return err; | 292 | return err; |
293 | } | 293 | } |
294 | 294 | ||
295 | static void interact_disconnect(struct gameport *gameport) | 295 | static void interact_disconnect(struct gameport *gameport) |
296 | { | 296 | { |
297 | struct interact *interact = gameport_get_drvdata(gameport); | 297 | struct interact *interact = gameport_get_drvdata(gameport); |
298 | 298 | ||
299 | input_unregister_device(interact->dev); | 299 | input_unregister_device(interact->dev); |
300 | gameport_close(gameport); | 300 | gameport_close(gameport); |
301 | gameport_set_drvdata(gameport, NULL); | 301 | gameport_set_drvdata(gameport, NULL); |
302 | kfree(interact); | 302 | kfree(interact); |
303 | } | 303 | } |
304 | 304 | ||
305 | static struct gameport_driver interact_drv = { | 305 | static struct gameport_driver interact_drv = { |
306 | .driver = { | 306 | .driver = { |
307 | .name = "interact", | 307 | .name = "interact", |
308 | }, | 308 | }, |
309 | .description = DRIVER_DESC, | 309 | .description = DRIVER_DESC, |
310 | .connect = interact_connect, | 310 | .connect = interact_connect, |
311 | .disconnect = interact_disconnect, | 311 | .disconnect = interact_disconnect, |
312 | }; | 312 | }; |
313 | 313 | ||
314 | static int __init interact_init(void) | 314 | module_gameport_driver(interact_drv); |
315 | { | ||
316 | return gameport_register_driver(&interact_drv); | ||
317 | } | ||
318 | |||
319 | static void __exit interact_exit(void) | ||
320 | { | ||
321 | gameport_unregister_driver(&interact_drv); | ||
322 | } | ||
323 | |||
324 | module_init(interact_init); | ||
325 | module_exit(interact_exit); | ||
326 | 315 |
drivers/input/joystick/joydump.c
1 | /* | 1 | /* |
2 | * Copyright (c) 1996-2001 Vojtech Pavlik | 2 | * Copyright (c) 1996-2001 Vojtech Pavlik |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
6 | * This is just a very simple driver that can dump the data | 6 | * This is just a very simple driver that can dump the data |
7 | * out of the joystick port into the syslog ... | 7 | * out of the joystick port into the syslog ... |
8 | */ | 8 | */ |
9 | 9 | ||
10 | /* | 10 | /* |
11 | * This program is free software; you can redistribute it and/or modify | 11 | * This program is free software; you can redistribute it and/or modify |
12 | * it under the terms of the GNU General Public License as published by | 12 | * it under the terms of the GNU General Public License as published by |
13 | * the Free Software Foundation; either version 2 of the License, or | 13 | * the Free Software Foundation; either version 2 of the License, or |
14 | * (at your option) any later version. | 14 | * (at your option) any later version. |
15 | * | 15 | * |
16 | * This program is distributed in the hope that it will be useful, | 16 | * This program is distributed in the hope that it will be useful, |
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
19 | * GNU General Public License for more details. | 19 | * GNU General Public License for more details. |
20 | * | 20 | * |
21 | * You should have received a copy of the GNU General Public License | 21 | * You should have received a copy of the GNU General Public License |
22 | * along with this program; if not, write to the Free Software | 22 | * along with this program; if not, write to the Free Software |
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
24 | * | 24 | * |
25 | * Should you need to contact me, the author, you can do so either by | 25 | * Should you need to contact me, the author, you can do so either by |
26 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 26 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
28 | */ | 28 | */ |
29 | 29 | ||
30 | #include <linux/module.h> | 30 | #include <linux/module.h> |
31 | #include <linux/gameport.h> | 31 | #include <linux/gameport.h> |
32 | #include <linux/kernel.h> | 32 | #include <linux/kernel.h> |
33 | #include <linux/delay.h> | 33 | #include <linux/delay.h> |
34 | #include <linux/init.h> | 34 | #include <linux/init.h> |
35 | #include <linux/slab.h> | 35 | #include <linux/slab.h> |
36 | 36 | ||
37 | #define DRIVER_DESC "Gameport data dumper module" | 37 | #define DRIVER_DESC "Gameport data dumper module" |
38 | 38 | ||
39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 39 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
40 | MODULE_DESCRIPTION(DRIVER_DESC); | 40 | MODULE_DESCRIPTION(DRIVER_DESC); |
41 | MODULE_LICENSE("GPL"); | 41 | MODULE_LICENSE("GPL"); |
42 | 42 | ||
43 | #define BUF_SIZE 256 | 43 | #define BUF_SIZE 256 |
44 | 44 | ||
45 | struct joydump { | 45 | struct joydump { |
46 | unsigned int time; | 46 | unsigned int time; |
47 | unsigned char data; | 47 | unsigned char data; |
48 | }; | 48 | }; |
49 | 49 | ||
50 | static int joydump_connect(struct gameport *gameport, struct gameport_driver *drv) | 50 | static int joydump_connect(struct gameport *gameport, struct gameport_driver *drv) |
51 | { | 51 | { |
52 | struct joydump *buf; /* all entries */ | 52 | struct joydump *buf; /* all entries */ |
53 | struct joydump *dump, *prev; /* one entry each */ | 53 | struct joydump *dump, *prev; /* one entry each */ |
54 | int axes[4], buttons; | 54 | int axes[4], buttons; |
55 | int i, j, t, timeout; | 55 | int i, j, t, timeout; |
56 | unsigned long flags; | 56 | unsigned long flags; |
57 | unsigned char u; | 57 | unsigned char u; |
58 | 58 | ||
59 | printk(KERN_INFO "joydump: ,------------------ START ----------------.\n"); | 59 | printk(KERN_INFO "joydump: ,------------------ START ----------------.\n"); |
60 | printk(KERN_INFO "joydump: | Dumping: %30s |\n", gameport->phys); | 60 | printk(KERN_INFO "joydump: | Dumping: %30s |\n", gameport->phys); |
61 | printk(KERN_INFO "joydump: | Speed: %28d kHz |\n", gameport->speed); | 61 | printk(KERN_INFO "joydump: | Speed: %28d kHz |\n", gameport->speed); |
62 | 62 | ||
63 | if (gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) { | 63 | if (gameport_open(gameport, drv, GAMEPORT_MODE_RAW)) { |
64 | 64 | ||
65 | printk(KERN_INFO "joydump: | Raw mode not available - trying cooked. |\n"); | 65 | printk(KERN_INFO "joydump: | Raw mode not available - trying cooked. |\n"); |
66 | 66 | ||
67 | if (gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) { | 67 | if (gameport_open(gameport, drv, GAMEPORT_MODE_COOKED)) { |
68 | 68 | ||
69 | printk(KERN_INFO "joydump: | Cooked not available either. Failing. |\n"); | 69 | printk(KERN_INFO "joydump: | Cooked not available either. Failing. |\n"); |
70 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); | 70 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); |
71 | return -ENODEV; | 71 | return -ENODEV; |
72 | } | 72 | } |
73 | 73 | ||
74 | gameport_cooked_read(gameport, axes, &buttons); | 74 | gameport_cooked_read(gameport, axes, &buttons); |
75 | 75 | ||
76 | for (i = 0; i < 4; i++) | 76 | for (i = 0; i < 4; i++) |
77 | printk(KERN_INFO "joydump: | Axis %d: %4d. |\n", i, axes[i]); | 77 | printk(KERN_INFO "joydump: | Axis %d: %4d. |\n", i, axes[i]); |
78 | printk(KERN_INFO "joydump: | Buttons %02x. |\n", buttons); | 78 | printk(KERN_INFO "joydump: | Buttons %02x. |\n", buttons); |
79 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); | 79 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); |
80 | } | 80 | } |
81 | 81 | ||
82 | timeout = gameport_time(gameport, 10000); /* 10 ms */ | 82 | timeout = gameport_time(gameport, 10000); /* 10 ms */ |
83 | 83 | ||
84 | buf = kmalloc(BUF_SIZE * sizeof(struct joydump), GFP_KERNEL); | 84 | buf = kmalloc(BUF_SIZE * sizeof(struct joydump), GFP_KERNEL); |
85 | if (!buf) { | 85 | if (!buf) { |
86 | printk(KERN_INFO "joydump: no memory for testing\n"); | 86 | printk(KERN_INFO "joydump: no memory for testing\n"); |
87 | goto jd_end; | 87 | goto jd_end; |
88 | } | 88 | } |
89 | dump = buf; | 89 | dump = buf; |
90 | t = 0; | 90 | t = 0; |
91 | i = 1; | 91 | i = 1; |
92 | 92 | ||
93 | local_irq_save(flags); | 93 | local_irq_save(flags); |
94 | 94 | ||
95 | u = gameport_read(gameport); | 95 | u = gameport_read(gameport); |
96 | 96 | ||
97 | dump->data = u; | 97 | dump->data = u; |
98 | dump->time = t; | 98 | dump->time = t; |
99 | dump++; | 99 | dump++; |
100 | 100 | ||
101 | gameport_trigger(gameport); | 101 | gameport_trigger(gameport); |
102 | 102 | ||
103 | while (i < BUF_SIZE && t < timeout) { | 103 | while (i < BUF_SIZE && t < timeout) { |
104 | 104 | ||
105 | dump->data = gameport_read(gameport); | 105 | dump->data = gameport_read(gameport); |
106 | 106 | ||
107 | if (dump->data ^ u) { | 107 | if (dump->data ^ u) { |
108 | u = dump->data; | 108 | u = dump->data; |
109 | dump->time = t; | 109 | dump->time = t; |
110 | i++; | 110 | i++; |
111 | dump++; | 111 | dump++; |
112 | } | 112 | } |
113 | t++; | 113 | t++; |
114 | } | 114 | } |
115 | 115 | ||
116 | local_irq_restore(flags); | 116 | local_irq_restore(flags); |
117 | 117 | ||
118 | /* | 118 | /* |
119 | * Dump data. | 119 | * Dump data. |
120 | */ | 120 | */ |
121 | 121 | ||
122 | t = i; | 122 | t = i; |
123 | dump = buf; | 123 | dump = buf; |
124 | prev = dump; | 124 | prev = dump; |
125 | 125 | ||
126 | printk(KERN_INFO "joydump: >------------------ DATA -----------------<\n"); | 126 | printk(KERN_INFO "joydump: >------------------ DATA -----------------<\n"); |
127 | printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", 0, 0); | 127 | printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", 0, 0); |
128 | for (j = 7; j >= 0; j--) | 128 | for (j = 7; j >= 0; j--) |
129 | printk("%d", (dump->data >> j) & 1); | 129 | printk("%d", (dump->data >> j) & 1); |
130 | printk(" |\n"); | 130 | printk(" |\n"); |
131 | dump++; | 131 | dump++; |
132 | 132 | ||
133 | for (i = 1; i < t; i++, dump++, prev++) { | 133 | for (i = 1; i < t; i++, dump++, prev++) { |
134 | printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", | 134 | printk(KERN_INFO "joydump: | index: %3d delta: %3d us data: ", |
135 | i, dump->time - prev->time); | 135 | i, dump->time - prev->time); |
136 | for (j = 7; j >= 0; j--) | 136 | for (j = 7; j >= 0; j--) |
137 | printk("%d", (dump->data >> j) & 1); | 137 | printk("%d", (dump->data >> j) & 1); |
138 | printk(" |\n"); | 138 | printk(" |\n"); |
139 | } | 139 | } |
140 | kfree(buf); | 140 | kfree(buf); |
141 | 141 | ||
142 | jd_end: | 142 | jd_end: |
143 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); | 143 | printk(KERN_INFO "joydump: `------------------- END -----------------'\n"); |
144 | 144 | ||
145 | return 0; | 145 | return 0; |
146 | } | 146 | } |
147 | 147 | ||
148 | static void joydump_disconnect(struct gameport *gameport) | 148 | static void joydump_disconnect(struct gameport *gameport) |
149 | { | 149 | { |
150 | gameport_close(gameport); | 150 | gameport_close(gameport); |
151 | } | 151 | } |
152 | 152 | ||
153 | static struct gameport_driver joydump_drv = { | 153 | static struct gameport_driver joydump_drv = { |
154 | .driver = { | 154 | .driver = { |
155 | .name = "joydump", | 155 | .name = "joydump", |
156 | }, | 156 | }, |
157 | .description = DRIVER_DESC, | 157 | .description = DRIVER_DESC, |
158 | .connect = joydump_connect, | 158 | .connect = joydump_connect, |
159 | .disconnect = joydump_disconnect, | 159 | .disconnect = joydump_disconnect, |
160 | }; | 160 | }; |
161 | 161 | ||
162 | static int __init joydump_init(void) | 162 | module_gameport_driver(joydump_drv); |
163 | { | ||
164 | return gameport_register_driver(&joydump_drv); | ||
165 | } | ||
166 | |||
167 | static void __exit joydump_exit(void) | ||
168 | { | ||
169 | gameport_unregister_driver(&joydump_drv); | ||
170 | } | ||
171 | |||
172 | module_init(joydump_init); | ||
173 | module_exit(joydump_exit); | ||
174 | 163 |
drivers/input/joystick/sidewinder.c
1 | /* | 1 | /* |
2 | * Copyright (c) 1998-2005 Vojtech Pavlik | 2 | * Copyright (c) 1998-2005 Vojtech Pavlik |
3 | */ | 3 | */ |
4 | 4 | ||
5 | /* | 5 | /* |
6 | * Microsoft SideWinder joystick family driver for Linux | 6 | * Microsoft SideWinder joystick family driver for Linux |
7 | */ | 7 | */ |
8 | 8 | ||
9 | /* | 9 | /* |
10 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
11 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
12 | * the Free Software Foundation; either version 2 of the License, or | 12 | * the Free Software Foundation; either version 2 of the License, or |
13 | * (at your option) any later version. | 13 | * (at your option) any later version. |
14 | * | 14 | * |
15 | * This program is distributed in the hope that it will be useful, | 15 | * This program is distributed in the hope that it will be useful, |
16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 16 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 17 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
18 | * GNU General Public License for more details. | 18 | * GNU General Public License for more details. |
19 | * | 19 | * |
20 | * You should have received a copy of the GNU General Public License | 20 | * You should have received a copy of the GNU General Public License |
21 | * along with this program; if not, write to the Free Software | 21 | * along with this program; if not, write to the Free Software |
22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | 22 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
23 | * | 23 | * |
24 | * Should you need to contact me, the author, you can do so either by | 24 | * Should you need to contact me, the author, you can do so either by |
25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | 25 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 26 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
27 | */ | 27 | */ |
28 | 28 | ||
29 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/module.h> | 31 | #include <linux/module.h> |
32 | #include <linux/slab.h> | 32 | #include <linux/slab.h> |
33 | #include <linux/init.h> | 33 | #include <linux/init.h> |
34 | #include <linux/input.h> | 34 | #include <linux/input.h> |
35 | #include <linux/gameport.h> | 35 | #include <linux/gameport.h> |
36 | #include <linux/jiffies.h> | 36 | #include <linux/jiffies.h> |
37 | 37 | ||
38 | #define DRIVER_DESC "Microsoft SideWinder joystick family driver" | 38 | #define DRIVER_DESC "Microsoft SideWinder joystick family driver" |
39 | 39 | ||
40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 40 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
41 | MODULE_DESCRIPTION(DRIVER_DESC); | 41 | MODULE_DESCRIPTION(DRIVER_DESC); |
42 | MODULE_LICENSE("GPL"); | 42 | MODULE_LICENSE("GPL"); |
43 | 43 | ||
44 | /* | 44 | /* |
45 | * These are really magic values. Changing them can make a problem go away, | 45 | * These are really magic values. Changing them can make a problem go away, |
46 | * as well as break everything. | 46 | * as well as break everything. |
47 | */ | 47 | */ |
48 | 48 | ||
49 | #undef SW_DEBUG | 49 | #undef SW_DEBUG |
50 | #undef SW_DEBUG_DATA | 50 | #undef SW_DEBUG_DATA |
51 | 51 | ||
52 | #define SW_START 600 /* The time we wait for the first bit [600 us] */ | 52 | #define SW_START 600 /* The time we wait for the first bit [600 us] */ |
53 | #define SW_STROBE 60 /* Max time per bit [60 us] */ | 53 | #define SW_STROBE 60 /* Max time per bit [60 us] */ |
54 | #define SW_TIMEOUT 6 /* Wait for everything to settle [6 ms] */ | 54 | #define SW_TIMEOUT 6 /* Wait for everything to settle [6 ms] */ |
55 | #define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */ | 55 | #define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */ |
56 | #define SW_END 8 /* Number of bits before end of packet to kick */ | 56 | #define SW_END 8 /* Number of bits before end of packet to kick */ |
57 | #define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */ | 57 | #define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */ |
58 | #define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */ | 58 | #define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */ |
59 | #define SW_OK 64 /* Number of packet read successes to switch optimization back on */ | 59 | #define SW_OK 64 /* Number of packet read successes to switch optimization back on */ |
60 | #define SW_LENGTH 512 /* Max number of bits in a packet */ | 60 | #define SW_LENGTH 512 /* Max number of bits in a packet */ |
61 | 61 | ||
62 | #ifdef SW_DEBUG | 62 | #ifdef SW_DEBUG |
63 | #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg) | 63 | #define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg) |
64 | #else | 64 | #else |
65 | #define dbg(format, arg...) do {} while (0) | 65 | #define dbg(format, arg...) do {} while (0) |
66 | #endif | 66 | #endif |
67 | 67 | ||
68 | /* | 68 | /* |
69 | * SideWinder joystick types ... | 69 | * SideWinder joystick types ... |
70 | */ | 70 | */ |
71 | 71 | ||
72 | #define SW_ID_3DP 0 | 72 | #define SW_ID_3DP 0 |
73 | #define SW_ID_GP 1 | 73 | #define SW_ID_GP 1 |
74 | #define SW_ID_PP 2 | 74 | #define SW_ID_PP 2 |
75 | #define SW_ID_FFP 3 | 75 | #define SW_ID_FFP 3 |
76 | #define SW_ID_FSP 4 | 76 | #define SW_ID_FSP 4 |
77 | #define SW_ID_FFW 5 | 77 | #define SW_ID_FFW 5 |
78 | 78 | ||
79 | /* | 79 | /* |
80 | * Names, buttons, axes ... | 80 | * Names, buttons, axes ... |
81 | */ | 81 | */ |
82 | 82 | ||
83 | static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro", | 83 | static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro", |
84 | "Force Feedback Wheel" }; | 84 | "Force Feedback Wheel" }; |
85 | 85 | ||
86 | static char sw_abs[][7] = { | 86 | static char sw_abs[][7] = { |
87 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, | 87 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, |
88 | { ABS_X, ABS_Y }, | 88 | { ABS_X, ABS_Y }, |
89 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, | 89 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, |
90 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, | 90 | { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, |
91 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, | 91 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y }, |
92 | { ABS_RX, ABS_RUDDER, ABS_THROTTLE }}; | 92 | { ABS_RX, ABS_RUDDER, ABS_THROTTLE }}; |
93 | 93 | ||
94 | static char sw_bit[][7] = { | 94 | static char sw_bit[][7] = { |
95 | { 10, 10, 9, 10, 1, 1 }, | 95 | { 10, 10, 9, 10, 1, 1 }, |
96 | { 1, 1 }, | 96 | { 1, 1 }, |
97 | { 10, 10, 6, 7, 1, 1 }, | 97 | { 10, 10, 6, 7, 1, 1 }, |
98 | { 10, 10, 6, 7, 1, 1 }, | 98 | { 10, 10, 6, 7, 1, 1 }, |
99 | { 10, 10, 6, 1, 1 }, | 99 | { 10, 10, 6, 1, 1 }, |
100 | { 10, 7, 7, 1, 1 }}; | 100 | { 10, 7, 7, 1, 1 }}; |
101 | 101 | ||
102 | static short sw_btn[][12] = { | 102 | static short sw_btn[][12] = { |
103 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE }, | 103 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE }, |
104 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE }, | 104 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE }, |
105 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT }, | 105 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT }, |
106 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT }, | 106 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT }, |
107 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }, | 107 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT }, |
108 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }}; | 108 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }}; |
109 | 109 | ||
110 | static struct { | 110 | static struct { |
111 | int x; | 111 | int x; |
112 | int y; | 112 | int y; |
113 | } sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | 113 | } sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; |
114 | 114 | ||
115 | struct sw { | 115 | struct sw { |
116 | struct gameport *gameport; | 116 | struct gameport *gameport; |
117 | struct input_dev *dev[4]; | 117 | struct input_dev *dev[4]; |
118 | char name[64]; | 118 | char name[64]; |
119 | char phys[4][32]; | 119 | char phys[4][32]; |
120 | int length; | 120 | int length; |
121 | int type; | 121 | int type; |
122 | int bits; | 122 | int bits; |
123 | int number; | 123 | int number; |
124 | int fail; | 124 | int fail; |
125 | int ok; | 125 | int ok; |
126 | int reads; | 126 | int reads; |
127 | int bads; | 127 | int bads; |
128 | }; | 128 | }; |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * sw_read_packet() is a function which reads either a data packet, or an | 131 | * sw_read_packet() is a function which reads either a data packet, or an |
132 | * identification packet from a SideWinder joystick. The protocol is very, | 132 | * identification packet from a SideWinder joystick. The protocol is very, |
133 | * very, very braindamaged. Microsoft patented it in US patent #5628686. | 133 | * very, very braindamaged. Microsoft patented it in US patent #5628686. |
134 | */ | 134 | */ |
135 | 135 | ||
136 | static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id) | 136 | static int sw_read_packet(struct gameport *gameport, unsigned char *buf, int length, int id) |
137 | { | 137 | { |
138 | unsigned long flags; | 138 | unsigned long flags; |
139 | int timeout, bitout, sched, i, kick, start, strobe; | 139 | int timeout, bitout, sched, i, kick, start, strobe; |
140 | unsigned char pending, u, v; | 140 | unsigned char pending, u, v; |
141 | 141 | ||
142 | i = -id; /* Don't care about data, only want ID */ | 142 | i = -id; /* Don't care about data, only want ID */ |
143 | timeout = id ? gameport_time(gameport, SW_TIMEOUT * 1000) : 0; /* Set up global timeout for ID packet */ | 143 | timeout = id ? gameport_time(gameport, SW_TIMEOUT * 1000) : 0; /* Set up global timeout for ID packet */ |
144 | kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */ | 144 | kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */ |
145 | start = gameport_time(gameport, SW_START); | 145 | start = gameport_time(gameport, SW_START); |
146 | strobe = gameport_time(gameport, SW_STROBE); | 146 | strobe = gameport_time(gameport, SW_STROBE); |
147 | bitout = start; | 147 | bitout = start; |
148 | pending = 0; | 148 | pending = 0; |
149 | sched = 0; | 149 | sched = 0; |
150 | 150 | ||
151 | local_irq_save(flags); /* Quiet, please */ | 151 | local_irq_save(flags); /* Quiet, please */ |
152 | 152 | ||
153 | gameport_trigger(gameport); /* Trigger */ | 153 | gameport_trigger(gameport); /* Trigger */ |
154 | v = gameport_read(gameport); | 154 | v = gameport_read(gameport); |
155 | 155 | ||
156 | do { | 156 | do { |
157 | bitout--; | 157 | bitout--; |
158 | u = v; | 158 | u = v; |
159 | v = gameport_read(gameport); | 159 | v = gameport_read(gameport); |
160 | } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */ | 160 | } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */ |
161 | 161 | ||
162 | if (bitout > 0) | 162 | if (bitout > 0) |
163 | bitout = strobe; /* Extend time if not timed out */ | 163 | bitout = strobe; /* Extend time if not timed out */ |
164 | 164 | ||
165 | while ((timeout > 0 || bitout > 0) && (i < length)) { | 165 | while ((timeout > 0 || bitout > 0) && (i < length)) { |
166 | 166 | ||
167 | timeout--; | 167 | timeout--; |
168 | bitout--; /* Decrement timers */ | 168 | bitout--; /* Decrement timers */ |
169 | sched--; | 169 | sched--; |
170 | 170 | ||
171 | u = v; | 171 | u = v; |
172 | v = gameport_read(gameport); | 172 | v = gameport_read(gameport); |
173 | 173 | ||
174 | if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */ | 174 | if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */ |
175 | if (i >= 0) /* Want this data */ | 175 | if (i >= 0) /* Want this data */ |
176 | buf[i] = v >> 5; /* Store it */ | 176 | buf[i] = v >> 5; /* Store it */ |
177 | i++; /* Advance index */ | 177 | i++; /* Advance index */ |
178 | bitout = strobe; /* Extend timeout for next bit */ | 178 | bitout = strobe; /* Extend timeout for next bit */ |
179 | } | 179 | } |
180 | 180 | ||
181 | if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */ | 181 | if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */ |
182 | sched = kick; /* Schedule second trigger */ | 182 | sched = kick; /* Schedule second trigger */ |
183 | kick = 0; /* Don't schedule next time on falling edge */ | 183 | kick = 0; /* Don't schedule next time on falling edge */ |
184 | pending = 1; /* Mark schedule */ | 184 | pending = 1; /* Mark schedule */ |
185 | } | 185 | } |
186 | 186 | ||
187 | if (pending && sched < 0 && (i > -SW_END)) { /* Second trigger time */ | 187 | if (pending && sched < 0 && (i > -SW_END)) { /* Second trigger time */ |
188 | gameport_trigger(gameport); /* Trigger */ | 188 | gameport_trigger(gameport); /* Trigger */ |
189 | bitout = start; /* Long bit timeout */ | 189 | bitout = start; /* Long bit timeout */ |
190 | pending = 0; /* Unmark schedule */ | 190 | pending = 0; /* Unmark schedule */ |
191 | timeout = 0; /* Switch from global to bit timeouts */ | 191 | timeout = 0; /* Switch from global to bit timeouts */ |
192 | } | 192 | } |
193 | } | 193 | } |
194 | 194 | ||
195 | local_irq_restore(flags); /* Done - relax */ | 195 | local_irq_restore(flags); /* Done - relax */ |
196 | 196 | ||
197 | #ifdef SW_DEBUG_DATA | 197 | #ifdef SW_DEBUG_DATA |
198 | { | 198 | { |
199 | int j; | 199 | int j; |
200 | printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i); | 200 | printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i); |
201 | for (j = 0; j < i; j++) printk("%d", buf[j]); | 201 | for (j = 0; j < i; j++) printk("%d", buf[j]); |
202 | printk("]\n"); | 202 | printk("]\n"); |
203 | } | 203 | } |
204 | #endif | 204 | #endif |
205 | 205 | ||
206 | return i; | 206 | return i; |
207 | } | 207 | } |
208 | 208 | ||
209 | /* | 209 | /* |
210 | * sw_get_bits() and GB() compose bits from the triplet buffer into a __u64. | 210 | * sw_get_bits() and GB() compose bits from the triplet buffer into a __u64. |
211 | * Parameter 'pos' is bit number inside packet where to start at, 'num' is number | 211 | * Parameter 'pos' is bit number inside packet where to start at, 'num' is number |
212 | * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits | 212 | * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits |
213 | * is number of bits per triplet. | 213 | * is number of bits per triplet. |
214 | */ | 214 | */ |
215 | 215 | ||
216 | #define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits) | 216 | #define GB(pos,num) sw_get_bits(buf, pos, num, sw->bits) |
217 | 217 | ||
218 | static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits) | 218 | static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits) |
219 | { | 219 | { |
220 | __u64 data = 0; | 220 | __u64 data = 0; |
221 | int tri = pos % bits; /* Start position */ | 221 | int tri = pos % bits; /* Start position */ |
222 | int i = pos / bits; | 222 | int i = pos / bits; |
223 | int bit = 0; | 223 | int bit = 0; |
224 | 224 | ||
225 | while (num--) { | 225 | while (num--) { |
226 | data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */ | 226 | data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */ |
227 | if (tri == bits) { | 227 | if (tri == bits) { |
228 | i++; /* Next triplet */ | 228 | i++; /* Next triplet */ |
229 | tri = 0; | 229 | tri = 0; |
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
233 | return data; | 233 | return data; |
234 | } | 234 | } |
235 | 235 | ||
236 | /* | 236 | /* |
237 | * sw_init_digital() initializes a SideWinder 3D Pro joystick | 237 | * sw_init_digital() initializes a SideWinder 3D Pro joystick |
238 | * into digital mode. | 238 | * into digital mode. |
239 | */ | 239 | */ |
240 | 240 | ||
241 | static void sw_init_digital(struct gameport *gameport) | 241 | static void sw_init_digital(struct gameport *gameport) |
242 | { | 242 | { |
243 | int seq[] = { 140, 140+725, 140+300, 0 }; | 243 | int seq[] = { 140, 140+725, 140+300, 0 }; |
244 | unsigned long flags; | 244 | unsigned long flags; |
245 | int i, t; | 245 | int i, t; |
246 | 246 | ||
247 | local_irq_save(flags); | 247 | local_irq_save(flags); |
248 | 248 | ||
249 | i = 0; | 249 | i = 0; |
250 | do { | 250 | do { |
251 | gameport_trigger(gameport); /* Trigger */ | 251 | gameport_trigger(gameport); /* Trigger */ |
252 | t = gameport_time(gameport, SW_TIMEOUT * 1000); | 252 | t = gameport_time(gameport, SW_TIMEOUT * 1000); |
253 | while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */ | 253 | while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */ |
254 | udelay(seq[i]); /* Delay magic time */ | 254 | udelay(seq[i]); /* Delay magic time */ |
255 | } while (seq[++i]); | 255 | } while (seq[++i]); |
256 | 256 | ||
257 | gameport_trigger(gameport); /* Last trigger */ | 257 | gameport_trigger(gameport); /* Last trigger */ |
258 | 258 | ||
259 | local_irq_restore(flags); | 259 | local_irq_restore(flags); |
260 | } | 260 | } |
261 | 261 | ||
262 | /* | 262 | /* |
263 | * sw_parity() computes parity of __u64 | 263 | * sw_parity() computes parity of __u64 |
264 | */ | 264 | */ |
265 | 265 | ||
266 | static int sw_parity(__u64 t) | 266 | static int sw_parity(__u64 t) |
267 | { | 267 | { |
268 | int x = t ^ (t >> 32); | 268 | int x = t ^ (t >> 32); |
269 | 269 | ||
270 | x ^= x >> 16; | 270 | x ^= x >> 16; |
271 | x ^= x >> 8; | 271 | x ^= x >> 8; |
272 | x ^= x >> 4; | 272 | x ^= x >> 4; |
273 | x ^= x >> 2; | 273 | x ^= x >> 2; |
274 | x ^= x >> 1; | 274 | x ^= x >> 1; |
275 | return x & 1; | 275 | return x & 1; |
276 | } | 276 | } |
277 | 277 | ||
278 | /* | 278 | /* |
279 | * sw_ccheck() checks synchronization bits and computes checksum of nibbles. | 279 | * sw_ccheck() checks synchronization bits and computes checksum of nibbles. |
280 | */ | 280 | */ |
281 | 281 | ||
282 | static int sw_check(__u64 t) | 282 | static int sw_check(__u64 t) |
283 | { | 283 | { |
284 | unsigned char sum = 0; | 284 | unsigned char sum = 0; |
285 | 285 | ||
286 | if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */ | 286 | if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */ |
287 | return -1; | 287 | return -1; |
288 | 288 | ||
289 | while (t) { /* Sum */ | 289 | while (t) { /* Sum */ |
290 | sum += t & 0xf; | 290 | sum += t & 0xf; |
291 | t >>= 4; | 291 | t >>= 4; |
292 | } | 292 | } |
293 | 293 | ||
294 | return sum & 0xf; | 294 | return sum & 0xf; |
295 | } | 295 | } |
296 | 296 | ||
297 | /* | 297 | /* |
298 | * sw_parse() analyzes SideWinder joystick data, and writes the results into | 298 | * sw_parse() analyzes SideWinder joystick data, and writes the results into |
299 | * the axes and buttons arrays. | 299 | * the axes and buttons arrays. |
300 | */ | 300 | */ |
301 | 301 | ||
302 | static int sw_parse(unsigned char *buf, struct sw *sw) | 302 | static int sw_parse(unsigned char *buf, struct sw *sw) |
303 | { | 303 | { |
304 | int hat, i, j; | 304 | int hat, i, j; |
305 | struct input_dev *dev; | 305 | struct input_dev *dev; |
306 | 306 | ||
307 | switch (sw->type) { | 307 | switch (sw->type) { |
308 | 308 | ||
309 | case SW_ID_3DP: | 309 | case SW_ID_3DP: |
310 | 310 | ||
311 | if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) | 311 | if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) |
312 | return -1; | 312 | return -1; |
313 | 313 | ||
314 | dev = sw->dev[0]; | 314 | dev = sw->dev[0]; |
315 | 315 | ||
316 | input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7)); | 316 | input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7)); |
317 | input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7)); | 317 | input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7)); |
318 | input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7)); | 318 | input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7)); |
319 | input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7)); | 319 | input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7)); |
320 | 320 | ||
321 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); | 321 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); |
322 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); | 322 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); |
323 | 323 | ||
324 | for (j = 0; j < 7; j++) | 324 | for (j = 0; j < 7; j++) |
325 | input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1)); | 325 | input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1)); |
326 | 326 | ||
327 | input_report_key(dev, BTN_BASE4, !GB(38,1)); | 327 | input_report_key(dev, BTN_BASE4, !GB(38,1)); |
328 | input_report_key(dev, BTN_BASE5, !GB(37,1)); | 328 | input_report_key(dev, BTN_BASE5, !GB(37,1)); |
329 | 329 | ||
330 | input_sync(dev); | 330 | input_sync(dev); |
331 | 331 | ||
332 | return 0; | 332 | return 0; |
333 | 333 | ||
334 | case SW_ID_GP: | 334 | case SW_ID_GP: |
335 | 335 | ||
336 | for (i = 0; i < sw->number; i ++) { | 336 | for (i = 0; i < sw->number; i ++) { |
337 | 337 | ||
338 | if (sw_parity(GB(i*15,15))) | 338 | if (sw_parity(GB(i*15,15))) |
339 | return -1; | 339 | return -1; |
340 | 340 | ||
341 | input_report_abs(sw->dev[i], ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); | 341 | input_report_abs(sw->dev[i], ABS_X, GB(i*15+3,1) - GB(i*15+2,1)); |
342 | input_report_abs(sw->dev[i], ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); | 342 | input_report_abs(sw->dev[i], ABS_Y, GB(i*15+0,1) - GB(i*15+1,1)); |
343 | 343 | ||
344 | for (j = 0; j < 10; j++) | 344 | for (j = 0; j < 10; j++) |
345 | input_report_key(sw->dev[i], sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); | 345 | input_report_key(sw->dev[i], sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1)); |
346 | 346 | ||
347 | input_sync(sw->dev[i]); | 347 | input_sync(sw->dev[i]); |
348 | } | 348 | } |
349 | 349 | ||
350 | return 0; | 350 | return 0; |
351 | 351 | ||
352 | case SW_ID_PP: | 352 | case SW_ID_PP: |
353 | case SW_ID_FFP: | 353 | case SW_ID_FFP: |
354 | 354 | ||
355 | if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) | 355 | if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) |
356 | return -1; | 356 | return -1; |
357 | 357 | ||
358 | dev = sw->dev[0]; | 358 | dev = sw->dev[0]; |
359 | input_report_abs(dev, ABS_X, GB( 9,10)); | 359 | input_report_abs(dev, ABS_X, GB( 9,10)); |
360 | input_report_abs(dev, ABS_Y, GB(19,10)); | 360 | input_report_abs(dev, ABS_Y, GB(19,10)); |
361 | input_report_abs(dev, ABS_RZ, GB(36, 6)); | 361 | input_report_abs(dev, ABS_RZ, GB(36, 6)); |
362 | input_report_abs(dev, ABS_THROTTLE, GB(29, 7)); | 362 | input_report_abs(dev, ABS_THROTTLE, GB(29, 7)); |
363 | 363 | ||
364 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); | 364 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); |
365 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); | 365 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); |
366 | 366 | ||
367 | for (j = 0; j < 9; j++) | 367 | for (j = 0; j < 9; j++) |
368 | input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1)); | 368 | input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1)); |
369 | 369 | ||
370 | input_sync(dev); | 370 | input_sync(dev); |
371 | 371 | ||
372 | return 0; | 372 | return 0; |
373 | 373 | ||
374 | case SW_ID_FSP: | 374 | case SW_ID_FSP: |
375 | 375 | ||
376 | if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) | 376 | if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) |
377 | return -1; | 377 | return -1; |
378 | 378 | ||
379 | dev = sw->dev[0]; | 379 | dev = sw->dev[0]; |
380 | input_report_abs(dev, ABS_X, GB( 0,10)); | 380 | input_report_abs(dev, ABS_X, GB( 0,10)); |
381 | input_report_abs(dev, ABS_Y, GB(16,10)); | 381 | input_report_abs(dev, ABS_Y, GB(16,10)); |
382 | input_report_abs(dev, ABS_THROTTLE, GB(32, 6)); | 382 | input_report_abs(dev, ABS_THROTTLE, GB(32, 6)); |
383 | 383 | ||
384 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); | 384 | input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x); |
385 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); | 385 | input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y); |
386 | 386 | ||
387 | for (j = 0; j < 6; j++) | 387 | for (j = 0; j < 6; j++) |
388 | input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1)); | 388 | input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1)); |
389 | 389 | ||
390 | input_report_key(dev, BTN_TR, !GB(26,1)); | 390 | input_report_key(dev, BTN_TR, !GB(26,1)); |
391 | input_report_key(dev, BTN_START, !GB(27,1)); | 391 | input_report_key(dev, BTN_START, !GB(27,1)); |
392 | input_report_key(dev, BTN_MODE, !GB(38,1)); | 392 | input_report_key(dev, BTN_MODE, !GB(38,1)); |
393 | input_report_key(dev, BTN_SELECT, !GB(39,1)); | 393 | input_report_key(dev, BTN_SELECT, !GB(39,1)); |
394 | 394 | ||
395 | input_sync(dev); | 395 | input_sync(dev); |
396 | 396 | ||
397 | return 0; | 397 | return 0; |
398 | 398 | ||
399 | case SW_ID_FFW: | 399 | case SW_ID_FFW: |
400 | 400 | ||
401 | if (!sw_parity(GB(0,33))) | 401 | if (!sw_parity(GB(0,33))) |
402 | return -1; | 402 | return -1; |
403 | 403 | ||
404 | dev = sw->dev[0]; | 404 | dev = sw->dev[0]; |
405 | input_report_abs(dev, ABS_RX, GB( 0,10)); | 405 | input_report_abs(dev, ABS_RX, GB( 0,10)); |
406 | input_report_abs(dev, ABS_RUDDER, GB(10, 6)); | 406 | input_report_abs(dev, ABS_RUDDER, GB(10, 6)); |
407 | input_report_abs(dev, ABS_THROTTLE, GB(16, 6)); | 407 | input_report_abs(dev, ABS_THROTTLE, GB(16, 6)); |
408 | 408 | ||
409 | for (j = 0; j < 8; j++) | 409 | for (j = 0; j < 8; j++) |
410 | input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1)); | 410 | input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1)); |
411 | 411 | ||
412 | input_sync(dev); | 412 | input_sync(dev); |
413 | 413 | ||
414 | return 0; | 414 | return 0; |
415 | } | 415 | } |
416 | 416 | ||
417 | return -1; | 417 | return -1; |
418 | } | 418 | } |
419 | 419 | ||
420 | /* | 420 | /* |
421 | * sw_read() reads SideWinder joystick data, and reinitializes | 421 | * sw_read() reads SideWinder joystick data, and reinitializes |
422 | * the joystick in case of persistent problems. This is the function that is | 422 | * the joystick in case of persistent problems. This is the function that is |
423 | * called from the generic code to poll the joystick. | 423 | * called from the generic code to poll the joystick. |
424 | */ | 424 | */ |
425 | 425 | ||
426 | static int sw_read(struct sw *sw) | 426 | static int sw_read(struct sw *sw) |
427 | { | 427 | { |
428 | unsigned char buf[SW_LENGTH]; | 428 | unsigned char buf[SW_LENGTH]; |
429 | int i; | 429 | int i; |
430 | 430 | ||
431 | i = sw_read_packet(sw->gameport, buf, sw->length, 0); | 431 | i = sw_read_packet(sw->gameport, buf, sw->length, 0); |
432 | 432 | ||
433 | if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */ | 433 | if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */ |
434 | 434 | ||
435 | if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */ | 435 | if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */ |
436 | printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s" | 436 | printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on %s" |
437 | " - going to reinitialize.\n", sw->gameport->phys); | 437 | " - going to reinitialize.\n", sw->gameport->phys); |
438 | sw->fail = SW_FAIL; /* Reinitialize */ | 438 | sw->fail = SW_FAIL; /* Reinitialize */ |
439 | i = 128; /* Bogus value */ | 439 | i = 128; /* Bogus value */ |
440 | } | 440 | } |
441 | 441 | ||
442 | if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */ | 442 | if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */ |
443 | i = 66; /* Everything is fine */ | 443 | i = 66; /* Everything is fine */ |
444 | 444 | ||
445 | if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */ | 445 | if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */ |
446 | i = 66; /* Everything is fine */ | 446 | i = 66; /* Everything is fine */ |
447 | 447 | ||
448 | if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */ | 448 | if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */ |
449 | memmove(buf, buf + i - 22, 22); /* Move data */ | 449 | memmove(buf, buf + i - 22, 22); /* Move data */ |
450 | i = 66; /* Carry on */ | 450 | i = 66; /* Carry on */ |
451 | } | 451 | } |
452 | } | 452 | } |
453 | 453 | ||
454 | if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */ | 454 | if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */ |
455 | 455 | ||
456 | sw->fail = 0; | 456 | sw->fail = 0; |
457 | sw->ok++; | 457 | sw->ok++; |
458 | 458 | ||
459 | if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */ | 459 | if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */ |
460 | && sw->ok > SW_OK) { | 460 | && sw->ok > SW_OK) { |
461 | 461 | ||
462 | printk(KERN_INFO "sidewinder.c: No more trouble on %s" | 462 | printk(KERN_INFO "sidewinder.c: No more trouble on %s" |
463 | " - enabling optimization again.\n", sw->gameport->phys); | 463 | " - enabling optimization again.\n", sw->gameport->phys); |
464 | sw->length = 22; | 464 | sw->length = 22; |
465 | } | 465 | } |
466 | 466 | ||
467 | return 0; | 467 | return 0; |
468 | } | 468 | } |
469 | 469 | ||
470 | sw->ok = 0; | 470 | sw->ok = 0; |
471 | sw->fail++; | 471 | sw->fail++; |
472 | 472 | ||
473 | if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */ | 473 | if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */ |
474 | 474 | ||
475 | printk(KERN_INFO "sidewinder.c: Many bit errors on %s" | 475 | printk(KERN_INFO "sidewinder.c: Many bit errors on %s" |
476 | " - disabling optimization.\n", sw->gameport->phys); | 476 | " - disabling optimization.\n", sw->gameport->phys); |
477 | sw->length = 66; | 477 | sw->length = 66; |
478 | } | 478 | } |
479 | 479 | ||
480 | if (sw->fail < SW_FAIL) | 480 | if (sw->fail < SW_FAIL) |
481 | return -1; /* Not enough, don't reinitialize yet */ | 481 | return -1; /* Not enough, don't reinitialize yet */ |
482 | 482 | ||
483 | printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s" | 483 | printk(KERN_WARNING "sidewinder.c: Too many bit errors on %s" |
484 | " - reinitializing joystick.\n", sw->gameport->phys); | 484 | " - reinitializing joystick.\n", sw->gameport->phys); |
485 | 485 | ||
486 | if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */ | 486 | if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */ |
487 | mdelay(3 * SW_TIMEOUT); | 487 | mdelay(3 * SW_TIMEOUT); |
488 | sw_init_digital(sw->gameport); | 488 | sw_init_digital(sw->gameport); |
489 | } | 489 | } |
490 | 490 | ||
491 | mdelay(SW_TIMEOUT); | 491 | mdelay(SW_TIMEOUT); |
492 | i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */ | 492 | i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */ |
493 | mdelay(SW_TIMEOUT); | 493 | mdelay(SW_TIMEOUT); |
494 | sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */ | 494 | sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */ |
495 | 495 | ||
496 | sw->fail = SW_FAIL; | 496 | sw->fail = SW_FAIL; |
497 | 497 | ||
498 | return -1; | 498 | return -1; |
499 | } | 499 | } |
500 | 500 | ||
501 | static void sw_poll(struct gameport *gameport) | 501 | static void sw_poll(struct gameport *gameport) |
502 | { | 502 | { |
503 | struct sw *sw = gameport_get_drvdata(gameport); | 503 | struct sw *sw = gameport_get_drvdata(gameport); |
504 | 504 | ||
505 | sw->reads++; | 505 | sw->reads++; |
506 | if (sw_read(sw)) | 506 | if (sw_read(sw)) |
507 | sw->bads++; | 507 | sw->bads++; |
508 | } | 508 | } |
509 | 509 | ||
510 | static int sw_open(struct input_dev *dev) | 510 | static int sw_open(struct input_dev *dev) |
511 | { | 511 | { |
512 | struct sw *sw = input_get_drvdata(dev); | 512 | struct sw *sw = input_get_drvdata(dev); |
513 | 513 | ||
514 | gameport_start_polling(sw->gameport); | 514 | gameport_start_polling(sw->gameport); |
515 | return 0; | 515 | return 0; |
516 | } | 516 | } |
517 | 517 | ||
518 | static void sw_close(struct input_dev *dev) | 518 | static void sw_close(struct input_dev *dev) |
519 | { | 519 | { |
520 | struct sw *sw = input_get_drvdata(dev); | 520 | struct sw *sw = input_get_drvdata(dev); |
521 | 521 | ||
522 | gameport_stop_polling(sw->gameport); | 522 | gameport_stop_polling(sw->gameport); |
523 | } | 523 | } |
524 | 524 | ||
525 | /* | 525 | /* |
526 | * sw_print_packet() prints the contents of a SideWinder packet. | 526 | * sw_print_packet() prints the contents of a SideWinder packet. |
527 | */ | 527 | */ |
528 | 528 | ||
529 | static void sw_print_packet(char *name, int length, unsigned char *buf, char bits) | 529 | static void sw_print_packet(char *name, int length, unsigned char *buf, char bits) |
530 | { | 530 | { |
531 | int i; | 531 | int i; |
532 | 532 | ||
533 | printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length); | 533 | printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length); |
534 | for (i = (((length + 3) >> 2) - 1); i >= 0; i--) | 534 | for (i = (((length + 3) >> 2) - 1); i >= 0; i--) |
535 | printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits)); | 535 | printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits)); |
536 | printk("]\n"); | 536 | printk("]\n"); |
537 | } | 537 | } |
538 | 538 | ||
539 | /* | 539 | /* |
540 | * sw_3dp_id() translates the 3DP id into a human legible string. | 540 | * sw_3dp_id() translates the 3DP id into a human legible string. |
541 | * Unfortunately I don't know how to do this for the other SW types. | 541 | * Unfortunately I don't know how to do this for the other SW types. |
542 | */ | 542 | */ |
543 | 543 | ||
544 | static void sw_3dp_id(unsigned char *buf, char *comment, size_t size) | 544 | static void sw_3dp_id(unsigned char *buf, char *comment, size_t size) |
545 | { | 545 | { |
546 | int i; | 546 | int i; |
547 | char pnp[8], rev[9]; | 547 | char pnp[8], rev[9]; |
548 | 548 | ||
549 | for (i = 0; i < 7; i++) /* ASCII PnP ID */ | 549 | for (i = 0; i < 7; i++) /* ASCII PnP ID */ |
550 | pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1); | 550 | pnp[i] = sw_get_bits(buf, 24+8*i, 8, 1); |
551 | 551 | ||
552 | for (i = 0; i < 8; i++) /* ASCII firmware revision */ | 552 | for (i = 0; i < 8; i++) /* ASCII firmware revision */ |
553 | rev[i] = sw_get_bits(buf, 88+8*i, 8, 1); | 553 | rev[i] = sw_get_bits(buf, 88+8*i, 8, 1); |
554 | 554 | ||
555 | pnp[7] = rev[8] = 0; | 555 | pnp[7] = rev[8] = 0; |
556 | 556 | ||
557 | snprintf(comment, size, " [PnP %d.%02d id %s rev %s]", | 557 | snprintf(comment, size, " [PnP %d.%02d id %s rev %s]", |
558 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */ | 558 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */ |
559 | sw_get_bits(buf, 16, 6, 1)) / 100, | 559 | sw_get_bits(buf, 16, 6, 1)) / 100, |
560 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | | 560 | (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | |
561 | sw_get_bits(buf, 16, 6, 1)) % 100, | 561 | sw_get_bits(buf, 16, 6, 1)) % 100, |
562 | pnp, rev); | 562 | pnp, rev); |
563 | } | 563 | } |
564 | 564 | ||
565 | /* | 565 | /* |
566 | * sw_guess_mode() checks the upper two button bits for toggling - | 566 | * sw_guess_mode() checks the upper two button bits for toggling - |
567 | * indication of that the joystick is in 3-bit mode. This is documented | 567 | * indication of that the joystick is in 3-bit mode. This is documented |
568 | * behavior for 3DP ID packet, and for example the FSP does this in | 568 | * behavior for 3DP ID packet, and for example the FSP does this in |
569 | * normal packets instead. Fun ... | 569 | * normal packets instead. Fun ... |
570 | */ | 570 | */ |
571 | 571 | ||
572 | static int sw_guess_mode(unsigned char *buf, int len) | 572 | static int sw_guess_mode(unsigned char *buf, int len) |
573 | { | 573 | { |
574 | int i; | 574 | int i; |
575 | unsigned char xor = 0; | 575 | unsigned char xor = 0; |
576 | 576 | ||
577 | for (i = 1; i < len; i++) | 577 | for (i = 1; i < len; i++) |
578 | xor |= (buf[i - 1] ^ buf[i]) & 6; | 578 | xor |= (buf[i - 1] ^ buf[i]) & 6; |
579 | 579 | ||
580 | return !!xor * 2 + 1; | 580 | return !!xor * 2 + 1; |
581 | } | 581 | } |
582 | 582 | ||
583 | /* | 583 | /* |
584 | * sw_connect() probes for SideWinder type joysticks. | 584 | * sw_connect() probes for SideWinder type joysticks. |
585 | */ | 585 | */ |
586 | 586 | ||
587 | static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) | 587 | static int sw_connect(struct gameport *gameport, struct gameport_driver *drv) |
588 | { | 588 | { |
589 | struct sw *sw; | 589 | struct sw *sw; |
590 | struct input_dev *input_dev; | 590 | struct input_dev *input_dev; |
591 | int i, j, k, l; | 591 | int i, j, k, l; |
592 | int err = 0; | 592 | int err = 0; |
593 | unsigned char *buf = NULL; /* [SW_LENGTH] */ | 593 | unsigned char *buf = NULL; /* [SW_LENGTH] */ |
594 | unsigned char *idbuf = NULL; /* [SW_LENGTH] */ | 594 | unsigned char *idbuf = NULL; /* [SW_LENGTH] */ |
595 | unsigned char m = 1; | 595 | unsigned char m = 1; |
596 | char comment[40]; | 596 | char comment[40]; |
597 | 597 | ||
598 | comment[0] = 0; | 598 | comment[0] = 0; |
599 | 599 | ||
600 | sw = kzalloc(sizeof(struct sw), GFP_KERNEL); | 600 | sw = kzalloc(sizeof(struct sw), GFP_KERNEL); |
601 | buf = kmalloc(SW_LENGTH, GFP_KERNEL); | 601 | buf = kmalloc(SW_LENGTH, GFP_KERNEL); |
602 | idbuf = kmalloc(SW_LENGTH, GFP_KERNEL); | 602 | idbuf = kmalloc(SW_LENGTH, GFP_KERNEL); |
603 | if (!sw || !buf || !idbuf) { | 603 | if (!sw || !buf || !idbuf) { |
604 | err = -ENOMEM; | 604 | err = -ENOMEM; |
605 | goto fail1; | 605 | goto fail1; |
606 | } | 606 | } |
607 | 607 | ||
608 | sw->gameport = gameport; | 608 | sw->gameport = gameport; |
609 | 609 | ||
610 | gameport_set_drvdata(gameport, sw); | 610 | gameport_set_drvdata(gameport, sw); |
611 | 611 | ||
612 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 612 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
613 | if (err) | 613 | if (err) |
614 | goto fail1; | 614 | goto fail1; |
615 | 615 | ||
616 | dbg("Init 0: Opened %s, io %#x, speed %d", | 616 | dbg("Init 0: Opened %s, io %#x, speed %d", |
617 | gameport->phys, gameport->io, gameport->speed); | 617 | gameport->phys, gameport->io, gameport->speed); |
618 | 618 | ||
619 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */ | 619 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */ |
620 | msleep(SW_TIMEOUT); | 620 | msleep(SW_TIMEOUT); |
621 | dbg("Init 1: Mode %d. Length %d.", m , i); | 621 | dbg("Init 1: Mode %d. Length %d.", m , i); |
622 | 622 | ||
623 | if (!i) { /* No data. 3d Pro analog mode? */ | 623 | if (!i) { /* No data. 3d Pro analog mode? */ |
624 | sw_init_digital(gameport); /* Switch to digital */ | 624 | sw_init_digital(gameport); /* Switch to digital */ |
625 | msleep(SW_TIMEOUT); | 625 | msleep(SW_TIMEOUT); |
626 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ | 626 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ |
627 | msleep(SW_TIMEOUT); | 627 | msleep(SW_TIMEOUT); |
628 | dbg("Init 1b: Length %d.", i); | 628 | dbg("Init 1b: Length %d.", i); |
629 | if (!i) { /* No data -> FAIL */ | 629 | if (!i) { /* No data -> FAIL */ |
630 | err = -ENODEV; | 630 | err = -ENODEV; |
631 | goto fail2; | 631 | goto fail2; |
632 | } | 632 | } |
633 | } | 633 | } |
634 | 634 | ||
635 | j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */ | 635 | j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */ |
636 | m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */ | 636 | m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */ |
637 | dbg("Init 2: Mode %d. ID Length %d.", m, j); | 637 | dbg("Init 2: Mode %d. ID Length %d.", m, j); |
638 | 638 | ||
639 | if (j <= 0) { /* Read ID failed. Happens in 1-bit mode on PP */ | 639 | if (j <= 0) { /* Read ID failed. Happens in 1-bit mode on PP */ |
640 | msleep(SW_TIMEOUT); | 640 | msleep(SW_TIMEOUT); |
641 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ | 641 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */ |
642 | m |= sw_guess_mode(buf, i); | 642 | m |= sw_guess_mode(buf, i); |
643 | dbg("Init 2b: Mode %d. Length %d.", m, i); | 643 | dbg("Init 2b: Mode %d. Length %d.", m, i); |
644 | if (!i) { | 644 | if (!i) { |
645 | err = -ENODEV; | 645 | err = -ENODEV; |
646 | goto fail2; | 646 | goto fail2; |
647 | } | 647 | } |
648 | msleep(SW_TIMEOUT); | 648 | msleep(SW_TIMEOUT); |
649 | j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */ | 649 | j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */ |
650 | dbg("Init 2c: ID Length %d.", j); | 650 | dbg("Init 2c: ID Length %d.", j); |
651 | } | 651 | } |
652 | 652 | ||
653 | sw->type = -1; | 653 | sw->type = -1; |
654 | k = SW_FAIL; /* Try SW_FAIL times */ | 654 | k = SW_FAIL; /* Try SW_FAIL times */ |
655 | l = 0; | 655 | l = 0; |
656 | 656 | ||
657 | do { | 657 | do { |
658 | k--; | 658 | k--; |
659 | msleep(SW_TIMEOUT); | 659 | msleep(SW_TIMEOUT); |
660 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */ | 660 | i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */ |
661 | dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k); | 661 | dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k); |
662 | 662 | ||
663 | if (i > l) { /* Longer? As we can only lose bits, it makes */ | 663 | if (i > l) { /* Longer? As we can only lose bits, it makes */ |
664 | /* no sense to try detection for a packet shorter */ | 664 | /* no sense to try detection for a packet shorter */ |
665 | l = i; /* than the previous one */ | 665 | l = i; /* than the previous one */ |
666 | 666 | ||
667 | sw->number = 1; | 667 | sw->number = 1; |
668 | sw->gameport = gameport; | 668 | sw->gameport = gameport; |
669 | sw->length = i; | 669 | sw->length = i; |
670 | sw->bits = m; | 670 | sw->bits = m; |
671 | 671 | ||
672 | dbg("Init 3a: Case %d.\n", i * m); | 672 | dbg("Init 3a: Case %d.\n", i * m); |
673 | 673 | ||
674 | switch (i * m) { | 674 | switch (i * m) { |
675 | case 60: | 675 | case 60: |
676 | sw->number++; | 676 | sw->number++; |
677 | case 45: /* Ambiguous packet length */ | 677 | case 45: /* Ambiguous packet length */ |
678 | if (j <= 40) { /* ID length less or eq 40 -> FSP */ | 678 | if (j <= 40) { /* ID length less or eq 40 -> FSP */ |
679 | case 43: | 679 | case 43: |
680 | sw->type = SW_ID_FSP; | 680 | sw->type = SW_ID_FSP; |
681 | break; | 681 | break; |
682 | } | 682 | } |
683 | sw->number++; | 683 | sw->number++; |
684 | case 30: | 684 | case 30: |
685 | sw->number++; | 685 | sw->number++; |
686 | case 15: | 686 | case 15: |
687 | sw->type = SW_ID_GP; | 687 | sw->type = SW_ID_GP; |
688 | break; | 688 | break; |
689 | case 33: | 689 | case 33: |
690 | case 31: | 690 | case 31: |
691 | sw->type = SW_ID_FFW; | 691 | sw->type = SW_ID_FFW; |
692 | break; | 692 | break; |
693 | case 48: /* Ambiguous */ | 693 | case 48: /* Ambiguous */ |
694 | if (j == 14) { /* ID length 14*3 -> FFP */ | 694 | if (j == 14) { /* ID length 14*3 -> FFP */ |
695 | sw->type = SW_ID_FFP; | 695 | sw->type = SW_ID_FFP; |
696 | sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on"); | 696 | sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on"); |
697 | } else | 697 | } else |
698 | sw->type = SW_ID_PP; | 698 | sw->type = SW_ID_PP; |
699 | break; | 699 | break; |
700 | case 66: | 700 | case 66: |
701 | sw->bits = 3; | 701 | sw->bits = 3; |
702 | case 198: | 702 | case 198: |
703 | sw->length = 22; | 703 | sw->length = 22; |
704 | case 64: | 704 | case 64: |
705 | sw->type = SW_ID_3DP; | 705 | sw->type = SW_ID_3DP; |
706 | if (j == 160) | 706 | if (j == 160) |
707 | sw_3dp_id(idbuf, comment, sizeof(comment)); | 707 | sw_3dp_id(idbuf, comment, sizeof(comment)); |
708 | break; | 708 | break; |
709 | } | 709 | } |
710 | } | 710 | } |
711 | 711 | ||
712 | } while (k && sw->type == -1); | 712 | } while (k && sw->type == -1); |
713 | 713 | ||
714 | if (sw->type == -1) { | 714 | if (sw->type == -1) { |
715 | printk(KERN_WARNING "sidewinder.c: unknown joystick device detected " | 715 | printk(KERN_WARNING "sidewinder.c: unknown joystick device detected " |
716 | "on %s, contact <vojtech@ucw.cz>\n", gameport->phys); | 716 | "on %s, contact <vojtech@ucw.cz>\n", gameport->phys); |
717 | sw_print_packet("ID", j * 3, idbuf, 3); | 717 | sw_print_packet("ID", j * 3, idbuf, 3); |
718 | sw_print_packet("Data", i * m, buf, m); | 718 | sw_print_packet("Data", i * m, buf, m); |
719 | err = -ENODEV; | 719 | err = -ENODEV; |
720 | goto fail2; | 720 | goto fail2; |
721 | } | 721 | } |
722 | 722 | ||
723 | #ifdef SW_DEBUG | 723 | #ifdef SW_DEBUG |
724 | sw_print_packet("ID", j * 3, idbuf, 3); | 724 | sw_print_packet("ID", j * 3, idbuf, 3); |
725 | sw_print_packet("Data", i * m, buf, m); | 725 | sw_print_packet("Data", i * m, buf, m); |
726 | #endif | 726 | #endif |
727 | 727 | ||
728 | gameport_set_poll_handler(gameport, sw_poll); | 728 | gameport_set_poll_handler(gameport, sw_poll); |
729 | gameport_set_poll_interval(gameport, 20); | 729 | gameport_set_poll_interval(gameport, 20); |
730 | 730 | ||
731 | k = i; | 731 | k = i; |
732 | l = j; | 732 | l = j; |
733 | 733 | ||
734 | for (i = 0; i < sw->number; i++) { | 734 | for (i = 0; i < sw->number; i++) { |
735 | int bits, code; | 735 | int bits, code; |
736 | 736 | ||
737 | snprintf(sw->name, sizeof(sw->name), | 737 | snprintf(sw->name, sizeof(sw->name), |
738 | "Microsoft SideWinder %s", sw_name[sw->type]); | 738 | "Microsoft SideWinder %s", sw_name[sw->type]); |
739 | snprintf(sw->phys[i], sizeof(sw->phys[i]), | 739 | snprintf(sw->phys[i], sizeof(sw->phys[i]), |
740 | "%s/input%d", gameport->phys, i); | 740 | "%s/input%d", gameport->phys, i); |
741 | 741 | ||
742 | sw->dev[i] = input_dev = input_allocate_device(); | 742 | sw->dev[i] = input_dev = input_allocate_device(); |
743 | if (!input_dev) { | 743 | if (!input_dev) { |
744 | err = -ENOMEM; | 744 | err = -ENOMEM; |
745 | goto fail3; | 745 | goto fail3; |
746 | } | 746 | } |
747 | 747 | ||
748 | input_dev->name = sw->name; | 748 | input_dev->name = sw->name; |
749 | input_dev->phys = sw->phys[i]; | 749 | input_dev->phys = sw->phys[i]; |
750 | input_dev->id.bustype = BUS_GAMEPORT; | 750 | input_dev->id.bustype = BUS_GAMEPORT; |
751 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; | 751 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_MICROSOFT; |
752 | input_dev->id.product = sw->type; | 752 | input_dev->id.product = sw->type; |
753 | input_dev->id.version = 0x0100; | 753 | input_dev->id.version = 0x0100; |
754 | input_dev->dev.parent = &gameport->dev; | 754 | input_dev->dev.parent = &gameport->dev; |
755 | 755 | ||
756 | input_set_drvdata(input_dev, sw); | 756 | input_set_drvdata(input_dev, sw); |
757 | 757 | ||
758 | input_dev->open = sw_open; | 758 | input_dev->open = sw_open; |
759 | input_dev->close = sw_close; | 759 | input_dev->close = sw_close; |
760 | 760 | ||
761 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 761 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
762 | 762 | ||
763 | for (j = 0; (bits = sw_bit[sw->type][j]); j++) { | 763 | for (j = 0; (bits = sw_bit[sw->type][j]); j++) { |
764 | int min, max, fuzz, flat; | 764 | int min, max, fuzz, flat; |
765 | 765 | ||
766 | code = sw_abs[sw->type][j]; | 766 | code = sw_abs[sw->type][j]; |
767 | min = bits == 1 ? -1 : 0; | 767 | min = bits == 1 ? -1 : 0; |
768 | max = (1 << bits) - 1; | 768 | max = (1 << bits) - 1; |
769 | fuzz = (bits >> 1) >= 2 ? 1 << ((bits >> 1) - 2) : 0; | 769 | fuzz = (bits >> 1) >= 2 ? 1 << ((bits >> 1) - 2) : 0; |
770 | flat = code == ABS_THROTTLE || bits < 5 ? | 770 | flat = code == ABS_THROTTLE || bits < 5 ? |
771 | 0 : 1 << (bits - 5); | 771 | 0 : 1 << (bits - 5); |
772 | 772 | ||
773 | input_set_abs_params(input_dev, code, | 773 | input_set_abs_params(input_dev, code, |
774 | min, max, fuzz, flat); | 774 | min, max, fuzz, flat); |
775 | } | 775 | } |
776 | 776 | ||
777 | for (j = 0; (code = sw_btn[sw->type][j]); j++) | 777 | for (j = 0; (code = sw_btn[sw->type][j]); j++) |
778 | __set_bit(code, input_dev->keybit); | 778 | __set_bit(code, input_dev->keybit); |
779 | 779 | ||
780 | dbg("%s%s [%d-bit id %d data %d]\n", sw->name, comment, m, l, k); | 780 | dbg("%s%s [%d-bit id %d data %d]\n", sw->name, comment, m, l, k); |
781 | 781 | ||
782 | err = input_register_device(sw->dev[i]); | 782 | err = input_register_device(sw->dev[i]); |
783 | if (err) | 783 | if (err) |
784 | goto fail4; | 784 | goto fail4; |
785 | } | 785 | } |
786 | 786 | ||
787 | out: kfree(buf); | 787 | out: kfree(buf); |
788 | kfree(idbuf); | 788 | kfree(idbuf); |
789 | 789 | ||
790 | return err; | 790 | return err; |
791 | 791 | ||
792 | fail4: input_free_device(sw->dev[i]); | 792 | fail4: input_free_device(sw->dev[i]); |
793 | fail3: while (--i >= 0) | 793 | fail3: while (--i >= 0) |
794 | input_unregister_device(sw->dev[i]); | 794 | input_unregister_device(sw->dev[i]); |
795 | fail2: gameport_close(gameport); | 795 | fail2: gameport_close(gameport); |
796 | fail1: gameport_set_drvdata(gameport, NULL); | 796 | fail1: gameport_set_drvdata(gameport, NULL); |
797 | kfree(sw); | 797 | kfree(sw); |
798 | goto out; | 798 | goto out; |
799 | } | 799 | } |
800 | 800 | ||
801 | static void sw_disconnect(struct gameport *gameport) | 801 | static void sw_disconnect(struct gameport *gameport) |
802 | { | 802 | { |
803 | struct sw *sw = gameport_get_drvdata(gameport); | 803 | struct sw *sw = gameport_get_drvdata(gameport); |
804 | int i; | 804 | int i; |
805 | 805 | ||
806 | for (i = 0; i < sw->number; i++) | 806 | for (i = 0; i < sw->number; i++) |
807 | input_unregister_device(sw->dev[i]); | 807 | input_unregister_device(sw->dev[i]); |
808 | gameport_close(gameport); | 808 | gameport_close(gameport); |
809 | gameport_set_drvdata(gameport, NULL); | 809 | gameport_set_drvdata(gameport, NULL); |
810 | kfree(sw); | 810 | kfree(sw); |
811 | } | 811 | } |
812 | 812 | ||
813 | static struct gameport_driver sw_drv = { | 813 | static struct gameport_driver sw_drv = { |
814 | .driver = { | 814 | .driver = { |
815 | .name = "sidewinder", | 815 | .name = "sidewinder", |
816 | .owner = THIS_MODULE, | 816 | .owner = THIS_MODULE, |
817 | }, | 817 | }, |
818 | .description = DRIVER_DESC, | 818 | .description = DRIVER_DESC, |
819 | .connect = sw_connect, | 819 | .connect = sw_connect, |
820 | .disconnect = sw_disconnect, | 820 | .disconnect = sw_disconnect, |
821 | }; | 821 | }; |
822 | 822 | ||
823 | static int __init sw_init(void) | 823 | module_gameport_driver(sw_drv); |
824 | { | ||
825 | return gameport_register_driver(&sw_drv); | ||
826 | } | ||
827 | |||
828 | static void __exit sw_exit(void) | ||
829 | { | ||
830 | gameport_unregister_driver(&sw_drv); | ||
831 | } | ||
832 | |||
833 | module_init(sw_init); | ||
834 | module_exit(sw_exit); | ||
835 | 824 |
drivers/input/joystick/tmdc.c
1 | /* | 1 | /* |
2 | * Copyright (c) 1998-2001 Vojtech Pavlik | 2 | * Copyright (c) 1998-2001 Vojtech Pavlik |
3 | * | 3 | * |
4 | * Based on the work of: | 4 | * Based on the work of: |
5 | * Trystan Larey-Williams | 5 | * Trystan Larey-Williams |
6 | */ | 6 | */ |
7 | 7 | ||
8 | /* | 8 | /* |
9 | * ThrustMaster DirectConnect (BSP) joystick family driver for Linux | 9 | * ThrustMaster DirectConnect (BSP) joystick family driver for Linux |
10 | */ | 10 | */ |
11 | 11 | ||
12 | /* | 12 | /* |
13 | * This program is free software; you can redistribute it and/or modify | 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 | 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 | 15 | * the Free Software Foundation; either version 2 of the License, or |
16 | * (at your option) any later version. | 16 | * (at your option) any later version. |
17 | * | 17 | * |
18 | * This program is distributed in the hope that it will be useful, | 18 | * This program is distributed in the hope that it will be useful, |
19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 19 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 20 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
21 | * GNU General Public License for more details. | 21 | * GNU General Public License for more details. |
22 | * | 22 | * |
23 | * You should have received a copy of the GNU General Public License | 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 | 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 | 25 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
26 | * | 26 | * |
27 | * Should you need to contact me, the author, you can do so either by | 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: | 28 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: |
29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | 29 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic |
30 | */ | 30 | */ |
31 | 31 | ||
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include <linux/kernel.h> | 33 | #include <linux/kernel.h> |
34 | #include <linux/slab.h> | 34 | #include <linux/slab.h> |
35 | #include <linux/module.h> | 35 | #include <linux/module.h> |
36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
37 | #include <linux/gameport.h> | 37 | #include <linux/gameport.h> |
38 | #include <linux/input.h> | 38 | #include <linux/input.h> |
39 | #include <linux/jiffies.h> | 39 | #include <linux/jiffies.h> |
40 | 40 | ||
41 | #define DRIVER_DESC "ThrustMaster DirectConnect joystick driver" | 41 | #define DRIVER_DESC "ThrustMaster DirectConnect joystick driver" |
42 | 42 | ||
43 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | 43 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); |
44 | MODULE_DESCRIPTION(DRIVER_DESC); | 44 | MODULE_DESCRIPTION(DRIVER_DESC); |
45 | MODULE_LICENSE("GPL"); | 45 | MODULE_LICENSE("GPL"); |
46 | 46 | ||
47 | #define TMDC_MAX_START 600 /* 600 us */ | 47 | #define TMDC_MAX_START 600 /* 600 us */ |
48 | #define TMDC_MAX_STROBE 60 /* 60 us */ | 48 | #define TMDC_MAX_STROBE 60 /* 60 us */ |
49 | #define TMDC_MAX_LENGTH 13 | 49 | #define TMDC_MAX_LENGTH 13 |
50 | 50 | ||
51 | #define TMDC_MODE_M3DI 1 | 51 | #define TMDC_MODE_M3DI 1 |
52 | #define TMDC_MODE_3DRP 3 | 52 | #define TMDC_MODE_3DRP 3 |
53 | #define TMDC_MODE_AT 4 | 53 | #define TMDC_MODE_AT 4 |
54 | #define TMDC_MODE_FM 8 | 54 | #define TMDC_MODE_FM 8 |
55 | #define TMDC_MODE_FGP 163 | 55 | #define TMDC_MODE_FGP 163 |
56 | 56 | ||
57 | #define TMDC_BYTE_ID 10 | 57 | #define TMDC_BYTE_ID 10 |
58 | #define TMDC_BYTE_REV 11 | 58 | #define TMDC_BYTE_REV 11 |
59 | #define TMDC_BYTE_DEF 12 | 59 | #define TMDC_BYTE_DEF 12 |
60 | 60 | ||
61 | #define TMDC_ABS 7 | 61 | #define TMDC_ABS 7 |
62 | #define TMDC_ABS_HAT 4 | 62 | #define TMDC_ABS_HAT 4 |
63 | #define TMDC_BTN 16 | 63 | #define TMDC_BTN 16 |
64 | 64 | ||
65 | static const unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; | 65 | static const unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 }; |
66 | static const unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; | 66 | static const unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 }; |
67 | 67 | ||
68 | static const signed char tmdc_abs[TMDC_ABS] = | 68 | static const signed char tmdc_abs[TMDC_ABS] = |
69 | { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; | 69 | { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ }; |
70 | static const signed char tmdc_abs_hat[TMDC_ABS_HAT] = | 70 | static const signed char tmdc_abs_hat[TMDC_ABS_HAT] = |
71 | { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; | 71 | { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y }; |
72 | static const signed char tmdc_abs_at[TMDC_ABS] = | 72 | static const signed char tmdc_abs_at[TMDC_ABS] = |
73 | { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE }; | 73 | { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE }; |
74 | static const signed char tmdc_abs_fm[TMDC_ABS] = | 74 | static const signed char tmdc_abs_fm[TMDC_ABS] = |
75 | { ABS_RX, ABS_RY, ABS_X, ABS_Y }; | 75 | { ABS_RX, ABS_RY, ABS_X, ABS_Y }; |
76 | 76 | ||
77 | static const short tmdc_btn_pad[TMDC_BTN] = | 77 | static const short tmdc_btn_pad[TMDC_BTN] = |
78 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; | 78 | { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR }; |
79 | static const short tmdc_btn_joy[TMDC_BTN] = | 79 | static const short tmdc_btn_joy[TMDC_BTN] = |
80 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, | 80 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE, |
81 | BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; | 81 | BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z }; |
82 | static const short tmdc_btn_fm[TMDC_BTN] = | 82 | static const short tmdc_btn_fm[TMDC_BTN] = |
83 | { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 }; | 83 | { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 }; |
84 | static const short tmdc_btn_at[TMDC_BTN] = | 84 | static const short tmdc_btn_at[TMDC_BTN] = |
85 | { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4, | 85 | { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4, |
86 | BTN_BASE3, BTN_BASE2, BTN_BASE }; | 86 | BTN_BASE3, BTN_BASE2, BTN_BASE }; |
87 | 87 | ||
88 | static const struct { | 88 | static const struct { |
89 | int x; | 89 | int x; |
90 | int y; | 90 | int y; |
91 | } tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}}; | 91 | } tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}}; |
92 | 92 | ||
93 | static const struct tmdc_model { | 93 | static const struct tmdc_model { |
94 | unsigned char id; | 94 | unsigned char id; |
95 | const char *name; | 95 | const char *name; |
96 | char abs; | 96 | char abs; |
97 | char hats; | 97 | char hats; |
98 | char btnc[4]; | 98 | char btnc[4]; |
99 | char btno[4]; | 99 | char btno[4]; |
100 | const signed char *axes; | 100 | const signed char *axes; |
101 | const short *buttons; | 101 | const short *buttons; |
102 | } tmdc_models[] = { | 102 | } tmdc_models[] = { |
103 | { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, | 103 | { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy }, |
104 | { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, | 104 | { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, |
105 | { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, | 105 | { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at }, |
106 | { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, | 106 | { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm }, |
107 | { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, | 107 | { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad }, |
108 | { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy } | 108 | { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy } |
109 | }; | 109 | }; |
110 | 110 | ||
111 | 111 | ||
112 | struct tmdc_port { | 112 | struct tmdc_port { |
113 | struct input_dev *dev; | 113 | struct input_dev *dev; |
114 | char name[64]; | 114 | char name[64]; |
115 | char phys[32]; | 115 | char phys[32]; |
116 | int mode; | 116 | int mode; |
117 | const signed char *abs; | 117 | const signed char *abs; |
118 | const short *btn; | 118 | const short *btn; |
119 | unsigned char absc; | 119 | unsigned char absc; |
120 | unsigned char btnc[4]; | 120 | unsigned char btnc[4]; |
121 | unsigned char btno[4]; | 121 | unsigned char btno[4]; |
122 | }; | 122 | }; |
123 | 123 | ||
124 | struct tmdc { | 124 | struct tmdc { |
125 | struct gameport *gameport; | 125 | struct gameport *gameport; |
126 | struct tmdc_port *port[2]; | 126 | struct tmdc_port *port[2]; |
127 | #if 0 | 127 | #if 0 |
128 | struct input_dev *dev[2]; | 128 | struct input_dev *dev[2]; |
129 | char name[2][64]; | 129 | char name[2][64]; |
130 | char phys[2][32]; | 130 | char phys[2][32]; |
131 | int mode[2]; | 131 | int mode[2]; |
132 | signed char *abs[2]; | 132 | signed char *abs[2]; |
133 | short *btn[2]; | 133 | short *btn[2]; |
134 | unsigned char absc[2]; | 134 | unsigned char absc[2]; |
135 | unsigned char btnc[2][4]; | 135 | unsigned char btnc[2][4]; |
136 | unsigned char btno[2][4]; | 136 | unsigned char btno[2][4]; |
137 | #endif | 137 | #endif |
138 | int reads; | 138 | int reads; |
139 | int bads; | 139 | int bads; |
140 | unsigned char exists; | 140 | unsigned char exists; |
141 | }; | 141 | }; |
142 | 142 | ||
143 | /* | 143 | /* |
144 | * tmdc_read_packet() reads a ThrustMaster packet. | 144 | * tmdc_read_packet() reads a ThrustMaster packet. |
145 | */ | 145 | */ |
146 | 146 | ||
147 | static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH]) | 147 | static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH]) |
148 | { | 148 | { |
149 | unsigned char u, v, w, x; | 149 | unsigned char u, v, w, x; |
150 | unsigned long flags; | 150 | unsigned long flags; |
151 | int i[2], j[2], t[2], p, k; | 151 | int i[2], j[2], t[2], p, k; |
152 | 152 | ||
153 | p = gameport_time(gameport, TMDC_MAX_STROBE); | 153 | p = gameport_time(gameport, TMDC_MAX_STROBE); |
154 | 154 | ||
155 | for (k = 0; k < 2; k++) { | 155 | for (k = 0; k < 2; k++) { |
156 | t[k] = gameport_time(gameport, TMDC_MAX_START); | 156 | t[k] = gameport_time(gameport, TMDC_MAX_START); |
157 | i[k] = j[k] = 0; | 157 | i[k] = j[k] = 0; |
158 | } | 158 | } |
159 | 159 | ||
160 | local_irq_save(flags); | 160 | local_irq_save(flags); |
161 | gameport_trigger(gameport); | 161 | gameport_trigger(gameport); |
162 | 162 | ||
163 | w = gameport_read(gameport) >> 4; | 163 | w = gameport_read(gameport) >> 4; |
164 | 164 | ||
165 | do { | 165 | do { |
166 | x = w; | 166 | x = w; |
167 | w = gameport_read(gameport) >> 4; | 167 | w = gameport_read(gameport) >> 4; |
168 | 168 | ||
169 | for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) { | 169 | for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) { |
170 | if (~v & u & 2) { | 170 | if (~v & u & 2) { |
171 | if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue; | 171 | if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue; |
172 | t[k] = p; | 172 | t[k] = p; |
173 | if (j[k] == 0) { /* Start bit */ | 173 | if (j[k] == 0) { /* Start bit */ |
174 | if (~v & 1) t[k] = 0; | 174 | if (~v & 1) t[k] = 0; |
175 | data[k][i[k]] = 0; j[k]++; continue; | 175 | data[k][i[k]] = 0; j[k]++; continue; |
176 | } | 176 | } |
177 | if (j[k] == 9) { /* Stop bit */ | 177 | if (j[k] == 9) { /* Stop bit */ |
178 | if (v & 1) t[k] = 0; | 178 | if (v & 1) t[k] = 0; |
179 | j[k] = 0; i[k]++; continue; | 179 | j[k] = 0; i[k]++; continue; |
180 | } | 180 | } |
181 | data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */ | 181 | data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */ |
182 | } | 182 | } |
183 | t[k]--; | 183 | t[k]--; |
184 | } | 184 | } |
185 | } while (t[0] > 0 || t[1] > 0); | 185 | } while (t[0] > 0 || t[1] > 0); |
186 | 186 | ||
187 | local_irq_restore(flags); | 187 | local_irq_restore(flags); |
188 | 188 | ||
189 | return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1); | 189 | return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1); |
190 | } | 190 | } |
191 | 191 | ||
192 | static int tmdc_parse_packet(struct tmdc_port *port, unsigned char *data) | 192 | static int tmdc_parse_packet(struct tmdc_port *port, unsigned char *data) |
193 | { | 193 | { |
194 | int i, k, l; | 194 | int i, k, l; |
195 | 195 | ||
196 | if (data[TMDC_BYTE_ID] != port->mode) | 196 | if (data[TMDC_BYTE_ID] != port->mode) |
197 | return -1; | 197 | return -1; |
198 | 198 | ||
199 | for (i = 0; i < port->absc; i++) { | 199 | for (i = 0; i < port->absc; i++) { |
200 | if (port->abs[i] < 0) | 200 | if (port->abs[i] < 0) |
201 | return 0; | 201 | return 0; |
202 | 202 | ||
203 | input_report_abs(port->dev, port->abs[i], data[tmdc_byte_a[i]]); | 203 | input_report_abs(port->dev, port->abs[i], data[tmdc_byte_a[i]]); |
204 | } | 204 | } |
205 | 205 | ||
206 | switch (port->mode) { | 206 | switch (port->mode) { |
207 | 207 | ||
208 | case TMDC_MODE_M3DI: | 208 | case TMDC_MODE_M3DI: |
209 | 209 | ||
210 | i = tmdc_byte_d[0]; | 210 | i = tmdc_byte_d[0]; |
211 | input_report_abs(port->dev, ABS_HAT0X, ((data[i] >> 3) & 1) - ((data[i] >> 1) & 1)); | 211 | input_report_abs(port->dev, ABS_HAT0X, ((data[i] >> 3) & 1) - ((data[i] >> 1) & 1)); |
212 | input_report_abs(port->dev, ABS_HAT0Y, ((data[i] >> 2) & 1) - ( data[i] & 1)); | 212 | input_report_abs(port->dev, ABS_HAT0Y, ((data[i] >> 2) & 1) - ( data[i] & 1)); |
213 | break; | 213 | break; |
214 | 214 | ||
215 | case TMDC_MODE_AT: | 215 | case TMDC_MODE_AT: |
216 | 216 | ||
217 | i = tmdc_byte_a[3]; | 217 | i = tmdc_byte_a[3]; |
218 | input_report_abs(port->dev, ABS_HAT0X, tmdc_hat_to_axis[(data[i] - 141) / 25].x); | 218 | input_report_abs(port->dev, ABS_HAT0X, tmdc_hat_to_axis[(data[i] - 141) / 25].x); |
219 | input_report_abs(port->dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[i] - 141) / 25].y); | 219 | input_report_abs(port->dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[i] - 141) / 25].y); |
220 | break; | 220 | break; |
221 | 221 | ||
222 | } | 222 | } |
223 | 223 | ||
224 | for (k = l = 0; k < 4; k++) { | 224 | for (k = l = 0; k < 4; k++) { |
225 | for (i = 0; i < port->btnc[k]; i++) | 225 | for (i = 0; i < port->btnc[k]; i++) |
226 | input_report_key(port->dev, port->btn[i + l], | 226 | input_report_key(port->dev, port->btn[i + l], |
227 | ((data[tmdc_byte_d[k]] >> (i + port->btno[k])) & 1)); | 227 | ((data[tmdc_byte_d[k]] >> (i + port->btno[k])) & 1)); |
228 | l += port->btnc[k]; | 228 | l += port->btnc[k]; |
229 | } | 229 | } |
230 | 230 | ||
231 | input_sync(port->dev); | 231 | input_sync(port->dev); |
232 | 232 | ||
233 | return 0; | 233 | return 0; |
234 | } | 234 | } |
235 | 235 | ||
236 | /* | 236 | /* |
237 | * tmdc_poll() reads and analyzes ThrustMaster joystick data. | 237 | * tmdc_poll() reads and analyzes ThrustMaster joystick data. |
238 | */ | 238 | */ |
239 | 239 | ||
240 | static void tmdc_poll(struct gameport *gameport) | 240 | static void tmdc_poll(struct gameport *gameport) |
241 | { | 241 | { |
242 | unsigned char data[2][TMDC_MAX_LENGTH]; | 242 | unsigned char data[2][TMDC_MAX_LENGTH]; |
243 | struct tmdc *tmdc = gameport_get_drvdata(gameport); | 243 | struct tmdc *tmdc = gameport_get_drvdata(gameport); |
244 | unsigned char r, bad = 0; | 244 | unsigned char r, bad = 0; |
245 | int i; | 245 | int i; |
246 | 246 | ||
247 | tmdc->reads++; | 247 | tmdc->reads++; |
248 | 248 | ||
249 | if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists) | 249 | if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists) |
250 | bad = 1; | 250 | bad = 1; |
251 | else { | 251 | else { |
252 | for (i = 0; i < 2; i++) { | 252 | for (i = 0; i < 2; i++) { |
253 | if (r & (1 << i) & tmdc->exists) { | 253 | if (r & (1 << i) & tmdc->exists) { |
254 | 254 | ||
255 | if (tmdc_parse_packet(tmdc->port[i], data[i])) | 255 | if (tmdc_parse_packet(tmdc->port[i], data[i])) |
256 | bad = 1; | 256 | bad = 1; |
257 | } | 257 | } |
258 | } | 258 | } |
259 | } | 259 | } |
260 | 260 | ||
261 | tmdc->bads += bad; | 261 | tmdc->bads += bad; |
262 | } | 262 | } |
263 | 263 | ||
264 | static int tmdc_open(struct input_dev *dev) | 264 | static int tmdc_open(struct input_dev *dev) |
265 | { | 265 | { |
266 | struct tmdc *tmdc = input_get_drvdata(dev); | 266 | struct tmdc *tmdc = input_get_drvdata(dev); |
267 | 267 | ||
268 | gameport_start_polling(tmdc->gameport); | 268 | gameport_start_polling(tmdc->gameport); |
269 | return 0; | 269 | return 0; |
270 | } | 270 | } |
271 | 271 | ||
272 | static void tmdc_close(struct input_dev *dev) | 272 | static void tmdc_close(struct input_dev *dev) |
273 | { | 273 | { |
274 | struct tmdc *tmdc = input_get_drvdata(dev); | 274 | struct tmdc *tmdc = input_get_drvdata(dev); |
275 | 275 | ||
276 | gameport_stop_polling(tmdc->gameport); | 276 | gameport_stop_polling(tmdc->gameport); |
277 | } | 277 | } |
278 | 278 | ||
279 | static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data) | 279 | static int tmdc_setup_port(struct tmdc *tmdc, int idx, unsigned char *data) |
280 | { | 280 | { |
281 | const struct tmdc_model *model; | 281 | const struct tmdc_model *model; |
282 | struct tmdc_port *port; | 282 | struct tmdc_port *port; |
283 | struct input_dev *input_dev; | 283 | struct input_dev *input_dev; |
284 | int i, j, b = 0; | 284 | int i, j, b = 0; |
285 | int err; | 285 | int err; |
286 | 286 | ||
287 | tmdc->port[idx] = port = kzalloc(sizeof (struct tmdc_port), GFP_KERNEL); | 287 | tmdc->port[idx] = port = kzalloc(sizeof (struct tmdc_port), GFP_KERNEL); |
288 | input_dev = input_allocate_device(); | 288 | input_dev = input_allocate_device(); |
289 | if (!port || !input_dev) { | 289 | if (!port || !input_dev) { |
290 | err = -ENOMEM; | 290 | err = -ENOMEM; |
291 | goto fail; | 291 | goto fail; |
292 | } | 292 | } |
293 | 293 | ||
294 | port->mode = data[TMDC_BYTE_ID]; | 294 | port->mode = data[TMDC_BYTE_ID]; |
295 | 295 | ||
296 | for (model = tmdc_models; model->id && model->id != port->mode; model++) | 296 | for (model = tmdc_models; model->id && model->id != port->mode; model++) |
297 | /* empty */; | 297 | /* empty */; |
298 | 298 | ||
299 | port->abs = model->axes; | 299 | port->abs = model->axes; |
300 | port->btn = model->buttons; | 300 | port->btn = model->buttons; |
301 | 301 | ||
302 | if (!model->id) { | 302 | if (!model->id) { |
303 | port->absc = data[TMDC_BYTE_DEF] >> 4; | 303 | port->absc = data[TMDC_BYTE_DEF] >> 4; |
304 | for (i = 0; i < 4; i++) | 304 | for (i = 0; i < 4; i++) |
305 | port->btnc[i] = i < (data[TMDC_BYTE_DEF] & 0xf) ? 8 : 0; | 305 | port->btnc[i] = i < (data[TMDC_BYTE_DEF] & 0xf) ? 8 : 0; |
306 | } else { | 306 | } else { |
307 | port->absc = model->abs; | 307 | port->absc = model->abs; |
308 | for (i = 0; i < 4; i++) | 308 | for (i = 0; i < 4; i++) |
309 | port->btnc[i] = model->btnc[i]; | 309 | port->btnc[i] = model->btnc[i]; |
310 | } | 310 | } |
311 | 311 | ||
312 | for (i = 0; i < 4; i++) | 312 | for (i = 0; i < 4; i++) |
313 | port->btno[i] = model->btno[i]; | 313 | port->btno[i] = model->btno[i]; |
314 | 314 | ||
315 | snprintf(port->name, sizeof(port->name), model->name, | 315 | snprintf(port->name, sizeof(port->name), model->name, |
316 | port->absc, (data[TMDC_BYTE_DEF] & 0xf) << 3, port->mode); | 316 | port->absc, (data[TMDC_BYTE_DEF] & 0xf) << 3, port->mode); |
317 | snprintf(port->phys, sizeof(port->phys), "%s/input%d", tmdc->gameport->phys, i); | 317 | snprintf(port->phys, sizeof(port->phys), "%s/input%d", tmdc->gameport->phys, i); |
318 | 318 | ||
319 | port->dev = input_dev; | 319 | port->dev = input_dev; |
320 | 320 | ||
321 | input_dev->name = port->name; | 321 | input_dev->name = port->name; |
322 | input_dev->phys = port->phys; | 322 | input_dev->phys = port->phys; |
323 | input_dev->id.bustype = BUS_GAMEPORT; | 323 | input_dev->id.bustype = BUS_GAMEPORT; |
324 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; | 324 | input_dev->id.vendor = GAMEPORT_ID_VENDOR_THRUSTMASTER; |
325 | input_dev->id.product = model->id; | 325 | input_dev->id.product = model->id; |
326 | input_dev->id.version = 0x0100; | 326 | input_dev->id.version = 0x0100; |
327 | input_dev->dev.parent = &tmdc->gameport->dev; | 327 | input_dev->dev.parent = &tmdc->gameport->dev; |
328 | 328 | ||
329 | input_set_drvdata(input_dev, tmdc); | 329 | input_set_drvdata(input_dev, tmdc); |
330 | 330 | ||
331 | input_dev->open = tmdc_open; | 331 | input_dev->open = tmdc_open; |
332 | input_dev->close = tmdc_close; | 332 | input_dev->close = tmdc_close; |
333 | 333 | ||
334 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); | 334 | input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); |
335 | 335 | ||
336 | for (i = 0; i < port->absc && i < TMDC_ABS; i++) | 336 | for (i = 0; i < port->absc && i < TMDC_ABS; i++) |
337 | if (port->abs[i] >= 0) | 337 | if (port->abs[i] >= 0) |
338 | input_set_abs_params(input_dev, port->abs[i], 8, 248, 2, 4); | 338 | input_set_abs_params(input_dev, port->abs[i], 8, 248, 2, 4); |
339 | 339 | ||
340 | for (i = 0; i < model->hats && i < TMDC_ABS_HAT; i++) | 340 | for (i = 0; i < model->hats && i < TMDC_ABS_HAT; i++) |
341 | input_set_abs_params(input_dev, tmdc_abs_hat[i], -1, 1, 0, 0); | 341 | input_set_abs_params(input_dev, tmdc_abs_hat[i], -1, 1, 0, 0); |
342 | 342 | ||
343 | for (i = 0; i < 4; i++) { | 343 | for (i = 0; i < 4; i++) { |
344 | for (j = 0; j < port->btnc[i] && j < TMDC_BTN; j++) | 344 | for (j = 0; j < port->btnc[i] && j < TMDC_BTN; j++) |
345 | set_bit(port->btn[j + b], input_dev->keybit); | 345 | set_bit(port->btn[j + b], input_dev->keybit); |
346 | b += port->btnc[i]; | 346 | b += port->btnc[i]; |
347 | } | 347 | } |
348 | 348 | ||
349 | err = input_register_device(port->dev); | 349 | err = input_register_device(port->dev); |
350 | if (err) | 350 | if (err) |
351 | goto fail; | 351 | goto fail; |
352 | 352 | ||
353 | return 0; | 353 | return 0; |
354 | 354 | ||
355 | fail: input_free_device(input_dev); | 355 | fail: input_free_device(input_dev); |
356 | kfree(port); | 356 | kfree(port); |
357 | return err; | 357 | return err; |
358 | } | 358 | } |
359 | 359 | ||
360 | /* | 360 | /* |
361 | * tmdc_probe() probes for ThrustMaster type joysticks. | 361 | * tmdc_probe() probes for ThrustMaster type joysticks. |
362 | */ | 362 | */ |
363 | 363 | ||
364 | static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) | 364 | static int tmdc_connect(struct gameport *gameport, struct gameport_driver *drv) |
365 | { | 365 | { |
366 | unsigned char data[2][TMDC_MAX_LENGTH]; | 366 | unsigned char data[2][TMDC_MAX_LENGTH]; |
367 | struct tmdc *tmdc; | 367 | struct tmdc *tmdc; |
368 | int i; | 368 | int i; |
369 | int err; | 369 | int err; |
370 | 370 | ||
371 | if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL))) | 371 | if (!(tmdc = kzalloc(sizeof(struct tmdc), GFP_KERNEL))) |
372 | return -ENOMEM; | 372 | return -ENOMEM; |
373 | 373 | ||
374 | tmdc->gameport = gameport; | 374 | tmdc->gameport = gameport; |
375 | 375 | ||
376 | gameport_set_drvdata(gameport, tmdc); | 376 | gameport_set_drvdata(gameport, tmdc); |
377 | 377 | ||
378 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); | 378 | err = gameport_open(gameport, drv, GAMEPORT_MODE_RAW); |
379 | if (err) | 379 | if (err) |
380 | goto fail1; | 380 | goto fail1; |
381 | 381 | ||
382 | if (!(tmdc->exists = tmdc_read_packet(gameport, data))) { | 382 | if (!(tmdc->exists = tmdc_read_packet(gameport, data))) { |
383 | err = -ENODEV; | 383 | err = -ENODEV; |
384 | goto fail2; | 384 | goto fail2; |
385 | } | 385 | } |
386 | 386 | ||
387 | gameport_set_poll_handler(gameport, tmdc_poll); | 387 | gameport_set_poll_handler(gameport, tmdc_poll); |
388 | gameport_set_poll_interval(gameport, 20); | 388 | gameport_set_poll_interval(gameport, 20); |
389 | 389 | ||
390 | for (i = 0; i < 2; i++) { | 390 | for (i = 0; i < 2; i++) { |
391 | if (tmdc->exists & (1 << i)) { | 391 | if (tmdc->exists & (1 << i)) { |
392 | 392 | ||
393 | err = tmdc_setup_port(tmdc, i, data[i]); | 393 | err = tmdc_setup_port(tmdc, i, data[i]); |
394 | if (err) | 394 | if (err) |
395 | goto fail3; | 395 | goto fail3; |
396 | } | 396 | } |
397 | } | 397 | } |
398 | 398 | ||
399 | return 0; | 399 | return 0; |
400 | 400 | ||
401 | fail3: while (--i >= 0) { | 401 | fail3: while (--i >= 0) { |
402 | if (tmdc->port[i]) { | 402 | if (tmdc->port[i]) { |
403 | input_unregister_device(tmdc->port[i]->dev); | 403 | input_unregister_device(tmdc->port[i]->dev); |
404 | kfree(tmdc->port[i]); | 404 | kfree(tmdc->port[i]); |
405 | } | 405 | } |
406 | } | 406 | } |
407 | fail2: gameport_close(gameport); | 407 | fail2: gameport_close(gameport); |
408 | fail1: gameport_set_drvdata(gameport, NULL); | 408 | fail1: gameport_set_drvdata(gameport, NULL); |
409 | kfree(tmdc); | 409 | kfree(tmdc); |
410 | return err; | 410 | return err; |
411 | } | 411 | } |
412 | 412 | ||
413 | static void tmdc_disconnect(struct gameport *gameport) | 413 | static void tmdc_disconnect(struct gameport *gameport) |
414 | { | 414 | { |
415 | struct tmdc *tmdc = gameport_get_drvdata(gameport); | 415 | struct tmdc *tmdc = gameport_get_drvdata(gameport); |
416 | int i; | 416 | int i; |
417 | 417 | ||
418 | for (i = 0; i < 2; i++) { | 418 | for (i = 0; i < 2; i++) { |
419 | if (tmdc->port[i]) { | 419 | if (tmdc->port[i]) { |
420 | input_unregister_device(tmdc->port[i]->dev); | 420 | input_unregister_device(tmdc->port[i]->dev); |
421 | kfree(tmdc->port[i]); | 421 | kfree(tmdc->port[i]); |
422 | } | 422 | } |
423 | } | 423 | } |
424 | gameport_close(gameport); | 424 | gameport_close(gameport); |
425 | gameport_set_drvdata(gameport, NULL); | 425 | gameport_set_drvdata(gameport, NULL); |
426 | kfree(tmdc); | 426 | kfree(tmdc); |
427 | } | 427 | } |
428 | 428 | ||
429 | static struct gameport_driver tmdc_drv = { | 429 | static struct gameport_driver tmdc_drv = { |
430 | .driver = { | 430 | .driver = { |
431 | .name = "tmdc", | 431 | .name = "tmdc", |
432 | .owner = THIS_MODULE, | 432 | .owner = THIS_MODULE, |
433 | }, | 433 | }, |
434 | .description = DRIVER_DESC, | 434 | .description = DRIVER_DESC, |
435 | .connect = tmdc_connect, | 435 | .connect = tmdc_connect, |
436 | .disconnect = tmdc_disconnect, | 436 | .disconnect = tmdc_disconnect, |
437 | }; | 437 | }; |
438 | 438 | ||
439 | static int __init tmdc_init(void) | 439 | module_gameport_driver(tmdc_drv); |
440 | { | ||
441 | return gameport_register_driver(&tmdc_drv); | ||
442 | } | ||
443 | |||
444 | static void __exit tmdc_exit(void) | ||
445 | { | ||
446 | gameport_unregister_driver(&tmdc_drv); | ||
447 | } | ||
448 | |||
449 | module_init(tmdc_init); | ||
450 | module_exit(tmdc_exit); | ||
451 | 440 |