diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/input/joystick/iforce |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/input/joystick/iforce')
-rw-r--r-- | drivers/input/joystick/iforce/Kconfig | 32 | ||||
-rw-r--r-- | drivers/input/joystick/iforce/Makefile | 20 | ||||
-rw-r--r-- | drivers/input/joystick/iforce/iforce-ff.c | 543 | ||||
-rw-r--r-- | drivers/input/joystick/iforce/iforce-main.c | 557 | ||||
-rw-r--r-- | drivers/input/joystick/iforce/iforce-packets.c | 319 | ||||
-rw-r--r-- | drivers/input/joystick/iforce/iforce-serio.c | 193 | ||||
-rw-r--r-- | drivers/input/joystick/iforce/iforce-usb.c | 243 | ||||
-rw-r--r-- | drivers/input/joystick/iforce/iforce.h | 191 |
8 files changed, 2098 insertions, 0 deletions
diff --git a/drivers/input/joystick/iforce/Kconfig b/drivers/input/joystick/iforce/Kconfig new file mode 100644 index 000000000000..8fde22a021b3 --- /dev/null +++ b/drivers/input/joystick/iforce/Kconfig | |||
@@ -0,0 +1,32 @@ | |||
1 | # | ||
2 | # I-Force driver configuration | ||
3 | # | ||
4 | config JOYSTICK_IFORCE | ||
5 | tristate "I-Force devices" | ||
6 | depends on INPUT && INPUT_JOYSTICK | ||
7 | help | ||
8 | Say Y here if you have an I-Force joystick or steering wheel | ||
9 | |||
10 | You also must choose at least one of the two options below. | ||
11 | |||
12 | To compile this driver as a module, choose M here: the | ||
13 | module will be called iforce. | ||
14 | |||
15 | config JOYSTICK_IFORCE_USB | ||
16 | bool "I-Force USB joysticks and wheels" | ||
17 | depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || USB=y) && USB | ||
18 | help | ||
19 | Say Y here if you have an I-Force joystick or steering wheel | ||
20 | connected to your USB port. | ||
21 | |||
22 | config JOYSTICK_IFORCE_232 | ||
23 | bool "I-Force Serial joysticks and wheels" | ||
24 | depends on JOYSTICK_IFORCE && (JOYSTICK_IFORCE=m || SERIO=y) && SERIO | ||
25 | help | ||
26 | Say Y here if you have an I-Force joystick or steering wheel | ||
27 | connected to your serial (COM) port. | ||
28 | |||
29 | You will need an additional utility called inputattach, see | ||
30 | <file:Documentation/input/joystick.txt> | ||
31 | and <file:Documentation/input/ff.txt>. | ||
32 | |||
diff --git a/drivers/input/joystick/iforce/Makefile b/drivers/input/joystick/iforce/Makefile new file mode 100644 index 000000000000..17ae42bf9ffd --- /dev/null +++ b/drivers/input/joystick/iforce/Makefile | |||
@@ -0,0 +1,20 @@ | |||
1 | # | ||
2 | # Makefile for the I-Force driver | ||
3 | # | ||
4 | # By Johann Deneux <deneux@ifrance.com> | ||
5 | # | ||
6 | |||
7 | # Goal definition | ||
8 | iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o | ||
9 | |||
10 | obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o | ||
11 | |||
12 | ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) | ||
13 | iforce-objs += iforce-serio.o | ||
14 | endif | ||
15 | |||
16 | ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) | ||
17 | iforce-objs += iforce-usb.o | ||
18 | endif | ||
19 | |||
20 | EXTRA_CFLAGS = -Werror-implicit-function-declaration | ||
diff --git a/drivers/input/joystick/iforce/iforce-ff.c b/drivers/input/joystick/iforce/iforce-ff.c new file mode 100644 index 000000000000..4678b6dab43b --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-ff.c | |||
@@ -0,0 +1,543 @@ | |||
1 | /* | ||
2 | * $Id: iforce-ff.c,v 1.9 2002/02/02 19:28:35 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
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 | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
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 | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
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: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | /* | ||
33 | * Set the magnitude of a constant force effect | ||
34 | * Return error code | ||
35 | * | ||
36 | * Note: caller must ensure exclusive access to device | ||
37 | */ | ||
38 | |||
39 | static int make_magnitude_modifier(struct iforce* iforce, | ||
40 | struct resource* mod_chunk, int no_alloc, __s16 level) | ||
41 | { | ||
42 | unsigned char data[3]; | ||
43 | |||
44 | if (!no_alloc) { | ||
45 | down(&iforce->mem_mutex); | ||
46 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, | ||
47 | iforce->device_memory.start, iforce->device_memory.end, 2L, | ||
48 | NULL, NULL)) { | ||
49 | up(&iforce->mem_mutex); | ||
50 | return -ENOMEM; | ||
51 | } | ||
52 | up(&iforce->mem_mutex); | ||
53 | } | ||
54 | |||
55 | data[0] = LO(mod_chunk->start); | ||
56 | data[1] = HI(mod_chunk->start); | ||
57 | data[2] = HIFIX80(level); | ||
58 | |||
59 | iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); | ||
60 | |||
61 | iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | /* | ||
66 | * Upload the component of an effect dealing with the period, phase and magnitude | ||
67 | */ | ||
68 | |||
69 | static int make_period_modifier(struct iforce* iforce, | ||
70 | struct resource* mod_chunk, int no_alloc, | ||
71 | __s16 magnitude, __s16 offset, u16 period, u16 phase) | ||
72 | { | ||
73 | unsigned char data[7]; | ||
74 | |||
75 | period = TIME_SCALE(period); | ||
76 | |||
77 | if (!no_alloc) { | ||
78 | down(&iforce->mem_mutex); | ||
79 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, | ||
80 | iforce->device_memory.start, iforce->device_memory.end, 2L, | ||
81 | NULL, NULL)) { | ||
82 | up(&iforce->mem_mutex); | ||
83 | return -ENOMEM; | ||
84 | } | ||
85 | up(&iforce->mem_mutex); | ||
86 | } | ||
87 | |||
88 | data[0] = LO(mod_chunk->start); | ||
89 | data[1] = HI(mod_chunk->start); | ||
90 | |||
91 | data[2] = HIFIX80(magnitude); | ||
92 | data[3] = HIFIX80(offset); | ||
93 | data[4] = HI(phase); | ||
94 | |||
95 | data[5] = LO(period); | ||
96 | data[6] = HI(period); | ||
97 | |||
98 | iforce_send_packet(iforce, FF_CMD_PERIOD, data); | ||
99 | |||
100 | return 0; | ||
101 | } | ||
102 | |||
103 | /* | ||
104 | * Uploads the part of an effect setting the envelope of the force | ||
105 | */ | ||
106 | |||
107 | static int make_envelope_modifier(struct iforce* iforce, | ||
108 | struct resource* mod_chunk, int no_alloc, | ||
109 | u16 attack_duration, __s16 initial_level, | ||
110 | u16 fade_duration, __s16 final_level) | ||
111 | { | ||
112 | unsigned char data[8]; | ||
113 | |||
114 | attack_duration = TIME_SCALE(attack_duration); | ||
115 | fade_duration = TIME_SCALE(fade_duration); | ||
116 | |||
117 | if (!no_alloc) { | ||
118 | down(&iforce->mem_mutex); | ||
119 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, | ||
120 | iforce->device_memory.start, iforce->device_memory.end, 2L, | ||
121 | NULL, NULL)) { | ||
122 | up(&iforce->mem_mutex); | ||
123 | return -ENOMEM; | ||
124 | } | ||
125 | up(&iforce->mem_mutex); | ||
126 | } | ||
127 | |||
128 | data[0] = LO(mod_chunk->start); | ||
129 | data[1] = HI(mod_chunk->start); | ||
130 | |||
131 | data[2] = LO(attack_duration); | ||
132 | data[3] = HI(attack_duration); | ||
133 | data[4] = HI(initial_level); | ||
134 | |||
135 | data[5] = LO(fade_duration); | ||
136 | data[6] = HI(fade_duration); | ||
137 | data[7] = HI(final_level); | ||
138 | |||
139 | iforce_send_packet(iforce, FF_CMD_ENVELOPE, data); | ||
140 | |||
141 | return 0; | ||
142 | } | ||
143 | |||
144 | /* | ||
145 | * Component of spring, friction, inertia... effects | ||
146 | */ | ||
147 | |||
148 | static int make_condition_modifier(struct iforce* iforce, | ||
149 | struct resource* mod_chunk, int no_alloc, | ||
150 | __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) | ||
151 | { | ||
152 | unsigned char data[10]; | ||
153 | |||
154 | if (!no_alloc) { | ||
155 | down(&iforce->mem_mutex); | ||
156 | if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, | ||
157 | iforce->device_memory.start, iforce->device_memory.end, 2L, | ||
158 | NULL, NULL)) { | ||
159 | up(&iforce->mem_mutex); | ||
160 | return -ENOMEM; | ||
161 | } | ||
162 | up(&iforce->mem_mutex); | ||
163 | } | ||
164 | |||
165 | data[0] = LO(mod_chunk->start); | ||
166 | data[1] = HI(mod_chunk->start); | ||
167 | |||
168 | data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ | ||
169 | data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ | ||
170 | |||
171 | center = (500*center)>>15; | ||
172 | data[4] = LO(center); | ||
173 | data[5] = HI(center); | ||
174 | |||
175 | db = (1000*db)>>16; | ||
176 | data[6] = LO(db); | ||
177 | data[7] = HI(db); | ||
178 | |||
179 | data[8] = (100*rsat)>>16; | ||
180 | data[9] = (100*lsat)>>16; | ||
181 | |||
182 | iforce_send_packet(iforce, FF_CMD_CONDITION, data); | ||
183 | iforce_dump_packet("condition", FF_CMD_CONDITION, data); | ||
184 | |||
185 | return 0; | ||
186 | } | ||
187 | |||
188 | static unsigned char find_button(struct iforce *iforce, signed short button) | ||
189 | { | ||
190 | int i; | ||
191 | for (i = 1; iforce->type->btn[i] >= 0; i++) | ||
192 | if (iforce->type->btn[i] == button) | ||
193 | return i + 1; | ||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | /* | ||
198 | * Analyse the changes in an effect, and tell if we need to send an condition | ||
199 | * parameter packet | ||
200 | */ | ||
201 | static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) | ||
202 | { | ||
203 | int id = new->id; | ||
204 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
205 | int ret=0; | ||
206 | int i; | ||
207 | |||
208 | if (new->type != FF_SPRING && new->type != FF_FRICTION) { | ||
209 | printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); | ||
210 | return FALSE; | ||
211 | } | ||
212 | |||
213 | for(i=0; i<2; i++) { | ||
214 | ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation | ||
215 | || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation | ||
216 | || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff | ||
217 | || old->u.condition[i].left_coeff != new->u.condition[i].left_coeff | ||
218 | || old->u.condition[i].deadband != new->u.condition[i].deadband | ||
219 | || old->u.condition[i].center != new->u.condition[i].center; | ||
220 | } | ||
221 | return ret; | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Analyse the changes in an effect, and tell if we need to send a magnitude | ||
226 | * parameter packet | ||
227 | */ | ||
228 | static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) | ||
229 | { | ||
230 | int id = effect->id; | ||
231 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
232 | |||
233 | if (effect->type != FF_CONSTANT) { | ||
234 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | ||
235 | return FALSE; | ||
236 | } | ||
237 | |||
238 | return (old->u.constant.level != effect->u.constant.level); | ||
239 | } | ||
240 | |||
241 | /* | ||
242 | * Analyse the changes in an effect, and tell if we need to send an envelope | ||
243 | * parameter packet | ||
244 | */ | ||
245 | static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect) | ||
246 | { | ||
247 | int id = effect->id; | ||
248 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
249 | |||
250 | switch (effect->type) { | ||
251 | case FF_CONSTANT: | ||
252 | if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length | ||
253 | || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level | ||
254 | || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length | ||
255 | || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) | ||
256 | return TRUE; | ||
257 | break; | ||
258 | |||
259 | case FF_PERIODIC: | ||
260 | if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length | ||
261 | || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level | ||
262 | || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length | ||
263 | || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) | ||
264 | return TRUE; | ||
265 | break; | ||
266 | |||
267 | default: | ||
268 | printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | ||
269 | } | ||
270 | |||
271 | return FALSE; | ||
272 | } | ||
273 | |||
274 | /* | ||
275 | * Analyse the changes in an effect, and tell if we need to send a periodic | ||
276 | * parameter effect | ||
277 | */ | ||
278 | static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) | ||
279 | { | ||
280 | int id = new->id; | ||
281 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
282 | |||
283 | if (new->type != FF_PERIODIC) { | ||
284 | printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); | ||
285 | return FALSE; | ||
286 | } | ||
287 | |||
288 | return (old->u.periodic.period != new->u.periodic.period | ||
289 | || old->u.periodic.magnitude != new->u.periodic.magnitude | ||
290 | || old->u.periodic.offset != new->u.periodic.offset | ||
291 | || old->u.periodic.phase != new->u.periodic.phase); | ||
292 | } | ||
293 | |||
294 | /* | ||
295 | * Analyse the changes in an effect, and tell if we need to send an effect | ||
296 | * packet | ||
297 | */ | ||
298 | static int need_core(struct iforce* iforce, struct ff_effect* new) | ||
299 | { | ||
300 | int id = new->id; | ||
301 | struct ff_effect* old = &iforce->core_effects[id].effect; | ||
302 | |||
303 | if (old->direction != new->direction | ||
304 | || old->trigger.button != new->trigger.button | ||
305 | || old->trigger.interval != new->trigger.interval | ||
306 | || old->replay.length != new->replay.length | ||
307 | || old->replay.delay != new->replay.delay) | ||
308 | return TRUE; | ||
309 | |||
310 | return FALSE; | ||
311 | } | ||
312 | /* | ||
313 | * Send the part common to all effects to the device | ||
314 | */ | ||
315 | static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, | ||
316 | u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, | ||
317 | u16 interval, u16 direction) | ||
318 | { | ||
319 | unsigned char data[14]; | ||
320 | |||
321 | duration = TIME_SCALE(duration); | ||
322 | delay = TIME_SCALE(delay); | ||
323 | interval = TIME_SCALE(interval); | ||
324 | |||
325 | data[0] = LO(id); | ||
326 | data[1] = effect_type; | ||
327 | data[2] = LO(axes) | find_button(iforce, button); | ||
328 | |||
329 | data[3] = LO(duration); | ||
330 | data[4] = HI(duration); | ||
331 | |||
332 | data[5] = HI(direction); | ||
333 | |||
334 | data[6] = LO(interval); | ||
335 | data[7] = HI(interval); | ||
336 | |||
337 | data[8] = LO(mod_id1); | ||
338 | data[9] = HI(mod_id1); | ||
339 | data[10] = LO(mod_id2); | ||
340 | data[11] = HI(mod_id2); | ||
341 | |||
342 | data[12] = LO(delay); | ||
343 | data[13] = HI(delay); | ||
344 | |||
345 | /* Stop effect */ | ||
346 | /* iforce_control_playback(iforce, id, 0);*/ | ||
347 | |||
348 | iforce_send_packet(iforce, FF_CMD_EFFECT, data); | ||
349 | |||
350 | /* If needed, restart effect */ | ||
351 | if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { | ||
352 | /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ | ||
353 | iforce_control_playback(iforce, id, 1); | ||
354 | } | ||
355 | |||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | * Upload a periodic effect to the device | ||
361 | * See also iforce_upload_constant. | ||
362 | */ | ||
363 | int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) | ||
364 | { | ||
365 | u8 wave_code; | ||
366 | int core_id = effect->id; | ||
367 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | ||
368 | struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | ||
369 | struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | ||
370 | int param1_err = 1; | ||
371 | int param2_err = 1; | ||
372 | int core_err = 0; | ||
373 | |||
374 | if (!is_update || need_period_modifier(iforce, effect)) { | ||
375 | param1_err = make_period_modifier(iforce, mod1_chunk, | ||
376 | is_update, | ||
377 | effect->u.periodic.magnitude, effect->u.periodic.offset, | ||
378 | effect->u.periodic.period, effect->u.periodic.phase); | ||
379 | if (param1_err) return param1_err; | ||
380 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | ||
381 | } | ||
382 | |||
383 | if (!is_update || need_envelope_modifier(iforce, effect)) { | ||
384 | param2_err = make_envelope_modifier(iforce, mod2_chunk, | ||
385 | is_update, | ||
386 | effect->u.periodic.envelope.attack_length, | ||
387 | effect->u.periodic.envelope.attack_level, | ||
388 | effect->u.periodic.envelope.fade_length, | ||
389 | effect->u.periodic.envelope.fade_level); | ||
390 | if (param2_err) return param2_err; | ||
391 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | ||
392 | } | ||
393 | |||
394 | switch (effect->u.periodic.waveform) { | ||
395 | case FF_SQUARE: wave_code = 0x20; break; | ||
396 | case FF_TRIANGLE: wave_code = 0x21; break; | ||
397 | case FF_SINE: wave_code = 0x22; break; | ||
398 | case FF_SAW_UP: wave_code = 0x23; break; | ||
399 | case FF_SAW_DOWN: wave_code = 0x24; break; | ||
400 | default: wave_code = 0x20; break; | ||
401 | } | ||
402 | |||
403 | if (!is_update || need_core(iforce, effect)) { | ||
404 | core_err = make_core(iforce, effect->id, | ||
405 | mod1_chunk->start, | ||
406 | mod2_chunk->start, | ||
407 | wave_code, | ||
408 | 0x20, | ||
409 | effect->replay.length, | ||
410 | effect->replay.delay, | ||
411 | effect->trigger.button, | ||
412 | effect->trigger.interval, | ||
413 | effect->direction); | ||
414 | } | ||
415 | |||
416 | /* If one of the parameter creation failed, we already returned an | ||
417 | * error code. | ||
418 | * If the core creation failed, we return its error code. | ||
419 | * Else: if one parameter at least was created, we return 0 | ||
420 | * else we return 1; | ||
421 | */ | ||
422 | return core_err < 0 ? core_err : (param1_err && param2_err); | ||
423 | } | ||
424 | |||
425 | /* | ||
426 | * Upload a constant force effect | ||
427 | * Return value: | ||
428 | * <0 Error code | ||
429 | * 0 Ok, effect created or updated | ||
430 | * 1 effect did not change since last upload, and no packet was therefore sent | ||
431 | */ | ||
432 | int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) | ||
433 | { | ||
434 | int core_id = effect->id; | ||
435 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | ||
436 | struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | ||
437 | struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | ||
438 | int param1_err = 1; | ||
439 | int param2_err = 1; | ||
440 | int core_err = 0; | ||
441 | |||
442 | if (!is_update || need_magnitude_modifier(iforce, effect)) { | ||
443 | param1_err = make_magnitude_modifier(iforce, mod1_chunk, | ||
444 | is_update, | ||
445 | effect->u.constant.level); | ||
446 | if (param1_err) return param1_err; | ||
447 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | ||
448 | } | ||
449 | |||
450 | if (!is_update || need_envelope_modifier(iforce, effect)) { | ||
451 | param2_err = make_envelope_modifier(iforce, mod2_chunk, | ||
452 | is_update, | ||
453 | effect->u.constant.envelope.attack_length, | ||
454 | effect->u.constant.envelope.attack_level, | ||
455 | effect->u.constant.envelope.fade_length, | ||
456 | effect->u.constant.envelope.fade_level); | ||
457 | if (param2_err) return param2_err; | ||
458 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | ||
459 | } | ||
460 | |||
461 | if (!is_update || need_core(iforce, effect)) { | ||
462 | core_err = make_core(iforce, effect->id, | ||
463 | mod1_chunk->start, | ||
464 | mod2_chunk->start, | ||
465 | 0x00, | ||
466 | 0x20, | ||
467 | effect->replay.length, | ||
468 | effect->replay.delay, | ||
469 | effect->trigger.button, | ||
470 | effect->trigger.interval, | ||
471 | effect->direction); | ||
472 | } | ||
473 | |||
474 | /* If one of the parameter creation failed, we already returned an | ||
475 | * error code. | ||
476 | * If the core creation failed, we return its error code. | ||
477 | * Else: if one parameter at least was created, we return 0 | ||
478 | * else we return 1; | ||
479 | */ | ||
480 | return core_err < 0 ? core_err : (param1_err && param2_err); | ||
481 | } | ||
482 | |||
483 | /* | ||
484 | * Upload an condition effect. Those are for example friction, inertia, springs... | ||
485 | */ | ||
486 | int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update) | ||
487 | { | ||
488 | int core_id = effect->id; | ||
489 | struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | ||
490 | struct resource* mod1_chunk = &(core_effect->mod1_chunk); | ||
491 | struct resource* mod2_chunk = &(core_effect->mod2_chunk); | ||
492 | u8 type; | ||
493 | int param_err = 1; | ||
494 | int core_err = 0; | ||
495 | |||
496 | switch (effect->type) { | ||
497 | case FF_SPRING: type = 0x40; break; | ||
498 | case FF_DAMPER: type = 0x41; break; | ||
499 | default: return -1; | ||
500 | } | ||
501 | |||
502 | if (!is_update || need_condition_modifier(iforce, effect)) { | ||
503 | param_err = make_condition_modifier(iforce, mod1_chunk, | ||
504 | is_update, | ||
505 | effect->u.condition[0].right_saturation, | ||
506 | effect->u.condition[0].left_saturation, | ||
507 | effect->u.condition[0].right_coeff, | ||
508 | effect->u.condition[0].left_coeff, | ||
509 | effect->u.condition[0].deadband, | ||
510 | effect->u.condition[0].center); | ||
511 | if (param_err) return param_err; | ||
512 | set_bit(FF_MOD1_IS_USED, core_effect->flags); | ||
513 | |||
514 | param_err = make_condition_modifier(iforce, mod2_chunk, | ||
515 | is_update, | ||
516 | effect->u.condition[1].right_saturation, | ||
517 | effect->u.condition[1].left_saturation, | ||
518 | effect->u.condition[1].right_coeff, | ||
519 | effect->u.condition[1].left_coeff, | ||
520 | effect->u.condition[1].deadband, | ||
521 | effect->u.condition[1].center); | ||
522 | if (param_err) return param_err; | ||
523 | set_bit(FF_MOD2_IS_USED, core_effect->flags); | ||
524 | |||
525 | } | ||
526 | |||
527 | if (!is_update || need_core(iforce, effect)) { | ||
528 | core_err = make_core(iforce, effect->id, | ||
529 | mod1_chunk->start, mod2_chunk->start, | ||
530 | type, 0xc0, | ||
531 | effect->replay.length, effect->replay.delay, | ||
532 | effect->trigger.button, effect->trigger.interval, | ||
533 | effect->direction); | ||
534 | } | ||
535 | |||
536 | /* If the parameter creation failed, we already returned an | ||
537 | * error code. | ||
538 | * If the core creation failed, we return its error code. | ||
539 | * Else: if a parameter was created, we return 0 | ||
540 | * else we return 1; | ||
541 | */ | ||
542 | return core_err < 0 ? core_err : param_err; | ||
543 | } | ||
diff --git a/drivers/input/joystick/iforce/iforce-main.c b/drivers/input/joystick/iforce/iforce-main.c new file mode 100644 index 000000000000..028f3513629a --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-main.c | |||
@@ -0,0 +1,557 @@ | |||
1 | /* | ||
2 | * $Id: iforce-main.c,v 1.19 2002/07/07 10:22:50 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
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 | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
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 | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
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: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <deneux@ifrance.com>"); | ||
33 | MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); | ||
34 | MODULE_LICENSE("GPL"); | ||
35 | |||
36 | static signed short btn_joystick[] = | ||
37 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | ||
38 | BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; | ||
39 | |||
40 | static signed short btn_avb_pegasus[] = | ||
41 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | ||
42 | BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; | ||
43 | |||
44 | static signed short btn_wheel[] = | ||
45 | { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | ||
46 | BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; | ||
47 | |||
48 | static signed short btn_avb_tw[] = | ||
49 | { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, | ||
50 | BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; | ||
51 | |||
52 | static signed short btn_avb_wheel[] = | ||
53 | { BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_BASE, BTN_BASE2, BTN_BASE3, | ||
54 | BTN_BASE4, BTN_BASE5, BTN_BASE6, -1 }; | ||
55 | |||
56 | static signed short abs_joystick[] = | ||
57 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; | ||
58 | |||
59 | static signed short abs_avb_pegasus[] = | ||
60 | { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, | ||
61 | ABS_HAT1X, ABS_HAT1Y, -1 }; | ||
62 | |||
63 | static signed short abs_wheel[] = | ||
64 | { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; | ||
65 | |||
66 | static signed short ff_iforce[] = | ||
67 | { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_DAMPER, | ||
68 | FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, | ||
69 | FF_AUTOCENTER, -1 }; | ||
70 | |||
71 | static struct iforce_device iforce_device[] = { | ||
72 | { 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce }, | ||
73 | { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, | ||
74 | { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, | ||
75 | { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_avb_pegasus, abs_avb_pegasus, ff_iforce }, | ||
76 | { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_avb_wheel, abs_wheel, ff_iforce }, | ||
77 | { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, //? | ||
78 | { 0x061c, 0xc0a4, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //? | ||
79 | { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? | ||
80 | { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? | ||
81 | { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } | ||
82 | }; | ||
83 | |||
84 | |||
85 | |||
86 | static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | ||
87 | { | ||
88 | struct iforce* iforce = (struct iforce*)(dev->private); | ||
89 | unsigned char data[3]; | ||
90 | |||
91 | if (type != EV_FF) | ||
92 | return -1; | ||
93 | |||
94 | switch (code) { | ||
95 | |||
96 | case FF_GAIN: | ||
97 | |||
98 | data[0] = value >> 9; | ||
99 | iforce_send_packet(iforce, FF_CMD_GAIN, data); | ||
100 | |||
101 | return 0; | ||
102 | |||
103 | case FF_AUTOCENTER: | ||
104 | |||
105 | data[0] = 0x03; | ||
106 | data[1] = value >> 9; | ||
107 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | ||
108 | |||
109 | data[0] = 0x04; | ||
110 | data[1] = 0x01; | ||
111 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | ||
112 | |||
113 | return 0; | ||
114 | |||
115 | default: /* Play or stop an effect */ | ||
116 | |||
117 | if (!CHECK_OWNERSHIP(code, iforce)) { | ||
118 | return -1; | ||
119 | } | ||
120 | if (value > 0) { | ||
121 | set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | ||
122 | } | ||
123 | else { | ||
124 | clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | ||
125 | } | ||
126 | |||
127 | iforce_control_playback(iforce, code, value); | ||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | return -1; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | * Function called when an ioctl is performed on the event dev entry. | ||
136 | * It uploads an effect to the device | ||
137 | */ | ||
138 | static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | ||
139 | { | ||
140 | struct iforce* iforce = (struct iforce*)(dev->private); | ||
141 | int id; | ||
142 | int ret; | ||
143 | int is_update; | ||
144 | |||
145 | /* Check this effect type is supported by this device */ | ||
146 | if (!test_bit(effect->type, iforce->dev.ffbit)) | ||
147 | return -EINVAL; | ||
148 | |||
149 | /* | ||
150 | * If we want to create a new effect, get a free id | ||
151 | */ | ||
152 | if (effect->id == -1) { | ||
153 | |||
154 | for (id=0; id < FF_EFFECTS_MAX; ++id) | ||
155 | if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; | ||
156 | |||
157 | if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) | ||
158 | return -ENOMEM; | ||
159 | |||
160 | effect->id = id; | ||
161 | iforce->core_effects[id].owner = current->pid; | ||
162 | iforce->core_effects[id].flags[0] = (1<<FF_CORE_IS_USED); /* Only IS_USED bit must be set */ | ||
163 | |||
164 | is_update = FALSE; | ||
165 | } | ||
166 | else { | ||
167 | /* We want to update an effect */ | ||
168 | if (!CHECK_OWNERSHIP(effect->id, iforce)) return -EACCES; | ||
169 | |||
170 | /* Parameter type cannot be updated */ | ||
171 | if (effect->type != iforce->core_effects[effect->id].effect.type) | ||
172 | return -EINVAL; | ||
173 | |||
174 | /* Check the effect is not already being updated */ | ||
175 | if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { | ||
176 | return -EAGAIN; | ||
177 | } | ||
178 | |||
179 | is_update = TRUE; | ||
180 | } | ||
181 | |||
182 | /* | ||
183 | * Upload the effect | ||
184 | */ | ||
185 | switch (effect->type) { | ||
186 | |||
187 | case FF_PERIODIC: | ||
188 | ret = iforce_upload_periodic(iforce, effect, is_update); | ||
189 | break; | ||
190 | |||
191 | case FF_CONSTANT: | ||
192 | ret = iforce_upload_constant(iforce, effect, is_update); | ||
193 | break; | ||
194 | |||
195 | case FF_SPRING: | ||
196 | case FF_DAMPER: | ||
197 | ret = iforce_upload_condition(iforce, effect, is_update); | ||
198 | break; | ||
199 | |||
200 | default: | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | if (ret == 0) { | ||
204 | /* A packet was sent, forbid new updates until we are notified | ||
205 | * that the packet was updated | ||
206 | */ | ||
207 | set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); | ||
208 | } | ||
209 | iforce->core_effects[effect->id].effect = *effect; | ||
210 | return ret; | ||
211 | } | ||
212 | |||
213 | /* | ||
214 | * Erases an effect: it frees the effect id and mark as unused the memory | ||
215 | * allocated for the parameters | ||
216 | */ | ||
217 | static int iforce_erase_effect(struct input_dev *dev, int effect_id) | ||
218 | { | ||
219 | struct iforce* iforce = (struct iforce*)(dev->private); | ||
220 | int err = 0; | ||
221 | struct iforce_core_effect* core_effect; | ||
222 | |||
223 | /* Check who is trying to erase this effect */ | ||
224 | if (iforce->core_effects[effect_id].owner != current->pid) { | ||
225 | printk(KERN_WARNING "iforce-main.c: %d tried to erase an effect belonging to %d\n", current->pid, iforce->core_effects[effect_id].owner); | ||
226 | return -EACCES; | ||
227 | } | ||
228 | |||
229 | if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) | ||
230 | return -EINVAL; | ||
231 | |||
232 | core_effect = iforce->core_effects + effect_id; | ||
233 | |||
234 | if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) | ||
235 | err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); | ||
236 | |||
237 | if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) | ||
238 | err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); | ||
239 | |||
240 | /*TODO: remember to change that if more FF_MOD* bits are added */ | ||
241 | core_effect->flags[0] = 0; | ||
242 | |||
243 | return err; | ||
244 | } | ||
245 | |||
246 | static int iforce_open(struct input_dev *dev) | ||
247 | { | ||
248 | struct iforce *iforce = dev->private; | ||
249 | |||
250 | switch (iforce->bus) { | ||
251 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
252 | case IFORCE_USB: | ||
253 | iforce->irq->dev = iforce->usbdev; | ||
254 | if (usb_submit_urb(iforce->irq, GFP_KERNEL)) | ||
255 | return -EIO; | ||
256 | break; | ||
257 | #endif | ||
258 | } | ||
259 | |||
260 | /* Enable force feedback */ | ||
261 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); | ||
262 | |||
263 | return 0; | ||
264 | } | ||
265 | |||
266 | static int iforce_flush(struct input_dev *dev, struct file *file) | ||
267 | { | ||
268 | struct iforce *iforce = dev->private; | ||
269 | int i; | ||
270 | |||
271 | /* Erase all effects this process owns */ | ||
272 | for (i=0; i<dev->ff_effects_max; ++i) { | ||
273 | |||
274 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | ||
275 | current->pid == iforce->core_effects[i].owner) { | ||
276 | |||
277 | /* Stop effect */ | ||
278 | input_report_ff(dev, i, 0); | ||
279 | |||
280 | /* Free ressources assigned to effect */ | ||
281 | if (iforce_erase_effect(dev, i)) { | ||
282 | printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i); | ||
283 | } | ||
284 | } | ||
285 | |||
286 | } | ||
287 | return 0; | ||
288 | } | ||
289 | |||
290 | static void iforce_release(struct input_dev *dev) | ||
291 | { | ||
292 | struct iforce *iforce = dev->private; | ||
293 | int i; | ||
294 | |||
295 | /* Check: no effect should be present in memory */ | ||
296 | for (i=0; i<dev->ff_effects_max; ++i) { | ||
297 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) | ||
298 | break; | ||
299 | } | ||
300 | if (i<dev->ff_effects_max) { | ||
301 | printk(KERN_WARNING "iforce_release: Device still owns effects\n"); | ||
302 | } | ||
303 | |||
304 | /* Disable force feedback playback */ | ||
305 | iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); | ||
306 | |||
307 | switch (iforce->bus) { | ||
308 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
309 | case IFORCE_USB: | ||
310 | usb_unlink_urb(iforce->irq); | ||
311 | |||
312 | /* The device was unplugged before the file | ||
313 | * was released */ | ||
314 | if (iforce->usbdev == NULL) { | ||
315 | iforce_delete_device(iforce); | ||
316 | kfree(iforce); | ||
317 | } | ||
318 | break; | ||
319 | #endif | ||
320 | } | ||
321 | } | ||
322 | |||
323 | void iforce_delete_device(struct iforce *iforce) | ||
324 | { | ||
325 | switch (iforce->bus) { | ||
326 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
327 | case IFORCE_USB: | ||
328 | iforce_usb_delete(iforce); | ||
329 | break; | ||
330 | #endif | ||
331 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
332 | case IFORCE_232: | ||
333 | //TODO: Wait for the last packets to be sent | ||
334 | break; | ||
335 | #endif | ||
336 | } | ||
337 | } | ||
338 | |||
339 | int iforce_init_device(struct iforce *iforce) | ||
340 | { | ||
341 | unsigned char c[] = "CEOV"; | ||
342 | int i; | ||
343 | |||
344 | init_waitqueue_head(&iforce->wait); | ||
345 | spin_lock_init(&iforce->xmit_lock); | ||
346 | init_MUTEX(&iforce->mem_mutex); | ||
347 | iforce->xmit.buf = iforce->xmit_data; | ||
348 | |||
349 | iforce->dev.ff_effects_max = 10; | ||
350 | |||
351 | /* | ||
352 | * Input device fields. | ||
353 | */ | ||
354 | |||
355 | switch (iforce->bus) { | ||
356 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
357 | case IFORCE_USB: | ||
358 | iforce->dev.id.bustype = BUS_USB; | ||
359 | iforce->dev.dev = &iforce->usbdev->dev; | ||
360 | break; | ||
361 | #endif | ||
362 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
363 | case IFORCE_232: | ||
364 | iforce->dev.id.bustype = BUS_RS232; | ||
365 | iforce->dev.dev = &iforce->serio->dev; | ||
366 | break; | ||
367 | #endif | ||
368 | } | ||
369 | |||
370 | iforce->dev.private = iforce; | ||
371 | iforce->dev.name = "Unknown I-Force device"; | ||
372 | iforce->dev.open = iforce_open; | ||
373 | iforce->dev.close = iforce_release; | ||
374 | iforce->dev.flush = iforce_flush; | ||
375 | iforce->dev.event = iforce_input_event; | ||
376 | iforce->dev.upload_effect = iforce_upload_effect; | ||
377 | iforce->dev.erase_effect = iforce_erase_effect; | ||
378 | |||
379 | /* | ||
380 | * On-device memory allocation. | ||
381 | */ | ||
382 | |||
383 | iforce->device_memory.name = "I-Force device effect memory"; | ||
384 | iforce->device_memory.start = 0; | ||
385 | iforce->device_memory.end = 200; | ||
386 | iforce->device_memory.flags = IORESOURCE_MEM; | ||
387 | iforce->device_memory.parent = NULL; | ||
388 | iforce->device_memory.child = NULL; | ||
389 | iforce->device_memory.sibling = NULL; | ||
390 | |||
391 | /* | ||
392 | * Wait until device ready - until it sends its first response. | ||
393 | */ | ||
394 | |||
395 | for (i = 0; i < 20; i++) | ||
396 | if (!iforce_get_id_packet(iforce, "O")) | ||
397 | break; | ||
398 | |||
399 | if (i == 20) { /* 5 seconds */ | ||
400 | printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n"); | ||
401 | return -1; | ||
402 | } | ||
403 | |||
404 | /* | ||
405 | * Get device info. | ||
406 | */ | ||
407 | |||
408 | if (!iforce_get_id_packet(iforce, "M")) | ||
409 | iforce->dev.id.vendor = (iforce->edata[2] << 8) | iforce->edata[1]; | ||
410 | else | ||
411 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n"); | ||
412 | |||
413 | if (!iforce_get_id_packet(iforce, "P")) | ||
414 | iforce->dev.id.product = (iforce->edata[2] << 8) | iforce->edata[1]; | ||
415 | else | ||
416 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n"); | ||
417 | |||
418 | if (!iforce_get_id_packet(iforce, "B")) | ||
419 | iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; | ||
420 | else | ||
421 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); | ||
422 | |||
423 | if (!iforce_get_id_packet(iforce, "N")) | ||
424 | iforce->dev.ff_effects_max = iforce->edata[1]; | ||
425 | else | ||
426 | printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); | ||
427 | |||
428 | /* Check if the device can store more effects than the driver can really handle */ | ||
429 | if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { | ||
430 | printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", | ||
431 | iforce->dev.ff_effects_max, FF_EFFECTS_MAX); | ||
432 | iforce->dev.ff_effects_max = FF_EFFECTS_MAX; | ||
433 | } | ||
434 | |||
435 | /* | ||
436 | * Display additional info. | ||
437 | */ | ||
438 | |||
439 | for (i = 0; c[i]; i++) | ||
440 | if (!iforce_get_id_packet(iforce, c + i)) | ||
441 | iforce_dump_packet("info", iforce->ecmd, iforce->edata); | ||
442 | |||
443 | /* | ||
444 | * Disable spring, enable force feedback. | ||
445 | * FIXME: We should use iforce_set_autocenter() et al here. | ||
446 | */ | ||
447 | |||
448 | iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); | ||
449 | |||
450 | /* | ||
451 | * Find appropriate device entry | ||
452 | */ | ||
453 | |||
454 | for (i = 0; iforce_device[i].idvendor; i++) | ||
455 | if (iforce_device[i].idvendor == iforce->dev.id.vendor && | ||
456 | iforce_device[i].idproduct == iforce->dev.id.product) | ||
457 | break; | ||
458 | |||
459 | iforce->type = iforce_device + i; | ||
460 | iforce->dev.name = iforce->type->name; | ||
461 | |||
462 | /* | ||
463 | * Set input device bitfields and ranges. | ||
464 | */ | ||
465 | |||
466 | iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); | ||
467 | |||
468 | for (i = 0; iforce->type->btn[i] >= 0; i++) { | ||
469 | signed short t = iforce->type->btn[i]; | ||
470 | set_bit(t, iforce->dev.keybit); | ||
471 | } | ||
472 | set_bit(BTN_DEAD, iforce->dev.keybit); | ||
473 | |||
474 | for (i = 0; iforce->type->abs[i] >= 0; i++) { | ||
475 | |||
476 | signed short t = iforce->type->abs[i]; | ||
477 | set_bit(t, iforce->dev.absbit); | ||
478 | |||
479 | switch (t) { | ||
480 | |||
481 | case ABS_X: | ||
482 | case ABS_Y: | ||
483 | case ABS_WHEEL: | ||
484 | |||
485 | iforce->dev.absmax[t] = 1920; | ||
486 | iforce->dev.absmin[t] = -1920; | ||
487 | iforce->dev.absflat[t] = 128; | ||
488 | iforce->dev.absfuzz[t] = 16; | ||
489 | |||
490 | set_bit(t, iforce->dev.ffbit); | ||
491 | break; | ||
492 | |||
493 | case ABS_THROTTLE: | ||
494 | case ABS_GAS: | ||
495 | case ABS_BRAKE: | ||
496 | |||
497 | iforce->dev.absmax[t] = 255; | ||
498 | iforce->dev.absmin[t] = 0; | ||
499 | break; | ||
500 | |||
501 | case ABS_RUDDER: | ||
502 | |||
503 | iforce->dev.absmax[t] = 127; | ||
504 | iforce->dev.absmin[t] = -128; | ||
505 | break; | ||
506 | |||
507 | case ABS_HAT0X: | ||
508 | case ABS_HAT0Y: | ||
509 | case ABS_HAT1X: | ||
510 | case ABS_HAT1Y: | ||
511 | iforce->dev.absmax[t] = 1; | ||
512 | iforce->dev.absmin[t] = -1; | ||
513 | break; | ||
514 | } | ||
515 | } | ||
516 | |||
517 | for (i = 0; iforce->type->ff[i] >= 0; i++) | ||
518 | set_bit(iforce->type->ff[i], iforce->dev.ffbit); | ||
519 | |||
520 | /* | ||
521 | * Register input device. | ||
522 | */ | ||
523 | |||
524 | input_register_device(&iforce->dev); | ||
525 | |||
526 | printk(KERN_DEBUG "iforce->dev.open = %p\n", iforce->dev.open); | ||
527 | |||
528 | printk(KERN_INFO "input: %s [%d effects, %ld bytes memory]\n", | ||
529 | iforce->dev.name, iforce->dev.ff_effects_max, | ||
530 | iforce->device_memory.end); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int __init iforce_init(void) | ||
536 | { | ||
537 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
538 | usb_register(&iforce_usb_driver); | ||
539 | #endif | ||
540 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
541 | serio_register_driver(&iforce_serio_drv); | ||
542 | #endif | ||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | static void __exit iforce_exit(void) | ||
547 | { | ||
548 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
549 | usb_deregister(&iforce_usb_driver); | ||
550 | #endif | ||
551 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
552 | serio_unregister_driver(&iforce_serio_drv); | ||
553 | #endif | ||
554 | } | ||
555 | |||
556 | module_init(iforce_init); | ||
557 | module_exit(iforce_exit); | ||
diff --git a/drivers/input/joystick/iforce/iforce-packets.c b/drivers/input/joystick/iforce/iforce-packets.c new file mode 100644 index 000000000000..58728ebaaf80 --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-packets.c | |||
@@ -0,0 +1,319 @@ | |||
1 | /* | ||
2 | * $Id: iforce-packets.c,v 1.16 2002/07/07 10:22:50 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
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 | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
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 | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
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: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | static struct { | ||
33 | __s32 x; | ||
34 | __s32 y; | ||
35 | } iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | ||
36 | |||
37 | |||
38 | void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) | ||
39 | { | ||
40 | int i; | ||
41 | |||
42 | printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); | ||
43 | for (i = 0; i < LO(cmd); i++) | ||
44 | printk("%02x ", data[i]); | ||
45 | printk(")\n"); | ||
46 | } | ||
47 | |||
48 | /* | ||
49 | * Send a packet of bytes to the device | ||
50 | */ | ||
51 | int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) | ||
52 | { | ||
53 | /* Copy data to buffer */ | ||
54 | int n = LO(cmd); | ||
55 | int c; | ||
56 | int empty; | ||
57 | int head, tail; | ||
58 | unsigned long flags; | ||
59 | |||
60 | /* | ||
61 | * Update head and tail of xmit buffer | ||
62 | */ | ||
63 | spin_lock_irqsave(&iforce->xmit_lock, flags); | ||
64 | |||
65 | head = iforce->xmit.head; | ||
66 | tail = iforce->xmit.tail; | ||
67 | |||
68 | if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { | ||
69 | printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n"); | ||
70 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
71 | return -1; | ||
72 | } | ||
73 | |||
74 | empty = head == tail; | ||
75 | XMIT_INC(iforce->xmit.head, n+2); | ||
76 | |||
77 | /* | ||
78 | * Store packet in xmit buffer | ||
79 | */ | ||
80 | iforce->xmit.buf[head] = HI(cmd); | ||
81 | XMIT_INC(head, 1); | ||
82 | iforce->xmit.buf[head] = LO(cmd); | ||
83 | XMIT_INC(head, 1); | ||
84 | |||
85 | c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); | ||
86 | if (n < c) c=n; | ||
87 | |||
88 | memcpy(&iforce->xmit.buf[head], | ||
89 | data, | ||
90 | c); | ||
91 | if (n != c) { | ||
92 | memcpy(&iforce->xmit.buf[0], | ||
93 | data + c, | ||
94 | n - c); | ||
95 | } | ||
96 | XMIT_INC(head, n); | ||
97 | |||
98 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
99 | /* | ||
100 | * If necessary, start the transmission | ||
101 | */ | ||
102 | switch (iforce->bus) { | ||
103 | |||
104 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
105 | case IFORCE_232: | ||
106 | if (empty) | ||
107 | iforce_serial_xmit(iforce); | ||
108 | break; | ||
109 | #endif | ||
110 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
111 | case IFORCE_USB: | ||
112 | |||
113 | if (iforce->usbdev && empty && | ||
114 | !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { | ||
115 | |||
116 | iforce_usb_xmit(iforce); | ||
117 | } | ||
118 | break; | ||
119 | #endif | ||
120 | } | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | /* Start or stop an effect */ | ||
125 | int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) | ||
126 | { | ||
127 | unsigned char data[3]; | ||
128 | |||
129 | printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); | ||
130 | |||
131 | data[0] = LO(id); | ||
132 | data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; | ||
133 | data[2] = LO(value); | ||
134 | return iforce_send_packet(iforce, FF_CMD_PLAY, data); | ||
135 | } | ||
136 | |||
137 | /* Mark an effect that was being updated as ready. That means it can be updated | ||
138 | * again */ | ||
139 | static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) | ||
140 | { | ||
141 | int i; | ||
142 | for (i=0; i<iforce->dev.ff_effects_max; ++i) { | ||
143 | if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | ||
144 | (iforce->core_effects[i].mod1_chunk.start == addr || | ||
145 | iforce->core_effects[i].mod2_chunk.start == addr)) { | ||
146 | clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags); | ||
147 | return 0; | ||
148 | } | ||
149 | } | ||
150 | printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr); | ||
151 | return -1; | ||
152 | } | ||
153 | |||
154 | void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs) | ||
155 | { | ||
156 | struct input_dev *dev = &iforce->dev; | ||
157 | int i; | ||
158 | static int being_used = 0; | ||
159 | |||
160 | if (being_used) | ||
161 | printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used); | ||
162 | being_used++; | ||
163 | |||
164 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
165 | if (HI(iforce->expect_packet) == HI(cmd)) { | ||
166 | iforce->expect_packet = 0; | ||
167 | iforce->ecmd = cmd; | ||
168 | memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); | ||
169 | wake_up(&iforce->wait); | ||
170 | } | ||
171 | #endif | ||
172 | |||
173 | if (!iforce->type) { | ||
174 | being_used--; | ||
175 | return; | ||
176 | } | ||
177 | |||
178 | switch (HI(cmd)) { | ||
179 | |||
180 | case 0x01: /* joystick position data */ | ||
181 | case 0x03: /* wheel position data */ | ||
182 | |||
183 | input_regs(dev, regs); | ||
184 | |||
185 | if (HI(cmd) == 1) { | ||
186 | input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); | ||
187 | input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); | ||
188 | input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); | ||
189 | if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) | ||
190 | input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); | ||
191 | } else { | ||
192 | input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); | ||
193 | input_report_abs(dev, ABS_GAS, 255 - data[2]); | ||
194 | input_report_abs(dev, ABS_BRAKE, 255 - data[3]); | ||
195 | } | ||
196 | |||
197 | input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); | ||
198 | input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); | ||
199 | |||
200 | for (i = 0; iforce->type->btn[i] >= 0; i++) | ||
201 | input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); | ||
202 | |||
203 | /* If there are untouched bits left, interpret them as the second hat */ | ||
204 | if (i <= 8) { | ||
205 | int btns = data[6]; | ||
206 | if (test_bit(ABS_HAT1X, dev->absbit)) { | ||
207 | if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1); | ||
208 | else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1); | ||
209 | else input_report_abs(dev, ABS_HAT1X, 0); | ||
210 | } | ||
211 | if (test_bit(ABS_HAT1Y, dev->absbit)) { | ||
212 | if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1); | ||
213 | else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1); | ||
214 | else input_report_abs(dev, ABS_HAT1Y, 0); | ||
215 | } | ||
216 | } | ||
217 | |||
218 | input_sync(dev); | ||
219 | |||
220 | break; | ||
221 | |||
222 | case 0x02: /* status report */ | ||
223 | input_regs(dev, regs); | ||
224 | input_report_key(dev, BTN_DEAD, data[0] & 0x02); | ||
225 | input_sync(dev); | ||
226 | |||
227 | /* Check if an effect was just started or stopped */ | ||
228 | i = data[1] & 0x7f; | ||
229 | if (data[1] & 0x80) { | ||
230 | if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | ||
231 | /* Report play event */ | ||
232 | input_report_ff_status(dev, i, FF_STATUS_PLAYING); | ||
233 | } | ||
234 | } | ||
235 | else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | ||
236 | /* Report stop event */ | ||
237 | input_report_ff_status(dev, i, FF_STATUS_STOPPED); | ||
238 | } | ||
239 | if (LO(cmd) > 3) { | ||
240 | int j; | ||
241 | for (j=3; j<LO(cmd); j+=2) { | ||
242 | mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); | ||
243 | } | ||
244 | } | ||
245 | break; | ||
246 | } | ||
247 | being_used--; | ||
248 | } | ||
249 | |||
250 | int iforce_get_id_packet(struct iforce *iforce, char *packet) | ||
251 | { | ||
252 | DECLARE_WAITQUEUE(wait, current); | ||
253 | int timeout = HZ; /* 1 second */ | ||
254 | |||
255 | switch (iforce->bus) { | ||
256 | |||
257 | case IFORCE_USB: | ||
258 | |||
259 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
260 | iforce->cr.bRequest = packet[0]; | ||
261 | iforce->ctrl->dev = iforce->usbdev; | ||
262 | |||
263 | set_current_state(TASK_INTERRUPTIBLE); | ||
264 | add_wait_queue(&iforce->wait, &wait); | ||
265 | |||
266 | if (usb_submit_urb(iforce->ctrl, GFP_ATOMIC)) { | ||
267 | set_current_state(TASK_RUNNING); | ||
268 | remove_wait_queue(&iforce->wait, &wait); | ||
269 | return -1; | ||
270 | } | ||
271 | |||
272 | while (timeout && iforce->ctrl->status == -EINPROGRESS) | ||
273 | timeout = schedule_timeout(timeout); | ||
274 | |||
275 | set_current_state(TASK_RUNNING); | ||
276 | remove_wait_queue(&iforce->wait, &wait); | ||
277 | |||
278 | if (!timeout) { | ||
279 | usb_unlink_urb(iforce->ctrl); | ||
280 | return -1; | ||
281 | } | ||
282 | #else | ||
283 | printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n"); | ||
284 | #endif | ||
285 | break; | ||
286 | |||
287 | case IFORCE_232: | ||
288 | |||
289 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
290 | iforce->expect_packet = FF_CMD_QUERY; | ||
291 | iforce_send_packet(iforce, FF_CMD_QUERY, packet); | ||
292 | |||
293 | set_current_state(TASK_INTERRUPTIBLE); | ||
294 | add_wait_queue(&iforce->wait, &wait); | ||
295 | |||
296 | while (timeout && iforce->expect_packet) | ||
297 | timeout = schedule_timeout(timeout); | ||
298 | |||
299 | set_current_state(TASK_RUNNING); | ||
300 | remove_wait_queue(&iforce->wait, &wait); | ||
301 | |||
302 | if (!timeout) { | ||
303 | iforce->expect_packet = 0; | ||
304 | return -1; | ||
305 | } | ||
306 | #else | ||
307 | printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n"); | ||
308 | #endif | ||
309 | break; | ||
310 | |||
311 | default: | ||
312 | printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n", | ||
313 | iforce->bus); | ||
314 | break; | ||
315 | } | ||
316 | |||
317 | return -(iforce->edata[0] != packet[0]); | ||
318 | } | ||
319 | |||
diff --git a/drivers/input/joystick/iforce/iforce-serio.c b/drivers/input/joystick/iforce/iforce-serio.c new file mode 100644 index 000000000000..11f51905cba7 --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-serio.c | |||
@@ -0,0 +1,193 @@ | |||
1 | /* | ||
2 | * $Id: iforce-serio.c,v 1.4 2002/01/28 22:45:00 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
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 | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
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 | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
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: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | void iforce_serial_xmit(struct iforce *iforce) | ||
33 | { | ||
34 | unsigned char cs; | ||
35 | int i; | ||
36 | unsigned long flags; | ||
37 | |||
38 | if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { | ||
39 | set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); | ||
40 | return; | ||
41 | } | ||
42 | |||
43 | spin_lock_irqsave(&iforce->xmit_lock, flags); | ||
44 | |||
45 | again: | ||
46 | if (iforce->xmit.head == iforce->xmit.tail) { | ||
47 | clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | ||
48 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
49 | return; | ||
50 | } | ||
51 | |||
52 | cs = 0x2b; | ||
53 | |||
54 | serio_write(iforce->serio, 0x2b); | ||
55 | |||
56 | serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); | ||
57 | cs ^= iforce->xmit.buf[iforce->xmit.tail]; | ||
58 | XMIT_INC(iforce->xmit.tail, 1); | ||
59 | |||
60 | for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { | ||
61 | serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); | ||
62 | cs ^= iforce->xmit.buf[iforce->xmit.tail]; | ||
63 | XMIT_INC(iforce->xmit.tail, 1); | ||
64 | } | ||
65 | |||
66 | serio_write(iforce->serio, cs); | ||
67 | |||
68 | if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) | ||
69 | goto again; | ||
70 | |||
71 | clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | ||
72 | |||
73 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
74 | } | ||
75 | |||
76 | static void iforce_serio_write_wakeup(struct serio *serio) | ||
77 | { | ||
78 | struct iforce *iforce = serio_get_drvdata(serio); | ||
79 | |||
80 | iforce_serial_xmit(iforce); | ||
81 | } | ||
82 | |||
83 | static irqreturn_t iforce_serio_irq(struct serio *serio, | ||
84 | unsigned char data, unsigned int flags, struct pt_regs *regs) | ||
85 | { | ||
86 | struct iforce *iforce = serio_get_drvdata(serio); | ||
87 | |||
88 | if (!iforce->pkt) { | ||
89 | if (data == 0x2b) | ||
90 | iforce->pkt = 1; | ||
91 | goto out; | ||
92 | } | ||
93 | |||
94 | if (!iforce->id) { | ||
95 | if (data > 3 && data != 0xff) | ||
96 | iforce->pkt = 0; | ||
97 | else | ||
98 | iforce->id = data; | ||
99 | goto out; | ||
100 | } | ||
101 | |||
102 | if (!iforce->len) { | ||
103 | if (data > IFORCE_MAX_LENGTH) { | ||
104 | iforce->pkt = 0; | ||
105 | iforce->id = 0; | ||
106 | } else { | ||
107 | iforce->len = data; | ||
108 | } | ||
109 | goto out; | ||
110 | } | ||
111 | |||
112 | if (iforce->idx < iforce->len) { | ||
113 | iforce->csum += iforce->data[iforce->idx++] = data; | ||
114 | goto out; | ||
115 | } | ||
116 | |||
117 | if (iforce->idx == iforce->len) { | ||
118 | iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data, regs); | ||
119 | iforce->pkt = 0; | ||
120 | iforce->id = 0; | ||
121 | iforce->len = 0; | ||
122 | iforce->idx = 0; | ||
123 | iforce->csum = 0; | ||
124 | } | ||
125 | out: | ||
126 | return IRQ_HANDLED; | ||
127 | } | ||
128 | |||
129 | static int iforce_serio_connect(struct serio *serio, struct serio_driver *drv) | ||
130 | { | ||
131 | struct iforce *iforce; | ||
132 | int err; | ||
133 | |||
134 | if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) | ||
135 | return -ENOMEM; | ||
136 | |||
137 | memset(iforce, 0, sizeof(struct iforce)); | ||
138 | |||
139 | iforce->bus = IFORCE_232; | ||
140 | iforce->serio = serio; | ||
141 | |||
142 | serio_set_drvdata(serio, iforce); | ||
143 | |||
144 | err = serio_open(serio, drv); | ||
145 | if (err) { | ||
146 | serio_set_drvdata(serio, NULL); | ||
147 | kfree(iforce); | ||
148 | return err; | ||
149 | } | ||
150 | |||
151 | if (iforce_init_device(iforce)) { | ||
152 | serio_close(serio); | ||
153 | serio_set_drvdata(serio, NULL); | ||
154 | kfree(iforce); | ||
155 | return -ENODEV; | ||
156 | } | ||
157 | |||
158 | return 0; | ||
159 | } | ||
160 | |||
161 | static void iforce_serio_disconnect(struct serio *serio) | ||
162 | { | ||
163 | struct iforce *iforce = serio_get_drvdata(serio); | ||
164 | |||
165 | input_unregister_device(&iforce->dev); | ||
166 | serio_close(serio); | ||
167 | serio_set_drvdata(serio, NULL); | ||
168 | kfree(iforce); | ||
169 | } | ||
170 | |||
171 | static struct serio_device_id iforce_serio_ids[] = { | ||
172 | { | ||
173 | .type = SERIO_RS232, | ||
174 | .proto = SERIO_IFORCE, | ||
175 | .id = SERIO_ANY, | ||
176 | .extra = SERIO_ANY, | ||
177 | }, | ||
178 | { 0 } | ||
179 | }; | ||
180 | |||
181 | MODULE_DEVICE_TABLE(serio, iforce_serio_ids); | ||
182 | |||
183 | struct serio_driver iforce_serio_drv = { | ||
184 | .driver = { | ||
185 | .name = "iforce", | ||
186 | }, | ||
187 | .description = "RS232 I-Force joysticks and wheels driver", | ||
188 | .id_table = iforce_serio_ids, | ||
189 | .write_wakeup = iforce_serio_write_wakeup, | ||
190 | .interrupt = iforce_serio_irq, | ||
191 | .connect = iforce_serio_connect, | ||
192 | .disconnect = iforce_serio_disconnect, | ||
193 | }; | ||
diff --git a/drivers/input/joystick/iforce/iforce-usb.c b/drivers/input/joystick/iforce/iforce-usb.c new file mode 100644 index 000000000000..617c0b0e5a39 --- /dev/null +++ b/drivers/input/joystick/iforce/iforce-usb.c | |||
@@ -0,0 +1,243 @@ | |||
1 | /* | ||
2 | * $Id: iforce-usb.c,v 1.16 2002/06/09 11:08:04 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
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 | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
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 | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
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: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include "iforce.h" | ||
31 | |||
32 | void iforce_usb_xmit(struct iforce *iforce) | ||
33 | { | ||
34 | int n, c; | ||
35 | unsigned long flags; | ||
36 | |||
37 | spin_lock_irqsave(&iforce->xmit_lock, flags); | ||
38 | |||
39 | if (iforce->xmit.head == iforce->xmit.tail) { | ||
40 | clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | ||
41 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
42 | return; | ||
43 | } | ||
44 | |||
45 | ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; | ||
46 | XMIT_INC(iforce->xmit.tail, 1); | ||
47 | n = iforce->xmit.buf[iforce->xmit.tail]; | ||
48 | XMIT_INC(iforce->xmit.tail, 1); | ||
49 | |||
50 | iforce->out->transfer_buffer_length = n + 1; | ||
51 | iforce->out->dev = iforce->usbdev; | ||
52 | |||
53 | /* Copy rest of data then */ | ||
54 | c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); | ||
55 | if (n < c) c=n; | ||
56 | |||
57 | memcpy(iforce->out->transfer_buffer + 1, | ||
58 | &iforce->xmit.buf[iforce->xmit.tail], | ||
59 | c); | ||
60 | if (n != c) { | ||
61 | memcpy(iforce->out->transfer_buffer + 1 + c, | ||
62 | &iforce->xmit.buf[0], | ||
63 | n-c); | ||
64 | } | ||
65 | XMIT_INC(iforce->xmit.tail, n); | ||
66 | |||
67 | if ( (n=usb_submit_urb(iforce->out, GFP_ATOMIC)) ) { | ||
68 | printk(KERN_WARNING "iforce-usb.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n); | ||
69 | } | ||
70 | |||
71 | /* The IFORCE_XMIT_RUNNING bit is not cleared here. That's intended. | ||
72 | * As long as the urb completion handler is not called, the transmiting | ||
73 | * is considered to be running */ | ||
74 | spin_unlock_irqrestore(&iforce->xmit_lock, flags); | ||
75 | } | ||
76 | |||
77 | static void iforce_usb_irq(struct urb *urb, struct pt_regs *regs) | ||
78 | { | ||
79 | struct iforce *iforce = urb->context; | ||
80 | int status; | ||
81 | |||
82 | switch (urb->status) { | ||
83 | case 0: | ||
84 | /* success */ | ||
85 | break; | ||
86 | case -ECONNRESET: | ||
87 | case -ENOENT: | ||
88 | case -ESHUTDOWN: | ||
89 | /* this urb is terminated, clean up */ | ||
90 | dbg("%s - urb shutting down with status: %d", | ||
91 | __FUNCTION__, urb->status); | ||
92 | return; | ||
93 | default: | ||
94 | dbg("%s - urb has status of: %d", __FUNCTION__, urb->status); | ||
95 | goto exit; | ||
96 | } | ||
97 | |||
98 | iforce_process_packet(iforce, | ||
99 | (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1, regs); | ||
100 | |||
101 | exit: | ||
102 | status = usb_submit_urb (urb, GFP_ATOMIC); | ||
103 | if (status) | ||
104 | err ("%s - usb_submit_urb failed with result %d", | ||
105 | __FUNCTION__, status); | ||
106 | } | ||
107 | |||
108 | static void iforce_usb_out(struct urb *urb, struct pt_regs *regs) | ||
109 | { | ||
110 | struct iforce *iforce = urb->context; | ||
111 | |||
112 | if (urb->status) { | ||
113 | printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status); | ||
114 | return; | ||
115 | } | ||
116 | |||
117 | iforce_usb_xmit(iforce); | ||
118 | |||
119 | wake_up(&iforce->wait); | ||
120 | } | ||
121 | |||
122 | static void iforce_usb_ctrl(struct urb *urb, struct pt_regs *regs) | ||
123 | { | ||
124 | struct iforce *iforce = urb->context; | ||
125 | if (urb->status) return; | ||
126 | iforce->ecmd = 0xff00 | urb->actual_length; | ||
127 | wake_up(&iforce->wait); | ||
128 | } | ||
129 | |||
130 | static int iforce_usb_probe(struct usb_interface *intf, | ||
131 | const struct usb_device_id *id) | ||
132 | { | ||
133 | struct usb_device *dev = interface_to_usbdev(intf); | ||
134 | struct usb_host_interface *interface; | ||
135 | struct usb_endpoint_descriptor *epirq, *epout; | ||
136 | struct iforce *iforce; | ||
137 | |||
138 | interface = intf->cur_altsetting; | ||
139 | |||
140 | epirq = &interface->endpoint[0].desc; | ||
141 | epout = &interface->endpoint[1].desc; | ||
142 | |||
143 | if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) | ||
144 | goto fail; | ||
145 | |||
146 | memset(iforce, 0, sizeof(struct iforce)); | ||
147 | |||
148 | if (!(iforce->irq = usb_alloc_urb(0, GFP_KERNEL))) { | ||
149 | goto fail; | ||
150 | } | ||
151 | |||
152 | if (!(iforce->out = usb_alloc_urb(0, GFP_KERNEL))) { | ||
153 | goto fail; | ||
154 | } | ||
155 | |||
156 | if (!(iforce->ctrl = usb_alloc_urb(0, GFP_KERNEL))) { | ||
157 | goto fail; | ||
158 | } | ||
159 | |||
160 | iforce->bus = IFORCE_USB; | ||
161 | iforce->usbdev = dev; | ||
162 | |||
163 | iforce->cr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; | ||
164 | iforce->cr.wIndex = 0; | ||
165 | iforce->cr.wLength = 16; | ||
166 | |||
167 | usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), | ||
168 | iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); | ||
169 | |||
170 | usb_fill_bulk_urb(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), | ||
171 | iforce + 1, 32, iforce_usb_out, iforce); | ||
172 | |||
173 | usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), | ||
174 | (void*) &iforce->cr, iforce->edata, 16, iforce_usb_ctrl, iforce); | ||
175 | |||
176 | if (iforce_init_device(iforce)) goto fail; | ||
177 | |||
178 | usb_set_intfdata(intf, iforce); | ||
179 | return 0; | ||
180 | |||
181 | fail: | ||
182 | if (iforce) { | ||
183 | if (iforce->irq) usb_free_urb(iforce->irq); | ||
184 | if (iforce->out) usb_free_urb(iforce->out); | ||
185 | if (iforce->ctrl) usb_free_urb(iforce->ctrl); | ||
186 | kfree(iforce); | ||
187 | } | ||
188 | |||
189 | return -ENODEV; | ||
190 | } | ||
191 | |||
192 | /* Called by iforce_delete() */ | ||
193 | void iforce_usb_delete(struct iforce* iforce) | ||
194 | { | ||
195 | usb_unlink_urb(iforce->irq); | ||
196 | /* Is it ok to unlink those ? */ | ||
197 | usb_unlink_urb(iforce->out); | ||
198 | usb_unlink_urb(iforce->ctrl); | ||
199 | |||
200 | usb_free_urb(iforce->irq); | ||
201 | usb_free_urb(iforce->out); | ||
202 | usb_free_urb(iforce->ctrl); | ||
203 | } | ||
204 | |||
205 | static void iforce_usb_disconnect(struct usb_interface *intf) | ||
206 | { | ||
207 | struct iforce *iforce = usb_get_intfdata(intf); | ||
208 | int open = 0; /* FIXME! iforce->dev.handle->open; */ | ||
209 | |||
210 | usb_set_intfdata(intf, NULL); | ||
211 | if (iforce) { | ||
212 | iforce->usbdev = NULL; | ||
213 | input_unregister_device(&iforce->dev); | ||
214 | |||
215 | if (!open) { | ||
216 | iforce_delete_device(iforce); | ||
217 | kfree(iforce); | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
222 | static struct usb_device_id iforce_usb_ids [] = { | ||
223 | { USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */ | ||
224 | { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ | ||
225 | { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ | ||
226 | { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ | ||
227 | { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ | ||
228 | { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ | ||
229 | { USB_DEVICE(0x061c, 0xc0a4) }, /* ACT LABS Force RS */ | ||
230 | { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ | ||
231 | { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ | ||
232 | { } /* Terminating entry */ | ||
233 | }; | ||
234 | |||
235 | MODULE_DEVICE_TABLE (usb, iforce_usb_ids); | ||
236 | |||
237 | struct usb_driver iforce_usb_driver = { | ||
238 | .owner = THIS_MODULE, | ||
239 | .name = "iforce", | ||
240 | .probe = iforce_usb_probe, | ||
241 | .disconnect = iforce_usb_disconnect, | ||
242 | .id_table = iforce_usb_ids, | ||
243 | }; | ||
diff --git a/drivers/input/joystick/iforce/iforce.h b/drivers/input/joystick/iforce/iforce.h new file mode 100644 index 000000000000..bce247bc300b --- /dev/null +++ b/drivers/input/joystick/iforce/iforce.h | |||
@@ -0,0 +1,191 @@ | |||
1 | /* | ||
2 | * $Id: iforce.h,v 1.13 2002/07/07 10:22:50 jdeneux Exp $ | ||
3 | * | ||
4 | * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | ||
5 | * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | ||
6 | * | ||
7 | * USB/RS232 I-Force joysticks and wheels. | ||
8 | */ | ||
9 | |||
10 | /* | ||
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 | ||
13 | * the Free Software Foundation; either version 2 of the License, or | ||
14 | * (at your option) any later version. | ||
15 | * | ||
16 | * This program is distributed in the hope that it will be useful, | ||
17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
19 | * GNU General Public License for more details. | ||
20 | * | ||
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 | ||
23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
24 | * | ||
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: | ||
27 | * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | ||
28 | */ | ||
29 | |||
30 | #include <linux/kernel.h> | ||
31 | #include <linux/slab.h> | ||
32 | #include <linux/input.h> | ||
33 | #include <linux/module.h> | ||
34 | #include <linux/init.h> | ||
35 | #include <linux/spinlock.h> | ||
36 | #include <linux/usb.h> | ||
37 | #include <linux/serio.h> | ||
38 | #include <linux/config.h> | ||
39 | #include <linux/circ_buf.h> | ||
40 | #include <asm/semaphore.h> | ||
41 | |||
42 | /* This module provides arbitrary resource management routines. | ||
43 | * I use it to manage the device's memory. | ||
44 | * Despite the name of this module, I am *not* going to access the ioports. | ||
45 | */ | ||
46 | #include <linux/ioport.h> | ||
47 | |||
48 | #define IFORCE_MAX_LENGTH 16 | ||
49 | |||
50 | /* iforce::bus */ | ||
51 | #define IFORCE_232 1 | ||
52 | #define IFORCE_USB 2 | ||
53 | |||
54 | #define FALSE 0 | ||
55 | #define TRUE 1 | ||
56 | |||
57 | #define FF_EFFECTS_MAX 32 | ||
58 | |||
59 | /* Each force feedback effect is made of one core effect, which can be | ||
60 | * associated to at most to effect modifiers | ||
61 | */ | ||
62 | #define FF_MOD1_IS_USED 0 | ||
63 | #define FF_MOD2_IS_USED 1 | ||
64 | #define FF_CORE_IS_USED 2 | ||
65 | #define FF_CORE_IS_PLAYED 3 /* Effect is currently being played */ | ||
66 | #define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */ | ||
67 | #define FF_CORE_UPDATE 5 /* Effect is being updated */ | ||
68 | #define FF_MODCORE_MAX 5 | ||
69 | |||
70 | #define CHECK_OWNERSHIP(i, iforce) \ | ||
71 | ((i) < FF_EFFECTS_MAX && i >= 0 && \ | ||
72 | test_bit(FF_CORE_IS_USED, (iforce)->core_effects[(i)].flags) && \ | ||
73 | (current->pid == 0 || \ | ||
74 | (iforce)->core_effects[(i)].owner == current->pid)) | ||
75 | |||
76 | struct iforce_core_effect { | ||
77 | /* Information about where modifiers are stored in the device's memory */ | ||
78 | struct resource mod1_chunk; | ||
79 | struct resource mod2_chunk; | ||
80 | unsigned long flags[NBITS(FF_MODCORE_MAX)]; | ||
81 | pid_t owner; | ||
82 | /* Used to keep track of parameters of an effect. They are needed | ||
83 | * to know what parts of an effect changed in an update operation. | ||
84 | * We try to send only parameter packets if possible, as sending | ||
85 | * effect parameter requires the effect to be stoped and restarted | ||
86 | */ | ||
87 | struct ff_effect effect; | ||
88 | }; | ||
89 | |||
90 | #define FF_CMD_EFFECT 0x010e | ||
91 | #define FF_CMD_ENVELOPE 0x0208 | ||
92 | #define FF_CMD_MAGNITUDE 0x0303 | ||
93 | #define FF_CMD_PERIOD 0x0407 | ||
94 | #define FF_CMD_CONDITION 0x050a | ||
95 | |||
96 | #define FF_CMD_AUTOCENTER 0x4002 | ||
97 | #define FF_CMD_PLAY 0x4103 | ||
98 | #define FF_CMD_ENABLE 0x4201 | ||
99 | #define FF_CMD_GAIN 0x4301 | ||
100 | |||
101 | #define FF_CMD_QUERY 0xff01 | ||
102 | |||
103 | /* Buffer for async write */ | ||
104 | #define XMIT_SIZE 256 | ||
105 | #define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1 | ||
106 | /* iforce::xmit_flags */ | ||
107 | #define IFORCE_XMIT_RUNNING 0 | ||
108 | #define IFORCE_XMIT_AGAIN 1 | ||
109 | |||
110 | struct iforce_device { | ||
111 | u16 idvendor; | ||
112 | u16 idproduct; | ||
113 | char *name; | ||
114 | signed short *btn; | ||
115 | signed short *abs; | ||
116 | signed short *ff; | ||
117 | }; | ||
118 | |||
119 | struct iforce { | ||
120 | struct input_dev dev; /* Input device interface */ | ||
121 | struct iforce_device *type; | ||
122 | int bus; | ||
123 | |||
124 | unsigned char data[IFORCE_MAX_LENGTH]; | ||
125 | unsigned char edata[IFORCE_MAX_LENGTH]; | ||
126 | u16 ecmd; | ||
127 | u16 expect_packet; | ||
128 | |||
129 | #ifdef CONFIG_JOYSTICK_IFORCE_232 | ||
130 | struct serio *serio; /* RS232 transfer */ | ||
131 | int idx, pkt, len, id; | ||
132 | unsigned char csum; | ||
133 | #endif | ||
134 | #ifdef CONFIG_JOYSTICK_IFORCE_USB | ||
135 | struct usb_device *usbdev; /* USB transfer */ | ||
136 | struct urb *irq, *out, *ctrl; | ||
137 | struct usb_ctrlrequest cr; | ||
138 | #endif | ||
139 | spinlock_t xmit_lock; | ||
140 | /* Buffer used for asynchronous sending of bytes to the device */ | ||
141 | struct circ_buf xmit; | ||
142 | unsigned char xmit_data[XMIT_SIZE]; | ||
143 | long xmit_flags[1]; | ||
144 | |||
145 | /* Force Feedback */ | ||
146 | wait_queue_head_t wait; | ||
147 | struct resource device_memory; | ||
148 | struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; | ||
149 | struct semaphore mem_mutex; | ||
150 | }; | ||
151 | |||
152 | /* Get hi and low bytes of a 16-bits int */ | ||
153 | #define HI(a) ((unsigned char)((a) >> 8)) | ||
154 | #define LO(a) ((unsigned char)((a) & 0xff)) | ||
155 | |||
156 | /* For many parameters, it seems that 0x80 is a special value that should | ||
157 | * be avoided. Instead, we replace this value by 0x7f | ||
158 | */ | ||
159 | #define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8)) | ||
160 | |||
161 | /* Encode a time value */ | ||
162 | #define TIME_SCALE(a) (a) | ||
163 | |||
164 | |||
165 | /* Public functions */ | ||
166 | /* iforce-serio.c */ | ||
167 | void iforce_serial_xmit(struct iforce *iforce); | ||
168 | |||
169 | /* iforce-usb.c */ | ||
170 | void iforce_usb_xmit(struct iforce *iforce); | ||
171 | void iforce_usb_delete(struct iforce *iforce); | ||
172 | |||
173 | /* iforce-main.c */ | ||
174 | int iforce_init_device(struct iforce *iforce); | ||
175 | void iforce_delete_device(struct iforce *iforce); | ||
176 | |||
177 | /* iforce-packets.c */ | ||
178 | int iforce_control_playback(struct iforce*, u16 id, unsigned int); | ||
179 | void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data, struct pt_regs *regs); | ||
180 | int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); | ||
181 | void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; | ||
182 | int iforce_get_id_packet(struct iforce *iforce, char *packet); | ||
183 | |||
184 | /* iforce-ff.c */ | ||
185 | int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); | ||
186 | int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); | ||
187 | int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); | ||
188 | |||
189 | /* Public variables */ | ||
190 | extern struct serio_driver iforce_serio_drv; | ||
191 | extern struct usb_driver iforce_usb_driver; | ||