]>
Commit | Line | Data |
---|---|---|
6c693fec | 1 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/Documentation/input/ff.txt linux-modified/Documentation/input/ff.txt |
2 | --- linux-vanilla/Documentation/input/ff.txt Thu Sep 13 00:34:06 2001 | |
3 | +++ linux-modified/Documentation/input/ff.txt Mon Jan 6 16:48:20 2003 | |
4 | @@ -1,6 +1,7 @@ | |
5 | Force feedback for Linux. | |
6 | By Johann Deneux <deneux@ifrance.com> on 2001/04/22. | |
7 | - | |
8 | +You may redistribute this file. Please remember to include shape.fig and | |
9 | +interactive.fig as well. | |
10 | ---------------------------------------------------------------------------- | |
11 | ||
12 | 0. Introduction | |
13 | @@ -38,13 +39,10 @@ | |
14 | ||
15 | You then need to insert the modules into the following order: | |
16 | % modprobe joydev | |
17 | -% modprobe serport | |
18 | +% modprobe serport # Only for serial | |
19 | % modprobe iforce | |
20 | % modprobe evdev | |
21 | % ./inputattach -ifor $2 & # Only for serial | |
22 | -For convenience, you may use the shell script named "ff" available from | |
23 | -the cvs tree of the Linux Console Project at sourceforge. You can also | |
24 | -retrieve it from http://www.esil.univ-mrs.fr/~jdeneux/projects/ff/. | |
25 | If you are using USB, you don't need the inputattach step. | |
26 | ||
27 | Please check that you have all the /dev/input entries needed: | |
28 | @@ -68,7 +66,7 @@ | |
29 | 2.1 Does it work ? | |
30 | ~~~~~~~~~~~~~~~~~~ | |
31 | There is an utility called fftest that will allow you to test the driver. | |
32 | -% fftest /dev/eventXX | |
33 | +% fftest /dev/input/eventXX | |
34 | ||
35 | 3. Instructions to the developper | |
36 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
37 | @@ -81,22 +79,30 @@ | |
38 | #include <linux/input.h> | |
39 | #include <sys/ioctl.h> | |
40 | ||
41 | +unsigned long features[1 + FF_MAX/sizeof(unsigned long)]; | |
42 | int ioctl(int file_descriptor, int request, unsigned long *features); | |
43 | ||
44 | -"request" must be EVIOCGBIT(EV_FF, sizeof(unsigned long)) | |
45 | +"request" must be EVIOCGBIT(EV_FF, size of features array in bytes ) | |
46 | ||
47 | Returns the features supported by the device. features is a bitfield with the | |
48 | following bits: | |
49 | -- FF_X has an X axis (should allways be the case) | |
50 | -- FF_Y has an Y axis (usually not the case for wheels) | |
51 | +- FF_X has an X axis (usually joysticks) | |
52 | +- FF_Y has an Y axis (usually joysticks) | |
53 | +- FF_WHEEL has a wheel (usually sterring wheels) | |
54 | - FF_CONSTANT can render constant force effects | |
55 | -- FF_PERIODIC can render periodic effects (sine, ramp, square...) | |
56 | +- FF_PERIODIC can render periodic effects (sine, triangle, square...) | |
57 | +- FF_RAMP can render ramp effects | |
58 | - FF_SPRING can simulate the presence of a spring | |
59 | -- FF_FRICTION can simulate friction (aka drag, damper effect...) | |
60 | +- FF_FRICTION can simulate friction | |
61 | +- FF_DAMPER can simulate damper effects | |
62 | - FF_RUMBLE rumble effects (normally the only effect supported by rumble | |
63 | pads) | |
64 | -- 8 bits from FF_N_EFFECTS_0 containing the number of effects that can be | |
65 | - simultaneously played. | |
66 | +- FF_INERTIA can simulate inertia | |
67 | + | |
68 | + | |
69 | +int ioctl(int fd, EVIOCGEFFECTS, int *n); | |
70 | + | |
71 | +Returns the number of effects the device can keep in its memory. | |
72 | ||
73 | 3.2 Uploading effects to the device | |
74 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
75 | @@ -112,7 +118,11 @@ | |
76 | The content of effect may be modified. In particular, its field "id" is set | |
77 | to the unique id assigned by the driver. This data is required for performing | |
78 | some operations (removing an effect, controlling the playback). | |
79 | -See <linux/input.h> for a description of the ff_effect stuct. | |
80 | +This if field must be set to -1 by the user in order to tell the driver to | |
81 | +allocate a new effect. | |
82 | +See <linux/input.h> for a description of the ff_effect stuct. You should also | |
83 | +find help in a few sketches, contained in files shape.fig and interactive.fig. | |
84 | +You need xfig to visualize these files. | |
85 | ||
86 | 3.3 Removing an effect from the device | |
87 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
88 | @@ -187,8 +197,31 @@ | |
89 | ||
90 | 3.7 Dynamic update of an effect | |
91 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
92 | -This consists in changing some parameters of an effect while it's playing. The | |
93 | -driver currently does not support that. You still have the brute-force method, | |
94 | -which consists in erasing the effect and uploading the updated version. It | |
95 | -actually works pretty well. You don't need to stop-and-start the effect. | |
96 | +Proceed as if you wanted to upload a new effect, except that instead of | |
97 | +setting the id field to -1, you set it to the wanted effect id. | |
98 | +Normally, the effect is not stopped and restarted. However, depending on the | |
99 | +type of device, not all paramaters can be dynamically updated. For example, | |
100 | +the direction of an effect cannot be updated with iforce devices. In this | |
101 | +case, the driver stops the effect, up-load it, and restart it. | |
102 | + | |
103 | + | |
104 | +3.8 Information about the status of effects | |
105 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
106 | +Every time the status of an effect is changed, an event is sent. The values | |
107 | +and meanings of the fields of the event are as follows: | |
108 | +struct input_event { | |
109 | +/* When the status of the effect changed */ | |
110 | + struct timeval time; | |
111 | + | |
112 | +/* Set to EV_FF_STATUS */ | |
113 | + unsigned short type; | |
114 | + | |
115 | +/* Contains the id of the effect */ | |
116 | + unsigned short code; | |
117 | + | |
118 | +/* Indicates the status */ | |
119 | + unsigned int value; | |
120 | +}; | |
121 | ||
122 | +FF_STATUS_STOPPED The effect stopped playing | |
123 | +FF_STATUS_PLAYING The effect started to play | |
124 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/Documentation/input/interactive.fig linux-modified/Documentation/input/interactive.fig | |
125 | --- linux-vanilla/Documentation/input/interactive.fig Thu Jan 1 02:00:00 1970 | |
126 | +++ linux-modified/Documentation/input/interactive.fig Mon Jan 6 16:48:20 2003 | |
127 | @@ -0,0 +1,42 @@ | |
128 | +#FIG 3.2 | |
129 | +Landscape | |
130 | +Center | |
131 | +Inches | |
132 | +Letter | |
133 | +100.00 | |
134 | +Single | |
135 | +-2 | |
136 | +1200 2 | |
137 | +2 1 0 2 0 7 50 0 -1 6.000 0 0 -1 0 0 6 | |
138 | + 1200 3600 1800 3600 2400 4800 3000 4800 4200 5700 4800 5700 | |
139 | +2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 | |
140 | + 1200 3150 4800 3150 4800 6300 1200 6300 1200 3150 | |
141 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
142 | + 1200 4800 4800 4800 | |
143 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4 | |
144 | + 2400 4800 2400 6525 1950 7125 1950 7800 | |
145 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4 | |
146 | + 3000 4800 3000 6525 3600 7125 3600 7800 | |
147 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3 | |
148 | + 0 0 1.00 60.00 120.00 | |
149 | + 3825 5400 4125 5100 5400 5100 | |
150 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3 | |
151 | + 0 0 1.00 60.00 120.00 | |
152 | + 2100 4200 2400 3900 5400 3900 | |
153 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
154 | + 4800 5700 5400 5700 | |
155 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
156 | + 1800 3600 5400 3600 | |
157 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3 | |
158 | + 0 0 1.00 60.00 120.00 | |
159 | + 2700 4800 2700 4425 5400 4425 | |
160 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 | |
161 | + 0 0 1.00 60.00 120.00 | |
162 | + 0 0 1.00 60.00 120.00 | |
163 | + 1950 7800 3600 7800 | |
164 | +4 1 0 50 0 0 12 0.0000 4 135 810 2775 7725 Dead band\001 | |
165 | +4 0 0 50 0 0 12 0.0000 4 180 1155 5400 5700 right saturation\001 | |
166 | +4 0 0 50 0 0 12 0.0000 4 135 1065 5400 3600 left saturation\001 | |
167 | +4 0 0 50 0 0 12 0.0000 4 180 2505 5400 3900 left coeff ( positive in that case )\001 | |
168 | +4 0 0 50 0 0 12 0.0000 4 180 2640 5475 5100 right coeff ( negative in that case )\001 | |
169 | +4 0 0 50 0 0 12 0.0000 4 105 480 5400 4425 center\001 | |
170 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/Documentation/input/joystick.txt linux-modified/Documentation/input/joystick.txt | |
171 | --- linux-vanilla/Documentation/input/joystick.txt Thu Sep 13 00:34:06 2001 | |
172 | +++ linux-modified/Documentation/input/joystick.txt Mon Jan 6 16:48:20 2003 | |
173 | @@ -1,7 +1,7 @@ | |
174 | Linux Joystick driver v2.0.0 | |
175 | - (c) 1996-2000 Vojtech Pavlik <vojtech@suse.cz> | |
176 | + (c) 1996-2000 Vojtech Pavlik <vojtech@ucw.cz> | |
177 | Sponsored by SuSE | |
178 | - $Id$ | |
179 | + $Id$ | |
180 | ---------------------------------------------------------------------------- | |
181 | ||
182 | 0. Disclaimer | |
183 | @@ -21,8 +21,8 @@ | |
184 | Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
185 | ||
186 | Should you need to contact me, the author, you can do so either by e-mail | |
187 | -- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik, | |
188 | -Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
189 | +- mail your message to <vojtech@ucw.cz>, or by paper mail: Vojtech Pavlik, | |
190 | +Simunkova 1594, Prague 8, 182 00 Czech Republic | |
191 | ||
192 | For your convenience, the GNU General Public License version 2 is included | |
193 | in the package: See the file COPYING. | |
194 | @@ -111,7 +111,7 @@ | |
195 | alias tty-ldisc-2 serport | |
196 | alias char-major-13 input | |
197 | above input joydev ns558 analog | |
198 | - options analog js=gameport | |
199 | + options analog js=gamepad | |
200 | ||
201 | 2.5 Verifying that it works | |
202 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
203 | @@ -503,15 +503,16 @@ | |
204 | ||
205 | 3.21 I-Force devices | |
206 | ~~~~~~~~~~~~~~~~~~~~ | |
207 | - All I-Force devices are supported by the iforce.c module. This includes: | |
208 | + All I-Force devices are supported by the iforce.o module. This includes: | |
209 | ||
210 | * AVB Mag Turbo Force | |
211 | * AVB Top Shot Pegasus | |
212 | +* AVB Top Shot Force Feedback Racing Wheel | |
213 | * Logitech WingMan Force | |
214 | -* Logitech WingMan Force 3D | |
215 | * Logitech WingMan Force Wheel | |
216 | -* Logitech WingMan Strike Force 3D | |
217 | * Guillemot Race Leader Force Feedback | |
218 | +* Guillemot Force Feedback Racing Wheel | |
219 | +* Thrustmaster Motor Sport GT | |
220 | ||
221 | To use it, you need to attach the serial port to the driver using the | |
222 | ||
223 | @@ -524,6 +525,10 @@ | |
224 | isn't needed. | |
225 | ||
226 | The I-Force driver now supports force feedback via the event interface. | |
227 | + | |
228 | + Please note that Logitech WingMan *3D devices are _not_ supported by this | |
229 | +module, rather by hid. Force feedback is not supported for those devices. | |
230 | +Logitech gamepads are also hid devices. | |
231 | ||
232 | 3.22 Gravis Stinger gamepad | |
233 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
234 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/Documentation/input/shape.fig linux-modified/Documentation/input/shape.fig | |
235 | --- linux-vanilla/Documentation/input/shape.fig Thu Jan 1 02:00:00 1970 | |
236 | +++ linux-modified/Documentation/input/shape.fig Mon Jan 6 16:48:20 2003 | |
237 | @@ -0,0 +1,65 @@ | |
238 | +#FIG 3.2 | |
239 | +Landscape | |
240 | +Center | |
241 | +Inches | |
242 | +Letter | |
243 | +100.00 | |
244 | +Single | |
245 | +-2 | |
246 | +1200 2 | |
247 | +2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 6 | |
248 | + 4200 3600 4200 3075 4950 2325 7425 2325 8250 3150 8250 3600 | |
249 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
250 | + 4200 3675 4200 5400 | |
251 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
252 | + 8250 3675 8250 5400 | |
253 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
254 | + 3675 3600 8700 3600 | |
255 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
256 | + 8775 3600 10200 3600 | |
257 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
258 | + 8325 3150 9075 3150 | |
259 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
260 | + 7500 2325 10200 2325 | |
261 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
262 | + 3600 3600 3000 3600 | |
263 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
264 | + 4125 3075 3000 3075 | |
265 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 | |
266 | + 0 0 1.00 60.00 120.00 | |
267 | + 0 0 1.00 60.00 120.00 | |
268 | + 4200 5400 8175 5400 | |
269 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 | |
270 | + 0 0 1.00 60.00 120.00 | |
271 | + 0 0 1.00 60.00 120.00 | |
272 | + 10125 2325 10125 3600 | |
273 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 | |
274 | + 0 0 1.00 60.00 120.00 | |
275 | + 0 0 1.00 60.00 120.00 | |
276 | + 3000 3150 3000 3600 | |
277 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 | |
278 | + 0 0 1.00 60.00 120.00 | |
279 | + 0 0 1.00 60.00 120.00 | |
280 | + 9075 3150 9075 3600 | |
281 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
282 | + 4950 2325 4950 1200 | |
283 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 | |
284 | + 7425 2325 7425 1200 | |
285 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4 | |
286 | + 4200 3075 4200 2400 3600 1800 3600 1200 | |
287 | +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4 | |
288 | + 8250 3150 8250 2475 8775 1950 8775 1200 | |
289 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 | |
290 | + 0 0 1.00 60.00 120.00 | |
291 | + 0 0 1.00 60.00 120.00 | |
292 | + 3600 1275 4950 1275 | |
293 | +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 | |
294 | + 0 0 1.00 60.00 120.00 | |
295 | + 0 0 1.00 60.00 120.00 | |
296 | + 7425 1275 8700 1275 | |
297 | +4 1 0 50 0 0 12 0.0000 4 135 1140 6075 5325 Effect duration\001 | |
298 | +4 0 0 50 0 0 12 0.0000 4 180 1305 10200 3000 Effect magnitude\001 | |
299 | +4 0 0 50 0 0 12 0.0000 4 135 780 9150 3450 Fade level\001 | |
300 | +4 1 0 50 0 0 12 0.0000 4 180 1035 4275 1200 Attack length\001 | |
301 | +4 1 0 50 0 0 12 0.0000 4 180 885 8175 1200 Fade length\001 | |
302 | +4 2 0 50 0 0 12 0.0000 4 135 930 2925 3375 Attack level\001 | |
303 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/Config.in linux-modified/drivers/char/joystick/Config.in | |
304 | --- linux-vanilla/drivers/char/joystick/Config.in Fri Nov 29 01:53:12 2002 | |
305 | +++ linux-modified/drivers/char/joystick/Config.in Mon Jan 6 16:48:20 2003 | |
306 | @@ -32,8 +32,7 @@ | |
307 | dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT | |
308 | dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT | |
309 | dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT | |
310 | - dep_tristate ' I-Force USB joysticks and wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB | |
311 | - dep_tristate ' I-Force Serial joysticks and wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT $CONFIG_INPUT_SERIO | |
312 | + source drivers/char/joystick/iforce/Config.in | |
313 | dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_SERIO | |
314 | dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_SERIO | |
315 | dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_SERIO | |
316 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/Makefile linux-modified/drivers/char/joystick/Makefile | |
317 | --- linux-vanilla/drivers/char/joystick/Makefile Fri Nov 29 01:53:12 2002 | |
318 | +++ linux-modified/drivers/char/joystick/Makefile Mon Jan 6 16:54:09 2003 | |
319 | @@ -8,19 +8,6 @@ | |
320 | ||
321 | export-objs := serio.o gameport.o pcigame.o | |
322 | ||
323 | -# I-Force may need both USB and RS-232 | |
324 | - | |
325 | -ifeq ($(CONFIG_INPUT_IFORCE_232),m) | |
326 | - ifeq ($(CONFIG_INPUT_IFORCE_USB),y) | |
327 | - CONFIG_INPUT_IFORCE_USB := m | |
328 | - endif | |
329 | -endif | |
330 | -ifeq ($(CONFIG_INPUT_IFORCE_USB),m) | |
331 | - ifeq ($(CONFIG_INPUT_IFORCE_232),y) | |
332 | - CONFIG_INPUT_IFORCE_232 := m | |
333 | - endif | |
334 | -endif | |
335 | - | |
336 | # Object file lists. | |
337 | ||
338 | obj-y := | |
339 | @@ -46,8 +33,6 @@ | |
340 | obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o | |
341 | obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o | |
342 | obj-$(CONFIG_INPUT_STINGER) += stinger.o | |
343 | -obj-$(CONFIG_INPUT_IFORCE_232) += iforce.o | |
344 | -obj-$(CONFIG_INPUT_IFORCE_USB) += iforce.o | |
345 | ||
346 | obj-$(CONFIG_INPUT_ANALOG) += analog.o | |
347 | obj-$(CONFIG_INPUT_A3D) += a3d.o | |
348 | @@ -64,6 +49,8 @@ | |
349 | obj-$(CONFIG_INPUT_TURBOGRAFX) += turbografx.o | |
350 | ||
351 | obj-$(CONFIG_INPUT_AMIJOY) += amijoy.o | |
352 | + | |
353 | +subdir-$(CONFIG_JOYSTICK_IFORCE) += iforce | |
354 | ||
355 | # The global Rules.make. | |
356 | ||
357 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/a3d.c linux-modified/drivers/char/joystick/a3d.c | |
358 | --- linux-vanilla/drivers/char/joystick/a3d.c Sat Aug 3 02:39:43 2002 | |
359 | +++ linux-modified/drivers/char/joystick/a3d.c Mon Jan 6 16:48:20 2003 | |
360 | @@ -347,8 +347,8 @@ | |
361 | a3d->dev.idversion = 0x0100; | |
362 | ||
363 | input_register_device(&a3d->dev); | |
364 | - printk(KERN_INFO "input%d: %s on gameport%d.0\n", | |
365 | - a3d->dev.number, a3d_names[a3d->mode], gameport->number); | |
366 | + printk(KERN_INFO "input: %s on gameport%d.0\n", | |
367 | + a3d_names[a3d->mode], gameport->number); | |
368 | ||
369 | return; | |
370 | fail2: gameport_close(gameport); | |
371 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/adi.c linux-modified/drivers/char/joystick/adi.c | |
372 | --- linux-vanilla/drivers/char/joystick/adi.c Thu Sep 13 00:34:06 2001 | |
373 | +++ linux-modified/drivers/char/joystick/adi.c Mon Jan 6 16:48:20 2003 | |
374 | @@ -514,8 +514,8 @@ | |
375 | if (port->adi[i].length > 0) { | |
376 | adi_init_center(port->adi + i); | |
377 | input_register_device(&port->adi[i].dev); | |
378 | - printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n", | |
379 | - port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i); | |
380 | + printk(KERN_INFO "input: %s [%s] on gameport%d.%d\n", | |
381 | + port->adi[i].name, port->adi[i].cname, gameport->number, i); | |
382 | } | |
383 | } | |
384 | ||
385 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/analog.c linux-modified/drivers/char/joystick/analog.c | |
386 | --- linux-vanilla/drivers/char/joystick/analog.c Fri Nov 29 01:53:12 2002 | |
387 | +++ linux-modified/drivers/char/joystick/analog.c Mon Jan 6 16:48:20 2003 | |
388 | @@ -490,8 +490,8 @@ | |
389 | ||
390 | input_register_device(&analog->dev); | |
391 | ||
392 | - printk(KERN_INFO "input%d: %s at gameport%d.%d", | |
393 | - analog->dev.number, analog->name, port->gameport->number, index); | |
394 | + printk(KERN_INFO "input: %s at gameport%d.%d", | |
395 | + analog->name, port->gameport->number, index); | |
396 | ||
397 | if (port->cooked) | |
398 | printk(" [ADC port]\n"); | |
399 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/cobra.c linux-modified/drivers/char/joystick/cobra.c | |
400 | --- linux-vanilla/drivers/char/joystick/cobra.c Thu Sep 13 00:34:06 2001 | |
401 | +++ linux-modified/drivers/char/joystick/cobra.c Mon Jan 6 16:48:20 2003 | |
402 | @@ -208,8 +208,8 @@ | |
403 | cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1; | |
404 | ||
405 | input_register_device(cobra->dev + i); | |
406 | - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", | |
407 | - cobra->dev[i].number, cobra_name, gameport->number, i); | |
408 | + printk(KERN_INFO "input: %s on gameport%d.%d\n", | |
409 | + cobra_name, gameport->number, i); | |
410 | } | |
411 | ||
412 | ||
413 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/db9.c linux-modified/drivers/char/joystick/db9.c | |
414 | --- linux-vanilla/drivers/char/joystick/db9.c Thu Sep 13 00:34:06 2001 | |
415 | +++ linux-modified/drivers/char/joystick/db9.c Mon Jan 6 16:48:20 2003 | |
416 | @@ -362,8 +362,8 @@ | |
417 | db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1; | |
418 | ||
419 | input_register_device(db9->dev + i); | |
420 | - printk(KERN_INFO "input%d: %s on %s\n", | |
421 | - db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name); | |
422 | + printk(KERN_INFO "input: %s on %s\n", | |
423 | + db9_name[db9->mode], db9->pd->port->name); | |
424 | } | |
425 | ||
426 | return db9; | |
427 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/gamecon.c linux-modified/drivers/char/joystick/gamecon.c | |
428 | --- linux-vanilla/drivers/char/joystick/gamecon.c Thu Sep 13 00:34:06 2001 | |
429 | +++ linux-modified/drivers/char/joystick/gamecon.c Mon Jan 6 16:48:20 2003 | |
430 | @@ -608,7 +608,7 @@ | |
431 | for (i = 0; i < 5; i++) | |
432 | if (gc->pads[0] & gc_status_bit[i]) { | |
433 | input_register_device(gc->dev + i); | |
434 | - printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name); | |
435 | + printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name); | |
436 | } | |
437 | ||
438 | return gc; | |
439 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/gf2k.c linux-modified/drivers/char/joystick/gf2k.c | |
440 | --- linux-vanilla/drivers/char/joystick/gf2k.c Thu Sep 13 00:34:06 2001 | |
441 | +++ linux-modified/drivers/char/joystick/gf2k.c Mon Jan 6 16:48:20 2003 | |
442 | @@ -323,8 +323,8 @@ | |
443 | } | |
444 | ||
445 | input_register_device(&gf2k->dev); | |
446 | - printk(KERN_INFO "input%d: %s on gameport%d.0\n", | |
447 | - gf2k->dev.number, gf2k_names[gf2k->id], gameport->number); | |
448 | + printk(KERN_INFO "input: %s on gameport%d.0\n", | |
449 | + gf2k_names[gf2k->id], gameport->number); | |
450 | ||
451 | return; | |
452 | fail2: gameport_close(gameport); | |
453 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/grip.c linux-modified/drivers/char/joystick/grip.c | |
454 | --- linux-vanilla/drivers/char/joystick/grip.c Thu Sep 13 00:34:06 2001 | |
455 | +++ linux-modified/drivers/char/joystick/grip.c Mon Jan 6 16:48:20 2003 | |
456 | @@ -382,8 +382,8 @@ | |
457 | ||
458 | input_register_device(grip->dev + i); | |
459 | ||
460 | - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", | |
461 | - grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i); | |
462 | + printk(KERN_INFO "input: %s on gameport%d.%d\n", | |
463 | + grip_name[grip->mode[i]], gameport->number, i); | |
464 | } | |
465 | ||
466 | return; | |
467 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/Config.help linux-modified/drivers/char/joystick/iforce/Config.help | |
468 | --- linux-vanilla/drivers/char/joystick/iforce/Config.help Thu Jan 1 02:00:00 1970 | |
469 | +++ linux-modified/drivers/char/joystick/iforce/Config.help Mon Jan 6 16:48:20 2003 | |
470 | @@ -0,0 +1,21 @@ | |
471 | +CONFIG_JOYSTICK_IFORCE | |
472 | + Say Y here if you have an I-Force joystick or steering wheel | |
473 | + | |
474 | + You also must choose at least one of the two options below. | |
475 | + | |
476 | + This driver is also available as a module ( = code which can be | |
477 | + inserted in and removed from the running kernel whenever you want). | |
478 | + The module will be called iforce.o. If you want to compile it as a | |
479 | + module, say M here and read <file:Documentation/modules.txt>. | |
480 | + | |
481 | +CONFIG_JOYSTICK_IFORCE_USB | |
482 | + Say Y here if you have an I-Force joystick or steering wheel | |
483 | + connected to your USB port. | |
484 | + | |
485 | +CONFIG_JOYSTICK_IFORCE_232 | |
486 | + Say Y here if you have an I-Force joystick or steering wheel | |
487 | + connected to your serial (COM) port. | |
488 | + | |
489 | + You will need an additional utility called inputattach, see | |
490 | + Documentation/input/joystick.txt and ff.txt. | |
491 | + | |
492 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/Config.in linux-modified/drivers/char/joystick/iforce/Config.in | |
493 | --- linux-vanilla/drivers/char/joystick/iforce/Config.in Thu Jan 1 02:00:00 1970 | |
494 | +++ linux-modified/drivers/char/joystick/iforce/Config.in Mon Jan 6 16:48:20 2003 | |
495 | @@ -0,0 +1,14 @@ | |
496 | +# | |
497 | +# I-Force driver configuration | |
498 | +# | |
499 | + | |
500 | +dep_tristate 'I-Force devices' CONFIG_JOYSTICK_IFORCE $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK | |
501 | + | |
502 | +if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_JOYSTICK_IFORCE" = "y" ]; then | |
503 | + if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_USB" = "y" ]; then | |
504 | + dep_mbool ' I-Force USB joysticks and wheels' CONFIG_JOYSTICK_IFORCE_USB $CONFIG_USB | |
505 | + fi | |
506 | + if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_INPUT_SERIO" = "y" ]; then | |
507 | + dep_mbool ' I-Force Serial joysticks and wheels' CONFIG_JOYSTICK_IFORCE_232 $CONFIG_INPUT_SERIO | |
508 | + fi | |
509 | +fi | |
510 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/Makefile linux-modified/drivers/char/joystick/iforce/Makefile | |
511 | --- linux-vanilla/drivers/char/joystick/iforce/Makefile Thu Jan 1 02:00:00 1970 | |
512 | +++ linux-modified/drivers/char/joystick/iforce/Makefile Mon Jan 6 16:48:20 2003 | |
513 | @@ -0,0 +1,30 @@ | |
514 | +# | |
515 | +# Makefile for the I-Force driver | |
516 | +# | |
517 | +# By Johann Deneux <deneux@ifrance.com> | |
518 | +# | |
519 | + | |
520 | +# Goal definition | |
521 | +list-multi := iforce.o | |
522 | +iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o | |
523 | + | |
524 | +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o | |
525 | + | |
526 | +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) | |
527 | + iforce-objs += iforce-serio.o | |
528 | +endif | |
529 | + | |
530 | +ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) | |
531 | + iforce-objs += iforce-usb.o | |
532 | +endif | |
533 | + | |
534 | +EXTRA_CFLAGS = -Werror-implicit-function-declaration | |
535 | + | |
536 | +# The global Rules.make. | |
537 | + | |
538 | +include $(TOPDIR)/Rules.make | |
539 | + | |
540 | +# Additional rules | |
541 | +iforce.o: $(iforce-objs) | |
542 | + $(LD) -r -o $@ $(iforce-objs) | |
543 | + | |
544 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/iforce-ff.c linux-modified/drivers/char/joystick/iforce/iforce-ff.c | |
545 | --- linux-vanilla/drivers/char/joystick/iforce/iforce-ff.c Thu Jan 1 02:00:00 1970 | |
546 | +++ linux-modified/drivers/char/joystick/iforce/iforce-ff.c Mon Jan 6 16:48:20 2003 | |
547 | @@ -0,0 +1,544 @@ | |
548 | +/* | |
549 | + * $Id$ | |
550 | + * | |
551 | + * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | |
552 | + * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | |
553 | + * | |
554 | + * USB/RS232 I-Force joysticks and wheels. | |
555 | + */ | |
556 | + | |
557 | +/* | |
558 | + * This program is free software; you can redistribute it and/or modify | |
559 | + * it under the terms of the GNU General Public License as published by | |
560 | + * the Free Software Foundation; either version 2 of the License, or | |
561 | + * (at your option) any later version. | |
562 | + * | |
563 | + * This program is distributed in the hope that it will be useful, | |
564 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
565 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
566 | + * GNU General Public License for more details. | |
567 | + * | |
568 | + * You should have received a copy of the GNU General Public License | |
569 | + * along with this program; if not, write to the Free Software | |
570 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
571 | + * | |
572 | + * Should you need to contact me, the author, you can do so either by | |
573 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
574 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
575 | + */ | |
576 | + | |
577 | +#include "iforce.h" | |
578 | + | |
579 | +/* | |
580 | + * Set the magnitude of a constant force effect | |
581 | + * Return error code | |
582 | + * | |
583 | + * Note: caller must ensure exclusive access to device | |
584 | + */ | |
585 | + | |
586 | +static int make_magnitude_modifier(struct iforce* iforce, | |
587 | + struct resource* mod_chunk, int no_alloc, __s16 level) | |
588 | +{ | |
589 | + unsigned char data[3]; | |
590 | + | |
591 | + if (!no_alloc) { | |
592 | + down(&iforce->mem_mutex); | |
593 | + if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, | |
594 | + iforce->device_memory.start, iforce->device_memory.end, 2L, | |
595 | + NULL, NULL)) { | |
596 | + up(&iforce->mem_mutex); | |
597 | + return -ENOMEM; | |
598 | + } | |
599 | + up(&iforce->mem_mutex); | |
600 | + } | |
601 | + | |
602 | + data[0] = LO(mod_chunk->start); | |
603 | + data[1] = HI(mod_chunk->start); | |
604 | + data[2] = HIFIX80(level); | |
605 | + | |
606 | + iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); | |
607 | + | |
608 | +// iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data); | |
609 | + return 0; | |
610 | +} | |
611 | + | |
612 | +/* | |
613 | + * Upload the component of an effect dealing with the period, phase and magnitude | |
614 | + */ | |
615 | + | |
616 | +static int make_period_modifier(struct iforce* iforce, | |
617 | + struct resource* mod_chunk, int no_alloc, | |
618 | + __s16 magnitude, __s16 offset, u16 period, u16 phase) | |
619 | +{ | |
620 | + unsigned char data[7]; | |
621 | + | |
622 | + period = TIME_SCALE(period); | |
623 | + | |
624 | + if (!no_alloc) { | |
625 | + down(&iforce->mem_mutex); | |
626 | + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, | |
627 | + iforce->device_memory.start, iforce->device_memory.end, 2L, | |
628 | + NULL, NULL)) { | |
629 | + up(&iforce->mem_mutex); | |
630 | + return -ENOMEM; | |
631 | + } | |
632 | + up(&iforce->mem_mutex); | |
633 | + } | |
634 | + | |
635 | + data[0] = LO(mod_chunk->start); | |
636 | + data[1] = HI(mod_chunk->start); | |
637 | + | |
638 | + data[2] = HIFIX80(magnitude); | |
639 | + data[3] = HIFIX80(offset); | |
640 | + data[4] = HI(phase); | |
641 | + | |
642 | + data[5] = LO(period); | |
643 | + data[6] = HI(period); | |
644 | + | |
645 | + iforce_send_packet(iforce, FF_CMD_PERIOD, data); | |
646 | + | |
647 | + return 0; | |
648 | +} | |
649 | + | |
650 | +/* | |
651 | + * Uploads the part of an effect setting the envelope of the force | |
652 | + */ | |
653 | + | |
654 | +static int make_envelope_modifier(struct iforce* iforce, | |
655 | + struct resource* mod_chunk, int no_alloc, | |
656 | + u16 attack_duration, __s16 initial_level, | |
657 | + u16 fade_duration, __s16 final_level) | |
658 | +{ | |
659 | + unsigned char data[8]; | |
660 | + | |
661 | + attack_duration = TIME_SCALE(attack_duration); | |
662 | + fade_duration = TIME_SCALE(fade_duration); | |
663 | + | |
664 | + if (!no_alloc) { | |
665 | + down(&iforce->mem_mutex); | |
666 | + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, | |
667 | + iforce->device_memory.start, iforce->device_memory.end, 2L, | |
668 | + NULL, NULL)) { | |
669 | + up(&iforce->mem_mutex); | |
670 | + return -ENOMEM; | |
671 | + } | |
672 | + up(&iforce->mem_mutex); | |
673 | + } | |
674 | + | |
675 | + data[0] = LO(mod_chunk->start); | |
676 | + data[1] = HI(mod_chunk->start); | |
677 | + | |
678 | + data[2] = LO(attack_duration); | |
679 | + data[3] = HI(attack_duration); | |
680 | + data[4] = HI(initial_level); | |
681 | + | |
682 | + data[5] = LO(fade_duration); | |
683 | + data[6] = HI(fade_duration); | |
684 | + data[7] = HI(final_level); | |
685 | + | |
686 | + iforce_send_packet(iforce, FF_CMD_ENVELOPE, data); | |
687 | + | |
688 | + return 0; | |
689 | +} | |
690 | + | |
691 | +/* | |
692 | + * Component of spring, friction, inertia... effects | |
693 | + */ | |
694 | + | |
695 | +static int make_condition_modifier(struct iforce* iforce, | |
696 | + struct resource* mod_chunk, int no_alloc, | |
697 | + __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) | |
698 | +{ | |
699 | + unsigned char data[10]; | |
700 | + | |
701 | + if (!no_alloc) { | |
702 | + down(&iforce->mem_mutex); | |
703 | + if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, | |
704 | + iforce->device_memory.start, iforce->device_memory.end, 2L, | |
705 | + NULL, NULL)) { | |
706 | + up(&iforce->mem_mutex); | |
707 | + return -ENOMEM; | |
708 | + } | |
709 | + up(&iforce->mem_mutex); | |
710 | + } | |
711 | + | |
712 | + data[0] = LO(mod_chunk->start); | |
713 | + data[1] = HI(mod_chunk->start); | |
714 | + | |
715 | + data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ | |
716 | + data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ | |
717 | + | |
718 | + center = (500*center)>>15; | |
719 | + data[4] = LO(center); | |
720 | + data[5] = HI(center); | |
721 | + | |
722 | + db = (1000*db)>>16; | |
723 | + data[6] = LO(db); | |
724 | + data[7] = HI(db); | |
725 | + | |
726 | + data[8] = (100*rsat)>>16; | |
727 | + data[9] = (100*lsat)>>16; | |
728 | + | |
729 | + iforce_send_packet(iforce, FF_CMD_CONDITION, data); | |
730 | +// iforce_dump_packet("condition", FF_CMD_CONDITION, data); | |
731 | + | |
732 | + return 0; | |
733 | +} | |
734 | + | |
735 | +static unsigned char find_button(struct iforce *iforce, signed short button) | |
736 | +{ | |
737 | + int i; | |
738 | + for (i = 1; iforce->type->btn[i] >= 0; i++) | |
739 | + if (iforce->type->btn[i] == button) | |
740 | + return i + 1; | |
741 | + return 0; | |
742 | +} | |
743 | + | |
744 | +/* | |
745 | + * Analyse the changes in an effect, and tell if we need to send an condition | |
746 | + * parameter packet | |
747 | + */ | |
748 | +static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) | |
749 | +{ | |
750 | + int id = new->id; | |
751 | + struct ff_effect* old = &iforce->core_effects[id].effect; | |
752 | + int ret=0; | |
753 | + int i; | |
754 | + | |
755 | + if (new->type != FF_SPRING && new->type != FF_FRICTION) { | |
756 | + printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); | |
757 | + return FALSE; | |
758 | + } | |
759 | + | |
760 | + for(i=0; i<2; i++) { | |
761 | + ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation | |
762 | + || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation | |
763 | + || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff | |
764 | + || old->u.condition[i].left_coeff != new->u.condition[i].left_coeff | |
765 | + || old->u.condition[i].deadband != new->u.condition[i].deadband | |
766 | + || old->u.condition[i].center != new->u.condition[i].center; | |
767 | + } | |
768 | + return ret; | |
769 | +} | |
770 | + | |
771 | +/* | |
772 | + * Analyse the changes in an effect, and tell if we need to send a magnitude | |
773 | + * parameter packet | |
774 | + */ | |
775 | +static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) | |
776 | +{ | |
777 | + int id = effect->id; | |
778 | + struct ff_effect* old = &iforce->core_effects[id].effect; | |
779 | + | |
780 | + if (effect->type != FF_CONSTANT) { | |
781 | + printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | |
782 | + return FALSE; | |
783 | + } | |
784 | + | |
785 | + return (old->u.constant.level != effect->u.constant.level); | |
786 | +} | |
787 | + | |
788 | +/* | |
789 | + * Analyse the changes in an effect, and tell if we need to send an envelope | |
790 | + * parameter packet | |
791 | + */ | |
792 | +static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect) | |
793 | +{ | |
794 | + int id = effect->id; | |
795 | + struct ff_effect* old = &iforce->core_effects[id].effect; | |
796 | + | |
797 | + switch (effect->type) { | |
798 | + case FF_CONSTANT: | |
799 | + if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length | |
800 | + || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level | |
801 | + || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length | |
802 | + || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) | |
803 | + return TRUE; | |
804 | + break; | |
805 | + | |
806 | + case FF_PERIODIC: | |
807 | + if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length | |
808 | + || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level | |
809 | + || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length | |
810 | + || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) | |
811 | + return TRUE; | |
812 | + break; | |
813 | + | |
814 | + default: | |
815 | + printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); | |
816 | + } | |
817 | + | |
818 | + return FALSE; | |
819 | +} | |
820 | + | |
821 | +/* | |
822 | + * Analyse the changes in an effect, and tell if we need to send a periodic | |
823 | + * parameter effect | |
824 | + */ | |
825 | +static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) | |
826 | +{ | |
827 | + int id = new->id; | |
828 | + struct ff_effect* old = &iforce->core_effects[id].effect; | |
829 | + | |
830 | + if (new->type != FF_PERIODIC) { | |
831 | + printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); | |
832 | + return FALSE; | |
833 | + } | |
834 | + | |
835 | + return (old->u.periodic.period != new->u.periodic.period | |
836 | + || old->u.periodic.magnitude != new->u.periodic.magnitude | |
837 | + || old->u.periodic.offset != new->u.periodic.offset | |
838 | + || old->u.periodic.phase != new->u.periodic.phase); | |
839 | +} | |
840 | + | |
841 | +/* | |
842 | + * Analyse the changes in an effect, and tell if we need to send an effect | |
843 | + * packet | |
844 | + */ | |
845 | +static int need_core(struct iforce* iforce, struct ff_effect* new) | |
846 | +{ | |
847 | + int id = new->id; | |
848 | + struct ff_effect* old = &iforce->core_effects[id].effect; | |
849 | + | |
850 | + if (old->direction != new->direction | |
851 | + || old->trigger.button != new->trigger.button | |
852 | + || old->trigger.interval != new->trigger.interval | |
853 | + || old->replay.length != new->replay.length | |
854 | + || old->replay.delay != new->replay.delay) | |
855 | + return TRUE; | |
856 | + | |
857 | + return FALSE; | |
858 | +} | |
859 | +/* | |
860 | + * Send the part common to all effects to the device | |
861 | + */ | |
862 | +static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, | |
863 | + u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, | |
864 | + u16 interval, u16 direction) | |
865 | +{ | |
866 | + unsigned char data[14]; | |
867 | + | |
868 | + duration = TIME_SCALE(duration); | |
869 | + delay = TIME_SCALE(delay); | |
870 | + interval = TIME_SCALE(interval); | |
871 | + | |
872 | + data[0] = LO(id); | |
873 | + data[1] = effect_type; | |
874 | + data[2] = LO(axes) | find_button(iforce, button); | |
875 | + | |
876 | + if (!duration) duration = 0xFFFF; | |
877 | + data[3] = LO(duration); | |
878 | + data[4] = HI(duration); | |
879 | + | |
880 | + data[5] = HI(direction); | |
881 | + | |
882 | + data[6] = LO(interval); | |
883 | + data[7] = HI(interval); | |
884 | + | |
885 | + data[8] = LO(mod_id1); | |
886 | + data[9] = HI(mod_id1); | |
887 | + data[10] = LO(mod_id2); | |
888 | + data[11] = HI(mod_id2); | |
889 | + | |
890 | + data[12] = LO(delay); | |
891 | + data[13] = HI(delay); | |
892 | + | |
893 | + /* Stop effect */ | |
894 | +/* iforce_control_playback(iforce, id, 0);*/ | |
895 | + | |
896 | + iforce_send_packet(iforce, FF_CMD_EFFECT, data); | |
897 | + | |
898 | + /* If needed, restart effect */ | |
899 | + if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { | |
900 | + /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ | |
901 | + iforce_control_playback(iforce, id, 1); | |
902 | + } | |
903 | + | |
904 | + return 0; | |
905 | +} | |
906 | + | |
907 | +/* | |
908 | + * Upload a periodic effect to the device | |
909 | + * See also iforce_upload_constant. | |
910 | + */ | |
911 | +int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) | |
912 | +{ | |
913 | + u8 wave_code; | |
914 | + int core_id = effect->id; | |
915 | + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
916 | + struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | |
917 | + struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | |
918 | + int param1_err = 1; | |
919 | + int param2_err = 1; | |
920 | + int core_err = 0; | |
921 | + | |
922 | + if (!is_update || need_period_modifier(iforce, effect)) { | |
923 | + param1_err = make_period_modifier(iforce, mod1_chunk, | |
924 | + is_update, | |
925 | + effect->u.periodic.magnitude, effect->u.periodic.offset, | |
926 | + effect->u.periodic.period, effect->u.periodic.phase); | |
927 | + if (param1_err) return param1_err; | |
928 | + set_bit(FF_MOD1_IS_USED, core_effect->flags); | |
929 | + } | |
930 | + | |
931 | + if (!is_update || need_envelope_modifier(iforce, effect)) { | |
932 | + param2_err = make_envelope_modifier(iforce, mod2_chunk, | |
933 | + is_update, | |
934 | + effect->u.periodic.envelope.attack_length, | |
935 | + effect->u.periodic.envelope.attack_level, | |
936 | + effect->u.periodic.envelope.fade_length, | |
937 | + effect->u.periodic.envelope.fade_level); | |
938 | + if (param2_err) return param2_err; | |
939 | + set_bit(FF_MOD2_IS_USED, core_effect->flags); | |
940 | + } | |
941 | + | |
942 | + switch (effect->u.periodic.waveform) { | |
943 | + case FF_SQUARE: wave_code = 0x20; break; | |
944 | + case FF_TRIANGLE: wave_code = 0x21; break; | |
945 | + case FF_SINE: wave_code = 0x22; break; | |
946 | + case FF_SAW_UP: wave_code = 0x23; break; | |
947 | + case FF_SAW_DOWN: wave_code = 0x24; break; | |
948 | + default: wave_code = 0x20; break; | |
949 | + } | |
950 | + | |
951 | + if (!is_update || need_core(iforce, effect)) { | |
952 | + core_err = make_core(iforce, effect->id, | |
953 | + mod1_chunk->start, | |
954 | + mod2_chunk->start, | |
955 | + wave_code, | |
956 | + 0x20, | |
957 | + effect->replay.length, | |
958 | + effect->replay.delay, | |
959 | + effect->trigger.button, | |
960 | + effect->trigger.interval, | |
961 | + effect->direction); | |
962 | + } | |
963 | + | |
964 | + /* If one of the parameter creation failed, we already returned an | |
965 | + * error code. | |
966 | + * If the core creation failed, we return its error code. | |
967 | + * Else: if one parameter at least was created, we return 0 | |
968 | + * else we return 1; | |
969 | + */ | |
970 | + return core_err < 0 ? core_err : (param1_err && param2_err); | |
971 | +} | |
972 | + | |
973 | +/* | |
974 | + * Upload a constant force effect | |
975 | + * Return value: | |
976 | + * <0 Error code | |
977 | + * 0 Ok, effect created or updated | |
978 | + * 1 effect did not change since last upload, and no packet was therefore sent | |
979 | + */ | |
980 | +int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) | |
981 | +{ | |
982 | + int core_id = effect->id; | |
983 | + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
984 | + struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | |
985 | + struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | |
986 | + int param1_err = 1; | |
987 | + int param2_err = 1; | |
988 | + int core_err = 0; | |
989 | + | |
990 | + if (!is_update || need_magnitude_modifier(iforce, effect)) { | |
991 | + param1_err = make_magnitude_modifier(iforce, mod1_chunk, | |
992 | + is_update, | |
993 | + effect->u.constant.level); | |
994 | + if (param1_err) return param1_err; | |
995 | + set_bit(FF_MOD1_IS_USED, core_effect->flags); | |
996 | + } | |
997 | + | |
998 | + if (!is_update || need_envelope_modifier(iforce, effect)) { | |
999 | + param2_err = make_envelope_modifier(iforce, mod2_chunk, | |
1000 | + is_update, | |
1001 | + effect->u.constant.envelope.attack_length, | |
1002 | + effect->u.constant.envelope.attack_level, | |
1003 | + effect->u.constant.envelope.fade_length, | |
1004 | + effect->u.constant.envelope.fade_level); | |
1005 | + if (param2_err) return param2_err; | |
1006 | + set_bit(FF_MOD2_IS_USED, core_effect->flags); | |
1007 | + } | |
1008 | + | |
1009 | + if (!is_update || need_core(iforce, effect)) { | |
1010 | + core_err = make_core(iforce, effect->id, | |
1011 | + mod1_chunk->start, | |
1012 | + mod2_chunk->start, | |
1013 | + 0x00, | |
1014 | + 0x20, | |
1015 | + effect->replay.length, | |
1016 | + effect->replay.delay, | |
1017 | + effect->trigger.button, | |
1018 | + effect->trigger.interval, | |
1019 | + effect->direction); | |
1020 | + } | |
1021 | + | |
1022 | + /* If one of the parameter creation failed, we already returned an | |
1023 | + * error code. | |
1024 | + * If the core creation failed, we return its error code. | |
1025 | + * Else: if one parameter at least was created, we return 0 | |
1026 | + * else we return 1; | |
1027 | + */ | |
1028 | + return core_err < 0 ? core_err : (param1_err && param2_err); | |
1029 | +} | |
1030 | + | |
1031 | +/* | |
1032 | + * Upload an condition effect. Those are for example friction, inertia, springs... | |
1033 | + */ | |
1034 | +int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update) | |
1035 | +{ | |
1036 | + int core_id = effect->id; | |
1037 | + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
1038 | + struct resource* mod1_chunk = &(core_effect->mod1_chunk); | |
1039 | + struct resource* mod2_chunk = &(core_effect->mod2_chunk); | |
1040 | + u8 type; | |
1041 | + int param_err = 1; | |
1042 | + int core_err = 0; | |
1043 | + | |
1044 | + switch (effect->type) { | |
1045 | + case FF_SPRING: type = 0x40; break; | |
1046 | + case FF_DAMPER: type = 0x41; break; | |
1047 | + default: return -1; | |
1048 | + } | |
1049 | + | |
1050 | + if (!is_update || need_condition_modifier(iforce, effect)) { | |
1051 | + param_err = make_condition_modifier(iforce, mod1_chunk, | |
1052 | + is_update, | |
1053 | + effect->u.condition[0].right_saturation, | |
1054 | + effect->u.condition[0].left_saturation, | |
1055 | + effect->u.condition[0].right_coeff, | |
1056 | + effect->u.condition[0].left_coeff, | |
1057 | + effect->u.condition[0].deadband, | |
1058 | + effect->u.condition[0].center); | |
1059 | + if (param_err) return param_err; | |
1060 | + set_bit(FF_MOD1_IS_USED, core_effect->flags); | |
1061 | + | |
1062 | + param_err = make_condition_modifier(iforce, mod2_chunk, | |
1063 | + is_update, | |
1064 | + effect->u.condition[1].right_saturation, | |
1065 | + effect->u.condition[1].left_saturation, | |
1066 | + effect->u.condition[1].right_coeff, | |
1067 | + effect->u.condition[1].left_coeff, | |
1068 | + effect->u.condition[1].deadband, | |
1069 | + effect->u.condition[1].center); | |
1070 | + if (param_err) return param_err; | |
1071 | + set_bit(FF_MOD2_IS_USED, core_effect->flags); | |
1072 | + | |
1073 | + } | |
1074 | + | |
1075 | + if (!is_update || need_core(iforce, effect)) { | |
1076 | + core_err = make_core(iforce, effect->id, | |
1077 | + mod1_chunk->start, mod2_chunk->start, | |
1078 | + type, 0xc0, | |
1079 | + effect->replay.length, effect->replay.delay, | |
1080 | + effect->trigger.button, effect->trigger.interval, | |
1081 | + effect->direction); | |
1082 | + } | |
1083 | + | |
1084 | + /* If the parameter creation failed, we already returned an | |
1085 | + * error code. | |
1086 | + * If the core creation failed, we return its error code. | |
1087 | + * Else: if a parameter was created, we return 0 | |
1088 | + * else we return 1; | |
1089 | + */ | |
1090 | + return core_err < 0 ? core_err : param_err; | |
1091 | +} | |
1092 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/iforce-main.c linux-modified/drivers/char/joystick/iforce/iforce-main.c | |
1093 | --- linux-vanilla/drivers/char/joystick/iforce/iforce-main.c Thu Jan 1 02:00:00 1970 | |
1094 | +++ linux-modified/drivers/char/joystick/iforce/iforce-main.c Wed Feb 26 20:36:04 2003 | |
1095 | @@ -0,0 +1,562 @@ | |
1096 | +/* | |
1097 | + * $Id$ | |
1098 | + * | |
1099 | + * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | |
1100 | + * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | |
1101 | + * | |
1102 | + * USB/RS232 I-Force joysticks and wheels. | |
1103 | + */ | |
1104 | + | |
1105 | +/* | |
1106 | + * This program is free software; you can redistribute it and/or modify | |
1107 | + * it under the terms of the GNU General Public License as published by | |
1108 | + * the Free Software Foundation; either version 2 of the License, or | |
1109 | + * (at your option) any later version. | |
1110 | + * | |
1111 | + * This program is distributed in the hope that it will be useful, | |
1112 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1113 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
1114 | + * GNU General Public License for more details. | |
1115 | + * | |
1116 | + * You should have received a copy of the GNU General Public License | |
1117 | + * along with this program; if not, write to the Free Software | |
1118 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
1119 | + * | |
1120 | + * Should you need to contact me, the author, you can do so either by | |
1121 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
1122 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
1123 | + */ | |
1124 | + | |
1125 | +#include "iforce.h" | |
1126 | + | |
1127 | +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>, Johann Deneux <deneux@ifrance.com>"); | |
1128 | +MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); | |
1129 | +MODULE_LICENSE("GPL"); | |
1130 | + | |
1131 | +#define USB_VENDOR_ID_SAITEK 0x06a3 | |
1132 | +#define USB_PRODUCT_ID_CYBORGFORCE 0xff12 | |
1133 | + | |
1134 | + | |
1135 | +static signed short btn_joystick[] = | |
1136 | +{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | |
1137 | + BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; | |
1138 | + | |
1139 | +static signed short btn_avb_pegasus[] = | |
1140 | +{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | |
1141 | + BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; | |
1142 | + | |
1143 | +static signed short btn_wheel[] = | |
1144 | +{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | |
1145 | + BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; | |
1146 | + | |
1147 | +static signed short btn_avb_tw[] = | |
1148 | +{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, | |
1149 | + BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; | |
1150 | + | |
1151 | +static signed short btn_avb_wheel[] = | |
1152 | +{ BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_BASE, BTN_BASE2, BTN_BASE3, | |
1153 | + BTN_BASE4, BTN_BASE5, BTN_BASE6, -1 }; | |
1154 | + | |
1155 | +static signed short abs_joystick[] = | |
1156 | +{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; | |
1157 | + | |
1158 | +static signed short abs_avb_pegasus[] = | |
1159 | +{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, | |
1160 | + ABS_HAT1X, ABS_HAT1Y, -1 }; | |
1161 | + | |
1162 | +static signed short abs_wheel[] = | |
1163 | +{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; | |
1164 | + | |
1165 | +static signed short btn_saitek_joystick[] = | |
1166 | +{ BTN_TRIGGER, BTN_TOP2, BTN_THUMB,BTN_THUMB2, BTN_TOP, | |
1167 | + BTN_BASE, BTN_BASE2, BTN_BASE4, BTN_BASE3, -1 }; | |
1168 | + | |
1169 | +static signed short abs_saitek_joystick[] = | |
1170 | +{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER,ABS_HAT0X, ABS_HAT0Y, -1 }; | |
1171 | + | |
1172 | + | |
1173 | + | |
1174 | +static signed short ff_iforce[] = | |
1175 | +{ FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_DAMPER, | |
1176 | + FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, | |
1177 | + FF_AUTOCENTER, -1 }; | |
1178 | + | |
1179 | +static struct iforce_device iforce_device[] = { | |
1180 | + { 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce }, | |
1181 | + { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, | |
1182 | + { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, | |
1183 | + { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_avb_pegasus, abs_avb_pegasus, ff_iforce }, | |
1184 | + { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_avb_wheel, abs_wheel, ff_iforce }, | |
1185 | + { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, //? | |
1186 | + { 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //? | |
1187 | + { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? | |
1188 | + { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? | |
1189 | + { 0x06a3, 0xff12, "Saitek Cyborgforce", btn_saitek_joystick, abs_saitek_joystick, ff_iforce }, | |
1190 | + { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } | |
1191 | +}; | |
1192 | + | |
1193 | + | |
1194 | + | |
1195 | +static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | |
1196 | +{ | |
1197 | + struct iforce* iforce = (struct iforce*)(dev->private); | |
1198 | + unsigned char data[3]; | |
1199 | + | |
1200 | + if (type != EV_FF) | |
1201 | + return -1; | |
1202 | + | |
1203 | + switch (code) { | |
1204 | + | |
1205 | + case FF_GAIN: | |
1206 | + | |
1207 | + data[0] = value >> 9; | |
1208 | + iforce_send_packet(iforce, FF_CMD_GAIN, data); | |
1209 | + | |
1210 | + return 0; | |
1211 | + | |
1212 | + case FF_AUTOCENTER: | |
1213 | + | |
1214 | + data[0] = 0x03; | |
1215 | + data[1] = value >> 9; | |
1216 | + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | |
1217 | + | |
1218 | + data[0] = 0x04; | |
1219 | + data[1] = 0x01; | |
1220 | + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); | |
1221 | + | |
1222 | + return 0; | |
1223 | + | |
1224 | + default: /* Play or stop an effect */ | |
1225 | + | |
1226 | + if (value > 0) { | |
1227 | + set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | |
1228 | + } | |
1229 | + else { | |
1230 | + clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); | |
1231 | + } | |
1232 | + | |
1233 | + iforce_control_playback(iforce, code, value); | |
1234 | + return 0; | |
1235 | + } | |
1236 | + | |
1237 | + return -1; | |
1238 | +} | |
1239 | + | |
1240 | +/* | |
1241 | + * Function called when an ioctl is performed on the event dev entry. | |
1242 | + * It uploads an effect to the device | |
1243 | + */ | |
1244 | +static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | |
1245 | +{ | |
1246 | + struct iforce* iforce = (struct iforce*)(dev->private); | |
1247 | + int id; | |
1248 | + int ret; | |
1249 | + int is_update; | |
1250 | + | |
1251 | +/* Check this effect type is supported by this device */ | |
1252 | + if (!test_bit(effect->type, iforce->dev.ffbit)) | |
1253 | + return -EINVAL; | |
1254 | + | |
1255 | +/* | |
1256 | + * If we want to create a new effect, get a free id | |
1257 | + */ | |
1258 | + if (effect->id == -1) { | |
1259 | + | |
1260 | + for (id=0; id < FF_EFFECTS_MAX; ++id) | |
1261 | + if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; | |
1262 | + | |
1263 | + if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) | |
1264 | + return -ENOMEM; | |
1265 | + | |
1266 | + effect->id = id; | |
1267 | + iforce->core_effects[id].owner = current->pid; | |
1268 | + iforce->core_effects[id].flags[0] = (1<<FF_CORE_IS_USED); /* Only IS_USED bit must be set */ | |
1269 | + | |
1270 | + is_update = FALSE; | |
1271 | + } | |
1272 | + else { | |
1273 | + /* We want to update an effect */ | |
1274 | + /* Parameter type cannot be updated */ | |
1275 | + if (effect->type != iforce->core_effects[effect->id].effect.type) | |
1276 | + return -EINVAL; | |
1277 | + | |
1278 | + /* Check the effect is not already being updated */ | |
1279 | + if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { | |
1280 | + return -EAGAIN; | |
1281 | + } | |
1282 | + | |
1283 | + is_update = TRUE; | |
1284 | + } | |
1285 | + | |
1286 | +/* | |
1287 | + * Upload the effect | |
1288 | + */ | |
1289 | + switch (effect->type) { | |
1290 | + | |
1291 | + case FF_PERIODIC: | |
1292 | + ret = iforce_upload_periodic(iforce, effect, is_update); | |
1293 | + break; | |
1294 | + | |
1295 | + case FF_CONSTANT: | |
1296 | + ret = iforce_upload_constant(iforce, effect, is_update); | |
1297 | + break; | |
1298 | + | |
1299 | + case FF_SPRING: | |
1300 | + case FF_DAMPER: | |
1301 | + ret = iforce_upload_condition(iforce, effect, is_update); | |
1302 | + break; | |
1303 | + | |
1304 | + default: | |
1305 | + return -EINVAL; | |
1306 | + } | |
1307 | + if (ret == 0) { | |
1308 | + /* A packet was sent, forbid new updates until we are notified | |
1309 | + * that the packet was updated | |
1310 | + */ | |
1311 | + set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); | |
1312 | + } | |
1313 | + iforce->core_effects[effect->id].effect = *effect; | |
1314 | + return ret; | |
1315 | +} | |
1316 | + | |
1317 | +/* | |
1318 | + * Erases an effect: it frees the effect id and mark as unused the memory | |
1319 | + * allocated for the parameters | |
1320 | + */ | |
1321 | +static int iforce_erase_effect(struct input_dev *dev, int effect_id) | |
1322 | +{ | |
1323 | + struct iforce* iforce = (struct iforce*)(dev->private); | |
1324 | + int err = 0; | |
1325 | + struct iforce_core_effect* core_effect; | |
1326 | + | |
1327 | + if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) | |
1328 | + return -EINVAL; | |
1329 | + | |
1330 | + core_effect = iforce->core_effects + effect_id; | |
1331 | + | |
1332 | + if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) | |
1333 | + err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); | |
1334 | + | |
1335 | + if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) | |
1336 | + err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); | |
1337 | + | |
1338 | + /*TODO: remember to change that if more FF_MOD* bits are added */ | |
1339 | + core_effect->flags[0] = 0; | |
1340 | + | |
1341 | + return err; | |
1342 | +} | |
1343 | + | |
1344 | +static int iforce_open(struct input_dev *dev) | |
1345 | +{ | |
1346 | + struct iforce *iforce = dev->private; | |
1347 | + | |
1348 | + switch (iforce->bus) { | |
1349 | +#ifdef CONFIG_JOYSTICK_IFORCE_USB | |
1350 | + case IFORCE_USB: | |
1351 | + iforce->irq->dev = iforce->usbdev; | |
1352 | + if (usb_submit_urb(iforce->irq)) | |
1353 | + return -EIO; | |
1354 | + break; | |
1355 | +#endif | |
1356 | + } | |
1357 | + | |
1358 | + /* Enable force feedback */ | |
1359 | + iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); | |
1360 | + | |
1361 | + return 0; | |
1362 | +} | |
1363 | + | |
1364 | +static int iforce_flush(struct input_dev *dev, struct file *file) | |
1365 | +{ | |
1366 | + struct iforce *iforce = dev->private; | |
1367 | + int i; | |
1368 | + | |
1369 | + /* Erase all effects this process owns */ | |
1370 | + for (i=0; i<dev->ff_effects_max; ++i) { | |
1371 | + | |
1372 | + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | |
1373 | + current->pid == iforce->core_effects[i].owner) { | |
1374 | + | |
1375 | + /* Stop effect */ | |
1376 | + input_report_ff(dev, i, 0); | |
1377 | + | |
1378 | + /* Free ressources assigned to effect */ | |
1379 | + if (iforce_erase_effect(dev, i)) { | |
1380 | + printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i); | |
1381 | + } | |
1382 | + } | |
1383 | + | |
1384 | + } | |
1385 | + return 0; | |
1386 | +} | |
1387 | + | |
1388 | +static void iforce_release(struct input_dev *dev) | |
1389 | +{ | |
1390 | + struct iforce *iforce = dev->private; | |
1391 | + int i; | |
1392 | + | |
1393 | + /* Check: no effect should be present in memory */ | |
1394 | + for (i=0; i<dev->ff_effects_max; ++i) { | |
1395 | + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) | |
1396 | + break; | |
1397 | + } | |
1398 | + if (i<dev->ff_effects_max) { | |
1399 | + printk(KERN_WARNING "iforce_release: Device still owns effects\n"); | |
1400 | + } | |
1401 | + | |
1402 | + /* Disable force feedback playback */ | |
1403 | + iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); | |
1404 | + | |
1405 | + switch (iforce->bus) { | |
1406 | +#ifdef CONFIG_JOYSTICK_IFORCE_USB | |
1407 | + case IFORCE_USB: | |
1408 | + usb_unlink_urb(iforce->irq); | |
1409 | + | |
1410 | + /* The device was unplugged before the file | |
1411 | + * was released */ | |
1412 | + if (iforce->usbdev == NULL) { | |
1413 | + iforce_delete_device(iforce); | |
1414 | + kfree(iforce); | |
1415 | + } | |
1416 | + break; | |
1417 | +#endif | |
1418 | + } | |
1419 | +} | |
1420 | + | |
1421 | +void iforce_delete_device(struct iforce *iforce) | |
1422 | +{ | |
1423 | + switch (iforce->bus) { | |
1424 | +#ifdef CONFIG_JOYSTICK_IFORCE_USB | |
1425 | + case IFORCE_USB: | |
1426 | + iforce_usb_delete(iforce); | |
1427 | + break; | |
1428 | +#endif | |
1429 | +#ifdef CONFIG_JOYSTICK_IFORCE_232 | |
1430 | + case IFORCE_232: | |
1431 | + //TODO: Wait for the last packets to be sent | |
1432 | + break; | |
1433 | +#endif | |
1434 | + } | |
1435 | +} | |
1436 | + | |
1437 | +int iforce_init_device(struct iforce *iforce) | |
1438 | +{ | |
1439 | + unsigned char c[] = "CEOV"; | |
1440 | + int i; | |
1441 | + | |
1442 | + init_waitqueue_head(&iforce->wait); | |
1443 | + spin_lock_init(&iforce->xmit_lock); | |
1444 | + init_MUTEX(&iforce->mem_mutex); | |
1445 | + iforce->xmit.buf = iforce->xmit_data; | |
1446 | + | |
1447 | + iforce->dev.ff_effects_max = 10; | |
1448 | + | |
1449 | +/* | |
1450 | + * Input device fields. | |
1451 | + */ | |
1452 | + | |
1453 | + iforce->dev.idbus = BUS_USB; | |
1454 | + iforce->dev.private = iforce; | |
1455 | + iforce->dev.name = "Unknown I-Force device"; | |
1456 | + iforce->dev.open = iforce_open; | |
1457 | + iforce->dev.close = iforce_release; | |
1458 | + iforce->dev.flush = iforce_flush; | |
1459 | + iforce->dev.event = iforce_input_event; | |
1460 | + iforce->dev.upload_effect = iforce_upload_effect; | |
1461 | + iforce->dev.erase_effect = iforce_erase_effect; | |
1462 | + | |
1463 | +/* | |
1464 | + * On-device memory allocation. | |
1465 | + */ | |
1466 | + | |
1467 | + iforce->device_memory.name = "I-Force device effect memory"; | |
1468 | + iforce->device_memory.start = 0; | |
1469 | + iforce->device_memory.end = 200; | |
1470 | + iforce->device_memory.flags = IORESOURCE_MEM; | |
1471 | + iforce->device_memory.parent = NULL; | |
1472 | + iforce->device_memory.child = NULL; | |
1473 | + iforce->device_memory.sibling = NULL; | |
1474 | + | |
1475 | +/* | |
1476 | + * Wait until device ready - until it sends its first response. | |
1477 | + */ | |
1478 | + | |
1479 | + for (i = 0; i < 20; i++) | |
1480 | + if (!iforce_get_id_packet(iforce, "O")) | |
1481 | + break; | |
1482 | + | |
1483 | + if (i == 20) { /* 5 seconds */ | |
1484 | + printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n"); | |
1485 | + return -1; | |
1486 | + } | |
1487 | + | |
1488 | +/* | |
1489 | + * Get device info. | |
1490 | + */ | |
1491 | + | |
1492 | + if (!iforce_get_id_packet(iforce, "M")) | |
1493 | + iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; | |
1494 | + else | |
1495 | + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n"); | |
1496 | + | |
1497 | + if (!iforce_get_id_packet(iforce, "P")) | |
1498 | + iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; | |
1499 | + else | |
1500 | + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n"); | |
1501 | + | |
1502 | + if (!iforce_get_id_packet(iforce, "B")) | |
1503 | + iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; | |
1504 | + else | |
1505 | + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); | |
1506 | + | |
1507 | + if (!iforce_get_id_packet(iforce, "N")) | |
1508 | + iforce->dev.ff_effects_max = iforce->edata[1]; | |
1509 | + else | |
1510 | + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); | |
1511 | + | |
1512 | + /* Check if the device can store more effects than the driver can really handle */ | |
1513 | + if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { | |
1514 | + printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", | |
1515 | + iforce->dev.ff_effects_max, FF_EFFECTS_MAX); | |
1516 | + iforce->dev.ff_effects_max = FF_EFFECTS_MAX; | |
1517 | + } | |
1518 | + | |
1519 | +/* | |
1520 | + * Display additional info. | |
1521 | + */ | |
1522 | + | |
1523 | + for (i = 0; c[i]; i++) | |
1524 | + if (!iforce_get_id_packet(iforce, c + i)) | |
1525 | + iforce_dump_packet("info", iforce->ecmd, iforce->edata); | |
1526 | + | |
1527 | +/* | |
1528 | + * Disable spring, enable force feedback. | |
1529 | + * FIXME: We should use iforce_set_autocenter() et al here. | |
1530 | + */ | |
1531 | + | |
1532 | + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); | |
1533 | + | |
1534 | +/* | |
1535 | + * Find appropriate device entry | |
1536 | + */ | |
1537 | + | |
1538 | + for (i = 0; iforce_device[i].idvendor; i++) | |
1539 | + if (iforce_device[i].idvendor == iforce->dev.idvendor && | |
1540 | + iforce_device[i].idproduct == iforce->dev.idproduct) | |
1541 | + break; | |
1542 | + | |
1543 | + iforce->type = iforce_device + i; | |
1544 | + iforce->dev.name = iforce->type->name; | |
1545 | + | |
1546 | +/* | |
1547 | + * Set input device bitfields and ranges. | |
1548 | + */ | |
1549 | + | |
1550 | + iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); | |
1551 | + | |
1552 | + for (i = 0; iforce->type->btn[i] >= 0; i++) { | |
1553 | + signed short t = iforce->type->btn[i]; | |
1554 | + set_bit(t, iforce->dev.keybit); | |
1555 | + } | |
1556 | + set_bit(BTN_DEAD, iforce->dev.keybit); | |
1557 | + | |
1558 | + for (i = 0; iforce->type->abs[i] >= 0; i++) { | |
1559 | + | |
1560 | + signed short t = iforce->type->abs[i]; | |
1561 | + set_bit(t, iforce->dev.absbit); | |
1562 | + | |
1563 | + switch (t) { | |
1564 | + | |
1565 | + case ABS_X: | |
1566 | + case ABS_Y: | |
1567 | + case ABS_WHEEL: | |
1568 | + if (iforce->dev.idvendor == USB_VENDOR_ID_SAITEK && iforce->dev.idproduct == USB_PRODUCT_ID_CYBORGFORCE) | |
1569 | + { | |
1570 | + iforce->dev.absmax[t] = 0x1000; | |
1571 | + iforce->dev.absmin[t] = 0; | |
1572 | + } | |
1573 | + else { | |
1574 | + iforce->dev.absmax[t] = 1920; | |
1575 | + iforce->dev.absmin[t] = -1920; | |
1576 | + } | |
1577 | + iforce->dev.absflat[t] = 128; | |
1578 | + iforce->dev.absfuzz[t] = 16; | |
1579 | + set_bit(t, iforce->dev.ffbit); | |
1580 | + break; | |
1581 | + | |
1582 | + case ABS_THROTTLE: | |
1583 | + case ABS_GAS: | |
1584 | + case ABS_BRAKE: | |
1585 | + | |
1586 | + iforce->dev.absmax[t] = 255; | |
1587 | + iforce->dev.absmin[t] = 0; | |
1588 | + break; | |
1589 | + | |
1590 | + case ABS_RUDDER: | |
1591 | + if (iforce->dev.idvendor == USB_VENDOR_ID_SAITEK && iforce->dev.idproduct == USB_PRODUCT_ID_CYBORGFORCE) | |
1592 | + { | |
1593 | + iforce->dev.absmax[t] = 255; | |
1594 | + iforce->dev.absmin[t] = 0; | |
1595 | + iforce->dev.absflat[t] = 10; | |
1596 | + iforce->dev.absfuzz[t] = 4; | |
1597 | + | |
1598 | + } | |
1599 | + else | |
1600 | + { | |
1601 | + iforce->dev.absmax[t] = 127; | |
1602 | + iforce->dev.absmin[t] = -128; | |
1603 | + | |
1604 | + } | |
1605 | + break; | |
1606 | + | |
1607 | + case ABS_HAT0X: | |
1608 | + case ABS_HAT0Y: | |
1609 | + case ABS_HAT1X: | |
1610 | + case ABS_HAT1Y: | |
1611 | + iforce->dev.absmax[t] = 1; | |
1612 | + iforce->dev.absmin[t] = -1; | |
1613 | + break; | |
1614 | + } | |
1615 | + } | |
1616 | + | |
1617 | + for (i = 0; iforce->type->ff[i] >= 0; i++) | |
1618 | + set_bit(iforce->type->ff[i], iforce->dev.ffbit); | |
1619 | + | |
1620 | +/* | |
1621 | + * Register input device. | |
1622 | + */ | |
1623 | + | |
1624 | + input_register_device(&iforce->dev); | |
1625 | + | |
1626 | + printk(KERN_DEBUG "iforce->dev.open = %p\n", iforce->dev.open); | |
1627 | + | |
1628 | + printk(KERN_INFO "input: %s [%d effects, %ld bytes memory]\n", | |
1629 | + iforce->dev.name, iforce->dev.ff_effects_max, | |
1630 | + iforce->device_memory.end); | |
1631 | + | |
1632 | + return 0; | |
1633 | +} | |
1634 | + | |
1635 | +static int __init iforce_init(void) | |
1636 | +{ | |
1637 | +#ifdef CONFIG_JOYSTICK_IFORCE_USB | |
1638 | + usb_register(&iforce_usb_driver); | |
1639 | +#endif | |
1640 | +#ifdef CONFIG_JOYSTICK_IFORCE_232 | |
1641 | + serio_register_device(&iforce_serio_dev); | |
1642 | +#endif | |
1643 | + return 0; | |
1644 | +} | |
1645 | + | |
1646 | +static void __exit iforce_exit(void) | |
1647 | +{ | |
1648 | +#ifdef CONFIG_JOYSTICK_IFORCE_USB | |
1649 | + usb_deregister(&iforce_usb_driver); | |
1650 | +#endif | |
1651 | +#ifdef CONFIG_JOYSTICK_IFORCE_232 | |
1652 | + serio_unregister_device(&iforce_serio_dev); | |
1653 | +#endif | |
1654 | +} | |
1655 | + | |
1656 | +module_init(iforce_init); | |
1657 | +module_exit(iforce_exit); | |
1658 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/iforce-packets.c linux-modified/drivers/char/joystick/iforce/iforce-packets.c | |
1659 | --- linux-vanilla/drivers/char/joystick/iforce/iforce-packets.c Thu Jan 1 02:00:00 1970 | |
1660 | +++ linux-modified/drivers/char/joystick/iforce/iforce-packets.c Mon Feb 17 21:28:41 2003 | |
1661 | @@ -0,0 +1,320 @@ | |
1662 | +/* | |
1663 | + * $Id$ | |
1664 | + * | |
1665 | + * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | |
1666 | + * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | |
1667 | + * | |
1668 | + * USB/RS232 I-Force joysticks and wheels. | |
1669 | + */ | |
1670 | + | |
1671 | +/* | |
1672 | + * This program is free software; you can redistribute it and/or modify | |
1673 | + * it under the terms of the GNU General Public License as published by | |
1674 | + * the Free Software Foundation; either version 2 of the License, or | |
1675 | + * (at your option) any later version. | |
1676 | + * | |
1677 | + * This program is distributed in the hope that it will be useful, | |
1678 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
1679 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
1680 | + * GNU General Public License for more details. | |
1681 | + * | |
1682 | + * You should have received a copy of the GNU General Public License | |
1683 | + * along with this program; if not, write to the Free Software | |
1684 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
1685 | + * | |
1686 | + * Should you need to contact me, the author, you can do so either by | |
1687 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
1688 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
1689 | + */ | |
1690 | + | |
1691 | +#include "iforce.h" | |
1692 | + | |
1693 | +static struct { | |
1694 | + __s32 x; | |
1695 | + __s32 y; | |
1696 | +} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | |
1697 | + | |
1698 | + | |
1699 | +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) | |
1700 | +{ | |
1701 | + int i; | |
1702 | + | |
1703 | + printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); | |
1704 | + for (i = 0; i < LO(cmd); i++) | |
1705 | + printk("%02x ", data[i]); | |
1706 | + printk(")\n"); | |
1707 | +} | |
1708 | + | |
1709 | +/* | |
1710 | + * Send a packet of bytes to the device | |
1711 | + */ | |
1712 | +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) | |
1713 | +{ | |
1714 | + /* Copy data to buffer */ | |
1715 | + int n = LO(cmd); | |
1716 | + int c; | |
1717 | + int empty; | |
1718 | + int head, tail; | |
1719 | + unsigned long flags; | |
1720 | + | |
1721 | +/* | |
1722 | + * Update head and tail of xmit buffer | |
1723 | + */ | |
1724 | + spin_lock_irqsave(&iforce->xmit_lock, flags); | |
1725 | + | |
1726 | + head = iforce->xmit.head; | |
1727 | + tail = iforce->xmit.tail; | |
1728 | + | |
1729 | + if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { | |
1730 | + printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n"); | |
1731 | + spin_unlock_irqrestore(&iforce->xmit_lock, flags); | |
1732 | + return -1; | |
1733 | + } | |
1734 | + | |
1735 | + empty = head == tail; | |
1736 | + XMIT_INC(iforce->xmit.head, n+2); | |
1737 | + | |
1738 | +/* | |
1739 | + * Store packet in xmit buffer | |
1740 | + */ | |
1741 | + iforce->xmit.buf[head] = HI(cmd); | |
1742 | + XMIT_INC(head, 1); | |
1743 | + iforce->xmit.buf[head] = LO(cmd); | |
1744 | + XMIT_INC(head, 1); | |
1745 | + | |
1746 | + c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); | |
1747 | + if (n < c) c=n; | |
1748 | + | |
1749 | + memcpy(&iforce->xmit.buf[head], | |
1750 | + data, | |
1751 | + c); | |
1752 | + if (n != c) { | |
1753 | + memcpy(&iforce->xmit.buf[0], | |
1754 | + data + c, | |
1755 | + n - c); | |
1756 | + } | |
1757 | + XMIT_INC(head, n); | |
1758 | + | |
1759 | + spin_unlock_irqrestore(&iforce->xmit_lock, flags); | |
1760 | +/* | |
1761 | + * If necessary, start the transmission | |
1762 | + */ | |
1763 | + switch (iforce->bus) { | |
1764 | + | |
1765 | +#ifdef CONFIG_JOYSTICK_IFORCE_232 | |
1766 | + case IFORCE_232: | |
1767 | + if (empty) | |
1768 | + iforce_serial_xmit(iforce); | |
1769 | + break; | |
1770 | +#endif | |
1771 | +#ifdef CONFIG_JOYSTICK_IFORCE_USB | |
1772 | + case IFORCE_USB: | |
1773 | + | |
1774 | + if (iforce->usbdev && empty && | |
1775 | + !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { | |
1776 | + | |
1777 | + iforce_usb_xmit(iforce); | |
1778 | + } | |
1779 | + break; | |
1780 | +#endif | |
1781 | + } | |
1782 | + return 0; | |
1783 | +} | |
1784 | + | |
1785 | +/* Start or stop an effect */ | |
1786 | +int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) | |
1787 | +{ | |
1788 | + unsigned char data[3]; | |
1789 | + | |
1790 | +//printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); | |
1791 | + | |
1792 | + data[0] = LO(id); | |
1793 | + data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; | |
1794 | + data[2] = LO(value); | |
1795 | + return iforce_send_packet(iforce, FF_CMD_PLAY, data); | |
1796 | +} | |
1797 | + | |
1798 | +/* Mark an effect that was being updated as ready. That means it can be updated | |
1799 | + * again */ | |
1800 | +static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) | |
1801 | +{ | |
1802 | + int i; | |
1803 | + for (i=0; i<iforce->dev.ff_effects_max; ++i) { | |
1804 | + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && | |
1805 | + (iforce->core_effects[i].mod1_chunk.start == addr || | |
1806 | + iforce->core_effects[i].mod2_chunk.start == addr)) { | |
1807 | + clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags); | |
1808 | + return 0; | |
1809 | + } | |
1810 | + } | |
1811 | + printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr); | |
1812 | + return -1; | |
1813 | +} | |
1814 | + | |
1815 | +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) | |
1816 | +{ | |
1817 | + struct input_dev *dev = &iforce->dev; | |
1818 | + int i; | |
1819 | + static int being_used = 0; | |
1820 | + | |
1821 | + if (being_used) | |
1822 | + printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used); | |
1823 | + being_used++; | |
1824 | + | |
1825 | +#ifdef CONFIG_JOYSTICK_IFORCE_232 | |
1826 | + if (HI(iforce->expect_packet) == HI(cmd)) { | |
1827 | + iforce->expect_packet = 0; | |
1828 | + iforce->ecmd = cmd; | |
1829 | + memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); | |
1830 | + if (waitqueue_active(&iforce->wait)) | |
1831 | + wake_up(&iforce->wait); | |
1832 | + } | |
1833 | +#endif | |
1834 | + | |
1835 | + if (!iforce->type) { | |
1836 | + being_used--; | |
1837 | + return; | |
1838 | + } | |
1839 | + | |
1840 | + switch (HI(cmd)) { | |
1841 | + | |
1842 | + case 0x01: /* joystick position data */ | |
1843 | + case 0x03: /* wheel position data */ | |
1844 | + case 0x06: /*saitek cyborgforve data */ | |
1845 | + if (HI(cmd) == 6) { | |
1846 | + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); | |
1847 | + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); | |
1848 | + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); | |
1849 | + input_report_abs(dev, ABS_RUDDER, 255 - data[7]); | |
1850 | + } | |
1851 | + else if (HI(cmd) == 1) { | |
1852 | + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); | |
1853 | + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); | |
1854 | + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); | |
1855 | + if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) | |
1856 | + input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); | |
1857 | + } else { | |
1858 | + input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); | |
1859 | + input_report_abs(dev, ABS_GAS, 255 - data[2]); | |
1860 | + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); | |
1861 | + } | |
1862 | + | |
1863 | + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); | |
1864 | + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); | |
1865 | + | |
1866 | + for (i = 0; iforce->type->btn[i] >= 0; i++) | |
1867 | + input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); | |
1868 | + | |
1869 | + /* If there are untouched bits left, interpret them as the second hat */ | |
1870 | + if (i <= 8) { | |
1871 | + int btns = data[6]; | |
1872 | + if (test_bit(ABS_HAT1X, dev->absbit)) { | |
1873 | + if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1); | |
1874 | + else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1); | |
1875 | + else input_report_abs(dev, ABS_HAT1X, 0); | |
1876 | + } | |
1877 | + if (test_bit(ABS_HAT1Y, dev->absbit)) { | |
1878 | + if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1); | |
1879 | + else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1); | |
1880 | + else input_report_abs(dev, ABS_HAT1Y, 0); | |
1881 | + } | |
1882 | + } | |
1883 | + | |
1884 | + break; | |
1885 | + | |
1886 | + case 0x02: /* status report */ | |
1887 | + input_report_key(dev, BTN_DEAD, data[0] & 0x02); | |
1888 | + | |
1889 | + /* Check if an effect was just started or stopped */ | |
1890 | + i = data[1] & 0x7f; | |
1891 | + if (data[1] & 0x80) { | |
1892 | + if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | |
1893 | + /* Report play event */ | |
1894 | + input_report_ff_status(dev, i, FF_STATUS_PLAYING); | |
1895 | + } | |
1896 | + } | |
1897 | + else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { | |
1898 | + /* Report stop event */ | |
1899 | + input_report_ff_status(dev, i, FF_STATUS_STOPPED); | |
1900 | + } | |
1901 | + if (LO(cmd) > 3) { | |
1902 | + int j; | |
1903 | + for (j=3; j<LO(cmd); j+=2) { | |
1904 | + mark_core_as_ready(iforce, data[j] | (data[j+1]<<8)); | |
1905 | + } | |
1906 | + } | |
1907 | + break; | |
1908 | + } | |
1909 | + being_used--; | |
1910 | +} | |
1911 | + | |
1912 | +int iforce_get_id_packet(struct iforce *iforce, char *packet) | |
1913 | +{ | |
1914 | + DECLARE_WAITQUEUE(wait, current); | |
1915 | + int timeout = HZ; /* 1 second */ | |
1916 | + | |
1917 | + switch (iforce->bus) { | |
1918 | + | |
1919 | + case IFORCE_USB: | |
1920 | + | |
1921 | +#ifdef CONFIG_JOYSTICK_IFORCE_USB | |
1922 | + iforce->dr.bRequest = packet[0]; | |
1923 | + iforce->ctrl->dev = iforce->usbdev; | |
1924 | + | |
1925 | + set_current_state(TASK_INTERRUPTIBLE); | |
1926 | + add_wait_queue(&iforce->wait, &wait); | |
1927 | + | |
1928 | + if (usb_submit_urb(iforce->ctrl)) { | |
1929 | + set_current_state(TASK_RUNNING); | |
1930 | + remove_wait_queue(&iforce->wait, &wait); | |
1931 | + return -1; | |
1932 | + } | |
1933 | + | |
1934 | + while (timeout && iforce->ctrl->status == -EINPROGRESS) | |
1935 | + timeout = schedule_timeout(timeout); | |
1936 | + | |
1937 | + set_current_state(TASK_RUNNING); | |
1938 | + remove_wait_queue(&iforce->wait, &wait); | |
1939 | + | |
1940 | + if (!timeout) { | |
1941 | + usb_unlink_urb(iforce->ctrl); | |
1942 | + return -1; | |
1943 | + } | |
1944 | +#else | |
1945 | + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n"); | |
1946 | +#endif | |
1947 | + break; | |
1948 | + | |
1949 | + case IFORCE_232: | |
1950 | + | |
1951 | +#ifdef CONFIG_JOYSTICK_IFORCE_232 | |
1952 | + iforce->expect_packet = FF_CMD_QUERY; | |
1953 | + iforce_send_packet(iforce, FF_CMD_QUERY, packet); | |
1954 | + | |
1955 | + set_current_state(TASK_INTERRUPTIBLE); | |
1956 | + add_wait_queue(&iforce->wait, &wait); | |
1957 | + | |
1958 | + while (timeout && iforce->expect_packet) | |
1959 | + timeout = schedule_timeout(timeout); | |
1960 | + | |
1961 | + set_current_state(TASK_RUNNING); | |
1962 | + remove_wait_queue(&iforce->wait, &wait); | |
1963 | + | |
1964 | + if (!timeout) { | |
1965 | + iforce->expect_packet = 0; | |
1966 | + return -1; | |
1967 | + } | |
1968 | +#else | |
1969 | + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n"); | |
1970 | +#endif | |
1971 | + break; | |
1972 | + | |
1973 | + default: | |
1974 | + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n", | |
1975 | + iforce->bus); | |
1976 | + break; | |
1977 | + } | |
1978 | + | |
1979 | + return -(iforce->edata[0] != packet[0]); | |
1980 | +} | |
1981 | + | |
1982 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/iforce-serio.c linux-modified/drivers/char/joystick/iforce/iforce-serio.c | |
1983 | --- linux-vanilla/drivers/char/joystick/iforce/iforce-serio.c Thu Jan 1 02:00:00 1970 | |
1984 | +++ linux-modified/drivers/char/joystick/iforce/iforce-serio.c Mon Jan 6 16:48:20 2003 | |
1985 | @@ -0,0 +1,166 @@ | |
1986 | +/* | |
1987 | + * $Id$ | |
1988 | + * | |
1989 | + * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> | |
1990 | + * Copyright (c) 2001 Johann Deneux <deneux@ifrance.com> | |
1991 | + * | |
1992 | + * USB/RS232 I-Force joysticks and wheels. | |
1993 | + */ | |
1994 | + | |
1995 | +/* | |
1996 | + * This program is free software; you can redistribute it and/or modify | |
1997 | + * it under the terms of the GNU General Public License as published by | |
1998 | + * the Free Software Foundation; either version 2 of the License, or | |
1999 | + * (at your option) any later version. | |
2000 | + * | |
2001 | + * This program is distributed in the hope that it will be useful, | |
2002 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2003 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2004 | + * GNU General Public License for more details. | |
2005 | + * | |
2006 | + * You should have received a copy of the GNU General Public License | |
2007 | + * along with this program; if not, write to the Free Software | |
2008 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
2009 | + * | |
2010 | + * Should you need to contact me, the author, you can do so either by | |
2011 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
2012 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
2013 | + */ | |
2014 | + | |
2015 | +#include "iforce.h" | |
2016 | + | |
2017 | +void iforce_serial_xmit(struct iforce *iforce) | |
2018 | +{ | |
2019 | + unsigned char cs; | |
2020 | + int i; | |
2021 | + unsigned long flags; | |
2022 | + | |
2023 | + if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { | |
2024 | + set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); | |
2025 | + return; | |
2026 | + } | |
2027 | + | |
2028 | + spin_lock_irqsave(&iforce->xmit_lock, flags); | |
2029 | + | |
2030 | +again: | |
2031 | + if (iforce->xmit.head == iforce->xmit.tail) { | |
2032 | + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | |
2033 | + spin_unlock_irqrestore(&iforce->xmit_lock, flags); | |
2034 | + return; | |
2035 | + } | |
2036 | + | |
2037 | + cs = 0x2b; | |
2038 | + | |
2039 | + serio_write(iforce->serio, 0x2b); | |
2040 | + | |
2041 | + serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); | |
2042 | + cs ^= iforce->xmit.buf[iforce->xmit.tail]; | |
2043 | + XMIT_INC(iforce->xmit.tail, 1); | |
2044 | + | |
2045 | + for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { | |
2046 | + serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); | |
2047 | + cs ^= iforce->xmit.buf[iforce->xmit.tail]; | |
2048 | + XMIT_INC(iforce->xmit.tail, 1); | |
2049 | + } | |
2050 | + | |
2051 | + serio_write(iforce->serio, cs); | |
2052 | + | |
2053 | + if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) | |
2054 | + goto again; | |
2055 | + | |
2056 | + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | |
2057 | + | |
2058 | + spin_unlock_irqrestore(&iforce->xmit_lock, flags); | |
2059 | +} | |
2060 | + | |
2061 | +static void iforce_serio_write_wakeup(struct serio *serio) | |
2062 | +{ | |
2063 | + iforce_serial_xmit((struct iforce *)serio->private); | |
2064 | +} | |
2065 | + | |
2066 | +static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) | |
2067 | +{ | |
2068 | + struct iforce* iforce = serio->private; | |
2069 | + | |
2070 | + if (!iforce->pkt) { | |
2071 | + if (data != 0x2b) { | |
2072 | + return; | |
2073 | + } | |
2074 | + iforce->pkt = 1; | |
2075 | + return; | |
2076 | + } | |
2077 | + | |
2078 | + if (!iforce->id) { | |
2079 | + if (data > 3 && data != 0xff) { | |
2080 | + iforce->pkt = 0; | |
2081 | + return; | |
2082 | + } | |
2083 | + iforce->id = data; | |
2084 | + return; | |
2085 | + } | |
2086 | + | |
2087 | + if (!iforce->len) { | |
2088 | + if (data > IFORCE_MAX_LENGTH) { | |
2089 | + iforce->pkt = 0; | |
2090 | + iforce->id = 0; | |
2091 | + return; | |
2092 | + } | |
2093 | + iforce->len = data; | |
2094 | + return; | |
2095 | + } | |
2096 | + | |
2097 | + if (iforce->idx < iforce->len) { | |
2098 | + iforce->csum += iforce->data[iforce->idx++] = data; | |
2099 | + return; | |
2100 | + } | |
2101 | + | |
2102 | + if (iforce->idx == iforce->len) { | |
2103 | + iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); | |
2104 | + iforce->pkt = 0; | |
2105 | + iforce->id = 0; | |
2106 | + iforce->len = 0; | |
2107 | + iforce->idx = 0; | |
2108 | + iforce->csum = 0; | |
2109 | + } | |
2110 | +} | |
2111 | + | |
2112 | +static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) | |
2113 | +{ | |
2114 | + struct iforce *iforce; | |
2115 | + if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) | |
2116 | + return; | |
2117 | + | |
2118 | + if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; | |
2119 | + memset(iforce, 0, sizeof(struct iforce)); | |
2120 | + | |
2121 | + iforce->bus = IFORCE_232; | |
2122 | + iforce->serio = serio; | |
2123 | + serio->private = iforce; | |
2124 | + | |
2125 | + if (serio_open(serio, dev)) { | |
2126 | + kfree(iforce); | |
2127 | + return; | |
2128 | + } | |
2129 | + | |
2130 | + if (iforce_init_device(iforce)) { | |
2131 | + serio_close(serio); | |
2132 | + kfree(iforce); | |
2133 | + return; | |
2134 | + } | |
2135 | +} | |
2136 | + | |
2137 | +static void iforce_serio_disconnect(struct serio *serio) | |
2138 | +{ | |
2139 | + struct iforce* iforce = serio->private; | |
2140 | + | |
2141 | + input_unregister_device(&iforce->dev); | |
2142 | + serio_close(serio); | |
2143 | + kfree(iforce); | |
2144 | +} | |
2145 | + | |
2146 | +struct serio_dev iforce_serio_dev = { | |
2147 | + write_wakeup: iforce_serio_write_wakeup, | |
2148 | + interrupt: iforce_serio_irq, | |
2149 | + connect: iforce_serio_connect, | |
2150 | + disconnect: iforce_serio_disconnect, | |
2151 | +}; | |
2152 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/iforce-usb.c linux-modified/drivers/char/joystick/iforce/iforce-usb.c | |
2153 | --- linux-vanilla/drivers/char/joystick/iforce/iforce-usb.c Thu Jan 1 02:00:00 1970 | |
2154 | +++ linux-modified/drivers/char/joystick/iforce/iforce-usb.c Mon Feb 17 21:28:41 2003 | |
2155 | @@ -0,0 +1,211 @@ | |
2156 | + /* | |
2157 | + * $Id$ | |
2158 | + * | |
2159 | + * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | |
2160 | + * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | |
2161 | + * | |
2162 | + * USB/RS232 I-Force joysticks and wheels. | |
2163 | + */ | |
2164 | + | |
2165 | +/* | |
2166 | + * This program is free software; you can redistribute it and/or modify | |
2167 | + * it under the terms of the GNU General Public License as published by | |
2168 | + * the Free Software Foundation; either version 2 of the License, or | |
2169 | + * (at your option) any later version. | |
2170 | + * | |
2171 | + * This program is distributed in the hope that it will be useful, | |
2172 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2173 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2174 | + * GNU General Public License for more details. | |
2175 | + * | |
2176 | + * You should have received a copy of the GNU General Public License | |
2177 | + * along with this program; if not, write to the Free Software | |
2178 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
2179 | + * | |
2180 | + * Should you need to contact me, the author, you can do so either by | |
2181 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
2182 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
2183 | + */ | |
2184 | + | |
2185 | +#include "iforce.h" | |
2186 | + | |
2187 | +void iforce_usb_xmit(struct iforce *iforce) | |
2188 | +{ | |
2189 | + int n, c; | |
2190 | + unsigned long flags; | |
2191 | + | |
2192 | + spin_lock_irqsave(&iforce->xmit_lock, flags); | |
2193 | + | |
2194 | + if (iforce->xmit.head == iforce->xmit.tail) { | |
2195 | + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); | |
2196 | + spin_unlock_irqrestore(&iforce->xmit_lock, flags); | |
2197 | + return; | |
2198 | + } | |
2199 | + | |
2200 | + ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; | |
2201 | + XMIT_INC(iforce->xmit.tail, 1); | |
2202 | + n = iforce->xmit.buf[iforce->xmit.tail]; | |
2203 | + XMIT_INC(iforce->xmit.tail, 1); | |
2204 | + | |
2205 | + iforce->out->transfer_buffer_length = n + 1; | |
2206 | + iforce->out->dev = iforce->usbdev; | |
2207 | + | |
2208 | + /* Copy rest of data then */ | |
2209 | + c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); | |
2210 | + if (n < c) c=n; | |
2211 | + | |
2212 | + memcpy(iforce->out->transfer_buffer + 1, | |
2213 | + &iforce->xmit.buf[iforce->xmit.tail], | |
2214 | + c); | |
2215 | + if (n != c) { | |
2216 | + memcpy(iforce->out->transfer_buffer + 1 + c, | |
2217 | + &iforce->xmit.buf[0], | |
2218 | + n-c); | |
2219 | + } | |
2220 | + XMIT_INC(iforce->xmit.tail, n); | |
2221 | + | |
2222 | + spin_unlock_irqrestore(&iforce->xmit_lock, flags); | |
2223 | + | |
2224 | + if ( (n=usb_submit_urb(iforce->out)) ) { | |
2225 | + printk(KERN_WARNING "iforce.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n); | |
2226 | + } | |
2227 | +} | |
2228 | + | |
2229 | +static void iforce_usb_irq(struct urb *urb) | |
2230 | +{ | |
2231 | + struct iforce *iforce = urb->context; | |
2232 | + if (urb->status) return; | |
2233 | + iforce_process_packet(iforce, | |
2234 | + (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); | |
2235 | +} | |
2236 | + | |
2237 | +static void iforce_usb_out(struct urb *urb) | |
2238 | +{ | |
2239 | + struct iforce *iforce = urb->context; | |
2240 | + | |
2241 | + if (urb->status) { | |
2242 | + printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status); | |
2243 | + return; | |
2244 | + } | |
2245 | + | |
2246 | + iforce_usb_xmit(iforce); | |
2247 | + | |
2248 | + if (waitqueue_active(&iforce->wait)) | |
2249 | + wake_up(&iforce->wait); | |
2250 | +} | |
2251 | + | |
2252 | +static void iforce_usb_ctrl(struct urb *urb) | |
2253 | +{ | |
2254 | + struct iforce *iforce = urb->context; | |
2255 | + if (urb->status) return; | |
2256 | + iforce->ecmd = 0xff00 | urb->actual_length; | |
2257 | + if (waitqueue_active(&iforce->wait)) | |
2258 | + wake_up(&iforce->wait); | |
2259 | +} | |
2260 | + | |
2261 | +static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, | |
2262 | + const struct usb_device_id *id) | |
2263 | +{ | |
2264 | + struct usb_endpoint_descriptor *epirq, *epout; | |
2265 | + struct iforce *iforce; | |
2266 | + | |
2267 | + epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; | |
2268 | + epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; | |
2269 | + | |
2270 | + if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) | |
2271 | + goto fail; | |
2272 | + | |
2273 | + memset(iforce, 0, sizeof(struct iforce)); | |
2274 | + | |
2275 | + if (!(iforce->irq = usb_alloc_urb(0))) { | |
2276 | + goto fail; | |
2277 | + } | |
2278 | + | |
2279 | + if (!(iforce->out = usb_alloc_urb(0))) { | |
2280 | + goto fail; | |
2281 | + } | |
2282 | + | |
2283 | + if (!(iforce->ctrl = usb_alloc_urb(0))) { | |
2284 | + goto fail; | |
2285 | + } | |
2286 | + | |
2287 | + iforce->bus = IFORCE_USB; | |
2288 | + iforce->usbdev = dev; | |
2289 | + | |
2290 | + iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; | |
2291 | + iforce->dr.wIndex = 0; | |
2292 | + iforce->dr.wLength = 16; | |
2293 | + | |
2294 | + usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), | |
2295 | + iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); | |
2296 | + | |
2297 | + usb_fill_bulk_urb(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), | |
2298 | + iforce + 1, 32, iforce_usb_out, iforce); | |
2299 | + | |
2300 | + usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), | |
2301 | + (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce); | |
2302 | + | |
2303 | + if (iforce_init_device(iforce)) goto fail; | |
2304 | + | |
2305 | + return iforce; | |
2306 | + | |
2307 | +fail: | |
2308 | + if (iforce) { | |
2309 | + if (iforce->irq) usb_free_urb(iforce->irq); | |
2310 | + if (iforce->out) usb_free_urb(iforce->out); | |
2311 | + if (iforce->ctrl) usb_free_urb(iforce->ctrl); | |
2312 | + kfree(iforce); | |
2313 | + } | |
2314 | + | |
2315 | + return NULL; | |
2316 | +} | |
2317 | + | |
2318 | +/* Called by iforce_delete() */ | |
2319 | +void iforce_usb_delete(struct iforce* iforce) | |
2320 | +{ | |
2321 | + usb_unlink_urb(iforce->irq); | |
2322 | + usb_unlink_urb(iforce->out); | |
2323 | + usb_unlink_urb(iforce->ctrl); | |
2324 | + | |
2325 | + usb_free_urb(iforce->irq); | |
2326 | + usb_free_urb(iforce->out); | |
2327 | + usb_free_urb(iforce->ctrl); | |
2328 | +} | |
2329 | + | |
2330 | +static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) | |
2331 | +{ | |
2332 | + struct iforce *iforce = ptr; | |
2333 | + int open = iforce->dev.handle->open; | |
2334 | + | |
2335 | + iforce->usbdev = NULL; | |
2336 | + input_unregister_device(&iforce->dev); | |
2337 | + | |
2338 | + if (!open) { | |
2339 | + iforce_delete_device(iforce); | |
2340 | + kfree(iforce); | |
2341 | + } | |
2342 | +} | |
2343 | + | |
2344 | +static struct usb_device_id iforce_usb_ids [] = { | |
2345 | + { USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */ | |
2346 | + { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ | |
2347 | + { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ | |
2348 | + { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ | |
2349 | + { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ | |
2350 | + { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ | |
2351 | + { USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */ | |
2352 | + { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ | |
2353 | + { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ | |
2354 | + { USB_DEVICE(0x06a3, 0xff12) }, /* Saitek Cyborgforce 3d */ | |
2355 | + { } /* Terminating entry */ | |
2356 | +}; | |
2357 | + | |
2358 | +MODULE_DEVICE_TABLE (usb, iforce_usb_ids); | |
2359 | + | |
2360 | +struct usb_driver iforce_usb_driver = { | |
2361 | +// owner: THIS_MODULE, | |
2362 | + name: "iforce", | |
2363 | + probe: iforce_usb_probe, | |
2364 | + disconnect: iforce_usb_disconnect, | |
2365 | + id_table: iforce_usb_ids, | |
2366 | +}; | |
2367 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce/iforce.h linux-modified/drivers/char/joystick/iforce/iforce.h | |
2368 | --- linux-vanilla/drivers/char/joystick/iforce/iforce.h Thu Jan 1 02:00:00 1970 | |
2369 | +++ linux-modified/drivers/char/joystick/iforce/iforce.h Sun Mar 9 16:58:46 2003 | |
2370 | @@ -0,0 +1,184 @@ | |
2371 | +/* | |
2372 | + * $Id$ | |
2373 | + * | |
2374 | + * Copyright (c) 2000-2002 Vojtech Pavlik <vojtech@ucw.cz> | |
2375 | + * Copyright (c) 2001-2002 Johann Deneux <deneux@ifrance.com> | |
2376 | + * | |
2377 | + * USB/RS232 I-Force joysticks and wheels. | |
2378 | + */ | |
2379 | + | |
2380 | +/* | |
2381 | + * This program is free software; you can redistribute it and/or modify | |
2382 | + * it under the terms of the GNU General Public License as published by | |
2383 | + * the Free Software Foundation; either version 2 of the License, or | |
2384 | + * (at your option) any later version. | |
2385 | + * | |
2386 | + * This program is distributed in the hope that it will be useful, | |
2387 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2388 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2389 | + * GNU General Public License for more details. | |
2390 | + * | |
2391 | + * You should have received a copy of the GNU General Public License | |
2392 | + * along with this program; if not, write to the Free Software | |
2393 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
2394 | + * | |
2395 | + * Should you need to contact me, the author, you can do so either by | |
2396 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
2397 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
2398 | + */ | |
2399 | + | |
2400 | +#include <linux/kernel.h> | |
2401 | +#include <linux/slab.h> | |
2402 | +#include <linux/input.h> | |
2403 | +#include <linux/module.h> | |
2404 | +#include <linux/init.h> | |
2405 | +#include <linux/spinlock.h> | |
2406 | +#include <linux/usb.h> | |
2407 | +#include <linux/serio.h> | |
2408 | +#include <linux/config.h> | |
2409 | +#include <linux/circ_buf.h> | |
2410 | +#include <asm/semaphore.h> | |
2411 | + | |
2412 | +/* FF: This module provides arbitrary resource management routines. | |
2413 | + * I use it to manage the device's memory. | |
2414 | + * Despite the name of this module, I am *not* going to access the ioports. | |
2415 | + */ | |
2416 | +#include <linux/ioport.h> | |
2417 | + | |
2418 | +#define IFORCE_MAX_LENGTH 16 | |
2419 | + | |
2420 | +#define IFORCE_232 1 | |
2421 | +#define IFORCE_USB 2 | |
2422 | + | |
2423 | +#define FALSE 0 | |
2424 | +#define TRUE 1 | |
2425 | + | |
2426 | +#define FF_EFFECTS_MAX 32 | |
2427 | + | |
2428 | +/* Each force feedback effect is made of one core effect, which can be | |
2429 | + * associated to at most to effect modifiers | |
2430 | + */ | |
2431 | +#define FF_MOD1_IS_USED 0 | |
2432 | +#define FF_MOD2_IS_USED 1 | |
2433 | +#define FF_CORE_IS_USED 2 | |
2434 | +#define FF_CORE_IS_PLAYED 3 /* Effect is currently being played */ | |
2435 | +#define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */ | |
2436 | +#define FF_CORE_UPDATE 5 /* Effect is being updated */ | |
2437 | +#define FF_MODCORE_MAX 5 | |
2438 | + | |
2439 | +struct iforce_core_effect { | |
2440 | + /* Information about where modifiers are stored in the device's memory */ | |
2441 | + struct resource mod1_chunk; | |
2442 | + struct resource mod2_chunk; | |
2443 | + unsigned long flags[NBITS(FF_MODCORE_MAX)]; | |
2444 | + pid_t owner; | |
2445 | + /* Used to keep track of parameters of an effect. They are needed | |
2446 | + * to know what parts of an effect changed in an update operation. | |
2447 | + * We try to send only parameter packets if possible, as sending | |
2448 | + * effect parameter requires the effect to be stoped and restarted | |
2449 | + */ | |
2450 | + struct ff_effect effect; | |
2451 | +}; | |
2452 | + | |
2453 | +#define FF_CMD_EFFECT 0x010e | |
2454 | +#define FF_CMD_ENVELOPE 0x0208 | |
2455 | +#define FF_CMD_MAGNITUDE 0x0303 | |
2456 | +#define FF_CMD_PERIOD 0x0407 | |
2457 | +#define FF_CMD_CONDITION 0x050a | |
2458 | + | |
2459 | +#define FF_CMD_AUTOCENTER 0x4002 | |
2460 | +#define FF_CMD_PLAY 0x4103 | |
2461 | +#define FF_CMD_ENABLE 0x4201 | |
2462 | +#define FF_CMD_GAIN 0x4301 | |
2463 | + | |
2464 | +#define FF_CMD_QUERY 0xff01 | |
2465 | + | |
2466 | +/* Buffer for async write */ | |
2467 | +#define XMIT_SIZE 256 | |
2468 | +#define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1 | |
2469 | +/* iforce::xmit_flags */ | |
2470 | +#define IFORCE_XMIT_RUNNING 0 | |
2471 | +#define IFORCE_XMIT_AGAIN 1 | |
2472 | + | |
2473 | +struct iforce_device { | |
2474 | + u16 idvendor; | |
2475 | + u16 idproduct; | |
2476 | + char *name; | |
2477 | + signed short *btn; | |
2478 | + signed short *abs; | |
2479 | + signed short *ff; | |
2480 | +}; | |
2481 | + | |
2482 | +struct iforce { | |
2483 | + struct input_dev dev; /* Input device interface */ | |
2484 | + struct iforce_device *type; | |
2485 | + int bus; | |
2486 | + | |
2487 | + unsigned char data[IFORCE_MAX_LENGTH]; | |
2488 | + unsigned char edata[IFORCE_MAX_LENGTH]; | |
2489 | + u16 ecmd; | |
2490 | + u16 expect_packet; | |
2491 | + | |
2492 | +#ifdef CONFIG_JOYSTICK_IFORCE_232 | |
2493 | + struct serio *serio; /* RS232 transfer */ | |
2494 | + int idx, pkt, len, id; | |
2495 | + unsigned char csum; | |
2496 | +#endif | |
2497 | +#ifdef CONFIG_JOYSTICK_IFORCE_USB | |
2498 | + struct usb_device *usbdev; /* USB transfer */ | |
2499 | + struct urb *irq, *out, *ctrl; | |
2500 | + struct usb_ctrlrequest dr; | |
2501 | +#endif | |
2502 | + spinlock_t xmit_lock; | |
2503 | + /* Buffer used for asynchronous sending of bytes to the device */ | |
2504 | + struct circ_buf xmit; | |
2505 | + unsigned char xmit_data[XMIT_SIZE]; | |
2506 | + long xmit_flags[1]; | |
2507 | + | |
2508 | + /* Force Feedback */ | |
2509 | + wait_queue_head_t wait; | |
2510 | + struct resource device_memory; | |
2511 | + struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; | |
2512 | + struct semaphore mem_mutex; | |
2513 | +}; | |
2514 | + | |
2515 | +/* Get hi and low bytes of a 16-bits int */ | |
2516 | +#define HI(a) ((unsigned char)((a) >> 8)) | |
2517 | +#define LO(a) ((unsigned char)((a) & 0xff)) | |
2518 | + | |
2519 | +/* For many parameters, it seems that 0x80 is a special value that should | |
2520 | + * be avoided. Instead, we replace this value by 0x7f | |
2521 | + */ | |
2522 | +#define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8)) | |
2523 | + | |
2524 | +/* Encode a time value */ | |
2525 | +#define TIME_SCALE(a) (a) | |
2526 | + | |
2527 | + | |
2528 | +/* Public functions */ | |
2529 | +/* iforce-serio.c */ | |
2530 | +void iforce_serial_xmit(struct iforce *iforce); | |
2531 | + | |
2532 | +/* iforce-usb.c */ | |
2533 | +void iforce_usb_xmit(struct iforce *iforce); | |
2534 | +void iforce_usb_delete(struct iforce *iforce); | |
2535 | + | |
2536 | +/* iforce-main.c */ | |
2537 | +int iforce_init_device(struct iforce *iforce); | |
2538 | +void iforce_delete_device(struct iforce *iforce); | |
2539 | + | |
2540 | +/* iforce-packets.c */ | |
2541 | +int iforce_control_playback(struct iforce*, u16 id, unsigned int); | |
2542 | +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); | |
2543 | +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); | |
2544 | +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; | |
2545 | +int iforce_get_id_packet(struct iforce *iforce, char *packet); | |
2546 | + | |
2547 | +/* iforce-ff.c */ | |
2548 | +int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); | |
2549 | +int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); | |
2550 | +int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); | |
2551 | + | |
2552 | +/* Public variables */ | |
2553 | +extern struct serio_dev iforce_serio_dev; | |
2554 | +extern struct usb_driver iforce_usb_driver; | |
2555 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/iforce.c linux-modified/drivers/char/joystick/iforce.c | |
2556 | --- linux-vanilla/drivers/char/joystick/iforce.c Mon Feb 3 20:32:38 2003 | |
2557 | +++ linux-modified/drivers/char/joystick/iforce.c Thu Jan 1 02:00:00 1970 | |
2558 | @@ -1,1199 +0,0 @@ | |
2559 | -/* | |
2560 | - * $Id$ | |
2561 | - * | |
2562 | - * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz> | |
2563 | - * Copyright (c) 2001 Johann Deneux <deneux@ifrance.com> | |
2564 | - * | |
2565 | - * USB/RS232 I-Force joysticks and wheels. | |
2566 | - * | |
2567 | - * Sponsored by SuSE | |
2568 | - */ | |
2569 | - | |
2570 | -/* | |
2571 | - * This program is free software; you can redistribute it and/or modify | |
2572 | - * it under the terms of the GNU General Public License as published by | |
2573 | - * the Free Software Foundation; either version 2 of the License, or | |
2574 | - * (at your option) any later version. | |
2575 | - * | |
2576 | - * This program is distributed in the hope that it will be useful, | |
2577 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
2578 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
2579 | - * GNU General Public License for more details. | |
2580 | - * | |
2581 | - * You should have received a copy of the GNU General Public License | |
2582 | - * along with this program; if not, write to the Free Software | |
2583 | - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
2584 | - * | |
2585 | - * Should you need to contact me, the author, you can do so either by | |
2586 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
2587 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
2588 | - */ | |
2589 | - | |
2590 | -#include <linux/kernel.h> | |
2591 | -#include <linux/slab.h> | |
2592 | -#include <linux/input.h> | |
2593 | -#include <linux/module.h> | |
2594 | -#include <linux/init.h> | |
2595 | -#include <linux/spinlock.h> | |
2596 | -#include <linux/usb.h> | |
2597 | -#include <linux/serio.h> | |
2598 | -#include <linux/config.h> | |
2599 | - | |
2600 | -/* FF: This module provides arbitrary resource management routines. | |
2601 | - * I use it to manage the device's memory. | |
2602 | - * Despite the name of this module, I am *not* going to access the ioports. | |
2603 | - */ | |
2604 | -#include <linux/ioport.h> | |
2605 | - | |
2606 | -MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>, Johann Deneux <deneux@ifrance.com>"); | |
2607 | -MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); | |
2608 | -MODULE_LICENSE("GPL"); | |
2609 | - | |
2610 | -#define IFORCE_MAX_LENGTH 16 | |
2611 | - | |
2612 | -#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE) | |
2613 | -#define IFORCE_232 1 | |
2614 | -#endif | |
2615 | -#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE) | |
2616 | -#define IFORCE_USB 2 | |
2617 | -#endif | |
2618 | - | |
2619 | -#define FF_EFFECTS_MAX 32 | |
2620 | - | |
2621 | -/* Each force feedback effect is made of one core effect, which can be | |
2622 | - * associated to at most to effect modifiers | |
2623 | - */ | |
2624 | -#define FF_MOD1_IS_USED 0 | |
2625 | -#define FF_MOD2_IS_USED 1 | |
2626 | -#define FF_CORE_IS_USED 2 | |
2627 | -#define FF_CORE_IS_PLAYED 3 | |
2628 | -#define FF_MODCORE_MAX 3 | |
2629 | - | |
2630 | -struct iforce_core_effect { | |
2631 | - /* Information about where modifiers are stored in the device's memory */ | |
2632 | - struct resource mod1_chunk; | |
2633 | - struct resource mod2_chunk; | |
2634 | - unsigned long flags[NBITS(FF_MODCORE_MAX)]; | |
2635 | -}; | |
2636 | - | |
2637 | -#define FF_CMD_EFFECT 0x010e | |
2638 | -#define FF_CMD_SHAPE 0x0208 | |
2639 | -#define FF_CMD_MAGNITUDE 0x0303 | |
2640 | -#define FF_CMD_PERIOD 0x0407 | |
2641 | -#define FF_CMD_INTERACT 0x050a | |
2642 | - | |
2643 | -#define FF_CMD_AUTOCENTER 0x4002 | |
2644 | -#define FF_CMD_PLAY 0x4103 | |
2645 | -#define FF_CMD_ENABLE 0x4201 | |
2646 | -#define FF_CMD_GAIN 0x4301 | |
2647 | - | |
2648 | -#define FF_CMD_QUERY 0xff01 | |
2649 | - | |
2650 | -static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | |
2651 | - BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 }; | |
2652 | -static signed short btn_wheel[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, | |
2653 | - BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; | |
2654 | -static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; | |
2655 | -static signed short abs_wheel[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; | |
2656 | -static signed short ff_iforce[] = { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION, | |
2657 | - FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 }; | |
2658 | - | |
2659 | -static struct iforce_device { | |
2660 | - u16 idvendor; | |
2661 | - u16 idproduct; | |
2662 | - char *name; | |
2663 | - signed short *btn; | |
2664 | - signed short *abs; | |
2665 | - signed short *ff; | |
2666 | -} iforce_device[] = { | |
2667 | - { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, | |
2668 | - { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, | |
2669 | - { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick, abs_joystick, ff_iforce }, | |
2670 | - { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce }, | |
2671 | - { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, | |
2672 | - { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } | |
2673 | -}; | |
2674 | - | |
2675 | -struct iforce { | |
2676 | - struct input_dev dev; /* Input device interface */ | |
2677 | - struct iforce_device *type; | |
2678 | - char name[64]; | |
2679 | - int open; | |
2680 | - int bus; | |
2681 | - | |
2682 | - unsigned char data[IFORCE_MAX_LENGTH]; | |
2683 | - unsigned char edata[IFORCE_MAX_LENGTH]; | |
2684 | - u16 ecmd; | |
2685 | - u16 expect_packet; | |
2686 | - | |
2687 | -#ifdef IFORCE_232 | |
2688 | - struct serio *serio; /* RS232 transfer */ | |
2689 | - int idx, pkt, len, id; | |
2690 | - unsigned char csum; | |
2691 | -#endif | |
2692 | -#ifdef IFORCE_USB | |
2693 | - struct usb_device *usbdev; /* USB transfer */ | |
2694 | - struct urb irq, out, ctrl; | |
2695 | - struct usb_ctrlrequest dr; | |
2696 | -#endif | |
2697 | - /* Force Feedback */ | |
2698 | - wait_queue_head_t wait; | |
2699 | - struct resource device_memory; | |
2700 | - struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; | |
2701 | -}; | |
2702 | - | |
2703 | -static struct { | |
2704 | - __s32 x; | |
2705 | - __s32 y; | |
2706 | -} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | |
2707 | - | |
2708 | -/* Get hi and low bytes of a 16-bits int */ | |
2709 | -#define HI(a) ((unsigned char)((a) >> 8)) | |
2710 | -#define LO(a) ((unsigned char)((a) & 0xff)) | |
2711 | - | |
2712 | -/* Encode a time value */ | |
2713 | -#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256) | |
2714 | - | |
2715 | -static void dump_packet(char *msg, u16 cmd, unsigned char *data) | |
2716 | -{ | |
2717 | - int i; | |
2718 | - | |
2719 | - printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); | |
2720 | - for (i = 0; i < LO(cmd); i++) | |
2721 | - printk("%02x ", data[i]); | |
2722 | - printk(")\n"); | |
2723 | -} | |
2724 | - | |
2725 | -/* | |
2726 | - * Send a packet of bytes to the device | |
2727 | - */ | |
2728 | -static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) | |
2729 | -{ | |
2730 | - switch (iforce->bus) { | |
2731 | - | |
2732 | -#ifdef IFORCE_232 | |
2733 | - case IFORCE_232: { | |
2734 | - | |
2735 | - int i; | |
2736 | - unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd); | |
2737 | - | |
2738 | - serio_write(iforce->serio, 0x2b); | |
2739 | - serio_write(iforce->serio, HI(cmd)); | |
2740 | - serio_write(iforce->serio, LO(cmd)); | |
2741 | - | |
2742 | - for (i = 0; i < LO(cmd); i++) { | |
2743 | - serio_write(iforce->serio, data[i]); | |
2744 | - csum = csum ^ data[i]; | |
2745 | - } | |
2746 | - | |
2747 | - serio_write(iforce->serio, csum); | |
2748 | - return; | |
2749 | - } | |
2750 | -#endif | |
2751 | -#ifdef IFORCE_USB | |
2752 | - case IFORCE_USB: { | |
2753 | - | |
2754 | - DECLARE_WAITQUEUE(wait, current); | |
2755 | - int timeout = HZ; /* 1 second */ | |
2756 | - | |
2757 | - memcpy(iforce->out.transfer_buffer + 1, data, LO(cmd)); | |
2758 | - ((char*)iforce->out.transfer_buffer)[0] = HI(cmd); | |
2759 | - iforce->out.transfer_buffer_length = LO(cmd) + 2; | |
2760 | - iforce->out.dev = iforce->usbdev; | |
2761 | - | |
2762 | - set_current_state(TASK_INTERRUPTIBLE); | |
2763 | - add_wait_queue(&iforce->wait, &wait); | |
2764 | - | |
2765 | - if (usb_submit_urb(&iforce->out)) { | |
2766 | - set_current_state(TASK_RUNNING); | |
2767 | - remove_wait_queue(&iforce->wait, &wait); | |
2768 | - return; | |
2769 | - } | |
2770 | - | |
2771 | - while (timeout && iforce->out.status == -EINPROGRESS) | |
2772 | - timeout = schedule_timeout(timeout); | |
2773 | - | |
2774 | - set_current_state(TASK_RUNNING); | |
2775 | - remove_wait_queue(&iforce->wait, &wait); | |
2776 | - | |
2777 | - if (!timeout) | |
2778 | - usb_unlink_urb(&iforce->out); | |
2779 | - | |
2780 | - return; | |
2781 | - } | |
2782 | -#endif | |
2783 | - } | |
2784 | -} | |
2785 | - | |
2786 | -static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) | |
2787 | -{ | |
2788 | - struct input_dev *dev = &iforce->dev; | |
2789 | - int i; | |
2790 | - | |
2791 | -#ifdef IFORCE_232 | |
2792 | - if (HI(iforce->expect_packet) == HI(cmd)) { | |
2793 | - iforce->expect_packet = 0; | |
2794 | - iforce->ecmd = cmd; | |
2795 | - memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); | |
2796 | - if (waitqueue_active(&iforce->wait)) | |
2797 | - wake_up(&iforce->wait); | |
2798 | - } | |
2799 | -#endif | |
2800 | - | |
2801 | - if (!iforce->type) | |
2802 | - return; | |
2803 | - | |
2804 | - switch (HI(cmd)) { | |
2805 | - | |
2806 | - case 0x01: /* joystick position data */ | |
2807 | - case 0x03: /* wheel position data */ | |
2808 | - | |
2809 | - if (HI(cmd) == 1) { | |
2810 | - input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); | |
2811 | - input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); | |
2812 | - input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); | |
2813 | - } else { | |
2814 | - input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); | |
2815 | - input_report_abs(dev, ABS_GAS, 255 - data[2]); | |
2816 | - input_report_abs(dev, ABS_BRAKE, 255 - data[3]); | |
2817 | - } | |
2818 | - | |
2819 | - input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); | |
2820 | - input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); | |
2821 | - | |
2822 | - for (i = 0; iforce->type->btn[i] >= 0; i++) | |
2823 | - input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); | |
2824 | - | |
2825 | - break; | |
2826 | - | |
2827 | - case 0x02: /* status report */ | |
2828 | - | |
2829 | - input_report_key(dev, BTN_DEAD, data[0] & 0x02); | |
2830 | - break; | |
2831 | - } | |
2832 | -} | |
2833 | - | |
2834 | -static int get_id_packet(struct iforce *iforce, char *packet) | |
2835 | -{ | |
2836 | - DECLARE_WAITQUEUE(wait, current); | |
2837 | - int timeout = HZ; /* 1 second */ | |
2838 | - | |
2839 | - switch (iforce->bus) { | |
2840 | - | |
2841 | -#ifdef IFORCE_USB | |
2842 | - case IFORCE_USB: | |
2843 | - | |
2844 | - iforce->dr.bRequest = packet[0]; | |
2845 | - iforce->ctrl.dev = iforce->usbdev; | |
2846 | - | |
2847 | - set_current_state(TASK_INTERRUPTIBLE); | |
2848 | - add_wait_queue(&iforce->wait, &wait); | |
2849 | - | |
2850 | - if (usb_submit_urb(&iforce->ctrl)) { | |
2851 | - set_current_state(TASK_RUNNING); | |
2852 | - remove_wait_queue(&iforce->wait, &wait); | |
2853 | - return -1; | |
2854 | - } | |
2855 | - | |
2856 | - while (timeout && iforce->ctrl.status == -EINPROGRESS) | |
2857 | - timeout = schedule_timeout(timeout); | |
2858 | - | |
2859 | - set_current_state(TASK_RUNNING); | |
2860 | - remove_wait_queue(&iforce->wait, &wait); | |
2861 | - | |
2862 | - if (!timeout) { | |
2863 | - usb_unlink_urb(&iforce->ctrl); | |
2864 | - return -1; | |
2865 | - } | |
2866 | - | |
2867 | - break; | |
2868 | -#endif | |
2869 | -#ifdef IFORCE_232 | |
2870 | - case IFORCE_232: | |
2871 | - | |
2872 | - iforce->expect_packet = FF_CMD_QUERY; | |
2873 | - send_packet(iforce, FF_CMD_QUERY, packet); | |
2874 | - | |
2875 | - set_current_state(TASK_INTERRUPTIBLE); | |
2876 | - add_wait_queue(&iforce->wait, &wait); | |
2877 | - | |
2878 | - while (timeout && iforce->expect_packet) | |
2879 | - timeout = schedule_timeout(timeout); | |
2880 | - | |
2881 | - set_current_state(TASK_RUNNING); | |
2882 | - remove_wait_queue(&iforce->wait, &wait); | |
2883 | - | |
2884 | - if (!timeout) { | |
2885 | - iforce->expect_packet = 0; | |
2886 | - return -1; | |
2887 | - } | |
2888 | - | |
2889 | - break; | |
2890 | -#endif | |
2891 | - } | |
2892 | - | |
2893 | - return -(iforce->edata[0] != packet[0]); | |
2894 | -} | |
2895 | - | |
2896 | -static int iforce_open(struct input_dev *dev) | |
2897 | -{ | |
2898 | - struct iforce *iforce = dev->private; | |
2899 | - | |
2900 | - switch (iforce->bus) { | |
2901 | -#ifdef IFORCE_USB | |
2902 | - case IFORCE_USB: | |
2903 | - if (iforce->open++) | |
2904 | - break; | |
2905 | - iforce->irq.dev = iforce->usbdev; | |
2906 | - if (usb_submit_urb(&iforce->irq)) | |
2907 | - return -EIO; | |
2908 | - break; | |
2909 | -#endif | |
2910 | - } | |
2911 | - return 0; | |
2912 | -} | |
2913 | - | |
2914 | -static void iforce_close(struct input_dev *dev) | |
2915 | -{ | |
2916 | - struct iforce *iforce = dev->private; | |
2917 | - | |
2918 | - switch (iforce->bus) { | |
2919 | -#ifdef IFORCE_USB | |
2920 | - case IFORCE_USB: | |
2921 | - if (!--iforce->open) | |
2922 | - usb_unlink_urb(&iforce->irq); | |
2923 | - break; | |
2924 | -#endif | |
2925 | - } | |
2926 | -} | |
2927 | - | |
2928 | -/* | |
2929 | - * Start or stop playing an effect | |
2930 | - */ | |
2931 | - | |
2932 | -static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | |
2933 | -{ | |
2934 | - struct iforce* iforce = (struct iforce*)(dev->private); | |
2935 | - unsigned char data[3]; | |
2936 | - | |
2937 | - printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value); | |
2938 | - | |
2939 | - if (type != EV_FF) | |
2940 | - return -1; | |
2941 | - | |
2942 | - switch (code) { | |
2943 | - | |
2944 | - case FF_GAIN: | |
2945 | - | |
2946 | - data[0] = value >> 9; | |
2947 | - send_packet(iforce, FF_CMD_GAIN, data); | |
2948 | - | |
2949 | - return 0; | |
2950 | - | |
2951 | - case FF_AUTOCENTER: | |
2952 | - | |
2953 | - data[0] = 0x03; | |
2954 | - data[1] = value >> 9; | |
2955 | - send_packet(iforce, FF_CMD_AUTOCENTER, data); | |
2956 | - | |
2957 | - data[0] = 0x04; | |
2958 | - data[1] = 0x01; | |
2959 | - send_packet(iforce, FF_CMD_AUTOCENTER, data); | |
2960 | - | |
2961 | - return 0; | |
2962 | - | |
2963 | - default: /* Play an effect */ | |
2964 | - | |
2965 | - if (code >= iforce->dev.ff_effects_max) | |
2966 | - return -1; | |
2967 | - | |
2968 | - data[0] = LO(code); | |
2969 | - data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; | |
2970 | - data[2] = LO(value); | |
2971 | - send_packet(iforce, FF_CMD_PLAY, data); | |
2972 | - | |
2973 | - return 0; | |
2974 | - } | |
2975 | - | |
2976 | - return -1; | |
2977 | -} | |
2978 | - | |
2979 | -/* | |
2980 | - * Set the magnitude of a constant force effect | |
2981 | - * Return error code | |
2982 | - * | |
2983 | - * Note: caller must ensure exclusive access to device | |
2984 | - */ | |
2985 | - | |
2986 | -static int make_magnitude_modifier(struct iforce* iforce, | |
2987 | - struct resource* mod_chunk, __s16 level) | |
2988 | -{ | |
2989 | - unsigned char data[3]; | |
2990 | - | |
2991 | - if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, | |
2992 | - iforce->device_memory.start, iforce->device_memory.end, 2L, | |
2993 | - NULL, NULL)) { | |
2994 | - return -ENOMEM; | |
2995 | - } | |
2996 | - | |
2997 | - data[0] = LO(mod_chunk->start); | |
2998 | - data[1] = HI(mod_chunk->start); | |
2999 | - data[2] = HI(level); | |
3000 | - | |
3001 | - send_packet(iforce, FF_CMD_MAGNITUDE, data); | |
3002 | - | |
3003 | - return 0; | |
3004 | -} | |
3005 | - | |
3006 | -/* | |
3007 | - * Upload the component of an effect dealing with the period, phase and magnitude | |
3008 | - */ | |
3009 | - | |
3010 | -static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk, | |
3011 | - __s16 magnitude, __s16 offset, u16 period, u16 phase) | |
3012 | -{ | |
3013 | - unsigned char data[7]; | |
3014 | - | |
3015 | - period = TIME_SCALE(period); | |
3016 | - | |
3017 | - if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, | |
3018 | - iforce->device_memory.start, iforce->device_memory.end, 2L, | |
3019 | - NULL, NULL)) { | |
3020 | - return -ENOMEM; | |
3021 | - } | |
3022 | - | |
3023 | - data[0] = LO(mod_chunk->start); | |
3024 | - data[1] = HI(mod_chunk->start); | |
3025 | - | |
3026 | - data[2] = HI(magnitude); | |
3027 | - data[3] = HI(offset); | |
3028 | - data[4] = HI(phase); | |
3029 | - | |
3030 | - data[5] = LO(period); | |
3031 | - data[6] = HI(period); | |
3032 | - | |
3033 | - send_packet(iforce, FF_CMD_PERIOD, data); | |
3034 | - | |
3035 | - return 0; | |
3036 | -} | |
3037 | - | |
3038 | -/* | |
3039 | - * Uploads the part of an effect setting the shape of the force | |
3040 | - */ | |
3041 | - | |
3042 | -static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk, | |
3043 | - u16 attack_duration, __s16 initial_level, | |
3044 | - u16 fade_duration, __s16 final_level) | |
3045 | -{ | |
3046 | - unsigned char data[8]; | |
3047 | - | |
3048 | - attack_duration = TIME_SCALE(attack_duration); | |
3049 | - fade_duration = TIME_SCALE(fade_duration); | |
3050 | - | |
3051 | - if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, | |
3052 | - iforce->device_memory.start, iforce->device_memory.end, 2L, | |
3053 | - NULL, NULL)) { | |
3054 | - return -ENOMEM; | |
3055 | - } | |
3056 | - | |
3057 | - data[0] = LO(mod_chunk->start); | |
3058 | - data[1] = HI(mod_chunk->start); | |
3059 | - | |
3060 | - data[2] = LO(attack_duration); | |
3061 | - data[3] = HI(attack_duration); | |
3062 | - data[4] = HI(initial_level); | |
3063 | - | |
3064 | - data[5] = LO(fade_duration); | |
3065 | - data[6] = HI(fade_duration); | |
3066 | - data[7] = HI(final_level); | |
3067 | - | |
3068 | - send_packet(iforce, FF_CMD_SHAPE, data); | |
3069 | - | |
3070 | - return 0; | |
3071 | -} | |
3072 | - | |
3073 | -/* | |
3074 | - * Component of spring, friction, inertia... effects | |
3075 | - */ | |
3076 | - | |
3077 | -static int make_interactive_modifier(struct iforce* iforce, | |
3078 | - struct resource* mod_chunk, | |
3079 | - __s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) | |
3080 | -{ | |
3081 | - unsigned char data[10]; | |
3082 | - | |
3083 | - if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, | |
3084 | - iforce->device_memory.start, iforce->device_memory.end, 2L, | |
3085 | - NULL, NULL)) { | |
3086 | - return -ENOMEM; | |
3087 | - } | |
3088 | - | |
3089 | - data[0] = LO(mod_chunk->start); | |
3090 | - data[1] = HI(mod_chunk->start); | |
3091 | - | |
3092 | - data[2] = HI(rk); | |
3093 | - data[3] = HI(lk); | |
3094 | - | |
3095 | - data[4] = LO(center); | |
3096 | - data[5] = HI(center); | |
3097 | - | |
3098 | - data[6] = LO(db); | |
3099 | - data[7] = HI(db); | |
3100 | - | |
3101 | - data[8] = HI(rsat); | |
3102 | - data[9] = HI(lsat); | |
3103 | - | |
3104 | - send_packet(iforce, FF_CMD_INTERACT, data); | |
3105 | - | |
3106 | - return 0; | |
3107 | -} | |
3108 | - | |
3109 | -static unsigned char find_button(struct iforce *iforce, signed short button) | |
3110 | -{ | |
3111 | - int i; | |
3112 | - for (i = 1; iforce->type->btn[i] >= 0; i++) | |
3113 | - if (iforce->type->btn[i] == button) | |
3114 | - return i + 1; | |
3115 | - return 0; | |
3116 | -} | |
3117 | - | |
3118 | -/* | |
3119 | - * Send the part common to all effects to the device | |
3120 | - */ | |
3121 | - | |
3122 | -static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, | |
3123 | - u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, | |
3124 | - u16 interval, u16 direction) | |
3125 | -{ | |
3126 | - unsigned char data[14]; | |
3127 | - | |
3128 | - duration = TIME_SCALE(duration); | |
3129 | - delay = TIME_SCALE(delay); | |
3130 | - interval = TIME_SCALE(interval); | |
3131 | - | |
3132 | - data[0] = LO(id); | |
3133 | - data[1] = effect_type; | |
3134 | - data[2] = LO(axes) | find_button(iforce, button); | |
3135 | - | |
3136 | - data[3] = LO(duration); | |
3137 | - data[4] = HI(duration); | |
3138 | - | |
3139 | - data[5] = HI(direction); | |
3140 | - | |
3141 | - data[6] = LO(interval); | |
3142 | - data[7] = HI(interval); | |
3143 | - | |
3144 | - data[8] = LO(mod_id1); | |
3145 | - data[9] = HI(mod_id1); | |
3146 | - data[10] = LO(mod_id2); | |
3147 | - data[11] = HI(mod_id2); | |
3148 | - | |
3149 | - data[12] = LO(delay); | |
3150 | - data[13] = HI(delay); | |
3151 | - | |
3152 | - send_packet(iforce, FF_CMD_EFFECT, data); | |
3153 | - | |
3154 | - return 0; | |
3155 | -} | |
3156 | - | |
3157 | -/* | |
3158 | - * Upload a periodic effect to the device | |
3159 | - */ | |
3160 | - | |
3161 | -static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect) | |
3162 | -{ | |
3163 | - u8 wave_code; | |
3164 | - int core_id = effect->id; | |
3165 | - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
3166 | - struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | |
3167 | - struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | |
3168 | - int err = 0; | |
3169 | - | |
3170 | - err = make_period_modifier(iforce, mod1_chunk, | |
3171 | - effect->u.periodic.magnitude, effect->u.periodic.offset, | |
3172 | - effect->u.periodic.period, effect->u.periodic.phase); | |
3173 | - if (err) return err; | |
3174 | - set_bit(FF_MOD1_IS_USED, core_effect->flags); | |
3175 | - | |
3176 | - err = make_shape_modifier(iforce, mod2_chunk, | |
3177 | - effect->u.periodic.shape.attack_length, | |
3178 | - effect->u.periodic.shape.attack_level, | |
3179 | - effect->u.periodic.shape.fade_length, | |
3180 | - effect->u.periodic.shape.fade_level); | |
3181 | - if (err) return err; | |
3182 | - set_bit(FF_MOD2_IS_USED, core_effect->flags); | |
3183 | - | |
3184 | - switch (effect->u.periodic.waveform) { | |
3185 | - case FF_SQUARE: wave_code = 0x20; break; | |
3186 | - case FF_TRIANGLE: wave_code = 0x21; break; | |
3187 | - case FF_SINE: wave_code = 0x22; break; | |
3188 | - case FF_SAW_UP: wave_code = 0x23; break; | |
3189 | - case FF_SAW_DOWN: wave_code = 0x24; break; | |
3190 | - default: wave_code = 0x20; break; | |
3191 | - } | |
3192 | - | |
3193 | - err = make_core(iforce, effect->id, | |
3194 | - mod1_chunk->start, | |
3195 | - mod2_chunk->start, | |
3196 | - wave_code, | |
3197 | - 0x20, | |
3198 | - effect->replay.length, | |
3199 | - effect->replay.delay, | |
3200 | - effect->trigger.button, | |
3201 | - effect->trigger.interval, | |
3202 | - effect->u.periodic.direction); | |
3203 | - | |
3204 | - return err; | |
3205 | -} | |
3206 | - | |
3207 | -/* | |
3208 | - * Upload a constant force effect | |
3209 | - */ | |
3210 | -static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect) | |
3211 | -{ | |
3212 | - int core_id = effect->id; | |
3213 | - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
3214 | - struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); | |
3215 | - struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); | |
3216 | - int err = 0; | |
3217 | - | |
3218 | - printk(KERN_DEBUG "iforce.c: make constant effect\n"); | |
3219 | - | |
3220 | - err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level); | |
3221 | - if (err) return err; | |
3222 | - set_bit(FF_MOD1_IS_USED, core_effect->flags); | |
3223 | - | |
3224 | - err = make_shape_modifier(iforce, mod2_chunk, | |
3225 | - effect->u.constant.shape.attack_length, | |
3226 | - effect->u.constant.shape.attack_level, | |
3227 | - effect->u.constant.shape.fade_length, | |
3228 | - effect->u.constant.shape.fade_level); | |
3229 | - if (err) return err; | |
3230 | - set_bit(FF_MOD2_IS_USED, core_effect->flags); | |
3231 | - | |
3232 | - err = make_core(iforce, effect->id, | |
3233 | - mod1_chunk->start, | |
3234 | - mod2_chunk->start, | |
3235 | - 0x00, | |
3236 | - 0x20, | |
3237 | - effect->replay.length, | |
3238 | - effect->replay.delay, | |
3239 | - effect->trigger.button, | |
3240 | - effect->trigger.interval, | |
3241 | - effect->u.constant.direction); | |
3242 | - | |
3243 | - return err; | |
3244 | -} | |
3245 | - | |
3246 | -/* | |
3247 | - * Upload an interactive effect. Those are for example friction, inertia, springs... | |
3248 | - */ | |
3249 | -static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect) | |
3250 | -{ | |
3251 | - int core_id = effect->id; | |
3252 | - struct iforce_core_effect* core_effect = iforce->core_effects + core_id; | |
3253 | - struct resource* mod_chunk = &(core_effect->mod1_chunk); | |
3254 | - u8 type, axes; | |
3255 | - u16 mod1, mod2, direction; | |
3256 | - int err = 0; | |
3257 | - | |
3258 | - printk(KERN_DEBUG "iforce.c: make interactive effect\n"); | |
3259 | - | |
3260 | - switch (effect->type) { | |
3261 | - case FF_SPRING: type = 0x40; break; | |
3262 | - case FF_FRICTION: type = 0x41; break; | |
3263 | - default: return -1; | |
3264 | - } | |
3265 | - | |
3266 | - err = make_interactive_modifier(iforce, mod_chunk, | |
3267 | - effect->u.interactive.right_saturation, | |
3268 | - effect->u.interactive.left_saturation, | |
3269 | - effect->u.interactive.right_coeff, | |
3270 | - effect->u.interactive.left_coeff, | |
3271 | - effect->u.interactive.deadband, | |
3272 | - effect->u.interactive.center); | |
3273 | - if (err) return err; | |
3274 | - set_bit(FF_MOD1_IS_USED, core_effect->flags); | |
3275 | - | |
3276 | - switch ((test_bit(ABS_X, &effect->u.interactive.axis) || | |
3277 | - test_bit(ABS_WHEEL, &effect->u.interactive.axis)) | | |
3278 | - (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) { | |
3279 | - | |
3280 | - case 0: /* Only one axis, choose orientation */ | |
3281 | - mod1 = mod_chunk->start; | |
3282 | - mod2 = 0xffff; | |
3283 | - direction = effect->u.interactive.direction; | |
3284 | - axes = 0x20; | |
3285 | - break; | |
3286 | - | |
3287 | - case 1: /* Only X axis */ | |
3288 | - mod1 = mod_chunk->start; | |
3289 | - mod2 = 0xffff; | |
3290 | - direction = 0x5a00; | |
3291 | - axes = 0x40; | |
3292 | - break; | |
3293 | - | |
3294 | - case 2: /* Only Y axis */ | |
3295 | - mod1 = 0xffff; | |
3296 | - mod2 = mod_chunk->start; | |
3297 | - direction = 0xb400; | |
3298 | - axes = 0x80; | |
3299 | - break; | |
3300 | - | |
3301 | - case 3: /* Both X and Y axes */ | |
3302 | - /* TODO: same setting for both axes is not mandatory */ | |
3303 | - mod1 = mod_chunk->start; | |
3304 | - mod2 = mod_chunk->start; | |
3305 | - direction = 0x6000; | |
3306 | - axes = 0xc0; | |
3307 | - break; | |
3308 | - | |
3309 | - default: | |
3310 | - return -1; | |
3311 | - } | |
3312 | - | |
3313 | - err = make_core(iforce, effect->id, | |
3314 | - mod1, mod2, | |
3315 | - type, axes, | |
3316 | - effect->replay.length, effect->replay.delay, | |
3317 | - effect->trigger.button, effect->trigger.interval, | |
3318 | - direction); | |
3319 | - | |
3320 | - return err; | |
3321 | -} | |
3322 | - | |
3323 | -/* | |
3324 | - * Function called when an ioctl is performed on the event dev entry. | |
3325 | - * It uploads an effect to the device | |
3326 | - */ | |
3327 | -static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) | |
3328 | -{ | |
3329 | - struct iforce* iforce = (struct iforce*)(dev->private); | |
3330 | - int id; | |
3331 | - | |
3332 | - printk(KERN_DEBUG "iforce.c: upload effect\n"); | |
3333 | - | |
3334 | -/* | |
3335 | - * Get a free id | |
3336 | - */ | |
3337 | - | |
3338 | - for (id=0; id < FF_EFFECTS_MAX; ++id) | |
3339 | - if (!test_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; | |
3340 | - | |
3341 | - if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) | |
3342 | - return -ENOMEM; | |
3343 | - | |
3344 | - effect->id = id; | |
3345 | - set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags); | |
3346 | - | |
3347 | -/* | |
3348 | - * Upload the effect | |
3349 | - */ | |
3350 | - | |
3351 | - switch (effect->type) { | |
3352 | - | |
3353 | - case FF_PERIODIC: | |
3354 | - return iforce_upload_periodic(iforce, effect); | |
3355 | - | |
3356 | - case FF_CONSTANT: | |
3357 | - return iforce_upload_constant(iforce, effect); | |
3358 | - | |
3359 | - case FF_SPRING: | |
3360 | - case FF_FRICTION: | |
3361 | - return iforce_upload_interactive(iforce, effect); | |
3362 | - | |
3363 | - default: | |
3364 | - return -1; | |
3365 | - } | |
3366 | -} | |
3367 | - | |
3368 | -/* | |
3369 | - * Erases an effect: it frees the effect id and mark as unused the memory | |
3370 | - * allocated for the parameters | |
3371 | - */ | |
3372 | -static int iforce_erase_effect(struct input_dev *dev, int effect_id) | |
3373 | -{ | |
3374 | - struct iforce* iforce = (struct iforce*)(dev->private); | |
3375 | - int err = 0; | |
3376 | - struct iforce_core_effect* core_effect; | |
3377 | - | |
3378 | - printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id); | |
3379 | - | |
3380 | - if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) | |
3381 | - return -EINVAL; | |
3382 | - | |
3383 | - core_effect = iforce->core_effects + effect_id; | |
3384 | - | |
3385 | - if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) | |
3386 | - err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); | |
3387 | - | |
3388 | - if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) | |
3389 | - err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); | |
3390 | - | |
3391 | - /*TODO: remember to change that if more FF_MOD* bits are added */ | |
3392 | - core_effect->flags[0] = 0; | |
3393 | - | |
3394 | - return err; | |
3395 | -} | |
3396 | -static int iforce_init_device(struct iforce *iforce) | |
3397 | -{ | |
3398 | - unsigned char c[] = "CEOV"; | |
3399 | - int i; | |
3400 | - | |
3401 | - init_waitqueue_head(&iforce->wait); | |
3402 | - iforce->dev.ff_effects_max = 10; | |
3403 | - | |
3404 | -/* | |
3405 | - * Input device fields. | |
3406 | - */ | |
3407 | - | |
3408 | - iforce->dev.idbus = BUS_USB; | |
3409 | - iforce->dev.private = iforce; | |
3410 | - iforce->dev.name = iforce->name; | |
3411 | - iforce->dev.open = iforce_open; | |
3412 | - iforce->dev.close = iforce_close; | |
3413 | - iforce->dev.event = iforce_input_event; | |
3414 | - iforce->dev.upload_effect = iforce_upload_effect; | |
3415 | - iforce->dev.erase_effect = iforce_erase_effect; | |
3416 | - | |
3417 | -/* | |
3418 | - * On-device memory allocation. | |
3419 | - */ | |
3420 | - | |
3421 | - iforce->device_memory.name = "I-Force device effect memory"; | |
3422 | - iforce->device_memory.start = 0; | |
3423 | - iforce->device_memory.end = 200; | |
3424 | - iforce->device_memory.flags = IORESOURCE_MEM; | |
3425 | - iforce->device_memory.parent = NULL; | |
3426 | - iforce->device_memory.child = NULL; | |
3427 | - iforce->device_memory.sibling = NULL; | |
3428 | - | |
3429 | -/* | |
3430 | - * Wait until device ready - until it sends its first response. | |
3431 | - */ | |
3432 | - | |
3433 | - for (i = 0; i < 20; i++) | |
3434 | - if (!get_id_packet(iforce, "O")) | |
3435 | - break; | |
3436 | - | |
3437 | - if (i == 20) { /* 5 seconds */ | |
3438 | - printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n"); | |
3439 | - iforce_close(&iforce->dev); | |
3440 | - return -1; | |
3441 | - } | |
3442 | - | |
3443 | -/* | |
3444 | - * Get device info. | |
3445 | - */ | |
3446 | - | |
3447 | - if (!get_id_packet(iforce, "M")) | |
3448 | - iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; | |
3449 | - if (!get_id_packet(iforce, "P")) | |
3450 | - iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; | |
3451 | - if (!get_id_packet(iforce, "B")) | |
3452 | - iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; | |
3453 | - if (!get_id_packet(iforce, "N")) | |
3454 | - iforce->dev.ff_effects_max = iforce->edata[1]; | |
3455 | - | |
3456 | -/* | |
3457 | - * Display additional info. | |
3458 | - */ | |
3459 | - | |
3460 | - for (i = 0; c[i]; i++) | |
3461 | - if (!get_id_packet(iforce, c + i)) | |
3462 | - dump_packet("info", iforce->ecmd, iforce->edata); | |
3463 | - | |
3464 | -/* | |
3465 | - * Disable spring, enable force feedback. | |
3466 | - * FIXME: We should use iforce_set_autocenter() et al here. | |
3467 | - */ | |
3468 | - | |
3469 | - send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); | |
3470 | - send_packet(iforce, FF_CMD_ENABLE, "\004"); | |
3471 | - | |
3472 | -/* | |
3473 | - * Find appropriate device entry | |
3474 | - */ | |
3475 | - | |
3476 | - for (i = 0; iforce_device[i].idvendor; i++) | |
3477 | - if (iforce_device[i].idvendor == iforce->dev.idvendor && | |
3478 | - iforce_device[i].idproduct == iforce->dev.idproduct) | |
3479 | - break; | |
3480 | - | |
3481 | - iforce->type = iforce_device + i; | |
3482 | - | |
3483 | - sprintf(iforce->name, iforce->type->name, | |
3484 | - iforce->dev.idproduct, iforce->dev.idvendor); | |
3485 | - | |
3486 | -/* | |
3487 | - * Set input device bitfields and ranges. | |
3488 | - */ | |
3489 | - | |
3490 | - iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF); | |
3491 | - | |
3492 | - for (i = 0; iforce->type->btn[i] >= 0; i++) { | |
3493 | - signed short t = iforce->type->btn[i]; | |
3494 | - set_bit(t, iforce->dev.keybit); | |
3495 | - if (t != BTN_DEAD) | |
3496 | - set_bit(FF_BTN(t), iforce->dev.ffbit); | |
3497 | - } | |
3498 | - | |
3499 | - for (i = 0; iforce->type->abs[i] >= 0; i++) { | |
3500 | - | |
3501 | - signed short t = iforce->type->abs[i]; | |
3502 | - set_bit(t, iforce->dev.absbit); | |
3503 | - | |
3504 | - switch (t) { | |
3505 | - | |
3506 | - case ABS_X: | |
3507 | - case ABS_Y: | |
3508 | - case ABS_WHEEL: | |
3509 | - | |
3510 | - iforce->dev.absmax[t] = 1920; | |
3511 | - iforce->dev.absmin[t] = -1920; | |
3512 | - iforce->dev.absflat[t] = 128; | |
3513 | - iforce->dev.absfuzz[t] = 16; | |
3514 | - | |
3515 | - set_bit(FF_ABS(t), iforce->dev.ffbit); | |
3516 | - break; | |
3517 | - | |
3518 | - case ABS_THROTTLE: | |
3519 | - case ABS_GAS: | |
3520 | - case ABS_BRAKE: | |
3521 | - | |
3522 | - iforce->dev.absmax[t] = 255; | |
3523 | - iforce->dev.absmin[t] = 0; | |
3524 | - break; | |
3525 | - | |
3526 | - case ABS_HAT0X: | |
3527 | - case ABS_HAT0Y: | |
3528 | - iforce->dev.absmax[t] = 1; | |
3529 | - iforce->dev.absmin[t] = -1; | |
3530 | - break; | |
3531 | - } | |
3532 | - } | |
3533 | - | |
3534 | - for (i = 0; iforce->type->ff[i] >= 0; i++) | |
3535 | - set_bit(iforce->type->ff[i], iforce->dev.ffbit); | |
3536 | - | |
3537 | -/* | |
3538 | - * Register input device. | |
3539 | - */ | |
3540 | - | |
3541 | - input_register_device(&iforce->dev); | |
3542 | - | |
3543 | - return 0; | |
3544 | -} | |
3545 | - | |
3546 | -#ifdef IFORCE_USB | |
3547 | - | |
3548 | -static void iforce_usb_irq(struct urb *urb) | |
3549 | -{ | |
3550 | - struct iforce *iforce = urb->context; | |
3551 | - if (urb->status) return; | |
3552 | - iforce_process_packet(iforce, | |
3553 | - (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); | |
3554 | -} | |
3555 | - | |
3556 | -static void iforce_usb_out(struct urb *urb) | |
3557 | -{ | |
3558 | - struct iforce *iforce = urb->context; | |
3559 | - if (urb->status) return; | |
3560 | - if (waitqueue_active(&iforce->wait)) | |
3561 | - wake_up(&iforce->wait); | |
3562 | -} | |
3563 | - | |
3564 | -static void iforce_usb_ctrl(struct urb *urb) | |
3565 | -{ | |
3566 | - struct iforce *iforce = urb->context; | |
3567 | - if (urb->status) return; | |
3568 | - iforce->ecmd = 0xff00 | urb->actual_length; | |
3569 | - if (waitqueue_active(&iforce->wait)) | |
3570 | - wake_up(&iforce->wait); | |
3571 | -} | |
3572 | - | |
3573 | -static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, | |
3574 | - const struct usb_device_id *id) | |
3575 | -{ | |
3576 | - struct usb_endpoint_descriptor *epirq, *epout; | |
3577 | - struct iforce *iforce; | |
3578 | - | |
3579 | - epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; | |
3580 | - epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; | |
3581 | - | |
3582 | - if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL; | |
3583 | - memset(iforce, 0, sizeof(struct iforce)); | |
3584 | - | |
3585 | - iforce->bus = IFORCE_USB; | |
3586 | - iforce->usbdev = dev; | |
3587 | - | |
3588 | - iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; | |
3589 | - iforce->dr.wIndex = 0; | |
3590 | - iforce->dr.wLength = 16; | |
3591 | - | |
3592 | - FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), | |
3593 | - iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); | |
3594 | - | |
3595 | - FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), | |
3596 | - iforce + 1, 32, iforce_usb_out, iforce); | |
3597 | - | |
3598 | - FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), | |
3599 | - (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce); | |
3600 | - | |
3601 | - if (iforce_init_device(iforce)) { | |
3602 | - kfree(iforce); | |
3603 | - return NULL; | |
3604 | - } | |
3605 | - | |
3606 | - printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n", | |
3607 | - iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max, | |
3608 | - iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum); | |
3609 | - | |
3610 | - return iforce; | |
3611 | -} | |
3612 | - | |
3613 | -static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) | |
3614 | -{ | |
3615 | - struct iforce *iforce = ptr; | |
3616 | - usb_unlink_urb(&iforce->irq); | |
3617 | - input_unregister_device(&iforce->dev); | |
3618 | - kfree(iforce); | |
3619 | -} | |
3620 | - | |
3621 | -static struct usb_device_id iforce_usb_ids [] = { | |
3622 | - { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ | |
3623 | - { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ | |
3624 | - { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ | |
3625 | - { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ | |
3626 | - { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ | |
3627 | - { } /* Terminating entry */ | |
3628 | -}; | |
3629 | - | |
3630 | -MODULE_DEVICE_TABLE (usb, iforce_usb_ids); | |
3631 | - | |
3632 | -static struct usb_driver iforce_usb_driver = { | |
3633 | - name: "iforce", | |
3634 | - probe: iforce_usb_probe, | |
3635 | - disconnect: iforce_usb_disconnect, | |
3636 | - id_table: iforce_usb_ids, | |
3637 | -}; | |
3638 | - | |
3639 | -#endif | |
3640 | - | |
3641 | -#ifdef IFORCE_232 | |
3642 | - | |
3643 | -static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) | |
3644 | -{ | |
3645 | - struct iforce* iforce = serio->private; | |
3646 | - | |
3647 | - if (!iforce->pkt) { | |
3648 | - if (data != 0x2b) { | |
3649 | - return; | |
3650 | - } | |
3651 | - iforce->pkt = 1; | |
3652 | - return; | |
3653 | - } | |
3654 | - | |
3655 | - if (!iforce->id) { | |
3656 | - if (data > 3 && data != 0xff) { | |
3657 | - iforce->pkt = 0; | |
3658 | - return; | |
3659 | - } | |
3660 | - iforce->id = data; | |
3661 | - return; | |
3662 | - } | |
3663 | - | |
3664 | - if (!iforce->len) { | |
3665 | - if (data > IFORCE_MAX_LENGTH) { | |
3666 | - iforce->pkt = 0; | |
3667 | - iforce->id = 0; | |
3668 | - return; | |
3669 | - } | |
3670 | - iforce->len = data; | |
3671 | - return; | |
3672 | - } | |
3673 | - | |
3674 | - if (iforce->idx < iforce->len) { | |
3675 | - iforce->csum += iforce->data[iforce->idx++] = data; | |
3676 | - return; | |
3677 | - } | |
3678 | - | |
3679 | - if (iforce->idx == iforce->len) { | |
3680 | - iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); | |
3681 | - iforce->pkt = 0; | |
3682 | - iforce->id = 0; | |
3683 | - iforce->len = 0; | |
3684 | - iforce->idx = 0; | |
3685 | - iforce->csum = 0; | |
3686 | - } | |
3687 | -} | |
3688 | - | |
3689 | -static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) | |
3690 | -{ | |
3691 | - struct iforce *iforce; | |
3692 | - if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) | |
3693 | - return; | |
3694 | - | |
3695 | - if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; | |
3696 | - memset(iforce, 0, sizeof(struct iforce)); | |
3697 | - | |
3698 | - iforce->bus = IFORCE_232; | |
3699 | - iforce->serio = serio; | |
3700 | - serio->private = iforce; | |
3701 | - | |
3702 | - if (serio_open(serio, dev)) { | |
3703 | - kfree(iforce); | |
3704 | - return; | |
3705 | - } | |
3706 | - | |
3707 | - if (iforce_init_device(iforce)) { | |
3708 | - serio_close(serio); | |
3709 | - kfree(iforce); | |
3710 | - return; | |
3711 | - } | |
3712 | - | |
3713 | - printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n", | |
3714 | - iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max, | |
3715 | - iforce->device_memory.end, serio->number); | |
3716 | -} | |
3717 | - | |
3718 | -static void iforce_serio_disconnect(struct serio *serio) | |
3719 | -{ | |
3720 | - struct iforce* iforce = serio->private; | |
3721 | - | |
3722 | - input_unregister_device(&iforce->dev); | |
3723 | - serio_close(serio); | |
3724 | - kfree(iforce); | |
3725 | -} | |
3726 | - | |
3727 | -static struct serio_dev iforce_serio_dev = { | |
3728 | - interrupt: iforce_serio_irq, | |
3729 | - connect: iforce_serio_connect, | |
3730 | - disconnect: iforce_serio_disconnect, | |
3731 | -}; | |
3732 | - | |
3733 | -#endif | |
3734 | - | |
3735 | -static int __init iforce_init(void) | |
3736 | -{ | |
3737 | -#ifdef IFORCE_USB | |
3738 | - usb_register(&iforce_usb_driver); | |
3739 | -#endif | |
3740 | -#ifdef IFORCE_232 | |
3741 | - serio_register_device(&iforce_serio_dev); | |
3742 | -#endif | |
3743 | - return 0; | |
3744 | -} | |
3745 | - | |
3746 | -static void __exit iforce_exit(void) | |
3747 | -{ | |
3748 | -#ifdef IFORCE_USB | |
3749 | - usb_deregister(&iforce_usb_driver); | |
3750 | -#endif | |
3751 | -#ifdef IFORCE_232 | |
3752 | - serio_unregister_device(&iforce_serio_dev); | |
3753 | -#endif | |
3754 | -} | |
3755 | - | |
3756 | -module_init(iforce_init); | |
3757 | -module_exit(iforce_exit); | |
3758 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/interact.c linux-modified/drivers/char/joystick/interact.c | |
3759 | --- linux-vanilla/drivers/char/joystick/interact.c Thu Sep 13 00:34:06 2001 | |
3760 | +++ linux-modified/drivers/char/joystick/interact.c Mon Jan 6 16:48:20 2003 | |
3761 | @@ -270,8 +270,8 @@ | |
3762 | set_bit(t, interact->dev.keybit); | |
3763 | ||
3764 | input_register_device(&interact->dev); | |
3765 | - printk(KERN_INFO "input%d: %s on gameport%d.0\n", | |
3766 | - interact->dev.number, interact_type[interact->type].name, gameport->number); | |
3767 | + printk(KERN_INFO "input: %s on gameport%d.0\n", | |
3768 | + interact_type[interact->type].name, gameport->number); | |
3769 | ||
3770 | return; | |
3771 | fail2: gameport_close(gameport); | |
3772 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/magellan.c linux-modified/drivers/char/joystick/magellan.c | |
3773 | --- linux-vanilla/drivers/char/joystick/magellan.c Thu Sep 13 00:34:06 2001 | |
3774 | +++ linux-modified/drivers/char/joystick/magellan.c Mon Jan 6 16:48:20 2003 | |
3775 | @@ -178,7 +178,7 @@ | |
3776 | ||
3777 | input_register_device(&magellan->dev); | |
3778 | ||
3779 | - printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number); | |
3780 | + printk(KERN_INFO "input: %s on serio %s\n", magellan_name, serio->name); | |
3781 | } | |
3782 | ||
3783 | /* | |
3784 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/serio.c linux-modified/drivers/char/joystick/serio.c | |
3785 | --- linux-vanilla/drivers/char/joystick/serio.c Thu Sep 13 00:34:06 2001 | |
3786 | +++ linux-modified/drivers/char/joystick/serio.c Mon Jan 6 16:48:20 2003 | |
3787 | @@ -1,9 +1,7 @@ | |
3788 | /* | |
3789 | - * $Id$ | |
3790 | + * $Id$ | |
3791 | * | |
3792 | - * Copyright (c) 1999-2000 Vojtech Pavlik | |
3793 | - * | |
3794 | - * Sponsored by SuSE | |
3795 | + * Copyright (c) 1999-2001 Vojtech Pavlik | |
3796 | */ | |
3797 | ||
3798 | /* | |
3799 | @@ -27,14 +25,16 @@ | |
3800 | * | |
3801 | * Should you need to contact me, the author, you can do so either by | |
3802 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
3803 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
3804 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
3805 | */ | |
3806 | ||
3807 | #include <linux/stddef.h> | |
3808 | #include <linux/module.h> | |
3809 | #include <linux/serio.h> | |
3810 | +#include <linux/errno.h> | |
3811 | ||
3812 | MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
3813 | +MODULE_DESCRIPTION("Serio abstraction core"); | |
3814 | MODULE_LICENSE("GPL"); | |
3815 | ||
3816 | EXPORT_SYMBOL(serio_register_port); | |
3817 | @@ -47,7 +47,6 @@ | |
3818 | ||
3819 | static struct serio *serio_list; | |
3820 | static struct serio_dev *serio_dev; | |
3821 | -static int serio_number; | |
3822 | ||
3823 | static void serio_find_dev(struct serio *serio) | |
3824 | { | |
3825 | @@ -69,7 +68,6 @@ | |
3826 | ||
3827 | void serio_register_port(struct serio *serio) | |
3828 | { | |
3829 | - serio->number = serio_number++; | |
3830 | serio->next = serio_list; | |
3831 | serio_list = serio; | |
3832 | serio_find_dev(serio); | |
3833 | @@ -84,8 +82,6 @@ | |
3834 | ||
3835 | if (serio->dev && serio->dev->disconnect) | |
3836 | serio->dev->disconnect(serio); | |
3837 | - | |
3838 | - serio_number--; | |
3839 | } | |
3840 | ||
3841 | void serio_register_device(struct serio_dev *dev) | |
3842 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/serport.c linux-modified/drivers/char/joystick/serport.c | |
3843 | --- linux-vanilla/drivers/char/joystick/serport.c Thu Sep 13 00:34:06 2001 | |
3844 | +++ linux-modified/drivers/char/joystick/serport.c Mon Jan 6 16:48:20 2003 | |
3845 | @@ -1,9 +1,7 @@ | |
3846 | /* | |
3847 | - * $Id$ | |
3848 | + * $Id$ | |
3849 | * | |
3850 | * Copyright (c) 1999-2001 Vojtech Pavlik | |
3851 | - * | |
3852 | - * Sponsored by SuSE | |
3853 | */ | |
3854 | ||
3855 | /* | |
3856 | @@ -28,7 +26,7 @@ | |
3857 | * | |
3858 | * Should you need to contact me, the author, you can do so either by | |
3859 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
3860 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
3861 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
3862 | */ | |
3863 | ||
3864 | #include <asm/uaccess.h> | |
3865 | @@ -39,12 +37,19 @@ | |
3866 | #include <linux/serio.h> | |
3867 | #include <linux/tty.h> | |
3868 | ||
3869 | +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
3870 | +MODULE_DESCRIPTION("Input device TTY line discipline"); | |
3871 | +MODULE_LICENSE("GPL"); | |
3872 | + | |
3873 | struct serport { | |
3874 | struct tty_struct *tty; | |
3875 | wait_queue_head_t wait; | |
3876 | struct serio serio; | |
3877 | + char phys[32]; | |
3878 | }; | |
3879 | ||
3880 | +char serport_name[] = "Serial port"; | |
3881 | + | |
3882 | /* | |
3883 | * Callback functions from the serio code. | |
3884 | */ | |
3885 | @@ -75,6 +80,8 @@ | |
3886 | static int serport_ldisc_open(struct tty_struct *tty) | |
3887 | { | |
3888 | struct serport *serport; | |
3889 | + char ttyname[64]; | |
3890 | + int i; | |
3891 | ||
3892 | MOD_INC_USE_COUNT; | |
3893 | ||
3894 | @@ -85,9 +92,19 @@ | |
3895 | ||
3896 | memset(serport, 0, sizeof(struct serport)); | |
3897 | ||
3898 | + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); | |
3899 | serport->tty = tty; | |
3900 | tty->disc_data = serport; | |
3901 | ||
3902 | + strcpy(ttyname, tty->driver.name); | |
3903 | + for (i = 0; ttyname[i] != 0 && ttyname[i] != '/'; i++); | |
3904 | + ttyname[i] = 0; | |
3905 | + | |
3906 | + sprintf(serport->phys, "%s%d/serio0", ttyname, MINOR(tty->device) - tty->driver.minor_start); | |
3907 | + | |
3908 | + serport->serio.name = serport_name; | |
3909 | + serport->serio.phys = serport->phys; | |
3910 | + | |
3911 | serport->serio.type = SERIO_RS232; | |
3912 | serport->serio.write = serport_serio_write; | |
3913 | serport->serio.open = serport_serio_open; | |
3914 | @@ -156,14 +173,14 @@ | |
3915 | ||
3916 | serio_register_port(&serport->serio); | |
3917 | ||
3918 | - printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name); | |
3919 | + printk(KERN_INFO "serio: Serial port %s\n", name); | |
3920 | ||
3921 | add_wait_queue(&serport->wait, &wait); | |
3922 | - current->state = TASK_INTERRUPTIBLE; | |
3923 | + set_current_state(TASK_INTERRUPTIBLE); | |
3924 | ||
3925 | while(serport->serio.type && !signal_pending(current)) schedule(); | |
3926 | ||
3927 | - current->state = TASK_RUNNING; | |
3928 | + set_current_state(TASK_RUNNING); | |
3929 | remove_wait_queue(&serport->wait, &wait); | |
3930 | ||
3931 | serio_unregister_port(&serport->serio); | |
3932 | @@ -187,6 +204,14 @@ | |
3933 | return -EINVAL; | |
3934 | } | |
3935 | ||
3936 | +static void serport_ldisc_write_wakeup(struct tty_struct * tty) | |
3937 | +{ | |
3938 | + struct serport *sp = (struct serport *) tty->disc_data; | |
3939 | + | |
3940 | + serio_dev_write_wakeup(&sp->serio); | |
3941 | + | |
3942 | +} | |
3943 | + | |
3944 | /* | |
3945 | * The line discipline structure. | |
3946 | */ | |
3947 | @@ -199,6 +224,7 @@ | |
3948 | ioctl: serport_ldisc_ioctl, | |
3949 | receive_buf: serport_ldisc_receive, | |
3950 | receive_room: serport_ldisc_room, | |
3951 | + write_wakeup: serport_ldisc_write_wakeup | |
3952 | }; | |
3953 | ||
3954 | /* | |
3955 | @@ -222,5 +248,3 @@ | |
3956 | ||
3957 | module_init(serport_init); | |
3958 | module_exit(serport_exit); | |
3959 | - | |
3960 | -MODULE_LICENSE("GPL"); | |
3961 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/sidewinder.c linux-modified/drivers/char/joystick/sidewinder.c | |
3962 | --- linux-vanilla/drivers/char/joystick/sidewinder.c Thu Sep 13 00:34:06 2001 | |
3963 | +++ linux-modified/drivers/char/joystick/sidewinder.c Mon Jan 6 16:48:20 2003 | |
3964 | @@ -719,8 +719,8 @@ | |
3965 | set_bit(code, sw->dev[i].keybit); | |
3966 | ||
3967 | input_register_device(sw->dev + i); | |
3968 | - printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n", | |
3969 | - sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k); | |
3970 | + printk(KERN_INFO "input: %s%s on gameport%d.%d [%d-bit id %d data %d]\n", | |
3971 | + sw->name, comment, gameport->number, i, m, l, k); | |
3972 | } | |
3973 | ||
3974 | return; | |
3975 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/spaceball.c linux-modified/drivers/char/joystick/spaceball.c | |
3976 | --- linux-vanilla/drivers/char/joystick/spaceball.c Thu Sep 13 00:34:06 2001 | |
3977 | +++ linux-modified/drivers/char/joystick/spaceball.c Mon Jan 6 16:48:20 2003 | |
3978 | @@ -81,8 +81,8 @@ | |
3979 | case '@': /* Reset packet */ | |
3980 | spaceball->data[spaceball->idx - 1] = 0; | |
3981 | for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++); | |
3982 | - printk(KERN_INFO "input%d: %s [%s] on serio%d\n", | |
3983 | - spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number); | |
3984 | + printk(KERN_INFO "input: %s [%s] on serio %s\n", | |
3985 | + spaceball_name, spaceball->data + i, spaceball->serio->name); | |
3986 | break; | |
3987 | ||
3988 | case 'D': /* Ball data */ | |
3989 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/spaceorb.c linux-modified/drivers/char/joystick/spaceorb.c | |
3990 | --- linux-vanilla/drivers/char/joystick/spaceorb.c Thu Sep 13 00:34:06 2001 | |
3991 | +++ linux-modified/drivers/char/joystick/spaceorb.c Mon Jan 6 16:48:20 2003 | |
3992 | @@ -88,8 +88,8 @@ | |
3993 | case 'R': /* Reset packet */ | |
3994 | spaceorb->data[spaceorb->idx - 1] = 0; | |
3995 | for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++); | |
3996 | - printk(KERN_INFO "input%d: %s [%s] on serio%d\n", | |
3997 | - spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number); | |
3998 | + printk(KERN_INFO "input: %s [%s] on serio %s\n", | |
3999 | + spaceorb_name, spaceorb->data + i, spaceorb->serio->name); | |
4000 | break; | |
4001 | ||
4002 | case 'D': /* Ball + button data */ | |
4003 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/stinger.c linux-modified/drivers/char/joystick/stinger.c | |
4004 | --- linux-vanilla/drivers/char/joystick/stinger.c Thu Sep 13 00:34:06 2001 | |
4005 | +++ linux-modified/drivers/char/joystick/stinger.c Mon Jan 6 16:48:20 2003 | |
4006 | @@ -168,7 +168,7 @@ | |
4007 | ||
4008 | input_register_device(&stinger->dev); | |
4009 | ||
4010 | - printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number); | |
4011 | + printk(KERN_INFO "input: %s on serio %s\n", stinger_name, serio->name); | |
4012 | } | |
4013 | ||
4014 | /* | |
4015 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/tmdc.c linux-modified/drivers/char/joystick/tmdc.c | |
4016 | --- linux-vanilla/drivers/char/joystick/tmdc.c Thu Sep 13 00:34:06 2001 | |
4017 | +++ linux-modified/drivers/char/joystick/tmdc.c Mon Jan 6 16:48:20 2003 | |
4018 | @@ -336,8 +336,8 @@ | |
4019 | } | |
4020 | ||
4021 | input_register_device(tmdc->dev + j); | |
4022 | - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", | |
4023 | - tmdc->dev[j].number, tmdc->name[j], gameport->number, j); | |
4024 | + printk(KERN_INFO "input: %s on gameport%d.%d\n", | |
4025 | + tmdc->name[j], gameport->number, j); | |
4026 | } | |
4027 | ||
4028 | return; | |
4029 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/turbografx.c linux-modified/drivers/char/joystick/turbografx.c | |
4030 | --- linux-vanilla/drivers/char/joystick/turbografx.c Thu Sep 13 00:34:06 2001 | |
4031 | +++ linux-modified/drivers/char/joystick/turbografx.c Mon Jan 6 16:48:20 2003 | |
4032 | @@ -190,8 +190,8 @@ | |
4033 | tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; | |
4034 | ||
4035 | input_register_device(tgfx->dev + i); | |
4036 | - printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n", | |
4037 | - tgfx->dev[i].number, config[i+1], tgfx->pd->port->name); | |
4038 | + printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", | |
4039 | + config[i+1], tgfx->pd->port->name); | |
4040 | } | |
4041 | ||
4042 | if (!tgfx->sticks) { | |
4043 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/char/joystick/warrior.c linux-modified/drivers/char/joystick/warrior.c | |
4044 | --- linux-vanilla/drivers/char/joystick/warrior.c Thu Sep 13 00:34:06 2001 | |
4045 | +++ linux-modified/drivers/char/joystick/warrior.c Mon Jan 6 16:48:20 2003 | |
4046 | @@ -180,7 +180,7 @@ | |
4047 | ||
4048 | input_register_device(&warrior->dev); | |
4049 | ||
4050 | - printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number); | |
4051 | + printk(KERN_INFO "input: Logitech WingMan Warrior on serio %s\n", serio->name); | |
4052 | } | |
4053 | ||
4054 | /* | |
4055 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/input/evdev.c linux-modified/drivers/input/evdev.c | |
4056 | --- linux-vanilla/drivers/input/evdev.c Mon Feb 25 21:37:58 2002 | |
4057 | +++ linux-modified/drivers/input/evdev.c Mon Jan 6 16:48:20 2003 | |
4058 | @@ -1,11 +1,9 @@ | |
4059 | /* | |
4060 | - * $Id$ | |
4061 | + * $Id$ | |
4062 | * | |
4063 | * Copyright (c) 1999-2001 Vojtech Pavlik | |
4064 | * | |
4065 | * Event char devices, giving access to raw input device events. | |
4066 | - * | |
4067 | - * Sponsored by SuSE | |
4068 | */ | |
4069 | ||
4070 | /* | |
4071 | @@ -24,8 +22,8 @@ | |
4072 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
4073 | * | |
4074 | * Should you need to contact me, the author, you can do so either by | |
4075 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
4076 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
4077 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
4078 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
4079 | */ | |
4080 | ||
4081 | #define EVDEV_MINOR_BASE 64 | |
4082 | @@ -43,6 +41,7 @@ | |
4083 | int exist; | |
4084 | int open; | |
4085 | int minor; | |
4086 | + char name[16]; | |
4087 | struct input_handle handle; | |
4088 | wait_queue_head_t wait; | |
4089 | devfs_handle_t devfs; | |
4090 | @@ -89,12 +88,20 @@ | |
4091 | return retval < 0 ? retval : 0; | |
4092 | } | |
4093 | ||
4094 | +static int evdev_flush(struct file * file) | |
4095 | +{ | |
4096 | + struct evdev_list *list = (struct evdev_list*)file->private_data; | |
4097 | + | |
4098 | + if (!list->evdev->exist) return -ENODEV; | |
4099 | + | |
4100 | + return input_flush_device(&list->evdev->handle, file); | |
4101 | +} | |
4102 | + | |
4103 | static int evdev_release(struct inode * inode, struct file * file) | |
4104 | { | |
4105 | struct evdev_list *list = file->private_data; | |
4106 | struct evdev_list **listptr; | |
4107 | ||
4108 | - lock_kernel(); | |
4109 | listptr = &list->evdev->list; | |
4110 | evdev_fasync(-1, file, 0); | |
4111 | ||
4112 | @@ -113,8 +120,7 @@ | |
4113 | } | |
4114 | ||
4115 | kfree(list); | |
4116 | - unlock_kernel(); | |
4117 | - | |
4118 | + | |
4119 | return 0; | |
4120 | } | |
4121 | ||
4122 | @@ -122,10 +128,16 @@ | |
4123 | { | |
4124 | struct evdev_list *list; | |
4125 | int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE; | |
4126 | + int accept_err; | |
4127 | ||
4128 | if (i >= EVDEV_MINORS || !evdev_table[i]) | |
4129 | return -ENODEV; | |
4130 | ||
4131 | + /* Ask the driver if he wishes to accept the open() */ | |
4132 | + if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) { | |
4133 | + return accept_err; | |
4134 | + } | |
4135 | + | |
4136 | if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) | |
4137 | return -ENOMEM; | |
4138 | memset(list, 0, sizeof(struct evdev_list)); | |
4139 | @@ -149,6 +161,8 @@ | |
4140 | struct input_event event; | |
4141 | int retval = 0; | |
4142 | ||
4143 | + if (!list->evdev->exist) return -ENODEV; | |
4144 | + | |
4145 | while (retval < count) { | |
4146 | ||
4147 | if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) | |
4148 | @@ -169,7 +183,7 @@ | |
4149 | if (list->head == list->tail) { | |
4150 | ||
4151 | add_wait_queue(&list->evdev->wait, &wait); | |
4152 | - current->state = TASK_INTERRUPTIBLE; | |
4153 | + set_current_state(TASK_INTERRUPTIBLE); | |
4154 | ||
4155 | while (list->head == list->tail) { | |
4156 | ||
4157 | @@ -189,7 +203,7 @@ | |
4158 | schedule(); | |
4159 | } | |
4160 | ||
4161 | - current->state = TASK_RUNNING; | |
4162 | + set_current_state(TASK_RUNNING); | |
4163 | remove_wait_queue(&list->evdev->wait, &wait); | |
4164 | } | |
4165 | ||
4166 | @@ -221,7 +235,9 @@ | |
4167 | struct evdev_list *list = file->private_data; | |
4168 | struct evdev *evdev = list->evdev; | |
4169 | struct input_dev *dev = evdev->handle.dev; | |
4170 | - int retval; | |
4171 | + int retval, t, u; | |
4172 | + | |
4173 | + if (!evdev->exist) return -ENODEV; | |
4174 | ||
4175 | switch (cmd) { | |
4176 | ||
4177 | @@ -234,6 +250,40 @@ | |
4178 | if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval; | |
4179 | if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval; | |
4180 | return 0; | |
4181 | + | |
4182 | + case EVIOCGREP: | |
4183 | + if ((retval = put_user(dev->rep[0], ((int *) arg) + 0))) return retval; | |
4184 | + if ((retval = put_user(dev->rep[1], ((int *) arg) + 1))) return retval; | |
4185 | + return 0; | |
4186 | + | |
4187 | + case EVIOCSREP: | |
4188 | + if ((retval = get_user(dev->rep[0], ((int *) arg) + 0))) return retval; | |
4189 | + if ((retval = get_user(dev->rep[1], ((int *) arg) + 1))) return retval; | |
4190 | + return 0; | |
4191 | + | |
4192 | + case EVIOCGKEYCODE: | |
4193 | + if ((retval = get_user(t, ((int *) arg) + 0))) return retval; | |
4194 | + if (t < 0 || t > dev->keycodemax) return -EINVAL; | |
4195 | + switch (dev->keycodesize) { | |
4196 | + case 1: u = *(u8*)(dev->keycode + t); break; | |
4197 | + case 2: u = *(u16*)(dev->keycode + t * 2); break; | |
4198 | + case 4: u = *(u32*)(dev->keycode + t * 4); break; | |
4199 | + default: return -EINVAL; | |
4200 | + } | |
4201 | + if ((retval = put_user(u, ((int *) arg) + 1))) return retval; | |
4202 | + return 0; | |
4203 | + | |
4204 | + case EVIOCSKEYCODE: | |
4205 | + if ((retval = get_user(t, ((int *) arg) + 0))) return retval; | |
4206 | + if (t < 0 || t > dev->keycodemax) return -EINVAL; | |
4207 | + if ((retval = get_user(u, ((int *) arg) + 1))) return retval; | |
4208 | + switch (dev->keycodesize) { | |
4209 | + case 1: *(u8*)(dev->keycode + t) = u; break; | |
4210 | + case 2: *(u16*)(dev->keycode + t * 2) = u; break; | |
4211 | + case 4: *(u32*)(dev->keycode + t * 4) = u; break; | |
4212 | + default: return -EINVAL; | |
4213 | + } | |
4214 | + return 0; | |
4215 | ||
4216 | case EVIOCSFF: | |
4217 | if (dev->upload_effect) { | |
4218 | @@ -282,22 +332,55 @@ | |
4219 | default: return -EINVAL; | |
4220 | } | |
4221 | len = NBITS(len) * sizeof(long); | |
4222 | - if (len > _IOC_SIZE(cmd)) { | |
4223 | - printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n", | |
4224 | - len, _IOC_SIZE(cmd)); | |
4225 | - len = _IOC_SIZE(cmd); | |
4226 | - } | |
4227 | + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
4228 | return copy_to_user((char *) arg, bits, len) ? -EFAULT : len; | |
4229 | } | |
4230 | ||
4231 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { | |
4232 | + int len; | |
4233 | + len = NBITS(KEY_MAX) * sizeof(long); | |
4234 | + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
4235 | + return copy_to_user((char *) arg, dev->key, len) ? -EFAULT : len; | |
4236 | + } | |
4237 | + | |
4238 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { | |
4239 | + int len; | |
4240 | + len = NBITS(LED_MAX) * sizeof(long); | |
4241 | + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
4242 | + return copy_to_user((char *) arg, dev->led, len) ? -EFAULT : len; | |
4243 | + } | |
4244 | + | |
4245 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { | |
4246 | + int len; | |
4247 | + len = NBITS(SND_MAX) * sizeof(long); | |
4248 | + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
4249 | + return copy_to_user((char *) arg, dev->snd, len) ? -EFAULT : len; | |
4250 | + } | |
4251 | + | |
4252 | if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { | |
4253 | int len; | |
4254 | - if (!dev->name) return 0; | |
4255 | + if (!dev->name) return -ENOENT; | |
4256 | len = strlen(dev->name) + 1; | |
4257 | if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
4258 | return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len; | |
4259 | } | |
4260 | ||
4261 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { | |
4262 | + int len; | |
4263 | + if (!dev->phys) return -ENOENT; | |
4264 | + len = strlen(dev->phys) + 1; | |
4265 | + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
4266 | + return copy_to_user((char *) arg, dev->phys, len) ? -EFAULT : len; | |
4267 | + } | |
4268 | + | |
4269 | + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { | |
4270 | + int len; | |
4271 | + if (!dev->uniq) return -ENOENT; | |
4272 | + len = strlen(dev->uniq) + 1; | |
4273 | + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); | |
4274 | + return copy_to_user((char *) arg, dev->uniq, len) ? -EFAULT : len; | |
4275 | + } | |
4276 | + | |
4277 | if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { | |
4278 | ||
4279 | int t = _IOC_NR(cmd) & ABS_MAX; | |
4280 | @@ -323,9 +406,10 @@ | |
4281 | release: evdev_release, | |
4282 | ioctl: evdev_ioctl, | |
4283 | fasync: evdev_fasync, | |
4284 | + flush: evdev_flush | |
4285 | }; | |
4286 | ||
4287 | -static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev) | |
4288 | +static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | |
4289 | { | |
4290 | struct evdev *evdev; | |
4291 | int minor; | |
4292 | @@ -344,16 +428,17 @@ | |
4293 | ||
4294 | evdev->minor = minor; | |
4295 | evdev_table[minor] = evdev; | |
4296 | + | |
4297 | + sprintf(evdev->name, "event%d", minor); | |
4298 | ||
4299 | evdev->handle.dev = dev; | |
4300 | + evdev->handle.name = evdev->name; | |
4301 | evdev->handle.handler = handler; | |
4302 | evdev->handle.private = evdev; | |
4303 | ||
4304 | - evdev->exist = 1; | |
4305 | - | |
4306 | evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE); | |
4307 | ||
4308 | -// printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number); | |
4309 | + evdev->exist = 1; | |
4310 | ||
4311 | return &evdev->handle; | |
4312 | } | |
4313 | @@ -374,12 +459,21 @@ | |
4314 | } | |
4315 | } | |
4316 | ||
4317 | +static struct input_device_id evdev_ids[] = { | |
4318 | + { driver_info: 1 }, /* Matches all devices */ | |
4319 | + { }, /* Terminating zero entry */ | |
4320 | +}; | |
4321 | + | |
4322 | +MODULE_DEVICE_TABLE(input, evdev_ids); | |
4323 | + | |
4324 | static struct input_handler evdev_handler = { | |
4325 | event: evdev_event, | |
4326 | connect: evdev_connect, | |
4327 | disconnect: evdev_disconnect, | |
4328 | fops: &evdev_fops, | |
4329 | minor: EVDEV_MINOR_BASE, | |
4330 | + name: "evdev", | |
4331 | + id_table: evdev_ids, | |
4332 | }; | |
4333 | ||
4334 | static int __init evdev_init(void) | |
4335 | @@ -396,7 +490,6 @@ | |
4336 | module_init(evdev_init); | |
4337 | module_exit(evdev_exit); | |
4338 | ||
4339 | -MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | |
4340 | -MODULE_DESCRIPTION("Event character device driver"); | |
4341 | +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
4342 | +MODULE_DESCRIPTION("Input driver event char devices"); | |
4343 | MODULE_LICENSE("GPL"); | |
4344 | - | |
4345 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/input/input.c linux-modified/drivers/input/input.c | |
4346 | --- linux-vanilla/drivers/input/input.c Mon Jan 6 15:58:02 2003 | |
4347 | +++ linux-modified/drivers/input/input.c Mon Jan 6 16:48:20 2003 | |
4348 | @@ -1,11 +1,9 @@ | |
4349 | /* | |
4350 | - * $Id$ | |
4351 | + * $Id$ | |
4352 | * | |
4353 | * Copyright (c) 1999-2001 Vojtech Pavlik | |
4354 | * | |
4355 | - * The input layer module itself | |
4356 | - * | |
4357 | - * Sponsored by SuSE | |
4358 | + * The input core | |
4359 | */ | |
4360 | ||
4361 | /* | |
4362 | @@ -24,8 +22,8 @@ | |
4363 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
4364 | * | |
4365 | * Should you need to contact me, the author, you can do so either by | |
4366 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
4367 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
4368 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
4369 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
4370 | */ | |
4371 | ||
4372 | #include <linux/init.h> | |
4373 | @@ -34,12 +32,16 @@ | |
4374 | #include <linux/input.h> | |
4375 | #include <linux/module.h> | |
4376 | #include <linux/random.h> | |
4377 | +#include <linux/pm.h> | |
4378 | +#include <linux/proc_fs.h> | |
4379 | +#include <linux/kmod.h> | |
4380 | +#include <linux/interrupt.h> | |
4381 | +#include <linux/poll.h> | |
4382 | ||
4383 | -MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | |
4384 | -MODULE_DESCRIPTION("Input layer module"); | |
4385 | +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
4386 | +MODULE_DESCRIPTION("Input core"); | |
4387 | MODULE_LICENSE("GPL"); | |
4388 | ||
4389 | - | |
4390 | EXPORT_SYMBOL(input_register_device); | |
4391 | EXPORT_SYMBOL(input_unregister_device); | |
4392 | EXPORT_SYMBOL(input_register_handler); | |
4393 | @@ -48,6 +50,8 @@ | |
4394 | EXPORT_SYMBOL(input_unregister_minor); | |
4395 | EXPORT_SYMBOL(input_open_device); | |
4396 | EXPORT_SYMBOL(input_close_device); | |
4397 | +EXPORT_SYMBOL(input_accept_process); | |
4398 | +EXPORT_SYMBOL(input_flush_device); | |
4399 | EXPORT_SYMBOL(input_event); | |
4400 | ||
4401 | #define INPUT_MAJOR 13 | |
4402 | @@ -57,20 +61,32 @@ | |
4403 | static struct input_handler *input_handler; | |
4404 | static struct input_handler *input_table[8]; | |
4405 | static devfs_handle_t input_devfs_handle; | |
4406 | -static int input_number; | |
4407 | -static long input_devices[NBITS(INPUT_DEVICES)]; | |
4408 | + | |
4409 | +#ifdef CONFIG_PROC_FS | |
4410 | +static struct proc_dir_entry *proc_bus_input_dir; | |
4411 | +DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait); | |
4412 | +static int input_devices_state; | |
4413 | +#endif | |
4414 | ||
4415 | void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | |
4416 | { | |
4417 | struct input_handle *handle = dev->handle; | |
4418 | ||
4419 | /* | |
4420 | + * Wake up the device if it is sleeping. | |
4421 | + */ | |
4422 | + if (dev->pm_dev) | |
4423 | + pm_access(dev->pm_dev); | |
4424 | + | |
4425 | +/* | |
4426 | * Filter non-events, and bad input values out. | |
4427 | */ | |
4428 | ||
4429 | if (type > EV_MAX || !test_bit(type, dev->evbit)) | |
4430 | return; | |
4431 | ||
4432 | + add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value); | |
4433 | + | |
4434 | switch (type) { | |
4435 | ||
4436 | case EV_KEY: | |
4437 | @@ -187,16 +203,36 @@ | |
4438 | mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]); | |
4439 | } | |
4440 | ||
4441 | +int input_accept_process(struct input_handle *handle, struct file *file) | |
4442 | +{ | |
4443 | + if (handle->dev->accept) | |
4444 | + return handle->dev->accept(handle->dev, file); | |
4445 | + | |
4446 | + return 0; | |
4447 | +} | |
4448 | + | |
4449 | int input_open_device(struct input_handle *handle) | |
4450 | { | |
4451 | + if (handle->dev->pm_dev) | |
4452 | + pm_access(handle->dev->pm_dev); | |
4453 | handle->open++; | |
4454 | if (handle->dev->open) | |
4455 | return handle->dev->open(handle->dev); | |
4456 | return 0; | |
4457 | } | |
4458 | ||
4459 | +int input_flush_device(struct input_handle* handle, struct file* file) | |
4460 | +{ | |
4461 | + if (handle->dev->flush) | |
4462 | + return handle->dev->flush(handle->dev, file); | |
4463 | + | |
4464 | + return 0; | |
4465 | +} | |
4466 | + | |
4467 | void input_close_device(struct input_handle *handle) | |
4468 | { | |
4469 | + if (handle->dev->pm_dev) | |
4470 | + pm_dev_idle(handle->dev->pm_dev); | |
4471 | if (handle->dev->close) | |
4472 | handle->dev->close(handle->dev); | |
4473 | handle->open--; | |
4474 | @@ -210,25 +246,197 @@ | |
4475 | handle->handler->handle = handle; | |
4476 | } | |
4477 | ||
4478 | +/** | |
4479 | + * input_find_and_remove - Find and remove node | |
4480 | + * | |
4481 | + * @type: data type | |
4482 | + * @initval: initial value | |
4483 | + * @targ: node to find | |
4484 | + * @next: next node in the list | |
4485 | + * | |
4486 | + * Searches the linked list for the target node @targ. If the node | |
4487 | + * is found, it is removed from the list. | |
4488 | + * | |
4489 | + * If the node is not found, the end of the list will be hit, | |
4490 | + * indicating that it wasn't in the list to begin with. | |
4491 | + * | |
4492 | + * Returns nothing. | |
4493 | + */ | |
4494 | +#define input_find_and_remove(type, initval, targ, next) \ | |
4495 | + do { \ | |
4496 | + type **ptr; \ | |
4497 | + for (ptr = &initval; *ptr; ptr = &((*ptr)->next)) \ | |
4498 | + if (*ptr == targ) break; \ | |
4499 | + if (*ptr) *ptr = (*ptr)->next; \ | |
4500 | + } while (0) | |
4501 | + | |
4502 | static void input_unlink_handle(struct input_handle *handle) | |
4503 | { | |
4504 | - struct input_handle **handleptr; | |
4505 | + input_find_and_remove(struct input_handle, handle->dev->handle, handle, dnext); | |
4506 | + input_find_and_remove(struct input_handle, handle->handler->handle, handle, hnext); | |
4507 | +} | |
4508 | + | |
4509 | +#define MATCH_BIT(bit, max) \ | |
4510 | + for (i = 0; i < NBITS(max); i++) \ | |
4511 | + if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \ | |
4512 | + break; \ | |
4513 | + if (i != NBITS(max)) \ | |
4514 | + continue; | |
4515 | + | |
4516 | +static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev) | |
4517 | +{ | |
4518 | + int i; | |
4519 | + | |
4520 | + for (; id->flags || id->driver_info; id++) { | |
4521 | + | |
4522 | + if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) | |
4523 | + if (id->idbus != dev->idbus) | |
4524 | + continue; | |
4525 | ||
4526 | - handleptr = &handle->dev->handle; | |
4527 | - while (*handleptr && (*handleptr != handle)) | |
4528 | - handleptr = &((*handleptr)->dnext); | |
4529 | - *handleptr = (*handleptr)->dnext; | |
4530 | - | |
4531 | - handleptr = &handle->handler->handle; | |
4532 | - while (*handleptr && (*handleptr != handle)) | |
4533 | - handleptr = &((*handleptr)->hnext); | |
4534 | - *handleptr = (*handleptr)->hnext; | |
4535 | + if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) | |
4536 | + if (id->idvendor != dev->idvendor) | |
4537 | + continue; | |
4538 | + | |
4539 | + if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) | |
4540 | + if (id->idproduct != dev->idproduct) | |
4541 | + continue; | |
4542 | + | |
4543 | + if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) | |
4544 | + if (id->idversion != dev->idversion) | |
4545 | + continue; | |
4546 | + | |
4547 | + MATCH_BIT(evbit, EV_MAX); | |
4548 | + MATCH_BIT(keybit, KEY_MAX); | |
4549 | + MATCH_BIT(relbit, REL_MAX); | |
4550 | + MATCH_BIT(absbit, ABS_MAX); | |
4551 | + MATCH_BIT(mscbit, MSC_MAX); | |
4552 | + MATCH_BIT(ledbit, LED_MAX); | |
4553 | + MATCH_BIT(sndbit, SND_MAX); | |
4554 | + MATCH_BIT(ffbit, FF_MAX); | |
4555 | + | |
4556 | + return id; | |
4557 | + } | |
4558 | + | |
4559 | + return NULL; | |
4560 | } | |
4561 | ||
4562 | +/* | |
4563 | + * Input hotplugging interface - loading event handlers based on | |
4564 | + * device bitfields. | |
4565 | + */ | |
4566 | + | |
4567 | +#ifdef CONFIG_HOTPLUG | |
4568 | + | |
4569 | +/* | |
4570 | + * Input hotplugging invokes what /proc/sys/kernel/hotplug says | |
4571 | + * (normally /sbin/hotplug) when input devices get added or removed. | |
4572 | + * | |
4573 | + * This invokes a user mode policy agent, typically helping to load driver | |
4574 | + * or other modules, configure the device, and more. Drivers can provide | |
4575 | + * a MODULE_DEVICE_TABLE to help with module loading subtasks. | |
4576 | + * | |
4577 | + */ | |
4578 | + | |
4579 | +#define SPRINTF_BIT_A(bit, name, max) \ | |
4580 | + do { \ | |
4581 | + envp[i++] = scratch; \ | |
4582 | + scratch += sprintf(scratch, name); \ | |
4583 | + for (j = NBITS(max) - 1; j >= 0; j--) \ | |
4584 | + if (dev->bit[j]) break; \ | |
4585 | + for (; j >= 0; j--) \ | |
4586 | + scratch += sprintf(scratch, "%lx ", dev->bit[j]); \ | |
4587 | + scratch++; \ | |
4588 | + } while (0) | |
4589 | + | |
4590 | +#define SPRINTF_BIT_A2(bit, name, max, ev) \ | |
4591 | + do { \ | |
4592 | + if (test_bit(ev, dev->evbit)) \ | |
4593 | + SPRINTF_BIT_A(bit, name, max); \ | |
4594 | + } while (0) | |
4595 | + | |
4596 | +static void input_call_hotplug(char *verb, struct input_dev *dev) | |
4597 | +{ | |
4598 | + char *argv[3], **envp, *buf, *scratch; | |
4599 | + int i = 0, j, value; | |
4600 | + | |
4601 | + if (!hotplug_path[0]) { | |
4602 | + printk(KERN_ERR "input.c: calling hotplug a hotplug agent defined\n"); | |
4603 | + return; | |
4604 | + } | |
4605 | + if (in_interrupt()) { | |
4606 | + printk(KERN_ERR "input.c: calling hotplug from interrupt\n"); | |
4607 | + return; | |
4608 | + } | |
4609 | + if (!current->fs->root) { | |
4610 | + printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n"); | |
4611 | + return; | |
4612 | + } | |
4613 | + if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) { | |
4614 | + printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); | |
4615 | + return; | |
4616 | + } | |
4617 | + if (!(buf = kmalloc(1024, GFP_KERNEL))) { | |
4618 | + kfree (envp); | |
4619 | + printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); | |
4620 | + return; | |
4621 | + } | |
4622 | + | |
4623 | + argv[0] = hotplug_path; | |
4624 | + argv[1] = "input"; | |
4625 | + argv[2] = 0; | |
4626 | + | |
4627 | + envp[i++] = "HOME=/"; | |
4628 | + envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; | |
4629 | + | |
4630 | + scratch = buf; | |
4631 | + | |
4632 | + envp[i++] = scratch; | |
4633 | + scratch += sprintf(scratch, "ACTION=%s", verb) + 1; | |
4634 | + | |
4635 | + envp[i++] = scratch; | |
4636 | + scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x", | |
4637 | + dev->idbus, dev->idvendor, dev->idproduct, dev->idversion) + 1; | |
4638 | + | |
4639 | + if (dev->name) { | |
4640 | + envp[i++] = scratch; | |
4641 | + scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; | |
4642 | + } | |
4643 | + | |
4644 | + if (dev->phys) { | |
4645 | + envp[i++] = scratch; | |
4646 | + scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; | |
4647 | + } | |
4648 | + | |
4649 | + SPRINTF_BIT_A(evbit, "EV=", EV_MAX); | |
4650 | + SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY); | |
4651 | + SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL); | |
4652 | + SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS); | |
4653 | + SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC); | |
4654 | + SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED); | |
4655 | + SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND); | |
4656 | + SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF); | |
4657 | + | |
4658 | + envp[i++] = 0; | |
4659 | + | |
4660 | + printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n", | |
4661 | + argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); | |
4662 | + | |
4663 | + value = call_usermodehelper(argv [0], argv, envp); | |
4664 | + | |
4665 | + kfree(buf); | |
4666 | + kfree(envp); | |
4667 | + | |
4668 | + if (value != 0) | |
4669 | + printk(KERN_WARNING "input.c: hotplug returned %d\n", value); | |
4670 | +} | |
4671 | + | |
4672 | +#endif | |
4673 | + | |
4674 | void input_register_device(struct input_dev *dev) | |
4675 | { | |
4676 | struct input_handler *handler = input_handler; | |
4677 | struct input_handle *handle; | |
4678 | + struct input_device_id *id; | |
4679 | ||
4680 | /* | |
4681 | * Initialize repeat timer to default values. | |
4682 | @@ -244,35 +452,70 @@ | |
4683 | * Add the device. | |
4684 | */ | |
4685 | ||
4686 | - if (input_number >= INPUT_DEVICES) { | |
4687 | - printk(KERN_WARNING "input: ran out of input device numbers!\n"); | |
4688 | - dev->number = input_number; | |
4689 | - } else { | |
4690 | - dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES); | |
4691 | - set_bit(dev->number, input_devices); | |
4692 | - } | |
4693 | - | |
4694 | dev->next = input_dev; | |
4695 | input_dev = dev; | |
4696 | - input_number++; | |
4697 | ||
4698 | /* | |
4699 | * Notify handlers. | |
4700 | */ | |
4701 | ||
4702 | while (handler) { | |
4703 | - if ((handle = handler->connect(handler, dev))) | |
4704 | - input_link_handle(handle); | |
4705 | + if ((id = input_match_device(handler->id_table, dev))) | |
4706 | + if ((handle = handler->connect(handler, dev, id))) | |
4707 | + input_link_handle(handle); | |
4708 | handler = handler->next; | |
4709 | } | |
4710 | + | |
4711 | +/* | |
4712 | + * Notify the hotplug agent. | |
4713 | + */ | |
4714 | + | |
4715 | +#ifdef CONFIG_HOTPLUG | |
4716 | + input_call_hotplug("add", dev); | |
4717 | +#endif | |
4718 | + | |
4719 | +/* | |
4720 | + * Notify /proc. | |
4721 | + */ | |
4722 | + | |
4723 | +#ifdef CONFIG_PROC_FS | |
4724 | + input_devices_state++; | |
4725 | + wake_up(&input_devices_poll_wait); | |
4726 | +#endif | |
4727 | +} | |
4728 | + | |
4729 | +#define DUMP_ARRAY(n, array) \ | |
4730 | +printk(KERN_DEBUG " ");\ | |
4731 | +for (i=0; i<NBITS(n); ++i)\ | |
4732 | + printk("%0X ", array[i]);\ | |
4733 | +printk("\n"); | |
4734 | + | |
4735 | +void dump_id_table(struct input_device_id* id) | |
4736 | +{ | |
4737 | + int i; | |
4738 | + | |
4739 | + printk(KERN_DEBUG "flags = %0X\n", id->flags); | |
4740 | + if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT) { | |
4741 | + DUMP_ARRAY(NBITS(EV_MAX), id->evbit); | |
4742 | + } | |
4743 | + if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT) { | |
4744 | + DUMP_ARRAY(NBITS(KEY_MAX), id->keybit); | |
4745 | + } | |
4746 | } | |
4747 | ||
4748 | void input_unregister_device(struct input_dev *dev) | |
4749 | { | |
4750 | struct input_handle *handle = dev->handle; | |
4751 | - struct input_dev **devptr = &input_dev; | |
4752 | struct input_handle *dnext; | |
4753 | ||
4754 | + if (!dev) return; | |
4755 | + | |
4756 | +/* | |
4757 | + * Turn off power management for the device. | |
4758 | + */ | |
4759 | + if (dev->pm_dev) | |
4760 | + pm_unregister(dev->pm_dev); | |
4761 | + | |
4762 | /* | |
4763 | * Kill any pending repeat timers. | |
4764 | */ | |
4765 | @@ -291,23 +534,35 @@ | |
4766 | } | |
4767 | ||
4768 | /* | |
4769 | - * Remove the device. | |
4770 | + * Notify the hotplug agent. | |
4771 | */ | |
4772 | ||
4773 | - while (*devptr && (*devptr != dev)) | |
4774 | - devptr = &((*devptr)->next); | |
4775 | - *devptr = (*devptr)->next; | |
4776 | +#ifdef CONFIG_HOTPLUG | |
4777 | + input_call_hotplug("remove", dev); | |
4778 | +#endif | |
4779 | + | |
4780 | +/* | |
4781 | + * Remove the device. | |
4782 | + */ | |
4783 | + input_find_and_remove(struct input_dev, input_dev, dev, next); | |
4784 | ||
4785 | - input_number--; | |
4786 | +/* | |
4787 | + * Notify /proc. | |
4788 | + */ | |
4789 | ||
4790 | - if (dev->number < INPUT_DEVICES) | |
4791 | - clear_bit(dev->number, input_devices); | |
4792 | +#ifdef CONFIG_PROC_FS | |
4793 | + input_devices_state++; | |
4794 | + wake_up(&input_devices_poll_wait); | |
4795 | +#endif | |
4796 | } | |
4797 | ||
4798 | void input_register_handler(struct input_handler *handler) | |
4799 | { | |
4800 | struct input_dev *dev = input_dev; | |
4801 | struct input_handle *handle; | |
4802 | + struct input_device_id *id; | |
4803 | + | |
4804 | + if (!handler) return; | |
4805 | ||
4806 | /* | |
4807 | * Add minors if needed. | |
4808 | @@ -326,17 +581,27 @@ | |
4809 | /* | |
4810 | * Notify it about all existing devices. | |
4811 | */ | |
4812 | +// dump_id_table(handler->id_table); | |
4813 | ||
4814 | while (dev) { | |
4815 | - if ((handle = handler->connect(handler, dev))) | |
4816 | - input_link_handle(handle); | |
4817 | + if ((id = input_match_device(handler->id_table, dev))) | |
4818 | + if ((handle = handler->connect(handler, dev, id))) | |
4819 | + input_link_handle(handle); | |
4820 | dev = dev->next; | |
4821 | } | |
4822 | + | |
4823 | +/* | |
4824 | + * Notify /proc. | |
4825 | + */ | |
4826 | + | |
4827 | +#ifdef CONFIG_PROC_FS | |
4828 | + input_devices_state++; | |
4829 | + wake_up(&input_devices_poll_wait); | |
4830 | +#endif | |
4831 | } | |
4832 | ||
4833 | void input_unregister_handler(struct input_handler *handler) | |
4834 | { | |
4835 | - struct input_handler **handlerptr = &input_handler; | |
4836 | struct input_handle *handle = handler->handle; | |
4837 | struct input_handle *hnext; | |
4838 | ||
4839 | @@ -354,18 +619,23 @@ | |
4840 | /* | |
4841 | * Remove it. | |
4842 | */ | |
4843 | - | |
4844 | - while (*handlerptr && (*handlerptr != handler)) | |
4845 | - handlerptr = &((*handlerptr)->next); | |
4846 | - | |
4847 | - *handlerptr = (*handlerptr)->next; | |
4848 | + input_find_and_remove(struct input_handler, input_handler, handler, | |
4849 | + next); | |
4850 | ||
4851 | /* | |
4852 | * Remove minors. | |
4853 | */ | |
4854 | - | |
4855 | if (handler->fops != NULL) | |
4856 | input_table[handler->minor >> 5] = NULL; | |
4857 | + | |
4858 | +/* | |
4859 | + * Notify /proc. | |
4860 | + */ | |
4861 | + | |
4862 | +#ifdef CONFIG_PROC_FS | |
4863 | + input_devices_state++; | |
4864 | + wake_up(&input_devices_poll_wait); | |
4865 | +#endif | |
4866 | } | |
4867 | ||
4868 | static int input_open_file(struct inode *inode, struct file *file) | |
4869 | @@ -389,9 +659,7 @@ | |
4870 | old_fops = file->f_op; | |
4871 | file->f_op = new_fops; | |
4872 | ||
4873 | - lock_kernel(); | |
4874 | err = new_fops->open(inode, file); | |
4875 | - unlock_kernel(); | |
4876 | ||
4877 | if (err) { | |
4878 | fops_put(file->f_op); | |
4879 | @@ -419,18 +687,164 @@ | |
4880 | devfs_unregister(handle); | |
4881 | } | |
4882 | ||
4883 | +/* | |
4884 | + * ProcFS interface for the input drivers. | |
4885 | + */ | |
4886 | + | |
4887 | +#ifdef CONFIG_PROC_FS | |
4888 | + | |
4889 | +#define SPRINTF_BIT_B(bit, name, max) \ | |
4890 | + do { \ | |
4891 | + len += sprintf(buf + len, "B: %s", name); \ | |
4892 | + for (i = NBITS(max) - 1; i >= 0; i--) \ | |
4893 | + if (dev->bit[i]) break; \ | |
4894 | + for (; i >= 0; i--) \ | |
4895 | + len += sprintf(buf + len, "%lx ", dev->bit[i]); \ | |
4896 | + len += sprintf(buf + len, "\n"); \ | |
4897 | + } while (0) | |
4898 | + | |
4899 | +#define SPRINTF_BIT_B2(bit, name, max, ev) \ | |
4900 | + do { \ | |
4901 | + if (test_bit(ev, dev->evbit)) \ | |
4902 | + SPRINTF_BIT_B(bit, name, max); \ | |
4903 | + } while (0) | |
4904 | + | |
4905 | + | |
4906 | +static unsigned int input_devices_poll(struct file *file, poll_table *wait) | |
4907 | +{ | |
4908 | + int state = input_devices_state; | |
4909 | + poll_wait(file, &input_devices_poll_wait, wait); | |
4910 | + if (state != input_devices_state) | |
4911 | + return POLLIN | POLLRDNORM; | |
4912 | + return 0; | |
4913 | +} | |
4914 | + | |
4915 | +static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) | |
4916 | +{ | |
4917 | + struct input_dev *dev = input_dev; | |
4918 | + struct input_handle *handle; | |
4919 | + | |
4920 | + off_t at = 0; | |
4921 | + int i, len, cnt = 0; | |
4922 | + | |
4923 | + while (dev) { | |
4924 | + | |
4925 | + len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", | |
4926 | + dev->idbus, dev->idvendor, dev->idproduct, dev->idversion); | |
4927 | + | |
4928 | + len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); | |
4929 | + len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); | |
4930 | + len += sprintf(buf + len, "D: Drivers="); | |
4931 | + | |
4932 | + handle = dev->handle; | |
4933 | + | |
4934 | + while (handle) { | |
4935 | + len += sprintf(buf + len, "%s ", handle->name); | |
4936 | + handle = handle->dnext; | |
4937 | + } | |
4938 | + | |
4939 | + len += sprintf(buf + len, "\n"); | |
4940 | + | |
4941 | + SPRINTF_BIT_B(evbit, "EV=", EV_MAX); | |
4942 | + SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); | |
4943 | + SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); | |
4944 | + SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); | |
4945 | + SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); | |
4946 | + SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); | |
4947 | + SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); | |
4948 | + SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); | |
4949 | + | |
4950 | + len += sprintf(buf + len, "\n"); | |
4951 | + | |
4952 | + at += len; | |
4953 | + | |
4954 | + if (at >= pos) { | |
4955 | + if (!*start) { | |
4956 | + *start = buf + (pos - (at - len)); | |
4957 | + cnt = at - pos; | |
4958 | + } else cnt += len; | |
4959 | + buf += len; | |
4960 | + if (cnt >= count) | |
4961 | + break; | |
4962 | + } | |
4963 | + | |
4964 | + dev = dev->next; | |
4965 | + } | |
4966 | + | |
4967 | + if (!dev) *eof = 1; | |
4968 | + | |
4969 | + return (count > cnt) ? cnt : count; | |
4970 | +} | |
4971 | + | |
4972 | +static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) | |
4973 | +{ | |
4974 | + struct input_handler *handler = input_handler; | |
4975 | + | |
4976 | + off_t at = 0; | |
4977 | + int len = 0, cnt = 0; | |
4978 | + int i = 0; | |
4979 | + | |
4980 | + while (handler) { | |
4981 | + | |
4982 | + if (handler->fops) | |
4983 | + len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n", | |
4984 | + i++, handler->name, handler->minor); | |
4985 | + else | |
4986 | + len = sprintf(buf, "N: Number=%d Name=%s\n", | |
4987 | + i++, handler->name); | |
4988 | + | |
4989 | + at += len; | |
4990 | + | |
4991 | + if (at >= pos) { | |
4992 | + if (!*start) { | |
4993 | + *start = buf + (pos - (at - len)); | |
4994 | + cnt = at - pos; | |
4995 | + } else cnt += len; | |
4996 | + buf += len; | |
4997 | + if (cnt >= count) | |
4998 | + break; | |
4999 | + } | |
5000 | + | |
5001 | + handler = handler->next; | |
5002 | + } | |
5003 | + | |
5004 | + if (!handler) *eof = 1; | |
5005 | + | |
5006 | + return (count > cnt) ? cnt : count; | |
5007 | +} | |
5008 | + | |
5009 | +#endif | |
5010 | + | |
5011 | static int __init input_init(void) | |
5012 | { | |
5013 | + struct proc_dir_entry *entry; | |
5014 | + | |
5015 | +#ifdef CONFIG_PROC_FS | |
5016 | + proc_bus_input_dir = proc_mkdir("input", proc_bus); | |
5017 | + proc_bus_input_dir->owner = THIS_MODULE; | |
5018 | + entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL); | |
5019 | + entry->owner = THIS_MODULE; | |
5020 | + entry->proc_fops->poll = input_devices_poll; | |
5021 | + entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL); | |
5022 | + entry->owner = THIS_MODULE; | |
5023 | +#endif | |
5024 | if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) { | |
5025 | printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); | |
5026 | return -EBUSY; | |
5027 | } | |
5028 | + | |
5029 | input_devfs_handle = devfs_mk_dir(NULL, "input", NULL); | |
5030 | + | |
5031 | return 0; | |
5032 | } | |
5033 | ||
5034 | static void __exit input_exit(void) | |
5035 | { | |
5036 | +#ifdef CONFIG_PROC_FS | |
5037 | + remove_proc_entry("devices", proc_bus_input_dir); | |
5038 | + remove_proc_entry("handlers", proc_bus_input_dir); | |
5039 | + remove_proc_entry("input", proc_bus); | |
5040 | +#endif | |
5041 | devfs_unregister(input_devfs_handle); | |
5042 | if (devfs_unregister_chrdev(INPUT_MAJOR, "input")) | |
5043 | printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR); | |
5044 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/input/joydev.c linux-modified/drivers/input/joydev.c | |
5045 | --- linux-vanilla/drivers/input/joydev.c Mon Feb 3 20:47:45 2003 | |
5046 | +++ linux-modified/drivers/input/joydev.c Tue Feb 4 21:26:33 2003 | |
5047 | @@ -1,12 +1,10 @@ | |
5048 | /* | |
5049 | - * $Id$ | |
5050 | + * $Id$ | |
5051 | * | |
5052 | - * Copyright (c) 1999-2000 Vojtech Pavlik | |
5053 | + * Copyright (c) 1999-2001 Vojtech Pavlik | |
5054 | * Copyright (c) 1999 Colin Van Dyke | |
5055 | * | |
5056 | * Joystick device driver for the input driver suite. | |
5057 | - * | |
5058 | - * Sponsored by SuSE and Intel | |
5059 | */ | |
5060 | ||
5061 | /* | |
5062 | @@ -25,8 +23,8 @@ | |
5063 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
5064 | * | |
5065 | * Should you need to contact me, the author, you can do so either by | |
5066 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
5067 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
5068 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
5069 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
5070 | */ | |
5071 | ||
5072 | #include <asm/io.h> | |
5073 | @@ -46,6 +44,11 @@ | |
5074 | #include <linux/init.h> | |
5075 | #include <linux/smp_lock.h> | |
5076 | ||
5077 | +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
5078 | +MODULE_DESCRIPTION("Joystick device interfaces"); | |
5079 | +MODULE_SUPPORTED_DEVICE("input/js"); | |
5080 | +MODULE_LICENSE("GPL"); | |
5081 | + | |
5082 | #define JOYDEV_MINOR_BASE 0 | |
5083 | #define JOYDEV_MINORS 32 | |
5084 | #define JOYDEV_BUFFER_SIZE 64 | |
5085 | @@ -56,6 +59,7 @@ | |
5086 | int exist; | |
5087 | int open; | |
5088 | int minor; | |
5089 | + char name[16]; | |
5090 | struct input_handle handle; | |
5091 | wait_queue_head_t wait; | |
5092 | devfs_handle_t devfs; | |
5093 | @@ -84,11 +88,6 @@ | |
5094 | ||
5095 | static struct joydev *joydev_table[JOYDEV_MINORS]; | |
5096 | ||
5097 | -MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | |
5098 | -MODULE_DESCRIPTION("Joystick device driver"); | |
5099 | -MODULE_LICENSE("GPL"); | |
5100 | -MODULE_SUPPORTED_DEVICE("input/js"); | |
5101 | - | |
5102 | static int joydev_correct(int value, struct js_corr *corr) | |
5103 | { | |
5104 | switch (corr->type) { | |
5105 | @@ -167,7 +166,6 @@ | |
5106 | struct joydev_list *list = file->private_data; | |
5107 | struct joydev_list **listptr; | |
5108 | ||
5109 | - lock_kernel(); | |
5110 | listptr = &list->joydev->list; | |
5111 | joydev_fasync(-1, file, 0); | |
5112 | ||
5113 | @@ -186,7 +184,6 @@ | |
5114 | } | |
5115 | ||
5116 | kfree(list); | |
5117 | - unlock_kernel(); | |
5118 | ||
5119 | return 0; | |
5120 | } | |
5121 | @@ -254,10 +251,15 @@ | |
5122 | if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) { | |
5123 | ||
5124 | add_wait_queue(&list->joydev->wait, &wait); | |
5125 | - current->state = TASK_INTERRUPTIBLE; | |
5126 | + set_current_state(TASK_INTERRUPTIBLE); | |
5127 | ||
5128 | while (list->head == list->tail) { | |
5129 | ||
5130 | + if (!joydev->exist) { | |
5131 | + retval = -ENODEV; | |
5132 | + break; | |
5133 | + } | |
5134 | + | |
5135 | if (file->f_flags & O_NONBLOCK) { | |
5136 | retval = -EAGAIN; | |
5137 | break; | |
5138 | @@ -270,7 +272,7 @@ | |
5139 | schedule(); | |
5140 | } | |
5141 | ||
5142 | - current->state = TASK_RUNNING; | |
5143 | + set_current_state(TASK_RUNNING); | |
5144 | remove_wait_queue(&list->joydev->wait, &wait); | |
5145 | } | |
5146 | ||
5147 | @@ -329,6 +331,8 @@ | |
5148 | struct input_dev *dev = joydev->handle.dev; | |
5149 | int i; | |
5150 | ||
5151 | + if (!joydev->exist) return -ENODEV; | |
5152 | + | |
5153 | switch (cmd) { | |
5154 | ||
5155 | case JS_SET_CAL: | |
5156 | @@ -410,16 +414,11 @@ | |
5157 | fasync: joydev_fasync, | |
5158 | }; | |
5159 | ||
5160 | -static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev) | |
5161 | +static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | |
5162 | { | |
5163 | struct joydev *joydev; | |
5164 | int i, j, t, minor; | |
5165 | ||
5166 | - if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) && | |
5167 | - (test_bit(ABS_X, dev->absbit) || test_bit(ABS_Y, dev->absbit)) && | |
5168 | - (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit) | |
5169 | - || test_bit(BTN_1, dev->keybit)))) return NULL; | |
5170 | - | |
5171 | for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); | |
5172 | if (minor == JOYDEV_MINORS) { | |
5173 | printk(KERN_ERR "joydev: no more free joydev devices\n"); | |
5174 | @@ -435,12 +434,13 @@ | |
5175 | joydev->minor = minor; | |
5176 | joydev_table[minor] = joydev; | |
5177 | ||
5178 | + sprintf(joydev->name, "js%d", minor); | |
5179 | + | |
5180 | joydev->handle.dev = dev; | |
5181 | + joydev->handle.name = joydev->name; | |
5182 | joydev->handle.handler = handler; | |
5183 | joydev->handle.private = joydev; | |
5184 | ||
5185 | - joydev->exist = 1; | |
5186 | - | |
5187 | for (i = 0; i < ABS_MAX; i++) | |
5188 | if (test_bit(i, dev->absbit)) { | |
5189 | joydev->absmap[i] = joydev->nabs; | |
5190 | @@ -484,6 +484,8 @@ | |
5191 | ||
5192 | // printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); | |
5193 | ||
5194 | + joydev->exist = 1; | |
5195 | + | |
5196 | return &joydev->handle; | |
5197 | } | |
5198 | ||
5199 | @@ -502,12 +504,35 @@ | |
5200 | } | |
5201 | } | |
5202 | ||
5203 | +static struct input_device_id joydev_ids[] = { | |
5204 | + { | |
5205 | + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | |
5206 | + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, | |
5207 | + absbit: { BIT(ABS_X) }, | |
5208 | + }, | |
5209 | + { | |
5210 | + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | |
5211 | + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, | |
5212 | + absbit: { BIT(ABS_WHEEL) }, | |
5213 | + }, | |
5214 | + { | |
5215 | + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | |
5216 | + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, | |
5217 | + absbit: { BIT(ABS_THROTTLE) }, | |
5218 | + }, | |
5219 | + { }, /* Terminating entry */ | |
5220 | +}; | |
5221 | + | |
5222 | +MODULE_DEVICE_TABLE(input, joydev_ids); | |
5223 | + | |
5224 | static struct input_handler joydev_handler = { | |
5225 | event: joydev_event, | |
5226 | connect: joydev_connect, | |
5227 | disconnect: joydev_disconnect, | |
5228 | fops: &joydev_fops, | |
5229 | minor: JOYDEV_MINOR_BASE, | |
5230 | + name: "joydev", | |
5231 | + id_table: joydev_ids, | |
5232 | }; | |
5233 | ||
5234 | static int __init joydev_init(void) | |
5235 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/input/keybdev.c linux-modified/drivers/input/keybdev.c | |
5236 | --- linux-vanilla/drivers/input/keybdev.c Thu Oct 11 18:14:32 2001 | |
5237 | +++ linux-modified/drivers/input/keybdev.c Mon Jan 6 16:48:20 2003 | |
5238 | @@ -177,20 +177,11 @@ | |
5239 | tasklet_schedule(&keyboard_tasklet); | |
5240 | } | |
5241 | ||
5242 | -static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev) | |
5243 | +static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id* id) | |
5244 | { | |
5245 | struct input_handle *handle; | |
5246 | int i; | |
5247 | ||
5248 | - if (!test_bit(EV_KEY, dev->evbit)) | |
5249 | - return NULL; | |
5250 | - | |
5251 | - for (i = KEY_RESERVED; i < BTN_MISC; i++) | |
5252 | - if (test_bit(i, dev->keybit)) break; | |
5253 | - | |
5254 | - if (i == BTN_MISC) | |
5255 | - return NULL; | |
5256 | - | |
5257 | if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) | |
5258 | return NULL; | |
5259 | memset(handle, 0, sizeof(struct input_handle)); | |
5260 | @@ -212,10 +203,25 @@ | |
5261 | kfree(handle); | |
5262 | } | |
5263 | ||
5264 | +static struct input_device_id keybdev_ids[] = { | |
5265 | + /* If it's got an "esc" key, it's a keyboard */ | |
5266 | + { | |
5267 | + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, | |
5268 | + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, | |
5269 | + keybit: { BIT(KEY_ESC) }, | |
5270 | + }, | |
5271 | + | |
5272 | + { }, /* Terminating entry */ | |
5273 | +}; | |
5274 | + | |
5275 | +MODULE_DEVICE_TABLE(input, keybdev_ids); | |
5276 | + | |
5277 | static struct input_handler keybdev_handler = { | |
5278 | event: keybdev_event, | |
5279 | connect: keybdev_connect, | |
5280 | disconnect: keybdev_disconnect, | |
5281 | + name: "keybdev", | |
5282 | + id_table: keybdev_ids, | |
5283 | }; | |
5284 | ||
5285 | static int __init keybdev_init(void) | |
5286 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/input/mousedev.c linux-modified/drivers/input/mousedev.c | |
5287 | --- linux-vanilla/drivers/input/mousedev.c Sun Sep 30 21:26:05 2001 | |
5288 | +++ linux-modified/drivers/input/mousedev.c Mon Jan 6 16:48:20 2003 | |
5289 | @@ -1,11 +1,9 @@ | |
5290 | /* | |
5291 | - * $Id$ | |
5292 | + * $Id$ | |
5293 | * | |
5294 | - * Copyright (c) 1999-2000 Vojtech Pavlik | |
5295 | + * Copyright (c) 1999-2001 Vojtech Pavlik | |
5296 | * | |
5297 | - * Input driver to ImExPS/2 device driver module. | |
5298 | - * | |
5299 | - * Sponsored by SuSE | |
5300 | + * Input driver to ExplorerPS/2 device driver module. | |
5301 | */ | |
5302 | ||
5303 | /* | |
5304 | @@ -24,8 +22,8 @@ | |
5305 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
5306 | * | |
5307 | * Should you need to contact me, the author, you can do so either by | |
5308 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
5309 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
5310 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
5311 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
5312 | */ | |
5313 | ||
5314 | #define MOUSEDEV_MINOR_BASE 32 | |
5315 | @@ -41,6 +39,10 @@ | |
5316 | #include <linux/smp_lock.h> | |
5317 | #include <linux/random.h> | |
5318 | ||
5319 | +MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>"); | |
5320 | +MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces"); | |
5321 | +MODULE_LICENSE("GPL"); | |
5322 | + | |
5323 | #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X | |
5324 | #define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 | |
5325 | #endif | |
5326 | @@ -52,6 +54,7 @@ | |
5327 | int exist; | |
5328 | int open; | |
5329 | int minor; | |
5330 | + char name[16]; | |
5331 | wait_queue_head_t wait; | |
5332 | struct mousedev_list *list; | |
5333 | struct input_handle handle; | |
5334 | @@ -89,8 +92,6 @@ | |
5335 | struct mousedev_list *list; | |
5336 | int index, size; | |
5337 | ||
5338 | - add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value); | |
5339 | - | |
5340 | while (*mousedev) { | |
5341 | list = (*mousedev)->list; | |
5342 | while (list) { | |
5343 | @@ -101,13 +102,23 @@ | |
5344 | switch (code) { | |
5345 | case ABS_X: | |
5346 | size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; | |
5347 | - list->dx += (value * xres - list->oldx) / size; | |
5348 | - list->oldx += list->dx * size; | |
5349 | + if (size != 0) { | |
5350 | + list->dx += (value * xres - list->oldx) / size; | |
5351 | + list->oldx += list->dx * size; | |
5352 | + } else { | |
5353 | + list->dx += value - list->oldx; | |
5354 | + list->oldx += list->dx; | |
5355 | + } | |
5356 | break; | |
5357 | case ABS_Y: | |
5358 | size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; | |
5359 | - list->dy -= (value * yres - list->oldy) / size; | |
5360 | - list->oldy -= list->dy * size; | |
5361 | + if (size != 0) { | |
5362 | + list->dy -= (value * yres - list->oldy) / size; | |
5363 | + list->oldy -= list->dy * size; | |
5364 | + } else { | |
5365 | + list->dy -= value - list->oldy; | |
5366 | + list->oldy -= list->dy; | |
5367 | + } | |
5368 | break; | |
5369 | } | |
5370 | break; | |
5371 | @@ -170,7 +181,6 @@ | |
5372 | struct mousedev_list *list = file->private_data; | |
5373 | struct mousedev_list **listptr; | |
5374 | ||
5375 | - lock_kernel(); | |
5376 | listptr = &list->mousedev->list; | |
5377 | mousedev_fasync(-1, file, 0); | |
5378 | ||
5379 | @@ -208,7 +218,6 @@ | |
5380 | } | |
5381 | ||
5382 | kfree(list); | |
5383 | - unlock_kernel(); | |
5384 | ||
5385 | return 0; | |
5386 | } | |
5387 | @@ -216,7 +225,14 @@ | |
5388 | static int mousedev_open(struct inode * inode, struct file * file) | |
5389 | { | |
5390 | struct mousedev_list *list; | |
5391 | - int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; | |
5392 | + int i; | |
5393 | + | |
5394 | +#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | |
5395 | + if (major(inode->i_rdev) == MISC_MAJOR)) | |
5396 | + i = MOUSEDEV_MIX; | |
5397 | + else | |
5398 | +#endif | |
5399 | + i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; | |
5400 | ||
5401 | if (i >= MOUSEDEV_MINORS || !mousedev_table[i]) | |
5402 | return -ENODEV; | |
5403 | @@ -346,7 +362,7 @@ | |
5404 | if (!list->ready && !list->buffer) { | |
5405 | ||
5406 | add_wait_queue(&list->mousedev->wait, &wait); | |
5407 | - current->state = TASK_INTERRUPTIBLE; | |
5408 | + set_current_state(TASK_INTERRUPTIBLE); | |
5409 | ||
5410 | while (!list->ready) { | |
5411 | ||
5412 | @@ -362,7 +378,7 @@ | |
5413 | schedule(); | |
5414 | } | |
5415 | ||
5416 | - current->state = TASK_RUNNING; | |
5417 | + set_current_state(TASK_RUNNING); | |
5418 | remove_wait_queue(&list->mousedev->wait, &wait); | |
5419 | } | |
5420 | ||
5421 | @@ -403,19 +419,11 @@ | |
5422 | fasync: mousedev_fasync, | |
5423 | }; | |
5424 | ||
5425 | -static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev) | |
5426 | +static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) | |
5427 | { | |
5428 | struct mousedev *mousedev; | |
5429 | int minor = 0; | |
5430 | ||
5431 | - if (!test_bit(EV_KEY, dev->evbit) || | |
5432 | - (!test_bit(BTN_LEFT, dev->keybit) && !test_bit(BTN_TOUCH, dev->keybit))) | |
5433 | - return NULL; | |
5434 | - | |
5435 | - if ((!test_bit(EV_REL, dev->evbit) || !test_bit(REL_X, dev->relbit)) && | |
5436 | - (!test_bit(EV_ABS, dev->evbit) || !test_bit(ABS_X, dev->absbit))) | |
5437 | - return NULL; | |
5438 | - | |
5439 | for (minor = 0; minor < MOUSEDEV_MINORS && mousedev_table[minor]; minor++); | |
5440 | if (minor == MOUSEDEV_MINORS) { | |
5441 | printk(KERN_ERR "mousedev: no more free mousedev devices\n"); | |
5442 | @@ -427,11 +435,12 @@ | |
5443 | memset(mousedev, 0, sizeof(struct mousedev)); | |
5444 | init_waitqueue_head(&mousedev->wait); | |
5445 | ||
5446 | - mousedev->exist = 1; | |
5447 | mousedev->minor = minor; | |
5448 | mousedev_table[minor] = mousedev; | |
5449 | + sprintf(mousedev->name, "mouse%d", minor); | |
5450 | ||
5451 | mousedev->handle.dev = dev; | |
5452 | + mousedev->handle.name = mousedev->name; | |
5453 | mousedev->handle.handler = handler; | |
5454 | mousedev->handle.private = mousedev; | |
5455 | ||
5456 | @@ -440,7 +449,7 @@ | |
5457 | if (mousedev_mix.open) | |
5458 | input_open_device(&mousedev->handle); | |
5459 | ||
5460 | -// printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number); | |
5461 | + mousedev->exist = 1; | |
5462 | ||
5463 | return &mousedev->handle; | |
5464 | } | |
5465 | @@ -461,6 +470,26 @@ | |
5466 | kfree(mousedev); | |
5467 | } | |
5468 | } | |
5469 | + | |
5470 | +static struct input_device_id mousedev_ids[] = { | |
5471 | + { | |
5472 | + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, | |
5473 | + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, | |
5474 | + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, | |
5475 | + relbit: { BIT(REL_X) | BIT(REL_Y) }, | |
5476 | + }, /* A mouse like device, at least one button, two relative axes */ | |
5477 | + | |
5478 | + { | |
5479 | + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, | |
5480 | + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, | |
5481 | + keybit: { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, | |
5482 | + absbit: { BIT(ABS_X) | BIT(ABS_Y) }, | |
5483 | + }, /* A tablet like device, at least touch detection, two absolute axes */ | |
5484 | + | |
5485 | + { }, /* Terminating entry */ | |
5486 | +}; | |
5487 | + | |
5488 | +MODULE_DEVICE_TABLE(input, mousedev_ids); | |
5489 | ||
5490 | static struct input_handler mousedev_handler = { | |
5491 | event: mousedev_event, | |
5492 | @@ -468,7 +497,15 @@ | |
5493 | disconnect: mousedev_disconnect, | |
5494 | fops: &mousedev_fops, | |
5495 | minor: MOUSEDEV_MINOR_BASE, | |
5496 | + name: "mousedev", | |
5497 | + id_table: mousedev_ids, | |
5498 | +}; | |
5499 | + | |
5500 | +#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | |
5501 | +static struct miscdevice psaux_mouse = { | |
5502 | + PSMOUSE_MINOR, "psaux", &mousedev_fops | |
5503 | }; | |
5504 | +#endif | |
5505 | ||
5506 | static int __init mousedev_init(void) | |
5507 | { | |
5508 | @@ -480,6 +517,9 @@ | |
5509 | mousedev_mix.exist = 1; | |
5510 | mousedev_mix.minor = MOUSEDEV_MIX; | |
5511 | mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE); | |
5512 | +#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | |
5513 | + misc_register(&psaux_mouse) | |
5514 | +#endif | |
5515 | ||
5516 | printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); | |
5517 | ||
5518 | @@ -488,16 +528,15 @@ | |
5519 | ||
5520 | static void __exit mousedev_exit(void) | |
5521 | { | |
5522 | +#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX | |
5523 | + misc_deregister(&psaux_mouse) | |
5524 | +#endif | |
5525 | input_unregister_minor(mousedev_mix.devfs); | |
5526 | input_unregister_handler(&mousedev_handler); | |
5527 | } | |
5528 | ||
5529 | module_init(mousedev_init); | |
5530 | module_exit(mousedev_exit); | |
5531 | - | |
5532 | -MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>"); | |
5533 | -MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver"); | |
5534 | -MODULE_LICENSE("GPL"); | |
5535 | ||
5536 | MODULE_PARM(xres, "i"); | |
5537 | MODULE_PARM_DESC(xres, "Horizontal screen resolution"); | |
5538 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/Config.in linux-modified/drivers/usb/Config.in | |
5539 | --- linux-vanilla/drivers/usb/Config.in Mon Jan 6 15:58:08 2003 | |
5540 | +++ linux-modified/drivers/usb/Config.in Mon Jan 6 16:48:20 2003 | |
5541 | @@ -62,6 +62,8 @@ | |
5542 | fi | |
5543 | dep_mbool ' HID input layer support' CONFIG_USB_HIDINPUT $CONFIG_INPUT $CONFIG_USB_HID | |
5544 | dep_mbool ' /dev/hiddev raw HID device support' CONFIG_USB_HIDDEV $CONFIG_USB_HID | |
5545 | + dep_mbool ' Force feedback support (EXPERIMENTAL)' CONFIG_HID_FF $CONFIG_USB_HID $CONFIG_EXPERIMENTAL | |
5546 | + dep_mbool ' Logitech WingMan 3D devices (EXPERIMENTAL)' CONFIG_LOGITECH_FF $CONFIG_HID_FF $CONFIG_EXPERIMENTAL | |
5547 | if [ "$CONFIG_USB_HID" != "y" ]; then | |
5548 | dep_tristate ' USB HIDBP Keyboard (basic) support' CONFIG_USB_KBD $CONFIG_USB $CONFIG_INPUT | |
5549 | dep_tristate ' USB HIDBP Mouse (basic) support' CONFIG_USB_MOUSE $CONFIG_USB $CONFIG_INPUT | |
5550 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/Makefile linux-modified/drivers/usb/Makefile | |
5551 | --- linux-vanilla/drivers/usb/Makefile Mon Jan 6 15:58:08 2003 | |
5552 | +++ linux-modified/drivers/usb/Makefile Mon Jan 6 16:48:20 2003 | |
5553 | @@ -34,6 +34,14 @@ | |
5554 | hid-objs += hid-input.o | |
5555 | endif | |
5556 | ||
5557 | +ifeq ($(CONFIG_HID_FF),y) | |
5558 | + hid-objs += hid-ff.o | |
5559 | +endif | |
5560 | + | |
5561 | +ifeq ($(CONFIG_LOGITECH_FF),y) | |
5562 | + hid-objs += hid-lgff.o | |
5563 | +endif | |
5564 | + | |
5565 | # Object file lists. | |
5566 | ||
5567 | obj-y := | |
5568 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/fixp-arith.h linux-modified/drivers/usb/fixp-arith.h | |
5569 | --- linux-vanilla/drivers/usb/fixp-arith.h Thu Jan 1 02:00:00 1970 | |
5570 | +++ linux-modified/drivers/usb/fixp-arith.h Sun Mar 9 17:01:24 2003 | |
5571 | @@ -0,0 +1,100 @@ | |
5572 | +#ifndef _FIXP_ARITH_H | |
5573 | +#define _FIXP_ARITH_H | |
5574 | + | |
5575 | +/* | |
5576 | + * $$ | |
5577 | + * | |
5578 | + * Simplistic fixed-point arithmetics. | |
5579 | + * Hmm, I'm probably duplicating some code :( | |
5580 | + * | |
5581 | + * Copyright (c) 2002 Johann Deneux | |
5582 | + */ | |
5583 | + | |
5584 | +/* | |
5585 | + * This program is free software; you can redistribute it and/or modify | |
5586 | + * it under the terms of the GNU General Public License as published by | |
5587 | + * the Free Software Foundation; either version 2 of the License, or | |
5588 | + * (at your option) any later version. | |
5589 | + * | |
5590 | + * This program is distributed in the hope that it will be useful, | |
5591 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
5592 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
5593 | + * GNU General Public License for more details. | |
5594 | + * | |
5595 | + * You should have received a copy of the GNU General Public License | |
5596 | + * along with this program; if not, write to the Free Software | |
5597 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
5598 | + * | |
5599 | + * Should you need to contact me, the author, you can do so by | |
5600 | + * e-mail - mail your message to <deneux@ifrance.com> | |
5601 | + */ | |
5602 | + | |
5603 | +#include <linux/types.h> | |
5604 | + | |
5605 | +// The type representing fixed-point values | |
5606 | +typedef s16 fixp_t; | |
5607 | + | |
5608 | +#define FRAC_N 8 | |
5609 | +#define FRAC_MASK ((1<<FRAC_N)-1) | |
5610 | + | |
5611 | +// Not to be used directly. Use fixp_{cos,sin} | |
5612 | +fixp_t cos_table[45] = { | |
5613 | + 0x0100, 0x00FF, 0x00FF, 0x00FE, 0x00FD, 0x00FC, 0x00FA, 0x00F8, | |
5614 | + 0x00F6, 0x00F3, 0x00F0, 0x00ED, 0x00E9, 0x00E6, 0x00E2, 0x00DD, | |
5615 | + 0x00D9, 0x00D4, 0x00CF, 0x00C9, 0x00C4, 0x00BE, 0x00B8, 0x00B1, | |
5616 | + 0x00AB, 0x00A4, 0x009D, 0x0096, 0x008F, 0x0087, 0x0080, 0x0078, | |
5617 | + 0x0070, 0x0068, 0x005F, 0x0057, 0x004F, 0x0046, 0x003D, 0x0035, | |
5618 | + 0x002C, 0x0023, 0x001A, 0x0011, 0x0008 | |
5619 | +}; | |
5620 | + | |
5621 | + | |
5622 | +/* a: 123 -> 123.0 */ | |
5623 | +inline fixp_t fixp_new(s16 a) | |
5624 | +{ | |
5625 | + return a<<FRAC_N; | |
5626 | +} | |
5627 | + | |
5628 | +/* a: 0xFFFF -> -1.0 | |
5629 | + 0x8000 -> 1.0 | |
5630 | + 0x0000 -> 0.0 | |
5631 | +*/ | |
5632 | +inline fixp_t fixp_new16(s16 a) | |
5633 | +{ | |
5634 | + return ((s32)a)>>(16-FRAC_N); | |
5635 | +} | |
5636 | + | |
5637 | +inline int fixp_toint(fixp_t x) | |
5638 | +{ | |
5639 | + return x>>FRAC_N; | |
5640 | +} | |
5641 | + | |
5642 | +inline fixp_t fixp_cos(unsigned int degrees) | |
5643 | +{ | |
5644 | + int quadrant = (degrees / 90) & 3; | |
5645 | + unsigned int i = degrees % 90; | |
5646 | + | |
5647 | + if (quadrant == 1 || quadrant == 3) { | |
5648 | + i = 89 - i; | |
5649 | + } | |
5650 | + | |
5651 | + i >>= 1; | |
5652 | + | |
5653 | + return (quadrant == 1 || quadrant == 2)? -cos_table[i] : cos_table[i]; | |
5654 | +} | |
5655 | + | |
5656 | +inline fixp_t fixp_sin(unsigned int degrees) | |
5657 | +{ | |
5658 | + return -fixp_cos(degrees + 90); | |
5659 | +} | |
5660 | + | |
5661 | +inline fixp_t fixp_mult(fixp_t a, fixp_t b) | |
5662 | +{ | |
5663 | + return ((s32)(a*b))>>FRAC_N; | |
5664 | +} | |
5665 | + | |
5666 | +inline fixp_t fixp_div(fixp_t a, fixp_t b) | |
5667 | +{ | |
5668 | + return (a/b)<<FRAC_N; | |
5669 | +} | |
5670 | + | |
5671 | +#endif | |
5672 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/hid-core.c linux-modified/drivers/usb/hid-core.c | |
5673 | --- linux-vanilla/drivers/usb/hid-core.c Mon Jan 6 15:58:08 2003 | |
5674 | +++ linux-modified/drivers/usb/hid-core.c Mon Jan 13 23:41:59 2003 | |
5675 | @@ -1,12 +1,10 @@ | |
5676 | /* | |
5677 | - * $Id$ | |
5678 | + * $Id$ | |
5679 | * | |
5680 | * Copyright (c) 1999 Andreas Gal | |
5681 | * Copyright (c) 2000-2001 Vojtech Pavlik | |
5682 | * | |
5683 | * USB HID support for Linux | |
5684 | - * | |
5685 | - * Sponsored by SuSE | |
5686 | */ | |
5687 | ||
5688 | /* | |
5689 | @@ -25,8 +23,8 @@ | |
5690 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
5691 | * | |
5692 | * Should you need to contact me, the author, you can do so either by | |
5693 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
5694 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
5695 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
5696 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
5697 | */ | |
5698 | ||
5699 | #include <linux/module.h> | |
5700 | @@ -47,15 +45,19 @@ | |
5701 | #include <linux/usb.h> | |
5702 | ||
5703 | #include "hid.h" | |
5704 | +#ifdef CONFIG_USB_HIDDEV | |
5705 | #include <linux/hiddev.h> | |
5706 | +#endif | |
5707 | + | |
5708 | ||
5709 | /* | |
5710 | * Version Information | |
5711 | */ | |
5712 | ||
5713 | -#define DRIVER_VERSION "v1.8.1" | |
5714 | -#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>" | |
5715 | -#define DRIVER_DESC "USB HID support drivers" | |
5716 | +#define DRIVER_VERSION "v1.31" | |
5717 | +#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@ucw.cz>" | |
5718 | +#define DRIVER_DESC "USB HID core driver" | |
5719 | +#define DRIVER_LICENSE "GPL" | |
5720 | ||
5721 | static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick", | |
5722 | "Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"}; | |
5723 | @@ -206,7 +208,6 @@ | |
5724 | dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum); | |
5725 | return -1; | |
5726 | } | |
5727 | - | |
5728 | usages = parser->local.usage_index; | |
5729 | ||
5730 | offset = report->size; | |
5731 | @@ -322,7 +323,7 @@ | |
5732 | return 0; | |
5733 | ||
5734 | case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT: | |
5735 | - parser->global.unit_exponent = item_udata(item); | |
5736 | + parser->global.unit_exponent = item_sdata(item); | |
5737 | return 0; | |
5738 | ||
5739 | case HID_GLOBAL_ITEM_TAG_UNIT: | |
5740 | @@ -507,8 +508,6 @@ | |
5741 | ||
5742 | for (n = 0; n < report->maxfield; n++) | |
5743 | kfree(report->field[n]); | |
5744 | - if (report->data) | |
5745 | - kfree(report->data); | |
5746 | kfree(report); | |
5747 | } | |
5748 | ||
5749 | @@ -520,6 +519,10 @@ | |
5750 | { | |
5751 | unsigned i,j; | |
5752 | ||
5753 | +#ifdef CONFIG_HID_FF | |
5754 | + hid_ff_exit(device); | |
5755 | +#endif | |
5756 | + | |
5757 | for (i = 0; i < HID_REPORT_TYPES; i++) { | |
5758 | struct hid_report_enum *report_enum = device->report_enum + i; | |
5759 | ||
5760 | @@ -537,60 +540,64 @@ | |
5761 | * items, though they are not used yet. | |
5762 | */ | |
5763 | ||
5764 | -static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) | |
5765 | +static u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item) | |
5766 | { | |
5767 | - if ((end - start) > 0) { | |
5768 | + u8 b; | |
5769 | ||
5770 | - __u8 b = *start++; | |
5771 | - item->type = (b >> 2) & 3; | |
5772 | - item->tag = (b >> 4) & 15; | |
5773 | + if ((end - start) <= 0) | |
5774 | + return NULL; | |
5775 | ||
5776 | - if (item->tag == HID_ITEM_TAG_LONG) { | |
5777 | + b = *start++; | |
5778 | ||
5779 | - item->format = HID_ITEM_FORMAT_LONG; | |
5780 | + item->type = (b >> 2) & 3; | |
5781 | + item->tag = (b >> 4) & 15; | |
5782 | ||
5783 | - if ((end - start) >= 2) { | |
5784 | + if (item->tag == HID_ITEM_TAG_LONG) { | |
5785 | ||
5786 | - item->size = *start++; | |
5787 | - item->tag = *start++; | |
5788 | + item->format = HID_ITEM_FORMAT_LONG; | |
5789 | ||
5790 | - if ((end - start) >= item->size) { | |
5791 | - item->data.longdata = start; | |
5792 | - start += item->size; | |
5793 | - return start; | |
5794 | - } | |
5795 | - } | |
5796 | - } else { | |
5797 | + if ((end - start) < 2) | |
5798 | + return NULL; | |
5799 | ||
5800 | - item->format = HID_ITEM_FORMAT_SHORT; | |
5801 | - item->size = b & 3; | |
5802 | - switch (item->size) { | |
5803 | - | |
5804 | - case 0: | |
5805 | - return start; | |
5806 | - | |
5807 | - case 1: | |
5808 | - if ((end - start) >= 1) { | |
5809 | - item->data.u8 = *start++; | |
5810 | - return start; | |
5811 | - } | |
5812 | - break; | |
5813 | - | |
5814 | - case 2: | |
5815 | - if ((end - start) >= 2) { | |
5816 | - item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++)); | |
5817 | - return start; | |
5818 | - } | |
5819 | - | |
5820 | - case 3: | |
5821 | - item->size++; | |
5822 | - if ((end - start) >= 4) { | |
5823 | - item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++)); | |
5824 | - return start; | |
5825 | - } | |
5826 | - } | |
5827 | - } | |
5828 | + item->size = *start++; | |
5829 | + item->tag = *start++; | |
5830 | + | |
5831 | + if ((end - start) < item->size) | |
5832 | + return NULL; | |
5833 | + | |
5834 | + item->data.longdata = start; | |
5835 | + start += item->size; | |
5836 | + return start; | |
5837 | + } | |
5838 | + | |
5839 | + item->format = HID_ITEM_FORMAT_SHORT; | |
5840 | + item->size = b & 3; | |
5841 | + | |
5842 | + switch (item->size) { | |
5843 | + | |
5844 | + case 0: | |
5845 | + return start; | |
5846 | + | |
5847 | + case 1: | |
5848 | + if ((end - start) < 1) | |
5849 | + return NULL; | |
5850 | + item->data.u8 = *start++; | |
5851 | + return start; | |
5852 | + | |
5853 | + case 2: | |
5854 | + if ((end - start) < 2) | |
5855 | + return NULL; | |
5856 | + item->data.u16 = le16_to_cpu(get_unaligned(((__u16*)start)++)); | |
5857 | + return start; | |
5858 | + | |
5859 | + case 3: | |
5860 | + item->size++; | |
5861 | + if ((end - start) < 4) | |
5862 | + return NULL; | |
5863 | + item->data.u32 = le32_to_cpu(get_unaligned(((__u32*)start)++)); | |
5864 | + return start; | |
5865 | } | |
5866 | + | |
5867 | return NULL; | |
5868 | } | |
5869 | ||
5870 | @@ -637,12 +644,14 @@ | |
5871 | ||
5872 | end = start + size; | |
5873 | while ((start = fetch_item(start, end, &item)) != 0) { | |
5874 | + | |
5875 | if (item.format != HID_ITEM_FORMAT_SHORT) { | |
5876 | dbg("unexpected long global item"); | |
5877 | hid_free_device(device); | |
5878 | kfree(parser); | |
5879 | return NULL; | |
5880 | } | |
5881 | + | |
5882 | if (dispatch_type[item.type](parser, &item)) { | |
5883 | dbg("item %u %u %u %u parsing failed\n", | |
5884 | item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag); | |
5885 | @@ -735,11 +744,24 @@ | |
5886 | hid_dump_input(usage, value); | |
5887 | if (hid->claimed & HID_CLAIMED_INPUT) | |
5888 | hidinput_hid_event(hid, field, usage, value); | |
5889 | - if (hid->claimed & HID_CLAIMED_HIDDEV) | |
5890 | - hiddev_hid_event(hid, usage->hid, value); | |
5891 | +#ifdef CONFIG_USB_HIDDEV | |
5892 | + if (hid->claimed & HID_CLAIMED_HIDDEV) { | |
5893 | + struct hiddev_usage_ref uref; | |
5894 | + unsigned type = field->report_type; | |
5895 | + uref.report_type = | |
5896 | + (type == HID_INPUT_REPORT) ? HID_REPORT_TYPE_INPUT : | |
5897 | + ((type == HID_OUTPUT_REPORT) ? HID_REPORT_TYPE_OUTPUT : | |
5898 | + ((type == HID_FEATURE_REPORT) ? HID_REPORT_TYPE_FEATURE:0)); | |
5899 | + uref.report_id = field->report->id; | |
5900 | + uref.field_index = field->index; | |
5901 | + uref.usage_index = (usage - field->usage); | |
5902 | + uref.usage_code = usage->hid; | |
5903 | + uref.value = value; | |
5904 | + hiddev_hid_event(hid, &uref); | |
5905 | + } | |
5906 | +#endif | |
5907 | } | |
5908 | ||
5909 | - | |
5910 | /* | |
5911 | * Analyse a received field, and fetch the data from it. The field | |
5912 | * content is stored for next report processing (we do differential | |
5913 | @@ -794,9 +816,12 @@ | |
5914 | memcpy(field->value, value, count * sizeof(__s32)); | |
5915 | } | |
5916 | ||
5917 | -static int hid_input_report(int type, u8 *data, int len, struct hid_device *hid) | |
5918 | +static int hid_input_report(int type, struct urb *urb) | |
5919 | { | |
5920 | + struct hid_device *hid = urb->context; | |
5921 | struct hid_report_enum *report_enum = hid->report_enum + type; | |
5922 | + u8 *data = urb->transfer_buffer; | |
5923 | + int len = urb->actual_length; | |
5924 | struct hid_report *report; | |
5925 | int n, size; | |
5926 | ||
5927 | @@ -815,95 +840,46 @@ | |
5928 | len--; | |
5929 | } | |
5930 | ||
5931 | - if (!(report = report_enum->report_id_hash[n])) { | |
5932 | - dbg("undefined report_id %d received", n); | |
5933 | -#ifdef DEBUG | |
5934 | - printk(KERN_DEBUG __FILE__ ": report (size %u) = ", len); | |
5935 | - for (n = 0; n < len; n++) | |
5936 | - printk(" %02x", data[n]); | |
5937 | - printk("\n"); | |
5938 | +#ifdef DEBUG_DATA | |
5939 | + { | |
5940 | + int i; | |
5941 | + printk(KERN_DEBUG __FILE__ ": report %d (size %u) = ", n, len); | |
5942 | + for (i = 0; i < n; i++) | |
5943 | + printk(" %02x", data[i]); | |
5944 | + printk("\n"); | |
5945 | + } | |
5946 | #endif | |
5947 | ||
5948 | + if (!(report = report_enum->report_id_hash[n])) { | |
5949 | + dbg("undefined report_id %d received", n); | |
5950 | return -1; | |
5951 | } | |
5952 | ||
5953 | size = ((report->size - 1) >> 3) + 1; | |
5954 | ||
5955 | if (len < size) { | |
5956 | - | |
5957 | - if (size <= 8) { | |
5958 | - dbg("report %d is too short, (%d < %d)", report->id, len, size); | |
5959 | - return -1; | |
5960 | - } | |
5961 | - | |
5962 | - /* | |
5963 | - * Some low-speed devices have large reports and maxpacketsize 8. | |
5964 | - * We buffer the data in that case and parse it when we got it all. | |
5965 | - * Works only for unnumbered reports. Doesn't make sense for numbered | |
5966 | - * reports anyway - then they don't need to be large. | |
5967 | - */ | |
5968 | - | |
5969 | - if (!report->data) | |
5970 | - if (!(report->data = kmalloc(size, GFP_ATOMIC))) { | |
5971 | - dbg("couldn't allocate report buffer"); | |
5972 | - return -1; | |
5973 | - } | |
5974 | - | |
5975 | - if (report->idx + len > size) { | |
5976 | - dbg("report data buffer overflow"); | |
5977 | - report->idx = 0; | |
5978 | - return -1; | |
5979 | - } | |
5980 | - | |
5981 | - memcpy(report->data + report->idx, data, len); | |
5982 | - report->idx += len; | |
5983 | - | |
5984 | - if (report->idx < size) | |
5985 | - return 0; | |
5986 | - | |
5987 | - data = report->data; | |
5988 | + dbg("report %d is too short, (%d < %d)", report->id, len, size); | |
5989 | + return -1; | |
5990 | } | |
5991 | ||
5992 | for (n = 0; n < report->maxfield; n++) | |
5993 | hid_input_field(hid, report->field[n], data); | |
5994 | ||
5995 | - report->idx = 0; | |
5996 | return 0; | |
5997 | } | |
5998 | ||
5999 | /* | |
6000 | - * Interrupt input handler. | |
6001 | + * Input interrupt completion handler. | |
6002 | */ | |
6003 | ||
6004 | -static void hid_irq(struct urb *urb) | |
6005 | +static void hid_irq_in(struct urb *urb) | |
6006 | { | |
6007 | if (urb->status) { | |
6008 | - dbg("nonzero status in irq %d", urb->status); | |
6009 | + dbg("nonzero status in input irq %d", urb->status); | |
6010 | return; | |
6011 | } | |
6012 | ||
6013 | - hid_input_report(HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, urb->context); | |
6014 | -} | |
6015 | - | |
6016 | -/* | |
6017 | - * hid_read_report() reads in report values without waiting for an irq urb. | |
6018 | - */ | |
6019 | - | |
6020 | -void hid_read_report(struct hid_device *hid, struct hid_report *report) | |
6021 | -{ | |
6022 | - int len = ((report->size - 1) >> 3) + 1 + hid->report_enum[report->type].numbered; | |
6023 | - u8 data[len]; | |
6024 | - int read; | |
6025 | - | |
6026 | - if (hid->quirks & HID_QUIRK_NOGET) | |
6027 | - return; | |
6028 | - | |
6029 | - if ((read = usb_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, data, len)) != len) { | |
6030 | - dbg("reading report type %d id %d failed len %d read %d", report->type + 1, report->id, len, read); | |
6031 | - return; | |
6032 | - } | |
6033 | - | |
6034 | - hid_input_report(report->type, data, len, hid); | |
6035 | + hid_input_report(HID_INPUT_REPORT, urb); | |
6036 | } | |
6037 | ||
6038 | /* | |
6039 | @@ -949,7 +925,8 @@ | |
6040 | hid_dump_input(field->usage + offset, value); | |
6041 | ||
6042 | if (offset >= field->report_count) { | |
6043 | - dbg("offset exceeds report_count"); | |
6044 | + dbg("offset (%d) exceeds report_count (%d)", offset, field->report_count); | |
6045 | + hid_dump_field(field, 8); | |
6046 | return -1; | |
6047 | } | |
6048 | if (field->logical_minimum < 0) { | |
6049 | @@ -958,11 +935,6 @@ | |
6050 | return -1; | |
6051 | } | |
6052 | } | |
6053 | - if ( (value > field->logical_maximum) | |
6054 | - || (value < field->logical_minimum)) { | |
6055 | - dbg("value %d is invalid", value); | |
6056 | - return -1; | |
6057 | - } | |
6058 | field->value[offset] = value; | |
6059 | return 0; | |
6060 | } | |
6061 | @@ -986,14 +958,54 @@ | |
6062 | return -1; | |
6063 | } | |
6064 | ||
6065 | +/* | |
6066 | + * Find a report with a specified HID usage. | |
6067 | + */ | |
6068 | + | |
6069 | +int hid_find_report_by_usage(struct hid_device *hid, __u32 wanted_usage, struct hid_report **report, int type) | |
6070 | +{ | |
6071 | + struct hid_report_enum *report_enum = hid->report_enum + type; | |
6072 | + struct list_head *list = report_enum->report_list.next; | |
6073 | + int i, j; | |
6074 | + | |
6075 | + while (list != &report_enum->report_list) { | |
6076 | + *report = (struct hid_report *) list; | |
6077 | + list = list->next; | |
6078 | + for (i = 0; i < (*report)->maxfield; i++) { | |
6079 | + struct hid_field *field = (*report)->field[i]; | |
6080 | + for (j = 0; j < field->maxusage; j++) | |
6081 | + if (field->logical == wanted_usage) | |
6082 | + return j; | |
6083 | + } | |
6084 | + } | |
6085 | + return -1; | |
6086 | +} | |
6087 | + | |
6088 | +int hid_find_field_in_report(struct hid_report *report, __u32 wanted_usage, struct hid_field **field) | |
6089 | +{ | |
6090 | + int i, j; | |
6091 | + | |
6092 | + for (i = 0; i < report->maxfield; i++) { | |
6093 | + *field = report->field[i]; | |
6094 | + for (j = 0; j < (*field)->maxusage; j++) | |
6095 | + if ((*field)->usage[j].hid == wanted_usage) | |
6096 | + return j; | |
6097 | + } | |
6098 | + | |
6099 | + return -1; | |
6100 | +} | |
6101 | + | |
6102 | static int hid_submit_out(struct hid_device *hid) | |
6103 | { | |
6104 | - hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.wLength); | |
6105 | - hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer; | |
6106 | - hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr); | |
6107 | - hid->urbout.dev = hid->dev; | |
6108 | + struct hid_report *report; | |
6109 | ||
6110 | - if (usb_submit_urb(&hid->urbout)) { | |
6111 | + report = hid->out[hid->outtail]; | |
6112 | + | |
6113 | + hid_output_report(report, hid->outbuf); | |
6114 | + hid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1; | |
6115 | + hid->urbout->dev = hid->dev; | |
6116 | + | |
6117 | + if (usb_submit_urb(hid->urbout)) { | |
6118 | err("usb_submit_urb(out) failed"); | |
6119 | return -1; | |
6120 | } | |
6121 | @@ -1001,33 +1013,168 @@ | |
6122 | return 0; | |
6123 | } | |
6124 | ||
6125 | +static int hid_submit_ctrl(struct hid_device *hid) | |
6126 | +{ | |
6127 | + struct hid_report *report; | |
6128 | + unsigned char dir; | |
6129 | + | |
6130 | + report = hid->ctrl[hid->ctrltail].report; | |
6131 | + dir = hid->ctrl[hid->ctrltail].dir; | |
6132 | + | |
6133 | + if (dir == USB_DIR_OUT) | |
6134 | + hid_output_report(report, hid->ctrlbuf); | |
6135 | + | |
6136 | + hid->urbctrl->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + ((report->id > 0) && (dir != USB_DIR_OUT)); | |
6137 | + hid->urbctrl->pipe = (dir == USB_DIR_OUT) ? usb_sndctrlpipe(hid->dev, 0) : usb_rcvctrlpipe(hid->dev, 0); | |
6138 | + hid->urbctrl->dev = hid->dev; | |
6139 | + | |
6140 | + hid->dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE | dir; | |
6141 | + hid->dr.bRequest = (dir == USB_DIR_OUT) ? HID_REQ_SET_REPORT : HID_REQ_GET_REPORT; | |
6142 | + hid->dr.wValue = ((report->type + 1) << 8) | report->id; | |
6143 | + hid->dr.wIndex = cpu_to_le16(hid->ifnum); | |
6144 | + hid->dr.wLength = cpu_to_le16(hid->urbctrl->transfer_buffer_length); | |
6145 | + | |
6146 | + if (usb_submit_urb(hid->urbctrl)) { | |
6147 | + err("usb_submit_urb(ctrl) failed"); | |
6148 | + return -1; | |
6149 | + } | |
6150 | + | |
6151 | + return 0; | |
6152 | +} | |
6153 | + | |
6154 | +/* | |
6155 | + * Output interrupt completion handler. | |
6156 | + */ | |
6157 | + | |
6158 | +static void hid_irq_out(struct urb *urb) | |
6159 | +{ | |
6160 | + struct hid_device *hid = urb->context; | |
6161 | + unsigned long flags; | |
6162 | + | |
6163 | + if (urb->status) | |
6164 | + warn("output irq status %d received", urb->status); | |
6165 | + | |
6166 | + spin_lock_irqsave(&hid->outlock, flags); | |
6167 | + | |
6168 | + hid->outtail = (hid->outtail + 1) & (HID_OUTPUT_FIFO_SIZE - 1); | |
6169 | + | |
6170 | + if (hid->outhead != hid->outtail) { | |
6171 | + hid_submit_out(hid); | |
6172 | + spin_unlock_irqrestore(&hid->outlock, flags); | |
6173 | + return; | |
6174 | + } | |
6175 | + | |
6176 | + clear_bit(HID_OUT_RUNNING, &hid->iofl); | |
6177 | + | |
6178 | + spin_unlock_irqrestore(&hid->outlock, flags); | |
6179 | + | |
6180 | + wake_up(&hid->wait); | |
6181 | +} | |
6182 | + | |
6183 | +/* | |
6184 | + * Control pipe completion handler. | |
6185 | + */ | |
6186 | + | |
6187 | static void hid_ctrl(struct urb *urb) | |
6188 | { | |
6189 | struct hid_device *hid = urb->context; | |
6190 | + unsigned long flags; | |
6191 | ||
6192 | if (urb->status) | |
6193 | warn("ctrl urb status %d received", urb->status); | |
6194 | ||
6195 | - hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); | |
6196 | + spin_lock_irqsave(&hid->ctrllock, flags); | |
6197 | ||
6198 | - if (hid->outhead != hid->outtail) | |
6199 | - hid_submit_out(hid); | |
6200 | + if (hid->ctrl[hid->ctrltail].dir == USB_DIR_IN) | |
6201 | + hid_input_report(hid->ctrl[hid->ctrltail].report->type, urb); | |
6202 | + | |
6203 | + hid->ctrltail = (hid->ctrltail + 1) & (HID_CONTROL_FIFO_SIZE - 1); | |
6204 | + | |
6205 | + if (hid->ctrlhead != hid->ctrltail) { | |
6206 | + hid_submit_ctrl(hid); | |
6207 | + spin_unlock_irqrestore(&hid->ctrllock, flags); | |
6208 | + return; | |
6209 | + } | |
6210 | + | |
6211 | + clear_bit(HID_CTRL_RUNNING, &hid->iofl); | |
6212 | + | |
6213 | + spin_unlock_irqrestore(&hid->ctrllock, flags); | |
6214 | + | |
6215 | + wake_up(&hid->wait); | |
6216 | } | |
6217 | ||
6218 | -void hid_write_report(struct hid_device *hid, struct hid_report *report) | |
6219 | +void hid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir) | |
6220 | { | |
6221 | - hid_output_report(report, hid->out[hid->outhead].buffer); | |
6222 | + int head; | |
6223 | + unsigned long flags; | |
6224 | ||
6225 | - hid->out[hid->outhead].dr.wValue = cpu_to_le16(0x200 | report->id); | |
6226 | - hid->out[hid->outhead].dr.wLength = cpu_to_le16((report->size + 7) >> 3); | |
6227 | + if (hid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) { | |
6228 | ||
6229 | - hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1); | |
6230 | + spin_lock_irqsave(&hid->outlock, flags); | |
6231 | ||
6232 | - if (hid->outhead == hid->outtail) | |
6233 | - hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1); | |
6234 | + if ((head = (hid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == hid->outtail) { | |
6235 | + spin_unlock_irqrestore(&hid->outlock, flags); | |
6236 | + warn("output queue full"); | |
6237 | + return; | |
6238 | + } | |
6239 | ||
6240 | - if (hid->urbout.status != -EINPROGRESS) | |
6241 | - hid_submit_out(hid); | |
6242 | + hid->out[hid->outhead] = report; | |
6243 | + hid->outhead = head; | |
6244 | + | |
6245 | + if (!test_and_set_bit(HID_OUT_RUNNING, &hid->iofl)) | |
6246 | + hid_submit_out(hid); | |
6247 | + | |
6248 | + spin_unlock_irqrestore(&hid->outlock, flags); | |
6249 | + return; | |
6250 | + } | |
6251 | + | |
6252 | + spin_lock_irqsave(&hid->ctrllock, flags); | |
6253 | + | |
6254 | + if ((head = (hid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == hid->ctrltail) { | |
6255 | + spin_unlock_irqrestore(&hid->ctrllock, flags); | |
6256 | + warn("control queue full"); | |
6257 | + return; | |
6258 | + } | |
6259 | + | |
6260 | + hid->ctrl[hid->ctrlhead].report = report; | |
6261 | + hid->ctrl[hid->ctrlhead].dir = dir; | |
6262 | + hid->ctrlhead = head; | |
6263 | + | |
6264 | + if (!test_and_set_bit(HID_CTRL_RUNNING, &hid->iofl)) | |
6265 | + hid_submit_ctrl(hid); | |
6266 | + | |
6267 | + spin_unlock_irqrestore(&hid->ctrllock, flags); | |
6268 | +} | |
6269 | + | |
6270 | +int hid_wait_io(struct hid_device *hid) | |
6271 | +{ | |
6272 | + DECLARE_WAITQUEUE(wait, current); | |
6273 | + int timeout = 10*HZ; | |
6274 | + | |
6275 | + set_current_state(TASK_UNINTERRUPTIBLE); | |
6276 | + add_wait_queue(&hid->wait, &wait); | |
6277 | + | |
6278 | + while (timeout && (test_bit(HID_CTRL_RUNNING, &hid->iofl) || | |
6279 | + test_bit(HID_OUT_RUNNING, &hid->iofl))) | |
6280 | + timeout = schedule_timeout(timeout); | |
6281 | + | |
6282 | + set_current_state(TASK_RUNNING); | |
6283 | + remove_wait_queue(&hid->wait, &wait); | |
6284 | + | |
6285 | + if (!timeout) { | |
6286 | + dbg("timeout waiting for ctrl or out queue to clear"); | |
6287 | + return -1; | |
6288 | + } | |
6289 | + | |
6290 | + return 0; | |
6291 | +} | |
6292 | +#define USB_CTRL_GET_TIMEOUT 5 | |
6293 | +static int hid_get_class_descriptor(struct usb_device *dev, int ifnum, | |
6294 | + unsigned char type, void *buf, int size) | |
6295 | +{ | |
6296 | + return usb_control_msg(dev, usb_rcvctrlpipe(dev, 0), | |
6297 | + USB_REQ_GET_DESCRIPTOR, USB_RECIP_INTERFACE | USB_DIR_IN, | |
6298 | + (type << 8), ifnum, buf, size, HZ * USB_CTRL_GET_TIMEOUT); | |
6299 | } | |
6300 | ||
6301 | int hid_open(struct hid_device *hid) | |
6302 | @@ -1035,9 +1182,9 @@ | |
6303 | if (hid->open++) | |
6304 | return 0; | |
6305 | ||
6306 | - hid->urb.dev = hid->dev; | |
6307 | + hid->urbin->dev = hid->dev; | |
6308 | ||
6309 | - if (usb_submit_urb(&hid->urb)) | |
6310 | + if (usb_submit_urb(hid->urbin)) | |
6311 | return -EIO; | |
6312 | ||
6313 | return 0; | |
6314 | @@ -1046,81 +1193,83 @@ | |
6315 | void hid_close(struct hid_device *hid) | |
6316 | { | |
6317 | if (!--hid->open) | |
6318 | - usb_unlink_urb(&hid->urb); | |
6319 | + usb_unlink_urb(hid->urbin); | |
6320 | } | |
6321 | ||
6322 | /* | |
6323 | - * Initialize all readable reports | |
6324 | + * Initialize all reports | |
6325 | */ | |
6326 | +#define USB_CTRL_SET_TIMEOUT 5 | |
6327 | void hid_init_reports(struct hid_device *hid) | |
6328 | { | |
6329 | - int i; | |
6330 | - struct hid_report *report; | |
6331 | struct hid_report_enum *report_enum; | |
6332 | + struct hid_report *report; | |
6333 | struct list_head *list; | |
6334 | + int len; | |
6335 | + int err, ret; | |
6336 | ||
6337 | - for (i = 0; i < HID_REPORT_TYPES; i++) { | |
6338 | - if (i == HID_FEATURE_REPORT || i == HID_INPUT_REPORT) { | |
6339 | - report_enum = hid->report_enum + i; | |
6340 | - list = report_enum->report_list.next; | |
6341 | - while (list != &report_enum->report_list) { | |
6342 | - report = (struct hid_report *) list; | |
6343 | - hid_read_report(hid, report); | |
6344 | - usb_set_idle(hid->dev, hid->ifnum, 0, report->id); | |
6345 | - list = list->next; | |
6346 | - } | |
6347 | - } | |
6348 | + report_enum = hid->report_enum + HID_INPUT_REPORT; | |
6349 | + list = report_enum->report_list.next; | |
6350 | + while (list != &report_enum->report_list) { | |
6351 | + report = (struct hid_report *) list; | |
6352 | + hid_submit_report(hid, report, USB_DIR_IN); | |
6353 | + list = list->next; | |
6354 | + } | |
6355 | + | |
6356 | + report_enum = hid->report_enum + HID_FEATURE_REPORT; | |
6357 | + list = report_enum->report_list.next; | |
6358 | + while (list != &report_enum->report_list) { | |
6359 | + report = (struct hid_report *) list; | |
6360 | + hid_submit_report(hid, report, USB_DIR_IN); | |
6361 | + list = list->next; | |
6362 | + } | |
6363 | + | |
6364 | + err = 0; | |
6365 | + while ((ret = hid_wait_io(hid))) { | |
6366 | + err |= ret; | |
6367 | + if (test_bit(HID_CTRL_RUNNING, &hid->iofl)) | |
6368 | + usb_unlink_urb(hid->urbctrl); | |
6369 | + if (test_bit(HID_OUT_RUNNING, &hid->iofl)) | |
6370 | + usb_unlink_urb(hid->urbout); | |
6371 | + } | |
6372 | + | |
6373 | + if (err) | |
6374 | + warn("timeout initializing reports\n"); | |
6375 | + | |
6376 | + report_enum = hid->report_enum + HID_INPUT_REPORT; | |
6377 | + list = report_enum->report_list.next; | |
6378 | + while (list != &report_enum->report_list) { | |
6379 | + report = (struct hid_report *) list; | |
6380 | + len = ((report->size - 1) >> 3) + 1 + report_enum->numbered; | |
6381 | + if (len > hid->urbin->transfer_buffer_length) | |
6382 | + hid->urbin->transfer_buffer_length = len < HID_BUFFER_SIZE ? len : HID_BUFFER_SIZE; | |
6383 | + usb_control_msg(hid->dev, usb_sndctrlpipe(hid->dev, 0), | |
6384 | + 0x0a, USB_TYPE_CLASS | USB_RECIP_INTERFACE, report->id, | |
6385 | + hid->ifnum, NULL, 0, HZ * USB_CTRL_SET_TIMEOUT); | |
6386 | + list = list->next; | |
6387 | } | |
6388 | } | |
6389 | ||
6390 | #define USB_VENDOR_ID_WACOM 0x056a | |
6391 | -#define USB_DEVICE_ID_WACOM_PENPARTNER 0x0000 | |
6392 | #define USB_DEVICE_ID_WACOM_GRAPHIRE 0x0010 | |
6393 | #define USB_DEVICE_ID_WACOM_INTUOS 0x0020 | |
6394 | -#define USB_DEVICE_ID_WACOM_PL 0x0030 | |
6395 | -#define USB_DEVICE_ID_WACOM_INTUOS2 0x0041 | |
6396 | - | |
6397 | -#define USB_VENDOR_ID_ATEN 0x0557 | |
6398 | -#define USB_DEVICE_ID_ATEN_UC100KM 0x2004 | |
6399 | -#define USB_DEVICE_ID_ATEN_CS124U 0x2202 | |
6400 | -#define USB_DEVICE_ID_ATEN_2PORTKVM 0x2204 | |
6401 | -#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205 | |
6402 | ||
6403 | #define USB_VENDOR_ID_GRIFFIN 0x077d | |
6404 | -#define USB_DEVICE_ID_POWERMATE 0x0410 /* Griffin PowerMate */ | |
6405 | -#define USB_DEVICE_ID_SOUNDKNOB 0x04AA /* Griffin SoundKnob */ | |
6406 | +#define USB_DEVICE_ID_POWERMATE 0x0410 | |
6407 | +#define USB_DEVICE_ID_SOUNDKNOB 0x04AA | |
6408 | ||
6409 | struct hid_blacklist { | |
6410 | __u16 idVendor; | |
6411 | __u16 idProduct; | |
6412 | - unsigned quirks; | |
6413 | } hid_blacklist[] = { | |
6414 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PENPARTNER, HID_QUIRK_IGNORE }, | |
6415 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE, HID_QUIRK_IGNORE }, | |
6416 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 1, HID_QUIRK_IGNORE }, | |
6417 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE + 2, HID_QUIRK_IGNORE }, | |
6418 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS, HID_QUIRK_IGNORE }, | |
6419 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1, HID_QUIRK_IGNORE }, | |
6420 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2, HID_QUIRK_IGNORE }, | |
6421 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3, HID_QUIRK_IGNORE }, | |
6422 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4, HID_QUIRK_IGNORE }, | |
6423 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL, HID_QUIRK_IGNORE }, | |
6424 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 1, HID_QUIRK_IGNORE }, | |
6425 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 2, HID_QUIRK_IGNORE }, | |
6426 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 3, HID_QUIRK_IGNORE }, | |
6427 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 4, HID_QUIRK_IGNORE }, | |
6428 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_PL + 5, HID_QUIRK_IGNORE }, | |
6429 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2, HID_QUIRK_IGNORE }, | |
6430 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 1, HID_QUIRK_IGNORE }, | |
6431 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 2, HID_QUIRK_IGNORE }, | |
6432 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 3, HID_QUIRK_IGNORE }, | |
6433 | - { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS2 + 4, HID_QUIRK_IGNORE }, | |
6434 | - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_UC100KM, HID_QUIRK_NOGET }, | |
6435 | - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_CS124U, HID_QUIRK_NOGET }, | |
6436 | - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_2PORTKVM, HID_QUIRK_NOGET }, | |
6437 | - { USB_VENDOR_ID_ATEN, USB_DEVICE_ID_ATEN_4PORTKVM, HID_QUIRK_NOGET }, | |
6438 | - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE, HID_QUIRK_IGNORE }, | |
6439 | - { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB, HID_QUIRK_IGNORE }, | |
6440 | + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE }, | |
6441 | + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS }, | |
6442 | + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1}, | |
6443 | + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2}, | |
6444 | + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3}, | |
6445 | + { USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4}, | |
6446 | + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_POWERMATE }, | |
6447 | + { USB_VENDOR_ID_GRIFFIN, USB_DEVICE_ID_SOUNDKNOB }, | |
6448 | { 0, 0 } | |
6449 | }; | |
6450 | ||
6451 | @@ -1129,26 +1278,23 @@ | |
6452 | struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0; | |
6453 | struct hid_descriptor *hdesc; | |
6454 | struct hid_device *hid; | |
6455 | - unsigned quirks = 0, rsize = 0; | |
6456 | + unsigned rsize = 0; | |
6457 | + u8 *rdesc; | |
6458 | char *buf; | |
6459 | int n; | |
6460 | ||
6461 | for (n = 0; hid_blacklist[n].idVendor; n++) | |
6462 | if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) && | |
6463 | - (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) | |
6464 | - quirks = hid_blacklist[n].quirks; | |
6465 | - | |
6466 | - if (quirks & HID_QUIRK_IGNORE) | |
6467 | - return NULL; | |
6468 | + (hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL; | |
6469 | ||
6470 | - if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc) && ((!interface->bNumEndpoints) || | |
6471 | - usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc))) { | |
6472 | + if (usb_get_extra_descriptor(interface, HID_DT_HID, &hdesc) && ((!interface->bNumEndpoints) || | |
6473 | + usb_get_extra_descriptor(&interface->endpoint[0], HID_DT_HID, &hdesc))) { | |
6474 | dbg("class descriptor not present\n"); | |
6475 | return NULL; | |
6476 | } | |
6477 | ||
6478 | for (n = 0; n < hdesc->bNumDescriptors; n++) | |
6479 | - if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT) | |
6480 | + if (hdesc->desc[n].bDescriptorType == HID_DT_REPORT) | |
6481 | rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength); | |
6482 | ||
6483 | if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) { | |
6484 | @@ -1156,118 +1302,158 @@ | |
6485 | return NULL; | |
6486 | } | |
6487 | ||
6488 | - { | |
6489 | - __u8 rdesc[rsize]; | |
6490 | + if (!(rdesc = kmalloc(rsize, GFP_KERNEL))) { | |
6491 | + dbg("couldn't allocate rdesc memory"); | |
6492 | + return NULL; | |
6493 | + } | |
6494 | ||
6495 | - if ((n = usb_get_class_descriptor(dev, interface->bInterfaceNumber, USB_DT_REPORT, 0, rdesc, rsize)) < 0) { | |
6496 | - dbg("reading report descriptor failed"); | |
6497 | - return NULL; | |
6498 | - } | |
6499 | + if ((n = hid_get_class_descriptor(dev, interface->bInterfaceNumber, HID_DT_REPORT, rdesc, rsize)) < 0) { | |
6500 | + dbg("reading report descriptor failed"); | |
6501 | + kfree(rdesc); | |
6502 | + return NULL; | |
6503 | + } | |
6504 | ||
6505 | #ifdef DEBUG_DATA | |
6506 | - printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); | |
6507 | - for (n = 0; n < rsize; n++) | |
6508 | - printk(" %02x", (unsigned) rdesc[n]); | |
6509 | - printk("\n"); | |
6510 | + printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n); | |
6511 | + for (n = 0; n < rsize; n++) | |
6512 | + printk(" %02x", (unsigned) rdesc[n]); | |
6513 | + printk("\n"); | |
6514 | #endif | |
6515 | ||
6516 | - if (!(hid = hid_parse_report(rdesc, rsize))) { | |
6517 | - dbg("parsing report descriptor failed"); | |
6518 | - return NULL; | |
6519 | - } | |
6520 | + if (!(hid = hid_parse_report(rdesc, rsize))) { | |
6521 | + dbg("parsing report descriptor failed"); | |
6522 | + kfree(rdesc); | |
6523 | + return NULL; | |
6524 | } | |
6525 | ||
6526 | - hid->quirks = quirks; | |
6527 | + kfree(rdesc); | |
6528 | ||
6529 | for (n = 0; n < interface->bNumEndpoints; n++) { | |
6530 | ||
6531 | struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n]; | |
6532 | - int pipe, maxp; | |
6533 | + int pipe; | |
6534 | ||
6535 | if ((endpoint->bmAttributes & 3) != 3) /* Not an interrupt endpoint */ | |
6536 | continue; | |
6537 | ||
6538 | - if (!(endpoint->bEndpointAddress & 0x80)) /* Not an input endpoint */ | |
6539 | - continue; | |
6540 | - | |
6541 | - pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); | |
6542 | - maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe)); | |
6543 | - | |
6544 | - FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval); | |
6545 | - | |
6546 | - break; | |
6547 | + if (endpoint->bEndpointAddress & USB_DIR_IN) { | |
6548 | + if (hid->urbin) | |
6549 | + continue; | |
6550 | + if (!(hid->urbin = usb_alloc_urb(0))) | |
6551 | + goto fail; | |
6552 | + pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress); | |
6553 | + FILL_INT_URB(hid->urbin, dev, pipe, hid->inbuf, 0, hid_irq_in, hid, endpoint->bInterval); | |
6554 | + } else { | |
6555 | + if (hid->urbout) | |
6556 | + continue; | |
6557 | + if (!(hid->urbout = usb_alloc_urb(0))) | |
6558 | + goto fail; | |
6559 | + pipe = usb_sndbulkpipe(dev, endpoint->bEndpointAddress); | |
6560 | + FILL_BULK_URB(hid->urbout, dev, pipe, hid->outbuf, 0, hid_irq_out, hid); | |
6561 | + hid->urbout->transfer_flags |= USB_ASYNC_UNLINK; | |
6562 | + } | |
6563 | } | |
6564 | ||
6565 | - if (n == interface->bNumEndpoints) { | |
6566 | - dbg("couldn't find an input interrupt endpoint"); | |
6567 | - hid_free_device(hid); | |
6568 | - return NULL; | |
6569 | + if (!hid->urbin) { | |
6570 | + err("couldn't find an input interrupt endpoint"); | |
6571 | + goto fail; | |
6572 | } | |
6573 | ||
6574 | + init_waitqueue_head(&hid->wait); | |
6575 | + | |
6576 | + hid->outlock = SPIN_LOCK_UNLOCKED; | |
6577 | + hid->ctrllock = SPIN_LOCK_UNLOCKED; | |
6578 | + | |
6579 | hid->version = hdesc->bcdHID; | |
6580 | hid->country = hdesc->bCountryCode; | |
6581 | hid->dev = dev; | |
6582 | hid->ifnum = interface->bInterfaceNumber; | |
6583 | ||
6584 | - for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) { | |
6585 | - hid->out[n].dr.bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE; | |
6586 | - hid->out[n].dr.bRequest = USB_REQ_SET_REPORT; | |
6587 | - hid->out[n].dr.wIndex = cpu_to_le16(hid->ifnum); | |
6588 | - } | |
6589 | - | |
6590 | hid->name[0] = 0; | |
6591 | ||
6592 | - if (!(buf = kmalloc(63, GFP_KERNEL))) | |
6593 | - return NULL; | |
6594 | + if (!(buf = kmalloc(64, GFP_KERNEL))) | |
6595 | + goto fail; | |
6596 | ||
6597 | - if (usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) { | |
6598 | + if (usb_string(dev, dev->descriptor.iManufacturer, buf, 64) > 0) { | |
6599 | strcat(hid->name, buf); | |
6600 | - if (usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0) | |
6601 | + if (usb_string(dev, dev->descriptor.iProduct, buf, 64) > 0) | |
6602 | sprintf(hid->name, "%s %s", hid->name, buf); | |
6603 | } else | |
6604 | sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct); | |
6605 | ||
6606 | - kfree(buf); | |
6607 | + usb_make_path(dev, buf, 63); | |
6608 | + sprintf(hid->phys, "%s/input%d", buf, ifnum); | |
6609 | ||
6610 | - FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0), | |
6611 | - (void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid); | |
6612 | + if (usb_string(dev, dev->descriptor.iSerialNumber, hid->uniq, 64) <= 0) | |
6613 | + hid->uniq[0] = 0; | |
6614 | ||
6615 | -/* | |
6616 | - * Some devices don't like this and crash. I don't know of any devices | |
6617 | - * needing this, so it is disabled for now. | |
6618 | - */ | |
6619 | + kfree(buf); | |
6620 | ||
6621 | -#if 0 | |
6622 | - if (interface->bInterfaceSubClass == 1) | |
6623 | - usb_set_protocol(dev, hid->ifnum, 1); | |
6624 | -#endif | |
6625 | + hid->urbctrl = usb_alloc_urb(0); | |
6626 | + FILL_CONTROL_URB(hid->urbctrl, dev, 0, (void*) &hid->dr, hid->ctrlbuf, 1, hid_ctrl, hid); | |
6627 | + hid->urbctrl->transfer_flags |= USB_ASYNC_UNLINK; | |
6628 | ||
6629 | return hid; | |
6630 | + | |
6631 | +fail: | |
6632 | + hid_free_device(hid); | |
6633 | + if (hid->urbin) usb_free_urb(hid->urbin); | |
6634 | + if (hid->urbout) usb_free_urb(hid->urbout); | |
6635 | + if (hid->urbctrl) usb_free_urb(hid->urbctrl); | |
6636 | + | |
6637 | + return NULL; | |
6638 | } | |
6639 | ||
6640 | static void* hid_probe(struct usb_device *dev, unsigned int ifnum, | |
6641 | const struct usb_device_id *id) | |
6642 | { | |
6643 | struct hid_device *hid; | |
6644 | + char path[64]; | |
6645 | int i; | |
6646 | char *c; | |
6647 | ||
6648 | dbg("HID probe called for ifnum %d", ifnum); | |
6649 | ||
6650 | - if (!(hid = usb_hid_configure(dev, ifnum))) | |
6651 | + if (!(hid = usb_hid_configure(dev, ifnum))) { | |
6652 | + err("usb_hid_configure failed"); | |
6653 | return NULL; | |
6654 | + } | |
6655 | ||
6656 | hid_init_reports(hid); | |
6657 | hid_dump_device(hid); | |
6658 | ||
6659 | +#ifdef CONFIG_HID_FF | |
6660 | + switch (hid_ff_init(hid)) { | |
6661 | + case 0: | |
6662 | + break; | |
6663 | + | |
6664 | + case -ENOSYS: | |
6665 | + info("No force feedback support for this hid device"); | |
6666 | + break; | |
6667 | + | |
6668 | + default: | |
6669 | + err("hid_ff_init failed"); | |
6670 | + hid_free_device(hid); | |
6671 | + return NULL; | |
6672 | + } | |
6673 | +#endif | |
6674 | + | |
6675 | if (!hidinput_connect(hid)) | |
6676 | hid->claimed |= HID_CLAIMED_INPUT; | |
6677 | +#ifdef CONFIG_USB_HIDDEV | |
6678 | if (!hiddev_connect(hid)) | |
6679 | hid->claimed |= HID_CLAIMED_HIDDEV; | |
6680 | +#endif | |
6681 | + | |
6682 | + if (!hid->claimed) { | |
6683 | + hid_free_device(hid); | |
6684 | + return NULL; | |
6685 | + } | |
6686 | + | |
6687 | printk(KERN_INFO); | |
6688 | ||
6689 | if (hid->claimed & HID_CLAIMED_INPUT) | |
6690 | - printk("input%d", hid->input.number); | |
6691 | + printk("input"); | |
6692 | if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV)) | |
6693 | printk(","); | |
6694 | if (hid->claimed & HID_CLAIMED_HIDDEV) | |
6695 | @@ -1280,9 +1466,10 @@ | |
6696 | break; | |
6697 | } | |
6698 | ||
6699 | - printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n", | |
6700 | - hid->version >> 8, hid->version & 0xff, c, hid->name, | |
6701 | - dev->bus->busnum, dev->devnum, ifnum); | |
6702 | + usb_make_path(dev, path, 63); | |
6703 | + | |
6704 | + printk(": USB HID v%x.%02x %s [%s] on %s\n", | |
6705 | + hid->version >> 8, hid->version & 0xff, c, hid->name, path); | |
6706 | ||
6707 | return hid; | |
6708 | } | |
6709 | @@ -1291,12 +1478,22 @@ | |
6710 | { | |
6711 | struct hid_device *hid = ptr; | |
6712 | ||
6713 | - dbg("cleanup called"); | |
6714 | - usb_unlink_urb(&hid->urb); | |
6715 | + usb_unlink_urb(hid->urbin); | |
6716 | + usb_unlink_urb(hid->urbout); | |
6717 | + usb_unlink_urb(hid->urbctrl); | |
6718 | + | |
6719 | if (hid->claimed & HID_CLAIMED_INPUT) | |
6720 | hidinput_disconnect(hid); | |
6721 | +#ifdef CONFIG_USB_HIDDEV | |
6722 | if (hid->claimed & HID_CLAIMED_HIDDEV) | |
6723 | hiddev_disconnect(hid); | |
6724 | +#endif | |
6725 | + | |
6726 | + usb_free_urb(hid->urbin); | |
6727 | + usb_free_urb(hid->urbctrl); | |
6728 | + if (hid->urbout) | |
6729 | + usb_free_urb(hid->urbout); | |
6730 | + | |
6731 | hid_free_device(hid); | |
6732 | } | |
6733 | ||
6734 | @@ -1317,23 +1514,26 @@ | |
6735 | ||
6736 | static int __init hid_init(void) | |
6737 | { | |
6738 | +#ifdef CONFIG_USB_HIDDEV | |
6739 | hiddev_init(); | |
6740 | +#endif | |
6741 | usb_register(&hid_driver); | |
6742 | - info(DRIVER_VERSION " " DRIVER_AUTHOR); | |
6743 | - info(DRIVER_DESC); | |
6744 | + info(DRIVER_VERSION ":" DRIVER_DESC); | |
6745 | ||
6746 | return 0; | |
6747 | } | |
6748 | ||
6749 | static void __exit hid_exit(void) | |
6750 | { | |
6751 | +#ifdef CONFIG_USB_HIDDEV | |
6752 | hiddev_exit(); | |
6753 | +#endif | |
6754 | usb_deregister(&hid_driver); | |
6755 | } | |
6756 | ||
6757 | module_init(hid_init); | |
6758 | module_exit(hid_exit); | |
6759 | ||
6760 | -MODULE_AUTHOR( DRIVER_AUTHOR ); | |
6761 | -MODULE_DESCRIPTION( DRIVER_DESC ); | |
6762 | -MODULE_LICENSE("GPL"); | |
6763 | +MODULE_AUTHOR(DRIVER_AUTHOR); | |
6764 | +MODULE_DESCRIPTION(DRIVER_DESC); | |
6765 | +MODULE_LICENSE(DRIVER_LICENSE); | |
6766 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/hid-debug.h linux-modified/drivers/usb/hid-debug.h | |
6767 | --- linux-vanilla/drivers/usb/hid-debug.h Thu Sep 13 00:34:06 2001 | |
6768 | +++ linux-modified/drivers/usb/hid-debug.h Mon Jan 6 16:48:21 2003 | |
6769 | @@ -1,12 +1,10 @@ | |
6770 | /* | |
6771 | - * $Id$ | |
6772 | + * $Id$ | |
6773 | * | |
6774 | * (c) 1999 Andreas Gal <gal@cs.uni-magdeburg.de> | |
6775 | - * (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz> | |
6776 | + * (c) 2000-2001 Vojtech Pavlik <vojtech@ucw.cz> | |
6777 | * | |
6778 | * Some debug stuff for the HID parser. | |
6779 | - * | |
6780 | - * Sponsored by SuSE | |
6781 | */ | |
6782 | ||
6783 | /* | |
6784 | @@ -25,8 +23,8 @@ | |
6785 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
6786 | * | |
6787 | * Should you need to contact me, the author, you can do so either by | |
6788 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
6789 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
6790 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
6791 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
6792 | */ | |
6793 | ||
6794 | struct hid_usage_entry { | |
6795 | @@ -36,6 +34,7 @@ | |
6796 | }; | |
6797 | ||
6798 | static struct hid_usage_entry hid_usage_table[] = { | |
6799 | + { 0, 0, "Undefined" }, | |
6800 | { 1, 0, "GenericDesktop" }, | |
6801 | {0, 0x01, "Pointer"}, | |
6802 | {0, 0x02, "Mouse"}, | |
6803 | @@ -87,6 +86,7 @@ | |
6804 | { 7, 0, "Keyboard" }, | |
6805 | { 8, 0, "LED" }, | |
6806 | { 9, 0, "Button" }, | |
6807 | + { 10, 0, "Ordinal" }, | |
6808 | { 12, 0, "Hotkey" }, | |
6809 | { 13, 0, "Digitizers" }, | |
6810 | {0, 0x01, "Digitizer"}, | |
6811 | @@ -112,6 +112,112 @@ | |
6812 | {0, 0x45, "Eraser"}, | |
6813 | {0, 0x46, "TabletPick"}, | |
6814 | { 15, 0, "PhysicalInterfaceDevice" }, | |
6815 | + {0, 0x00, "Undefined"}, | |
6816 | + {0, 0x01, "Physical_Interface_Device"}, | |
6817 | + {0, 0x20, "Normal"}, | |
6818 | + {0, 0x21, "Set_Effect_Report"}, | |
6819 | + {0, 0x22, "Effect_Block_Index"}, | |
6820 | + {0, 0x23, "Parameter_Block_Offset"}, | |
6821 | + {0, 0x24, "ROM_Flag"}, | |
6822 | + {0, 0x25, "Effect_Type"}, | |
6823 | + {0, 0x26, "ET_Constant_Force"}, | |
6824 | + {0, 0x27, "ET_Ramp"}, | |
6825 | + {0, 0x28, "ET_Custom_Force_Data"}, | |
6826 | + {0, 0x30, "ET_Square"}, | |
6827 | + {0, 0x31, "ET_Sine"}, | |
6828 | + {0, 0x32, "ET_Triangle"}, | |
6829 | + {0, 0x33, "ET_Sawtooth_Up"}, | |
6830 | + {0, 0x34, "ET_Sawtooth_Down"}, | |
6831 | + {0, 0x40, "ET_Spring"}, | |
6832 | + {0, 0x41, "ET_Damper"}, | |
6833 | + {0, 0x42, "ET_Inertia"}, | |
6834 | + {0, 0x43, "ET_Friction"}, | |
6835 | + {0, 0x50, "Duration"}, | |
6836 | + {0, 0x51, "Sample_Period"}, | |
6837 | + {0, 0x52, "Gain"}, | |
6838 | + {0, 0x53, "Trigger_Button"}, | |
6839 | + {0, 0x54, "Trigger_Repeat_Interval"}, | |
6840 | + {0, 0x55, "Axes_Enable"}, | |
6841 | + {0, 0x56, "Direction_Enable"}, | |
6842 | + {0, 0x57, "Direction"}, | |
6843 | + {0, 0x58, "Type_Specific_Block_Offset"}, | |
6844 | + {0, 0x59, "Block_Type"}, | |
6845 | + {0, 0x5A, "Set_Envelope_Report"}, | |
6846 | + {0, 0x5B, "Attack_Level"}, | |
6847 | + {0, 0x5C, "Attack_Time"}, | |
6848 | + {0, 0x5D, "Fade_Level"}, | |
6849 | + {0, 0x5E, "Fade_Time"}, | |
6850 | + {0, 0x5F, "Set_Condition_Report"}, | |
6851 | + {0, 0x60, "CP_Offset"}, | |
6852 | + {0, 0x61, "Positive_Coefficient"}, | |
6853 | + {0, 0x62, "Negative_Coefficient"}, | |
6854 | + {0, 0x63, "Positive_Saturation"}, | |
6855 | + {0, 0x64, "Negative_Saturation"}, | |
6856 | + {0, 0x65, "Dead_Band"}, | |
6857 | + {0, 0x66, "Download_Force_Sample"}, | |
6858 | + {0, 0x67, "Isoch_Custom_Force_Enable"}, | |
6859 | + {0, 0x68, "Custom_Force_Data_Report"}, | |
6860 | + {0, 0x69, "Custom_Force_Data"}, | |
6861 | + {0, 0x6A, "Custom_Force_Vendor_Defined_Data"}, | |
6862 | + {0, 0x6B, "Set_Custom_Force_Report"}, | |
6863 | + {0, 0x6C, "Custom_Force_Data_Offset"}, | |
6864 | + {0, 0x6D, "Sample_Count"}, | |
6865 | + {0, 0x6E, "Set_Periodic_Report"}, | |
6866 | + {0, 0x6F, "Offset"}, | |
6867 | + {0, 0x70, "Magnitude"}, | |
6868 | + {0, 0x71, "Phase"}, | |
6869 | + {0, 0x72, "Period"}, | |
6870 | + {0, 0x73, "Set_Constant_Force_Report"}, | |
6871 | + {0, 0x74, "Set_Ramp_Force_Report"}, | |
6872 | + {0, 0x75, "Ramp_Start"}, | |
6873 | + {0, 0x76, "Ramp_End"}, | |
6874 | + {0, 0x77, "Effect_Operation_Report"}, | |
6875 | + {0, 0x78, "Effect_Operation"}, | |
6876 | + {0, 0x79, "Op_Effect_Start"}, | |
6877 | + {0, 0x7A, "Op_Effect_Start_Solo"}, | |
6878 | + {0, 0x7B, "Op_Effect_Stop"}, | |
6879 | + {0, 0x7C, "Loop_Count"}, | |
6880 | + {0, 0x7D, "Device_Gain_Report"}, | |
6881 | + {0, 0x7E, "Device_Gain"}, | |
6882 | + {0, 0x7F, "PID_Pool_Report"}, | |
6883 | + {0, 0x80, "RAM_Pool_Size"}, | |
6884 | + {0, 0x81, "ROM_Pool_Size"}, | |
6885 | + {0, 0x82, "ROM_Effect_Block_Count"}, | |
6886 | + {0, 0x83, "Simultaneous_Effects_Max"}, | |
6887 | + {0, 0x84, "Pool_Alignment"}, | |
6888 | + {0, 0x85, "PID_Pool_Move_Report"}, | |
6889 | + {0, 0x86, "Move_Source"}, | |
6890 | + {0, 0x87, "Move_Destination"}, | |
6891 | + {0, 0x88, "Move_Length"}, | |
6892 | + {0, 0x89, "PID_Block_Load_Report"}, | |
6893 | + {0, 0x8B, "Block_Load_Status"}, | |
6894 | + {0, 0x8C, "Block_Load_Success"}, | |
6895 | + {0, 0x8D, "Block_Load_Full"}, | |
6896 | + {0, 0x8E, "Block_Load_Error"}, | |
6897 | + {0, 0x8F, "Block_Handle"}, | |
6898 | + {0, 0x90, "PID_Block_Free_Report"}, | |
6899 | + {0, 0x91, "Type_Specific_Block_Handle"}, | |
6900 | + {0, 0x92, "PID_State_Report"}, | |
6901 | + {0, 0x94, "Effect_Playing"}, | |
6902 | + {0, 0x95, "PID_Device_Control_Report"}, | |
6903 | + {0, 0x96, "PID_Device_Control"}, | |
6904 | + {0, 0x97, "DC_Enable_Actuators"}, | |
6905 | + {0, 0x98, "DC_Disable_Actuators"}, | |
6906 | + {0, 0x99, "DC_Stop_All_Effects"}, | |
6907 | + {0, 0x9A, "DC_Device_Reset"}, | |
6908 | + {0, 0x9B, "DC_Device_Pause"}, | |
6909 | + {0, 0x9C, "DC_Device_Continue"}, | |
6910 | + {0, 0x9F, "Device_Paused"}, | |
6911 | + {0, 0xA0, "Actuators_Enabled"}, | |
6912 | + {0, 0xA4, "Safety_Switch"}, | |
6913 | + {0, 0xA5, "Actuator_Override_Switch"}, | |
6914 | + {0, 0xA6, "Actuator_Power"}, | |
6915 | + {0, 0xA7, "Start_Delay"}, | |
6916 | + {0, 0xA8, "Parameter_Block_Size"}, | |
6917 | + {0, 0xA9, "Device_Managed_Pool"}, | |
6918 | + {0, 0xAA, "Shared_Parameter_Blocks"}, | |
6919 | + {0, 0xAB, "Create_New_Effect_Report"}, | |
6920 | + {0, 0xAC, "RAM_Pool_Available"}, | |
6921 | { 0, 0, NULL } | |
6922 | }; | |
6923 | ||
6924 | @@ -176,7 +282,50 @@ | |
6925 | tab(n); printk("Unit Exponent(%d)\n", field->unit_exponent); | |
6926 | } | |
6927 | if (field->unit) { | |
6928 | - tab(n); printk("Unit(%u)\n", field->unit); | |
6929 | + char *systems[5] = { "None", "SI Linear", "SI Rotation", "English Linear", "English Rotation" }; | |
6930 | + char *units[5][8] = { | |
6931 | + { "None", "None", "None", "None", "None", "None", "None", "None" }, | |
6932 | + { "None", "Centimeter", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, | |
6933 | + { "None", "Radians", "Gram", "Seconds", "Kelvin", "Ampere", "Candela", "None" }, | |
6934 | + { "None", "Inch", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" }, | |
6935 | + { "None", "Degrees", "Slug", "Seconds", "Fahrenheit", "Ampere", "Candela", "None" } | |
6936 | + }; | |
6937 | + | |
6938 | + int i; | |
6939 | + int sys; | |
6940 | + __u32 data = field->unit; | |
6941 | + | |
6942 | + /* First nibble tells us which system we're in. */ | |
6943 | + sys = data & 0xf; | |
6944 | + data >>= 4; | |
6945 | + | |
6946 | + if(sys > 4) { | |
6947 | + tab(n); printk("Unit(Invalid)\n"); | |
6948 | + } | |
6949 | + else { | |
6950 | + int earlier_unit = 0; | |
6951 | + | |
6952 | + tab(n); printk("Unit(%s : ", systems[sys]); | |
6953 | + | |
6954 | + for (i=1 ; i<sizeof(__u32)*2 ; i++) { | |
6955 | + char nibble = data & 0xf; | |
6956 | + data >>= 4; | |
6957 | + if (nibble != 0) { | |
6958 | + if(earlier_unit++ > 0) | |
6959 | + printk("*"); | |
6960 | + printk("%s", units[sys][i]); | |
6961 | + if(nibble != 1) { | |
6962 | + /* This is a _signed_ nibble(!) */ | |
6963 | + | |
6964 | + int val = nibble & 0x7; | |
6965 | + if(nibble & 0x08) | |
6966 | + val = -((0x7 & ~val) +1); | |
6967 | + printk("^%d", val); | |
6968 | + } | |
6969 | + } | |
6970 | + } | |
6971 | + printk(")\n"); | |
6972 | + } | |
6973 | } | |
6974 | tab(n); printk("Report Size(%u)\n", field->report_size); | |
6975 | tab(n); printk("Report Count(%u)\n", field->report_count); | |
6976 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/hid-ff.c linux-modified/drivers/usb/hid-ff.c | |
6977 | --- linux-vanilla/drivers/usb/hid-ff.c Thu Jan 1 02:00:00 1970 | |
6978 | +++ linux-modified/drivers/usb/hid-ff.c Mon Jan 6 16:48:21 2003 | |
6979 | @@ -0,0 +1,69 @@ | |
6980 | +/* | |
6981 | + * Force feedback support for hid devices. | |
6982 | + * Not all hid devices use the same protocol. For example, some use PID, | |
6983 | + * other use their own proprietary procotol. | |
6984 | + * | |
6985 | + * Copyright (c) 2002 Johann Deneux | |
6986 | + */ | |
6987 | + | |
6988 | +/* | |
6989 | + * This program is free software; you can redistribute it and/or modify | |
6990 | + * it under the terms of the GNU General Public License as published by | |
6991 | + * the Free Software Foundation; either version 2 of the License, or | |
6992 | + * (at your option) any later version. | |
6993 | + * | |
6994 | + * This program is distributed in the hope that it will be useful, | |
6995 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
6996 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
6997 | + * GNU General Public License for more details. | |
6998 | + * | |
6999 | + * You should have received a copy of the GNU General Public License | |
7000 | + * along with this program; if not, write to the Free Software | |
7001 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
7002 | + * | |
7003 | + * Should you need to contact me, the author, you can do so by | |
7004 | + * e-mail - mail your message to <deneux@ifrance.com> | |
7005 | + */ | |
7006 | + | |
7007 | +#include <linux/input.h> | |
7008 | + | |
7009 | +#define DEBUG | |
7010 | +#include <linux/usb.h> | |
7011 | + | |
7012 | +#include "hid.h" | |
7013 | + | |
7014 | +/* Drivers' initializing functions */ | |
7015 | +extern int hid_lgff_init(struct hid_device* hid); | |
7016 | +extern int hid_pid_init(struct hid_device* hid); | |
7017 | + | |
7018 | +/* Each hid force feedback driver must provide an init function. | |
7019 | + It must return 1 if the driver does not handle this device, | |
7020 | + 0 if it could and the initialization itself went smoothly, | |
7021 | + <0 if the driver should have been able to handle the device, but failed | |
7022 | +*/ | |
7023 | +static int (*inits[])(struct hid_device*) = { | |
7024 | +#ifdef CONFIG_LOGITECH_FF | |
7025 | + hid_lgff_init, | |
7026 | +#endif | |
7027 | +#ifdef CONFIG_HID_PID | |
7028 | + hid_pid_init, | |
7029 | +#endif | |
7030 | + NULL | |
7031 | +}; | |
7032 | + | |
7033 | +int hid_ff_init(struct hid_device* hid) | |
7034 | +{ | |
7035 | + int i; | |
7036 | + int status; | |
7037 | + | |
7038 | + for (i=0; inits[i]; ++i) { | |
7039 | + switch (status = inits[i](hid)) { | |
7040 | + case 0: return 0; // Device handled and init ok | |
7041 | + case 1: break; // Device not handled | |
7042 | + default: return status; // Device handled, init failed | |
7043 | + } | |
7044 | + } | |
7045 | + | |
7046 | + dbg("hid_ff_init could not find initializer"); | |
7047 | + return -ENOSYS; | |
7048 | +} | |
7049 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/hid-input.c linux-modified/drivers/usb/hid-input.c | |
7050 | --- linux-vanilla/drivers/usb/hid-input.c Sun Nov 11 20:09:37 2001 | |
7051 | +++ linux-modified/drivers/usb/hid-input.c Mon Jan 6 16:48:21 2003 | |
7052 | @@ -1,11 +1,9 @@ | |
7053 | /* | |
7054 | - * $Id$ | |
7055 | + * $Id$ | |
7056 | * | |
7057 | * Copyright (c) 2000-2001 Vojtech Pavlik | |
7058 | * | |
7059 | - * USB HID to Linux Input mapping module | |
7060 | - * | |
7061 | - * Sponsored by SuSE | |
7062 | + * USB HID to Linux Input mapping | |
7063 | */ | |
7064 | ||
7065 | /* | |
7066 | @@ -24,13 +22,12 @@ | |
7067 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
7068 | * | |
7069 | * Should you need to contact me, the author, you can do so either by | |
7070 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
7071 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
7072 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
7073 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
7074 | */ | |
7075 | ||
7076 | #include <linux/module.h> | |
7077 | #include <linux/slab.h> | |
7078 | -#include <linux/init.h> | |
7079 | #include <linux/kernel.h> | |
7080 | #include <linux/input.h> | |
7081 | #include <linux/usb.h> | |
7082 | @@ -61,12 +58,13 @@ | |
7083 | static struct { | |
7084 | __s32 x; | |
7085 | __s32 y; | |
7086 | -} hid_hat_to_axis[] = {{0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | |
7087 | +} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; | |
7088 | ||
7089 | static void hidinput_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage) | |
7090 | { | |
7091 | struct input_dev *input = &device->input; | |
7092 | int max; | |
7093 | + int is_abs = 0; | |
7094 | unsigned long *bit; | |
7095 | ||
7096 | switch (usage->hid & HID_USAGE_PAGE) { | |
7097 | @@ -198,6 +196,7 @@ | |
7098 | ||
7099 | case HID_UP_CONSUMER: /* USB HUT v1.1, pages 56-62 */ | |
7100 | ||
7101 | + set_bit(EV_REP, input->evbit); | |
7102 | switch (usage->hid & HID_USAGE) { | |
7103 | case 0x000: usage->code = 0; break; | |
7104 | case 0x034: usage->code = KEY_SLEEP; break; | |
7105 | @@ -205,14 +204,21 @@ | |
7106 | case 0x08a: usage->code = KEY_WWW; break; | |
7107 | case 0x095: usage->code = KEY_HELP; break; | |
7108 | ||
7109 | + case 0x0b0: usage->code = KEY_PLAY; break; | |
7110 | + case 0x0b1: usage->code = KEY_PAUSE; break; | |
7111 | + case 0x0b2: usage->code = KEY_RECORD; break; | |
7112 | + case 0x0b3: usage->code = KEY_FASTFORWARD; break; | |
7113 | case 0x0b4: usage->code = KEY_REWIND; break; | |
7114 | case 0x0b5: usage->code = KEY_NEXTSONG; break; | |
7115 | case 0x0b6: usage->code = KEY_PREVIOUSSONG; break; | |
7116 | case 0x0b7: usage->code = KEY_STOPCD; break; | |
7117 | case 0x0b8: usage->code = KEY_EJECTCD; break; | |
7118 | case 0x0cd: usage->code = KEY_PLAYPAUSE; break; | |
7119 | - | |
7120 | + case 0x0e0: is_abs = 1; | |
7121 | + usage->code = ABS_VOLUME; | |
7122 | + break; | |
7123 | case 0x0e2: usage->code = KEY_MUTE; break; | |
7124 | + case 0x0e5: usage->code = KEY_BASSBOOST; break; | |
7125 | case 0x0e9: usage->code = KEY_VOLUMEUP; break; | |
7126 | case 0x0ea: usage->code = KEY_VOLUMEDOWN; break; | |
7127 | ||
7128 | @@ -220,7 +226,6 @@ | |
7129 | case 0x18a: usage->code = KEY_MAIL; break; | |
7130 | case 0x192: usage->code = KEY_CALC; break; | |
7131 | case 0x194: usage->code = KEY_FILE; break; | |
7132 | - | |
7133 | case 0x21a: usage->code = KEY_UNDO; break; | |
7134 | case 0x21b: usage->code = KEY_COPY; break; | |
7135 | case 0x21c: usage->code = KEY_CUT; break; | |
7136 | @@ -235,6 +240,34 @@ | |
7137 | case 0x22a: usage->code = KEY_BOOKMARKS; break; | |
7138 | ||
7139 | default: usage->code = KEY_UNKNOWN; break; | |
7140 | + } | |
7141 | + | |
7142 | + if (is_abs) { | |
7143 | + usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; | |
7144 | + } else { | |
7145 | + usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX; | |
7146 | + } | |
7147 | + break; | |
7148 | + | |
7149 | + case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */ | |
7150 | + | |
7151 | + set_bit(EV_REP, input->evbit); | |
7152 | + switch (usage->hid & HID_USAGE) { | |
7153 | + case 0x021: usage->code = KEY_PRINT; break; | |
7154 | + case 0x070: usage->code = KEY_HP; break; | |
7155 | + case 0x071: usage->code = KEY_CAMERA; break; | |
7156 | + case 0x072: usage->code = KEY_SOUND; break; | |
7157 | + case 0x073: usage->code = KEY_QUESTION; break; | |
7158 | + | |
7159 | + case 0x080: usage->code = KEY_EMAIL; break; | |
7160 | + case 0x081: usage->code = KEY_CHAT; break; | |
7161 | + case 0x082: usage->code = KEY_SEARCH; break; | |
7162 | + case 0x083: usage->code = KEY_CONNECT; break; | |
7163 | + case 0x084: usage->code = KEY_FINANCE; break; | |
7164 | + case 0x085: usage->code = KEY_SPORT; break; | |
7165 | + case 0x086: usage->code = KEY_SHOP; break; | |
7166 | + | |
7167 | + default: usage->code = KEY_UNKNOWN; break; | |
7168 | ||
7169 | } | |
7170 | ||
7171 | @@ -344,16 +377,28 @@ | |
7172 | static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) | |
7173 | { | |
7174 | struct hid_device *hid = dev->private; | |
7175 | - struct hid_field *field = NULL; | |
7176 | - int offset; | |
7177 | ||
7178 | - if ((offset = hid_find_field(hid, type, code, &field)) == -1) { | |
7179 | - warn("event field not found"); | |
7180 | - return -1; | |
7181 | + warn("hid input event"); | |
7182 | + | |
7183 | +#ifdef CONFIG_HID_FF | |
7184 | + if (type == EV_FF) { | |
7185 | + return hid_ff_event(hid, dev, type, code, value); | |
7186 | } | |
7187 | +#else | |
7188 | + if (0) {} | |
7189 | +#endif | |
7190 | + else { | |
7191 | + struct hid_field *field = NULL; | |
7192 | + int offset; | |
7193 | + | |
7194 | + if ((offset = hid_find_field(hid, type, code, &field)) == -1) { | |
7195 | + warn("event field not found"); | |
7196 | + return -1; | |
7197 | + } | |
7198 | ||
7199 | - hid_set_field(field, offset, value); | |
7200 | - hid_write_report(hid, field->report); | |
7201 | + hid_set_field(field, offset, value); | |
7202 | + hid_submit_report(hid, field->report, USB_DIR_OUT); | |
7203 | + } | |
7204 | ||
7205 | return 0; | |
7206 | } | |
7207 | @@ -361,12 +406,22 @@ | |
7208 | static int hidinput_open(struct input_dev *dev) | |
7209 | { | |
7210 | struct hid_device *hid = dev->private; | |
7211 | +/* | |
7212 | +#ifdef CONFIG_HID_FF | |
7213 | + hid_ff_open(hid); | |
7214 | +#endif | |
7215 | +*/ | |
7216 | return hid_open(hid); | |
7217 | } | |
7218 | ||
7219 | static void hidinput_close(struct input_dev *dev) | |
7220 | { | |
7221 | struct hid_device *hid = dev->private; | |
7222 | +/* | |
7223 | +#ifdef CONFIG_HID_FF | |
7224 | + hid_ff_close(hid); | |
7225 | +#endif | |
7226 | +*/ | |
7227 | hid_close(hid); | |
7228 | } | |
7229 | ||
7230 | @@ -395,8 +450,9 @@ | |
7231 | hid->input.event = hidinput_input_event; | |
7232 | hid->input.open = hidinput_open; | |
7233 | hid->input.close = hidinput_close; | |
7234 | - | |
7235 | hid->input.name = hid->name; | |
7236 | + hid->input.phys = hid->phys; | |
7237 | + hid->input.uniq = hid->uniq; | |
7238 | hid->input.idbus = BUS_USB; | |
7239 | hid->input.idvendor = dev->descriptor.idVendor; | |
7240 | hid->input.idproduct = dev->descriptor.idProduct; | |
7241 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/hid-lgff.c linux-modified/drivers/usb/hid-lgff.c | |
7242 | --- linux-vanilla/drivers/usb/hid-lgff.c Thu Jan 1 02:00:00 1970 | |
7243 | +++ linux-modified/drivers/usb/hid-lgff.c Sun Mar 9 18:03:20 2003 | |
7244 | @@ -0,0 +1,588 @@ | |
7245 | +/* | |
7246 | + * Force feedback support for hid-compliant for some of the devices from | |
7247 | + * Logitech, namely: | |
7248 | + * - WingMan Cordless RumblePad | |
7249 | + * - WingMan Force 3D | |
7250 | + * - WingMan Strike Force 3D | |
7251 | + * Other possibly supported devices: | |
7252 | + * Apparently *not* supported: | |
7253 | + * - WingMan Formula Force GP | |
7254 | + * - WingMan RumblePad (ie the non-cordless one) | |
7255 | + * | |
7256 | + * Copyright (c) 2002 Johann Deneux | |
7257 | + */ | |
7258 | + | |
7259 | +/* | |
7260 | + * This program is free software; you can redistribute it and/or modify | |
7261 | + * it under the terms of the GNU General Public License as published by | |
7262 | + * the Free Software Foundation; either version 2 of the License, or | |
7263 | + * (at your option) any later version. | |
7264 | + * | |
7265 | + * This program is distributed in the hope that it will be useful, | |
7266 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
7267 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
7268 | + * GNU General Public License for more details. | |
7269 | + * | |
7270 | + * You should have received a copy of the GNU General Public License | |
7271 | + * along with this program; if not, write to the Free Software | |
7272 | + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
7273 | + * | |
7274 | + * Should you need to contact me, the author, you can do so by | |
7275 | + * e-mail - mail your message to <deneux@ifrance.com> | |
7276 | + */ | |
7277 | + | |
7278 | +/* TODO: | |
7279 | + Support periodic, custom and condition effects. | |
7280 | + Support gain setting + default spring. | |
7281 | +*/ | |
7282 | + | |
7283 | +#include <linux/input.h> | |
7284 | +#include <linux/sched.h> | |
7285 | + | |
7286 | +#define DEBUG | |
7287 | +#include <linux/usb.h> | |
7288 | + | |
7289 | +#include <linux/circ_buf.h> | |
7290 | + | |
7291 | +#include "hid.h" | |
7292 | +#include "fixp-arith.h" | |
7293 | + | |
7294 | + | |
7295 | +/* Periodicity of the update */ | |
7296 | +#define PERIOD (HZ/10) | |
7297 | + | |
7298 | +#define RUN_AT(t) (jiffies + (t)) | |
7299 | + | |
7300 | +/* Effect status */ | |
7301 | +#define EFFECT_STARTED 0 /* Effect is going to play after some time | |
7302 | + (ff_replay.delay) */ | |
7303 | +#define EFFECT_PLAYING 1 /* Effect is being played */ | |
7304 | +#define EFFECT_USED 2 | |
7305 | + | |
7306 | +// For lgff_device::flags | |
7307 | +#define DEVICE_CLOSING 0 /* The driver is being unitialised */ | |
7308 | + | |
7309 | +#define LGFF_EFFECTS 8 | |
7310 | + | |
7311 | +struct device_type { | |
7312 | + u16 idVendor; | |
7313 | + u16 idProduct; | |
7314 | + signed short *ff; | |
7315 | +}; | |
7316 | + | |
7317 | +struct lgff_effect { | |
7318 | + pid_t owner; | |
7319 | + | |
7320 | + struct ff_effect effect; | |
7321 | + | |
7322 | + unsigned long flags[1]; | |
7323 | + unsigned int count; /* Number of times left to play */ | |
7324 | + unsigned long started_at; /* When the effect started to play */ | |
7325 | +}; | |
7326 | + | |
7327 | +struct lgff_device { | |
7328 | + struct hid_device* hid; | |
7329 | + | |
7330 | + struct hid_report* constant; | |
7331 | + struct hid_report* rumble; | |
7332 | + struct hid_report* condition; | |
7333 | + | |
7334 | + struct lgff_effect effects[LGFF_EFFECTS]; | |
7335 | + spinlock_t lock; /* device-level lock. Having locks on | |
7336 | + a per-effect basis could be nice, but | |
7337 | + isn't really necessary */ | |
7338 | + | |
7339 | + unsigned long flags[1]; /* Contains various information about the | |
7340 | + state of the driver for this device */ | |
7341 | + | |
7342 | + struct timer_list timer; | |
7343 | +}; | |
7344 | + | |
7345 | +/* Callbacks */ | |
7346 | +static void hid_lgff_exit(struct hid_device* hid); | |
7347 | +static int hid_lgff_event(struct hid_device *hid, struct input_dev *input, | |
7348 | + unsigned int type, unsigned int code, int value); | |
7349 | +static int hid_lgff_flush(struct input_dev *input, struct file *file); | |
7350 | +static int hid_lgff_upload_effect(struct input_dev *input, | |
7351 | + struct ff_effect *effect); | |
7352 | +static int hid_lgff_erase(struct input_dev *input, int id); | |
7353 | + | |
7354 | +/* Local functions */ | |
7355 | +static void hid_lgff_input_init(struct hid_device* hid); | |
7356 | +static void hid_lgff_timer(unsigned long timer_data); | |
7357 | +static struct hid_report* hid_lgff_duplicate_report(struct hid_report*); | |
7358 | +static void hid_lgff_delete_report(struct hid_report*); | |
7359 | + | |
7360 | +static signed short ff_rumble[] = { | |
7361 | + FF_RUMBLE, | |
7362 | + -1 | |
7363 | +}; | |
7364 | + | |
7365 | +static signed short ff_joystick[] = { | |
7366 | + FF_CONSTANT, | |
7367 | + ABS_X, | |
7368 | + ABS_Y, | |
7369 | + -1 | |
7370 | +}; | |
7371 | + | |
7372 | +static struct device_type devices[] = { | |
7373 | + {0x046d, 0xc211, ff_rumble}, | |
7374 | + {0x046d, 0xc283, ff_joystick}, | |
7375 | + {0x046d, 0xc285, ff_joystick}, | |
7376 | + {0x0000, 0x0000, ff_joystick} | |
7377 | +}; | |
7378 | + | |
7379 | +int hid_lgff_init(struct hid_device* hid) | |
7380 | +{ | |
7381 | + struct lgff_device *private; | |
7382 | + struct hid_report* report; | |
7383 | + struct hid_field* field; | |
7384 | + | |
7385 | + switch (hid->dev->descriptor.idVendor) { | |
7386 | + case 0x46d: // Logitech | |
7387 | + switch (hid->dev->descriptor.idProduct) { | |
7388 | + /* Supported devices */ | |
7389 | + case 0xc211: // Cordless rumblepad | |
7390 | + case 0xc283: // Force 3D | |
7391 | + case 0xc285: // Strike Force 3D | |
7392 | + break; | |
7393 | + /* Unsupported or unknown devices */ | |
7394 | + default: return 1; | |
7395 | + } | |
7396 | + break; | |
7397 | + | |
7398 | + case 0x6a3: // Saitek | |
7399 | + switch (hid->dev->descriptor.idProduct) { | |
7400 | + case 0xff12: // Cyborg 3D Force | |
7401 | + break; | |
7402 | + default: return 1; | |
7403 | + } | |
7404 | + break; | |
7405 | + | |
7406 | + default: return 1; | |
7407 | + } | |
7408 | + | |
7409 | + /* Find the report to use */ | |
7410 | + if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) { | |
7411 | + err("No output report found"); | |
7412 | + return -1; | |
7413 | + } | |
7414 | + /* Check that the report looks ok */ | |
7415 | + report = (struct hid_report*)hid->report_enum[HID_OUTPUT_REPORT].report_list.next; | |
7416 | + if (!report) { | |
7417 | + err("NULL output report"); | |
7418 | + return -1; | |
7419 | + } | |
7420 | + field = report->field[0]; | |
7421 | + if (!field) { | |
7422 | + err("NULL field"); | |
7423 | + return -1; | |
7424 | + } | |
7425 | + | |
7426 | + private = kmalloc(sizeof(struct lgff_device), GFP_KERNEL); | |
7427 | + if (!private) return -1; | |
7428 | + memset(private, 0, sizeof(struct lgff_device)); | |
7429 | + hid->ff_private = private; | |
7430 | + | |
7431 | + /* Input init */ | |
7432 | + hid_lgff_input_init(hid); | |
7433 | + | |
7434 | + | |
7435 | + private->constant = hid_lgff_duplicate_report(report); | |
7436 | + if (!private->constant) { | |
7437 | + kfree(private); | |
7438 | + return -1; | |
7439 | + } | |
7440 | + private->constant->field[0]->value[0] = 0x51; | |
7441 | + private->constant->field[0]->value[1] = 0x08; | |
7442 | + private->constant->field[0]->value[2] = 0x7f; | |
7443 | + private->constant->field[0]->value[3] = 0x7f; | |
7444 | + | |
7445 | + private->rumble = hid_lgff_duplicate_report(report); | |
7446 | + if (!private->rumble) { | |
7447 | + hid_lgff_delete_report(private->constant); | |
7448 | + kfree(private); | |
7449 | + return -1; | |
7450 | + } | |
7451 | + private->rumble->field[0]->value[0] = 0x03; | |
7452 | + private->rumble->field[0]->value[1] = 0x42; | |
7453 | + | |
7454 | + | |
7455 | + private->condition = hid_lgff_duplicate_report(report); | |
7456 | + if (!private->condition) { | |
7457 | + hid_lgff_delete_report(private->rumble); | |
7458 | + hid_lgff_delete_report(private->constant); | |
7459 | + kfree(private); | |
7460 | + return -1; | |
7461 | + } | |
7462 | + | |
7463 | + private->hid = hid; | |
7464 | + | |
7465 | + spin_lock_init(&private->lock); | |
7466 | + init_timer(&private->timer); | |
7467 | + private->timer.data = (unsigned long)private; | |
7468 | + private->timer.function = hid_lgff_timer; | |
7469 | + | |
7470 | + /* Event and exit callbacks */ | |
7471 | + hid->ff_exit = hid_lgff_exit; | |
7472 | + hid->ff_event = hid_lgff_event; | |
7473 | + | |
7474 | + /* Start the update task */ | |
7475 | + private->timer.expires = RUN_AT(PERIOD); | |
7476 | + add_timer(&private->timer); /*TODO: only run the timer when at least | |
7477 | + one effect is playing */ | |
7478 | + | |
7479 | + printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <deneux@ifrance.com>\n"); | |
7480 | + | |
7481 | + return 0; | |
7482 | +} | |
7483 | + | |
7484 | +static struct hid_report* hid_lgff_duplicate_report(struct hid_report* report) | |
7485 | +{ | |
7486 | + struct hid_report* ret; | |
7487 | + | |
7488 | + ret = kmalloc(sizeof(struct lgff_device), GFP_KERNEL); | |
7489 | + if (!ret) return NULL; | |
7490 | + *ret = *report; | |
7491 | + | |
7492 | + ret->field[0] = kmalloc(sizeof(struct hid_field), GFP_KERNEL); | |
7493 | + if (!ret->field[0]) { | |
7494 | + kfree(ret); | |
7495 | + return NULL; | |
7496 | + } | |
7497 | + *ret->field[0] = *report->field[0]; | |
7498 | + | |
7499 | + ret->field[0]->value = kmalloc(sizeof(s32[8]), GFP_KERNEL); | |
7500 | + if (!ret->field[0]->value) { | |
7501 | + kfree(ret->field[0]); | |
7502 | + kfree(ret); | |
7503 | + return NULL; | |
7504 | + } | |
7505 | + memset(ret->field[0]->value, 0, sizeof(s32[8])); | |
7506 | + | |
7507 | + return ret; | |
7508 | +} | |
7509 | + | |
7510 | +static void hid_lgff_delete_report(struct hid_report* report) | |
7511 | +{ | |
7512 | + if (report) { | |
7513 | + kfree(report->field[0]->value); | |
7514 | + kfree(report->field[0]); | |
7515 | + kfree(report); | |
7516 | + } | |
7517 | +} | |
7518 | + | |
7519 | +static void hid_lgff_input_init(struct hid_device* hid) | |
7520 | +{ | |
7521 | + struct device_type* dev = devices; | |
7522 | + signed short* ff; | |
7523 | + u16 idVendor = hid->dev->descriptor.idVendor; | |
7524 | + u16 idProduct = hid->dev->descriptor.idProduct; | |
7525 | + | |
7526 | + while (dev->idVendor && (idVendor != dev->idVendor || idProduct != dev->idProduct)) | |
7527 | + dev++; | |
7528 | + | |
7529 | + ff = dev->ff; | |
7530 | + | |
7531 | + while (*ff >= 0) { | |
7532 | + set_bit(*ff, hid->input.ffbit); | |
7533 | + ++ff; | |
7534 | + } | |
7535 | + | |
7536 | + hid->input.upload_effect = hid_lgff_upload_effect; | |
7537 | + hid->input.flush = hid_lgff_flush; | |
7538 | + | |
7539 | + set_bit(EV_FF, hid->input.evbit); | |
7540 | + hid->input.ff_effects_max = LGFF_EFFECTS; | |
7541 | +} | |
7542 | + | |
7543 | +static void hid_lgff_exit(struct hid_device* hid) | |
7544 | +{ | |
7545 | + struct lgff_device *lgff = hid->ff_private; | |
7546 | + | |
7547 | + set_bit(DEVICE_CLOSING, lgff->flags); | |
7548 | + del_timer_sync(&lgff->timer); | |
7549 | + | |
7550 | + hid_lgff_delete_report(lgff->condition); | |
7551 | + hid_lgff_delete_report(lgff->rumble); | |
7552 | + hid_lgff_delete_report(lgff->constant); | |
7553 | + | |
7554 | + kfree(lgff); | |
7555 | +} | |
7556 | + | |
7557 | +static int hid_lgff_event(struct hid_device *hid, struct input_dev* input, | |
7558 | + unsigned int type, unsigned int code, int value) | |
7559 | +{ | |
7560 | + struct lgff_device *lgff = hid->ff_private; | |
7561 | + struct lgff_effect *effect = lgff->effects + code; | |
7562 | + unsigned long flags; | |
7563 | + | |
7564 | + if (type != EV_FF) return -EINVAL; | |
7565 | + if (value < 0) return -EINVAL; | |
7566 | + | |
7567 | + spin_lock_irqsave(&lgff->lock, flags); | |
7568 | + | |
7569 | + if (value > 0) { | |
7570 | + if (test_bit(EFFECT_STARTED, effect->flags)) { | |
7571 | + spin_unlock_irqrestore(&lgff->lock, flags); | |
7572 | + return -EBUSY; | |
7573 | + } | |
7574 | + if (test_bit(EFFECT_PLAYING, effect->flags)) { | |
7575 | + spin_unlock_irqrestore(&lgff->lock, flags); | |
7576 | + return -EBUSY; | |
7577 | + } | |
7578 | + | |
7579 | + effect->count = value; | |
7580 | + | |
7581 | + if (effect->effect.replay.delay) { | |
7582 | + set_bit(EFFECT_STARTED, effect->flags); | |
7583 | + } else { | |
7584 | + set_bit(EFFECT_PLAYING, effect->flags); | |
7585 | + } | |
7586 | + effect->started_at = jiffies; | |
7587 | + } | |
7588 | + else { /* value == 0 */ | |
7589 | + clear_bit(EFFECT_STARTED, effect->flags); | |
7590 | + clear_bit(EFFECT_PLAYING, effect->flags); | |
7591 | + } | |
7592 | + | |
7593 | + spin_unlock_irqrestore(&lgff->lock, flags); | |
7594 | + | |
7595 | + return 0; | |
7596 | + | |
7597 | +} | |
7598 | + | |
7599 | +/* Erase all effects this process owns */ | |
7600 | +static int hid_lgff_flush(struct input_dev *dev, struct file *file) | |
7601 | +{ | |
7602 | + struct hid_device *hid = dev->private; | |
7603 | + struct lgff_device *lgff = hid->ff_private; | |
7604 | + int i; | |
7605 | + | |
7606 | + for (i=0; i<dev->ff_effects_max; ++i) { | |
7607 | + | |
7608 | + /*NOTE: no need to lock here. The only times EFFECT_USED is | |
7609 | + modified is when effects are uploaded or when an effect is | |
7610 | + erased. But a process cannot close its dev/input/eventX fd | |
7611 | + and perform ioctls on the same fd all at the same time */ | |
7612 | + if ( current->pid == lgff->effects[i].owner | |
7613 | + && test_bit(EFFECT_USED, lgff->effects[i].flags)) { | |
7614 | + | |
7615 | + if (hid_lgff_erase(dev, i)) | |
7616 | + warn("erase effect %d failed", i); | |
7617 | + } | |
7618 | + | |
7619 | + } | |
7620 | + | |
7621 | + return 0; | |
7622 | +} | |
7623 | + | |
7624 | +static int hid_lgff_erase(struct input_dev *dev, int id) | |
7625 | +{ | |
7626 | + struct hid_device *hid = dev->private; | |
7627 | + struct lgff_device *lgff = hid->ff_private; | |
7628 | + unsigned long flags; | |
7629 | + | |
7630 | + spin_lock_irqsave(&lgff->lock, flags); | |
7631 | + lgff->effects[id].flags[0] = 0; | |
7632 | + spin_unlock_irqrestore(&lgff->lock, flags); | |
7633 | + | |
7634 | + return 0; | |
7635 | +} | |
7636 | + | |
7637 | +static int hid_lgff_upload_effect(struct input_dev* input, | |
7638 | + struct ff_effect* effect) | |
7639 | +{ | |
7640 | + struct hid_device *hid = input->private; | |
7641 | + struct lgff_device *lgff = hid->ff_private; | |
7642 | + struct lgff_effect new; | |
7643 | + int id; | |
7644 | + unsigned long flags; | |
7645 | + | |
7646 | + dbg("ioctl rumble"); | |
7647 | + | |
7648 | + if (!test_bit(effect->type, input->ffbit)) return -EINVAL; | |
7649 | + | |
7650 | + spin_lock_irqsave(&lgff->lock, flags); | |
7651 | + | |
7652 | + if (effect->id == -1) { | |
7653 | + int i; | |
7654 | + | |
7655 | + for (i=0; i<LGFF_EFFECTS && test_bit(EFFECT_USED, lgff->effects[i].flags); ++i); | |
7656 | + if (i >= LGFF_EFFECTS) { | |
7657 | + spin_unlock_irqrestore(&lgff->lock, flags); | |
7658 | + return -ENOSPC; | |
7659 | + } | |
7660 | + | |
7661 | + effect->id = i; | |
7662 | + lgff->effects[i].owner = current->pid; | |
7663 | + lgff->effects[i].flags[0] = 0; | |
7664 | + set_bit(EFFECT_USED, lgff->effects[i].flags); | |
7665 | + } | |
7666 | + | |
7667 | + id = effect->id; | |
7668 | + new = lgff->effects[id]; | |
7669 | + | |
7670 | + new.effect = *effect; | |
7671 | + | |
7672 | + if (test_bit(EFFECT_STARTED, lgff->effects[id].flags) | |
7673 | + || test_bit(EFFECT_STARTED, lgff->effects[id].flags)) { | |
7674 | + | |
7675 | + /* Changing replay parameters is not allowed (for the time | |
7676 | + being) */ | |
7677 | + if (new.effect.replay.delay != lgff->effects[id].effect.replay.delay | |
7678 | + || new.effect.replay.length != lgff->effects[id].effect.replay.length) { | |
7679 | + spin_unlock_irqrestore(&lgff->lock, flags); | |
7680 | + return -ENOSYS; | |
7681 | + } | |
7682 | + | |
7683 | + lgff->effects[id] = new; | |
7684 | + | |
7685 | + } else { | |
7686 | + lgff->effects[id] = new; | |
7687 | + } | |
7688 | + | |
7689 | + spin_unlock_irqrestore(&lgff->lock, flags); | |
7690 | + return 0; | |
7691 | +} | |
7692 | + | |
7693 | +static void hid_lgff_compute_constant(struct lgff_effect *effect, | |
7694 | + int *x, int *y) | |
7695 | +{ | |
7696 | + int level; | |
7697 | + unsigned long now = jiffies; | |
7698 | + int degrees; | |
7699 | + | |
7700 | + // During attack ? | |
7701 | + if (effect->effect.u.constant.envelope.attack_length && | |
7702 | + !time_after(now, | |
7703 | + effect->started_at | |
7704 | + + (effect->effect.u.constant.envelope.attack_length + effect->effect.replay.delay)*HZ/1000)) { | |
7705 | + level = effect->effect.u.constant.level | |
7706 | + - effect->effect.u.constant.envelope.attack_level; | |
7707 | + //TODO compute incrementally, to save mults and divs | |
7708 | + level *= now - effect->started_at - effect->effect.replay.delay; | |
7709 | + level /= effect->effect.u.constant.envelope.attack_length; | |
7710 | +// dbg("During attack"); | |
7711 | + } | |
7712 | + // During fade ? | |
7713 | + else if (effect->effect.replay.length && | |
7714 | + effect->effect.u.constant.envelope.fade_length && | |
7715 | + time_after(now, | |
7716 | + effect->started_at | |
7717 | + + (effect->effect.replay.delay + effect->effect.replay.length) * HZ/1000)) { | |
7718 | + level = effect->effect.u.constant.envelope.fade_level | |
7719 | + - effect->effect.u.constant.level; | |
7720 | + //TODO compute incrementally, to save mults and divs | |
7721 | + level *= now - (effect->started_at + effect->effect.replay.delay + effect->effect.replay.length - effect->effect.u.constant.envelope.fade_length) ; | |
7722 | + level /= effect->effect.u.constant.envelope.fade_length; | |
7723 | +// dbg("During fade"); | |
7724 | + } | |
7725 | + else { | |
7726 | + level = effect->effect.u.constant.level; | |
7727 | +// dbg("During middle"); | |
7728 | + } | |
7729 | +// dbg("level = %d", level); | |
7730 | + | |
7731 | + degrees = effect->effect.direction * 360 >> 16; | |
7732 | + *x += fixp_mult(fixp_sin(degrees), | |
7733 | + level); | |
7734 | + *y += fixp_mult(-fixp_cos(degrees), | |
7735 | + level); | |
7736 | +} | |
7737 | + | |
7738 | +static void hid_lgff_timer(unsigned long timer_data) | |
7739 | +{ | |
7740 | + struct lgff_device *lgff = (struct lgff_device*)timer_data; | |
7741 | + struct hid_device *hid = lgff->hid; | |
7742 | + unsigned long flags; | |
7743 | + int x=0x7fff, y=0x7fff; // Coordinates of constant effects | |
7744 | + unsigned int left = 0, right = 0; // Rumbling | |
7745 | + int i; | |
7746 | + | |
7747 | + spin_lock_irqsave(&lgff->lock, flags); | |
7748 | + | |
7749 | + for (i=0; i<LGFF_EFFECTS; ++i) { | |
7750 | + struct lgff_effect* effect = lgff->effects +i; | |
7751 | + | |
7752 | + if (test_bit(EFFECT_PLAYING, effect->flags)) { | |
7753 | + | |
7754 | + switch (effect->effect.type) { | |
7755 | + case FF_CONSTANT: | |
7756 | + hid_lgff_compute_constant(effect, &x, &y); | |
7757 | + break; | |
7758 | + case FF_RUMBLE: | |
7759 | + right += effect->effect.u.rumble.strong_magnitude; | |
7760 | + left += effect->effect.u.rumble.weak_magnitude; | |
7761 | + break; | |
7762 | + }; | |
7763 | + | |
7764 | + /* One run of the effect is finished playing */ | |
7765 | + if (effect->effect.replay.length && | |
7766 | + time_after(jiffies, | |
7767 | + effect->started_at | |
7768 | + + effect->effect.replay.delay*HZ/1000 | |
7769 | + + effect->effect.replay.length*HZ/1000)) { | |
7770 | + dbg("Finished playing once %d", i); | |
7771 | + if (--effect->count <= 0) { | |
7772 | + dbg("Stopped %d", i); | |
7773 | + clear_bit(EFFECT_PLAYING, effect->flags); | |
7774 | + } | |
7775 | + else { | |
7776 | + dbg("Start again %d", i); | |
7777 | + if (effect->effect.replay.length != 0) { | |
7778 | + clear_bit(EFFECT_PLAYING, effect->flags); | |
7779 | + set_bit(EFFECT_STARTED, effect->flags); | |
7780 | + } | |
7781 | + effect->started_at = jiffies; | |
7782 | + } | |
7783 | + } | |
7784 | + | |
7785 | + } else if (test_bit(EFFECT_STARTED, lgff->effects[i].flags)) { | |
7786 | + /* Check if we should start playing the effect */ | |
7787 | + if (time_after(jiffies, | |
7788 | + lgff->effects[i].started_at | |
7789 | + + lgff->effects[i].effect.replay.delay*HZ/1000)) { | |
7790 | + dbg("Now playing %d", i); | |
7791 | + clear_bit(EFFECT_STARTED, lgff->effects[i].flags); | |
7792 | + set_bit(EFFECT_PLAYING, lgff->effects[i].flags); | |
7793 | + } | |
7794 | + } | |
7795 | + } | |
7796 | + | |
7797 | + x >>= 8; | |
7798 | + y >>= 8; | |
7799 | + | |
7800 | +#define CLAMP(x) if (x < 0) x = 0; if (x > 0xff) x = 0xff | |
7801 | + | |
7802 | + // Clamp values | |
7803 | + CLAMP(x); | |
7804 | + CLAMP(y); | |
7805 | + CLAMP(left); | |
7806 | + CLAMP(right); | |
7807 | + | |
7808 | +#undef CLAMP | |
7809 | + | |
7810 | + if (x != lgff->constant->field[0]->value[2] | |
7811 | + || y != lgff->constant->field[0]->value[3]) { | |
7812 | + lgff->constant->field[0]->value[2] = x; | |
7813 | + lgff->constant->field[0]->value[3] = y; | |
7814 | + dbg("(x,y)=(%04x, %04x)", x, y); | |
7815 | + hid_submit_report(hid, lgff->constant, USB_DIR_OUT); | |
7816 | + } | |
7817 | + | |
7818 | + if (left != lgff->rumble->field[0]->value[3] | |
7819 | + || right != lgff->rumble->field[0]->value[4]) { | |
7820 | + lgff->rumble->field[0]->value[3] = left; | |
7821 | + lgff->rumble->field[0]->value[4] = right; | |
7822 | + dbg("(left,right)=(%04x, %04x)", left, right); | |
7823 | + hid_submit_report(hid, lgff->rumble, USB_DIR_OUT); | |
7824 | + } | |
7825 | + | |
7826 | + if (!test_bit(DEVICE_CLOSING, lgff->flags)) { | |
7827 | + lgff->timer.expires = RUN_AT(PERIOD); | |
7828 | + add_timer(&lgff->timer); | |
7829 | + } | |
7830 | + | |
7831 | + spin_unlock_irqrestore(&lgff->lock, flags); | |
7832 | +} | |
7833 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/hid.h linux-modified/drivers/usb/hid.h | |
7834 | --- linux-vanilla/drivers/usb/hid.h Fri Nov 29 01:53:14 2002 | |
7835 | +++ linux-modified/drivers/usb/hid.h Sun Mar 9 17:01:16 2003 | |
7836 | @@ -2,12 +2,10 @@ | |
7837 | #define __HID_H | |
7838 | ||
7839 | /* | |
7840 | - * $Id$ | |
7841 | + * $Id$ | |
7842 | * | |
7843 | * Copyright (c) 1999 Andreas Gal | |
7844 | * Copyright (c) 2000-2001 Vojtech Pavlik | |
7845 | - * | |
7846 | - * Sponsored by SuSE | |
7847 | */ | |
7848 | ||
7849 | /* | |
7850 | @@ -26,8 +24,8 @@ | |
7851 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
7852 | * | |
7853 | * Should you need to contact me, the author, you can do so either by | |
7854 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
7855 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
7856 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
7857 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
7858 | */ | |
7859 | ||
7860 | #include <linux/types.h> | |
7861 | @@ -41,6 +39,25 @@ | |
7862 | #define USB_INTERFACE_CLASS_HID 3 | |
7863 | ||
7864 | /* | |
7865 | + * HID class requests | |
7866 | + */ | |
7867 | + | |
7868 | +#define HID_REQ_GET_REPORT 0x01 | |
7869 | +#define HID_REQ_GET_IDLE 0x02 | |
7870 | +#define HID_REQ_GET_PROTOCOL 0x03 | |
7871 | +#define HID_REQ_SET_REPORT 0x09 | |
7872 | +#define HID_REQ_SET_IDLE 0x0A | |
7873 | +#define HID_REQ_SET_PROTOCOL 0x0B | |
7874 | + | |
7875 | +/* | |
7876 | + * HID class descriptor types | |
7877 | + */ | |
7878 | + | |
7879 | +#define HID_DT_HID (USB_TYPE_CLASS | 0x01) | |
7880 | +#define HID_DT_REPORT (USB_TYPE_CLASS | 0x02) | |
7881 | +#define HID_DT_PHYSICAL (USB_TYPE_CLASS | 0x03) | |
7882 | + | |
7883 | +/* | |
7884 | * We parse each description item into this structure. Short items data | |
7885 | * values are expanded to 32-bit signed int, long items contain a pointer | |
7886 | * into the data area. | |
7887 | @@ -158,9 +175,11 @@ | |
7888 | #define HID_UP_KEYBOARD 0x00070000 | |
7889 | #define HID_UP_LED 0x00080000 | |
7890 | #define HID_UP_BUTTON 0x00090000 | |
7891 | +#define HID_UP_ORDINAL 0x000a0000 | |
7892 | #define HID_UP_CONSUMER 0x000c0000 | |
7893 | #define HID_UP_DIGITIZER 0x000d0000 | |
7894 | #define HID_UP_PID 0x000f0000 | |
7895 | +#define HID_UP_HPVENDOR 0xff7f0000 | |
7896 | ||
7897 | #define HID_USAGE 0x0000ffff | |
7898 | ||
7899 | @@ -199,7 +218,7 @@ | |
7900 | __s32 logical_maximum; | |
7901 | __s32 physical_minimum; | |
7902 | __s32 physical_maximum; | |
7903 | - unsigned unit_exponent; | |
7904 | + __s32 unit_exponent; | |
7905 | unsigned unit; | |
7906 | unsigned report_id; | |
7907 | unsigned report_size; | |
7908 | @@ -256,9 +275,10 @@ | |
7909 | __s32 logical_maximum; | |
7910 | __s32 physical_minimum; | |
7911 | __s32 physical_maximum; | |
7912 | - unsigned unit_exponent; | |
7913 | + __s32 unit_exponent; | |
7914 | unsigned unit; | |
7915 | struct hid_report *report; /* associated report */ | |
7916 | + unsigned index; /* index into report->field[] */ | |
7917 | }; | |
7918 | ||
7919 | #define HID_MAX_FIELDS 64 | |
7920 | @@ -270,8 +290,6 @@ | |
7921 | struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */ | |
7922 | unsigned maxfield; /* maximum valid field index */ | |
7923 | unsigned size; /* size of the report (bits) */ | |
7924 | - unsigned idx; /* where we're in data */ | |
7925 | - unsigned char *data; /* data for multi-packet reports */ | |
7926 | struct hid_device *device; /* associated device */ | |
7927 | }; | |
7928 | ||
7929 | @@ -284,16 +302,20 @@ | |
7930 | #define HID_REPORT_TYPES 3 | |
7931 | ||
7932 | #define HID_BUFFER_SIZE 32 | |
7933 | -#define HID_CONTROL_FIFO_SIZE 8 | |
7934 | +#define HID_CONTROL_FIFO_SIZE 64 | |
7935 | +#define HID_OUTPUT_FIFO_SIZE 64 | |
7936 | ||
7937 | struct hid_control_fifo { | |
7938 | - struct usb_ctrlrequest dr; | |
7939 | - char buffer[HID_BUFFER_SIZE]; | |
7940 | + unsigned char dir; | |
7941 | + struct hid_report *report; | |
7942 | }; | |
7943 | ||
7944 | #define HID_CLAIMED_INPUT 1 | |
7945 | #define HID_CLAIMED_HIDDEV 2 | |
7946 | ||
7947 | +#define HID_CTRL_RUNNING 1 | |
7948 | +#define HID_OUT_RUNNING 2 | |
7949 | + | |
7950 | struct hid_device { /* device report descriptor */ | |
7951 | __u8 *rdesc; | |
7952 | unsigned rsize; | |
7953 | @@ -306,12 +328,23 @@ | |
7954 | struct usb_device *dev; /* USB device */ | |
7955 | int ifnum; /* USB interface number */ | |
7956 | ||
7957 | - struct urb urb; /* USB URB structure */ | |
7958 | - char buffer[HID_BUFFER_SIZE]; /* Rx buffer */ | |
7959 | + unsigned long iofl; /* I/O flags (CTRL_RUNNING, OUT_RUNNING) */ | |
7960 | ||
7961 | - struct urb urbout; /* Output URB */ | |
7962 | - struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE]; /* Transmit buffer */ | |
7963 | - unsigned char outhead, outtail; /* Tx buffer head & tail */ | |
7964 | + struct urb *urbin; /* Input URB */ | |
7965 | + char inbuf[HID_BUFFER_SIZE]; /* Input buffer */ | |
7966 | + | |
7967 | + struct urb *urbctrl; /* Control URB */ | |
7968 | + struct usb_ctrlrequest dr; /* Control request struct */ | |
7969 | + struct hid_control_fifo ctrl[HID_CONTROL_FIFO_SIZE]; /* Control fifo */ | |
7970 | + unsigned char ctrlhead, ctrltail; /* Control fifo head & tail */ | |
7971 | + char ctrlbuf[HID_BUFFER_SIZE]; /* Control buffer */ | |
7972 | + spinlock_t ctrllock; /* Control fifo spinlock */ | |
7973 | + | |
7974 | + struct urb *urbout; /* Output URB */ | |
7975 | + struct hid_report *out[HID_CONTROL_FIFO_SIZE]; /* Output pipe fifo */ | |
7976 | + unsigned char outhead, outtail; /* Output pipe fifo head & tail */ | |
7977 | + char outbuf[HID_BUFFER_SIZE]; /* Output buffer */ | |
7978 | + spinlock_t outlock; /* Output fifo spinlock */ | |
7979 | ||
7980 | unsigned claimed; /* Claimed by hidinput, hiddev? */ | |
7981 | unsigned quirks; /* Various quirks the device can pull on us */ | |
7982 | @@ -320,8 +353,17 @@ | |
7983 | void *hiddev; /* The hiddev structure */ | |
7984 | int minor; /* Hiddev minor number */ | |
7985 | ||
7986 | + wait_queue_head_t wait; /* For sleeping */ | |
7987 | + | |
7988 | int open; /* is the device open by anyone? */ | |
7989 | char name[128]; /* Device name */ | |
7990 | + char phys[64]; /* Device physical location */ | |
7991 | + char uniq[64]; /* Device unique identifier (serial #) */ | |
7992 | + | |
7993 | + void *ff_private; /* Private data for the force-feedback driver */ | |
7994 | + void (*ff_exit)(struct hid_device*); /* Called by hid_exit_ff(hid) */ | |
7995 | + int (*ff_event)(struct hid_device *hid, struct input_dev *input, | |
7996 | + unsigned int type, unsigned int code, int value); | |
7997 | }; | |
7998 | ||
7999 | #define HID_GLOBAL_STACK_SIZE 4 | |
8000 | @@ -352,32 +394,44 @@ | |
8001 | struct hid_class_descriptor desc[1]; | |
8002 | } __attribute__ ((packed)); | |
8003 | ||
8004 | +void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); | |
8005 | +int hidinput_connect(struct hid_device *); | |
8006 | +void hidinput_disconnect(struct hid_device *); | |
8007 | ||
8008 | #ifdef DEBUG | |
8009 | #include "hid-debug.h" | |
8010 | #else | |
8011 | #define hid_dump_input(a,b) do { } while (0) | |
8012 | #define hid_dump_device(c) do { } while (0) | |
8013 | +#define hid_dump_field(a,b) do { } while (0) | |
8014 | #endif | |
8015 | ||
8016 | #endif | |
8017 | ||
8018 | -#ifdef CONFIG_USB_HIDINPUT | |
8019 | -#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || (a == 0x00010080) || ( a == 0x000c0001)) | |
8020 | -extern void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32); | |
8021 | -extern int hidinput_connect(struct hid_device *); | |
8022 | -extern void hidinput_disconnect(struct hid_device *); | |
8023 | -#else | |
8024 | -#define IS_INPUT_APPLICATION(a) (0) | |
8025 | -static inline void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { } | |
8026 | -static inline int hidinput_connect(struct hid_device *hid) { return -ENODEV; } | |
8027 | -static inline void hidinput_disconnect(struct hid_device *hid) { } | |
8028 | -#endif | |
8029 | +/* Applications from HID Usage Tables 4/8/99 Version 1.1 */ | |
8030 | +/* We ignore a few input applications that are not widely used */ | |
8031 | +#define IS_INPUT_APPLICATION(a) (((a >= 0x00010000) && (a <= 0x00010008)) || ( a == 0x00010080) || ( a == 0x000c0001)) | |
8032 | ||
8033 | int hid_open(struct hid_device *); | |
8034 | void hid_close(struct hid_device *); | |
8035 | int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **); | |
8036 | int hid_set_field(struct hid_field *, unsigned, __s32); | |
8037 | -void hid_write_report(struct hid_device *, struct hid_report *); | |
8038 | -void hid_read_report(struct hid_device *, struct hid_report *); | |
8039 | +void hid_submit_report(struct hid_device *, struct hid_report *, unsigned char dir); | |
8040 | void hid_init_reports(struct hid_device *hid); | |
8041 | + | |
8042 | + | |
8043 | +#ifdef CONFIG_HID_FF | |
8044 | + | |
8045 | +int hid_ff_init(struct hid_device *hid); | |
8046 | +static inline void hid_ff_exit(struct hid_device *hid) | |
8047 | +{ | |
8048 | + if (hid->ff_exit) hid->ff_exit(hid); | |
8049 | +} | |
8050 | + | |
8051 | +static inline int hid_ff_event(struct hid_device *hid, struct input_dev *input, | |
8052 | + unsigned int type, unsigned int code, int value) | |
8053 | +{ | |
8054 | + if (hid->ff_event) return hid->ff_event(hid, input, type, code, value); | |
8055 | + return -ENOSYS; | |
8056 | +} | |
8057 | +#endif | |
8058 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/hiddev.c linux-modified/drivers/usb/hiddev.c | |
8059 | --- linux-vanilla/drivers/usb/hiddev.c Sun Oct 21 04:13:11 2001 | |
8060 | +++ linux-modified/drivers/usb/hiddev.c Mon Jan 6 16:48:21 2003 | |
8061 | @@ -50,9 +50,10 @@ | |
8062 | }; | |
8063 | ||
8064 | struct hiddev_list { | |
8065 | - struct hiddev_event buffer[HIDDEV_BUFFER_SIZE]; | |
8066 | + struct hiddev_usage_ref buffer[HIDDEV_BUFFER_SIZE]; | |
8067 | int head; | |
8068 | int tail; | |
8069 | + unsigned flags; | |
8070 | struct fasync_struct *fasync; | |
8071 | struct hiddev *hiddev; | |
8072 | struct hiddev_list *next; | |
8073 | @@ -146,17 +147,19 @@ | |
8074 | * This is where hid.c calls into hiddev to pass an event that occurred over | |
8075 | * the interrupt pipe | |
8076 | */ | |
8077 | -void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) | |
8078 | +void hiddev_hid_event(struct hid_device *hid, struct hiddev_usage_ref *uref) | |
8079 | { | |
8080 | struct hiddev *hiddev = hid->hiddev; | |
8081 | struct hiddev_list *list = hiddev->list; | |
8082 | ||
8083 | while (list) { | |
8084 | - list->buffer[list->head].hid = usage; | |
8085 | - list->buffer[list->head].value = value; | |
8086 | - list->head = (list->head + 1) & (HIDDEV_BUFFER_SIZE - 1); | |
8087 | - | |
8088 | - kill_fasync(&list->fasync, SIGIO, POLL_IN); | |
8089 | + if (uref->field_index != HID_FIELD_INDEX_NONE || | |
8090 | + (list->flags & HIDDEV_FLAG_REPORT) != 0) { | |
8091 | + list->buffer[list->head] = *uref; | |
8092 | + list->head = (list->head + 1) & | |
8093 | + (HIDDEV_BUFFER_SIZE - 1); | |
8094 | + kill_fasync(&list->fasync, SIGIO, POLL_IN); | |
8095 | + } | |
8096 | ||
8097 | list = list->next; | |
8098 | } | |
8099 | @@ -193,7 +196,6 @@ | |
8100 | struct hiddev_list *list = file->private_data; | |
8101 | struct hiddev_list **listptr; | |
8102 | ||
8103 | - lock_kernel(); | |
8104 | listptr = &list->hiddev->list; | |
8105 | hiddev_fasync(-1, file, 0); | |
8106 | ||
8107 | @@ -209,7 +211,6 @@ | |
8108 | } | |
8109 | ||
8110 | kfree(list); | |
8111 | - unlock_kernel(); | |
8112 | ||
8113 | return 0; | |
8114 | } | |
8115 | @@ -220,7 +221,7 @@ | |
8116 | static int hiddev_open(struct inode * inode, struct file * file) { | |
8117 | struct hiddev_list *list; | |
8118 | ||
8119 | - int i = MINOR(inode->i_rdev) - HIDDEV_MINOR_BASE; | |
8120 | + int i = minor(inode->i_rdev) - HIDDEV_MINOR_BASE; | |
8121 | ||
8122 | if (i >= HIDDEV_MINORS || !hiddev_table[i]) | |
8123 | return -ENODEV; | |
8124 | @@ -259,43 +260,67 @@ | |
8125 | { | |
8126 | DECLARE_WAITQUEUE(wait, current); | |
8127 | struct hiddev_list *list = file->private_data; | |
8128 | + int event_size; | |
8129 | int retval = 0; | |
8130 | ||
8131 | - if (list->head == list->tail) { | |
8132 | - | |
8133 | - add_wait_queue(&list->hiddev->wait, &wait); | |
8134 | - set_current_state(TASK_INTERRUPTIBLE); | |
8135 | + event_size = ((list->flags & HIDDEV_FLAG_UREF) != 0) ? | |
8136 | + sizeof(struct hiddev_usage_ref) : sizeof(struct hiddev_event); | |
8137 | ||
8138 | - while (list->head == list->tail) { | |
8139 | + if (count < event_size) return 0; | |
8140 | ||
8141 | - if (file->f_flags & O_NONBLOCK) { | |
8142 | - retval = -EAGAIN; | |
8143 | - break; | |
8144 | - } | |
8145 | - if (signal_pending(current)) { | |
8146 | - retval = -ERESTARTSYS; | |
8147 | - break; | |
8148 | - } | |
8149 | - if (!list->hiddev->exist) { | |
8150 | - retval = -EIO; | |
8151 | - break; | |
8152 | + while (retval == 0) { | |
8153 | + if (list->head == list->tail) { | |
8154 | + add_wait_queue(&list->hiddev->wait, &wait); | |
8155 | + set_current_state(TASK_INTERRUPTIBLE); | |
8156 | + | |
8157 | + while (list->head == list->tail) { | |
8158 | + if (file->f_flags & O_NONBLOCK) { | |
8159 | + retval = -EAGAIN; | |
8160 | + break; | |
8161 | + } | |
8162 | + if (signal_pending(current)) { | |
8163 | + retval = -ERESTARTSYS; | |
8164 | + break; | |
8165 | + } | |
8166 | + if (!list->hiddev->exist) { | |
8167 | + retval = -EIO; | |
8168 | + break; | |
8169 | + } | |
8170 | + | |
8171 | + schedule(); | |
8172 | } | |
8173 | ||
8174 | - schedule(); | |
8175 | + set_current_state(TASK_RUNNING); | |
8176 | + remove_wait_queue(&list->hiddev->wait, &wait); | |
8177 | } | |
8178 | ||
8179 | - set_current_state(TASK_RUNNING); | |
8180 | - remove_wait_queue(&list->hiddev->wait, &wait); | |
8181 | - } | |
8182 | + if (retval) | |
8183 | + return retval; | |
8184 | ||
8185 | - if (retval) | |
8186 | - return retval; | |
8187 | ||
8188 | - while (list->head != list->tail && retval + sizeof(struct hiddev_event) <= count) { | |
8189 | - if (copy_to_user(buffer + retval, list->buffer + list->tail, | |
8190 | - sizeof(struct hiddev_event))) return -EFAULT; | |
8191 | - list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); | |
8192 | - retval += sizeof(struct hiddev_event); | |
8193 | + while (list->head != list->tail && | |
8194 | + retval + event_size <= count) { | |
8195 | + if ((list->flags & HIDDEV_FLAG_UREF) == 0) { | |
8196 | + if (list->buffer[list->tail].field_index != | |
8197 | + HID_FIELD_INDEX_NONE) { | |
8198 | + struct hiddev_event event; | |
8199 | + event.hid = list->buffer[list->tail].usage_code; | |
8200 | + event.value = list->buffer[list->tail].value; | |
8201 | + if (copy_to_user(buffer + retval, &event, sizeof(struct hiddev_event))) | |
8202 | + return -EFAULT; | |
8203 | + retval += sizeof(struct hiddev_event); | |
8204 | + } | |
8205 | + } else { | |
8206 | + if (list->buffer[list->tail].field_index != HID_FIELD_INDEX_NONE || | |
8207 | + (list->flags & HIDDEV_FLAG_REPORT) != 0) { | |
8208 | + if (copy_to_user(buffer + retval, list->buffer + list->tail, sizeof(struct hiddev_usage_ref))) | |
8209 | + return -EFAULT; | |
8210 | + retval += sizeof(struct hiddev_usage_ref); | |
8211 | + } | |
8212 | + } | |
8213 | + list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1); | |
8214 | + } | |
8215 | + | |
8216 | } | |
8217 | ||
8218 | return retval; | |
8219 | @@ -360,6 +385,25 @@ | |
8220 | return copy_to_user((void *) arg, &dinfo, sizeof(dinfo)); | |
8221 | } | |
8222 | ||
8223 | + case HIDIOCGFLAG: | |
8224 | + return put_user(list->flags, (int *) arg); | |
8225 | + | |
8226 | + case HIDIOCSFLAG: | |
8227 | + { | |
8228 | + int newflags; | |
8229 | + if (get_user(newflags, (int *) arg)) | |
8230 | + return -EFAULT; | |
8231 | + | |
8232 | + if ((newflags & ~HIDDEV_FLAGS) != 0 || | |
8233 | + ((newflags & HIDDEV_FLAG_REPORT) != 0 && | |
8234 | + (newflags & HIDDEV_FLAG_UREF) == 0)) | |
8235 | + return -EINVAL; | |
8236 | + | |
8237 | + list->flags = newflags; | |
8238 | + | |
8239 | + return 0; | |
8240 | + } | |
8241 | + | |
8242 | case HIDIOCGSTRING: | |
8243 | { | |
8244 | int idx, len; | |
8245 | @@ -402,7 +446,7 @@ | |
8246 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | |
8247 | return -EINVAL; | |
8248 | ||
8249 | - hid_read_report(hid, report); | |
8250 | + hid_submit_report(hid, report, USB_DIR_IN); | |
8251 | ||
8252 | return 0; | |
8253 | ||
8254 | @@ -416,7 +460,7 @@ | |
8255 | if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL) | |
8256 | return -EINVAL; | |
8257 | ||
8258 | - hid_write_report(hid, report); | |
8259 | + hid_submit_report(hid, report, USB_DIR_OUT); | |
8260 | ||
8261 | return 0; | |
8262 | ||
8263 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/usb-ohci.c linux-modified/drivers/usb/usb-ohci.c | |
8264 | --- linux-vanilla/drivers/usb/usb-ohci.c Fri Nov 29 01:53:15 2002 | |
8265 | +++ linux-modified/drivers/usb/usb-ohci.c Mon Jan 6 16:48:21 2003 | |
8266 | @@ -74,7 +74,7 @@ | |
8267 | #include <asm/unaligned.h> | |
8268 | ||
8269 | #define OHCI_USE_NPS // force NoPowerSwitching mode | |
8270 | -// #define OHCI_VERBOSE_DEBUG /* not always helpful */ | |
8271 | +#undef OHCI_VERBOSE_DEBUG /* not always helpful */ | |
8272 | ||
8273 | #include "usb-ohci.h" | |
8274 | ||
8275 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/usbkbd.c linux-modified/drivers/usb/usbkbd.c | |
8276 | --- linux-vanilla/drivers/usb/usbkbd.c Fri Nov 29 01:53:15 2002 | |
8277 | +++ linux-modified/drivers/usb/usbkbd.c Mon Jan 6 16:48:21 2003 | |
8278 | @@ -250,8 +250,8 @@ | |
8279 | ||
8280 | input_register_device(&kbd->dev); | |
8281 | ||
8282 | - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", | |
8283 | - kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum); | |
8284 | + printk(KERN_INFO "input: %s on usb%d:%d.%d\n", | |
8285 | + kbd->name, dev->bus->busnum, dev->devnum, ifnum); | |
8286 | ||
8287 | return kbd; | |
8288 | } | |
8289 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/usbmouse.c linux-modified/drivers/usb/usbmouse.c | |
8290 | --- linux-vanilla/drivers/usb/usbmouse.c Sat Aug 3 02:39:45 2002 | |
8291 | +++ linux-modified/drivers/usb/usbmouse.c Mon Jan 6 16:48:21 2003 | |
8292 | @@ -166,8 +166,8 @@ | |
8293 | ||
8294 | input_register_device(&mouse->dev); | |
8295 | ||
8296 | - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", | |
8297 | - mouse->dev.number, mouse->name, dev->bus->busnum, dev->devnum, ifnum); | |
8298 | + printk(KERN_INFO "input: %s on usb%d:%d.%d\n", | |
8299 | + mouse->name, dev->bus->busnum, dev->devnum, ifnum); | |
8300 | ||
8301 | return mouse; | |
8302 | } | |
8303 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/drivers/usb/wacom.c linux-modified/drivers/usb/wacom.c | |
8304 | --- linux-vanilla/drivers/usb/wacom.c Fri Nov 29 01:53:15 2002 | |
8305 | +++ linux-modified/drivers/usb/wacom.c Mon Jan 6 16:48:21 2003 | |
8306 | @@ -491,8 +491,8 @@ | |
8307 | usb_set_report(dev, ifnum, 3, 5, rep_data, 0); | |
8308 | usb_set_report(dev, ifnum, 3, 6, rep_data, 0); | |
8309 | ||
8310 | - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", | |
8311 | - wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum); | |
8312 | + printk(KERN_INFO "input: %s on usb%d:%d.%d\n", | |
8313 | + wacom->features->name, dev->bus->busnum, dev->devnum, ifnum); | |
8314 | ||
8315 | return wacom; | |
8316 | } | |
8317 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/include/linux/hiddev.h linux-modified/include/linux/hiddev.h | |
8318 | --- linux-vanilla/include/linux/hiddev.h Fri Nov 29 01:53:15 2002 | |
8319 | +++ linux-modified/include/linux/hiddev.h Sun Mar 9 17:01:16 2003 | |
8320 | @@ -2,7 +2,7 @@ | |
8321 | #define _HIDDEV_H | |
8322 | ||
8323 | /* | |
8324 | - * $Id$ | |
8325 | + * $Id$ | |
8326 | * | |
8327 | * Copyright (c) 1999-2000 Vojtech Pavlik | |
8328 | * | |
8329 | @@ -25,8 +25,8 @@ | |
8330 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
8331 | * | |
8332 | * Should you need to contact me, the author, you can do so either by | |
8333 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
8334 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
8335 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
8336 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
8337 | */ | |
8338 | ||
8339 | /* | |
8340 | @@ -119,12 +119,17 @@ | |
8341 | __s32 value; | |
8342 | }; | |
8343 | ||
8344 | +/* FIELD_INDEX_NONE is returned in read() data from the kernel when flags | |
8345 | + * is set to (HIDDEV_FLAG_UREF | HIDDEV_FLAG_REPORT) and a new report has | |
8346 | + * been sent by the device | |
8347 | + */ | |
8348 | +#define HID_FIELD_INDEX_NONE 0xffffffff | |
8349 | ||
8350 | /* | |
8351 | * Protocol version. | |
8352 | */ | |
8353 | ||
8354 | -#define HID_VERSION 0x010002 | |
8355 | +#define HID_VERSION 0x010003 | |
8356 | ||
8357 | /* | |
8358 | * IOCTLs (0x00 - 0x7f) | |
8359 | @@ -138,11 +143,20 @@ | |
8360 | #define HIDIOCGNAME(len) _IOC(_IOC_READ, 'H', 0x06, len) | |
8361 | #define HIDIOCGREPORT _IOW('H', 0x07, struct hiddev_report_info) | |
8362 | #define HIDIOCSREPORT _IOW('H', 0x08, struct hiddev_report_info) | |
8363 | -#define HIDIOCGREPORTINFO _IOWR('H', 0x09, struct hiddev_report_info) | |
8364 | -#define HIDIOCGFIELDINFO _IOWR('H', 0x0A, struct hiddev_field_info) | |
8365 | -#define HIDIOCGUSAGE _IOWR('H', 0x0B, struct hiddev_usage_ref) | |
8366 | -#define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref) | |
8367 | -#define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) | |
8368 | +#define HIDIOCGREPORTINFO _IOWR('H', 0x09, struct hiddev_report_info) | |
8369 | +#define HIDIOCGFIELDINFO _IOWR('H', 0x0A, struct hiddev_field_info) | |
8370 | +#define HIDIOCGUSAGE _IOWR('H', 0x0B, struct hiddev_usage_ref) | |
8371 | +#define HIDIOCSUSAGE _IOW('H', 0x0C, struct hiddev_usage_ref) | |
8372 | +#define HIDIOCGUCODE _IOWR('H', 0x0D, struct hiddev_usage_ref) | |
8373 | +#define HIDIOCGFLAG _IOR('H', 0x0E, int) | |
8374 | +#define HIDIOCSFLAG _IOW('H', 0x0F, int) | |
8375 | + | |
8376 | +/* | |
8377 | + * Flags to be used in HIDIOCSFLAG | |
8378 | + */ | |
8379 | +#define HIDDEV_FLAG_UREF 0x1 | |
8380 | +#define HIDDEV_FLAG_REPORT 0x2 | |
8381 | +#define HIDDEV_FLAGS 0x3 | |
8382 | ||
8383 | /* To traverse the input report descriptor info for a HID device, perform the | |
8384 | * following: | |
8385 | @@ -179,13 +193,13 @@ | |
8386 | #ifdef CONFIG_USB_HIDDEV | |
8387 | int hiddev_connect(struct hid_device *); | |
8388 | void hiddev_disconnect(struct hid_device *); | |
8389 | -void hiddev_hid_event(struct hid_device *, unsigned int usage, int value); | |
8390 | +void hiddev_hid_event(struct hid_device *, struct hiddev_usage_ref *ref); | |
8391 | int __init hiddev_init(void); | |
8392 | void __exit hiddev_exit(void); | |
8393 | #else | |
8394 | static inline int hiddev_connect(struct hid_device *hid) { return -1; } | |
8395 | static inline void hiddev_disconnect(struct hid_device *hid) { } | |
8396 | -static inline void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value) { } | |
8397 | +static inline void hiddev_hid_event(struct hid_device *, struct hiddev_usage_ref *ref) { } | |
8398 | static inline int hiddev_init(void) { return 0; } | |
8399 | static inline void hiddev_exit(void) { } | |
8400 | #endif | |
8401 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/include/linux/input.h linux-modified/include/linux/input.h | |
8402 | --- linux-vanilla/include/linux/input.h Sun Jan 26 16:09:49 2003 | |
8403 | +++ linux-modified/include/linux/input.h Sun Mar 9 16:58:14 2003 | |
8404 | @@ -2,11 +2,9 @@ | |
8405 | #define _INPUT_H | |
8406 | ||
8407 | /* | |
8408 | - * $Id$ | |
8409 | + * $Id$ | |
8410 | * | |
8411 | - * Copyright (c) 1999-2000 Vojtech Pavlik | |
8412 | - * | |
8413 | - * Sponsored by SuSE | |
8414 | + * Copyright (c) 1999-2001 Vojtech Pavlik | |
8415 | */ | |
8416 | ||
8417 | /* | |
8418 | @@ -17,7 +15,7 @@ | |
8419 | * | |
8420 | * This program is distributed in the hope that it will be useful, | |
8421 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8422 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
8423 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
8424 | * GNU General Public License for more details. | |
8425 | * | |
8426 | * You should have received a copy of the GNU General Public License | |
8427 | @@ -25,8 +23,8 @@ | |
8428 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
8429 | * | |
8430 | * Should you need to contact me, the author, you can do so either by | |
8431 | - * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail: | |
8432 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
8433 | + * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
8434 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
8435 | */ | |
8436 | ||
8437 | #ifdef __KERNEL__ | |
8438 | @@ -64,17 +62,20 @@ | |
8439 | #define EVIOCSREP _IOW('E', 0x03, int[2]) /* get repeat settings */ | |
8440 | #define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ | |
8441 | #define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */ | |
8442 | -#define EVIOCGKEY _IOR('E', 0x05, int[2]) /* get key value */ | |
8443 | + | |
8444 | #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ | |
8445 | -#define EVIOCGBUS _IOR('E', 0x07, short[4]) /* get bus address */ | |
8446 | +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ | |
8447 | +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ | |
8448 | + | |
8449 | +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */ | |
8450 | +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ | |
8451 | +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ | |
8452 | ||
8453 | #define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ | |
8454 | #define EVIOCGABS(abs) _IOR('E', 0x40 + abs, int[5]) /* get abs value/limits */ | |
8455 | ||
8456 | #define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ | |
8457 | #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ | |
8458 | -#define EVIOCSGAIN _IOW('E', 0x82, unsigned short) /* Set overall gain */ | |
8459 | -#define EVIOCSAUTOCENTER _IOW('E', 0x83, unsigned short) /* Enable or disable auto-centering */ | |
8460 | #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ | |
8461 | ||
8462 | /* | |
8463 | @@ -90,6 +91,8 @@ | |
8464 | #define EV_SND 0x12 | |
8465 | #define EV_REP 0x14 | |
8466 | #define EV_FF 0x15 | |
8467 | +#define EV_PWR 0x16 | |
8468 | +#define EV_FF_STATUS 0x17 | |
8469 | #define EV_MAX 0x1f | |
8470 | ||
8471 | /* | |
8472 | @@ -304,8 +307,27 @@ | |
8473 | #define KEY_PROG4 203 | |
8474 | #define KEY_SUSPEND 205 | |
8475 | #define KEY_CLOSE 206 | |
8476 | +#define KEY_PLAY 207 | |
8477 | +#define KEY_FASTFORWARD 208 | |
8478 | +#define KEY_BASSBOOST 209 | |
8479 | +#define KEY_PRINT 210 | |
8480 | +#define KEY_HP 211 | |
8481 | +#define KEY_CAMERA 212 | |
8482 | +#define KEY_SOUND 213 | |
8483 | +#define KEY_QUESTION 214 | |
8484 | +#define KEY_EMAIL 215 | |
8485 | +#define KEY_CHAT 216 | |
8486 | +#define KEY_SEARCH 217 | |
8487 | +#define KEY_CONNECT 218 | |
8488 | +#define KEY_FINANCE 219 | |
8489 | +#define KEY_SPORT 220 | |
8490 | +#define KEY_SHOP 221 | |
8491 | +#define KEY_ALTERASE 222 | |
8492 | +#define KEY_CANCEL 223 | |
8493 | +#define KEY_BRIGHTNESSDOWN 224 | |
8494 | +#define KEY_BRIGHTNESSUP 225 | |
8495 | ||
8496 | -#define KEY_UNKNOWN 220 | |
8497 | +#define KEY_UNKNOWN 240 | |
8498 | ||
8499 | #define KEY_BRIGHTNESSDOWN 224 | |
8500 | #define KEY_BRIGHTNESSUP 225 | |
8501 | @@ -376,6 +398,10 @@ | |
8502 | #define BTN_STYLUS 0x14b | |
8503 | #define BTN_STYLUS2 0x14c | |
8504 | ||
8505 | +#define BTN_WHEEL 0x150 | |
8506 | +#define BTN_GEAR_DOWN 0x150 | |
8507 | +#define BTN_GEAR_UP 0x151 | |
8508 | + | |
8509 | #define KEY_MAX 0x1ff | |
8510 | ||
8511 | /* | |
8512 | @@ -419,7 +445,8 @@ | |
8513 | #define ABS_TILT_X 0x1a | |
8514 | #define ABS_TILT_Y 0x1b | |
8515 | #define ABS_MISC 0x1c | |
8516 | -#define ABS_MAX 0x1f | |
8517 | +#define ABS_VOLUME 0x20 | |
8518 | +#define ABS_MAX 0x3f | |
8519 | ||
8520 | /* | |
8521 | * Misc events | |
8522 | @@ -485,67 +512,89 @@ | |
8523 | #define BUS_I2C 0x18 | |
8524 | ||
8525 | /* | |
8526 | + * Values describing the status of an effect | |
8527 | + */ | |
8528 | +#define FF_STATUS_STOPPED 0x00 | |
8529 | +#define FF_STATUS_PLAYING 0x01 | |
8530 | +#define FF_STATUS_MAX 0x01 | |
8531 | + | |
8532 | +/* | |
8533 | * Structures used in ioctls to upload effects to a device | |
8534 | * The first structures are not passed directly by using ioctls. | |
8535 | * They are sub-structures of the actually sent structure (called ff_effect) | |
8536 | */ | |
8537 | ||
8538 | struct ff_replay { | |
8539 | - __u16 length; /* Duration of an effect */ | |
8540 | + __u16 length; /* Duration of an effect in ms. | |
8541 | + All other times are also expressed in ms. | |
8542 | + 0 means "play for ever" */ | |
8543 | __u16 delay; /* Time to wait before to start playing an effect */ | |
8544 | }; | |
8545 | ||
8546 | struct ff_trigger { | |
8547 | __u16 button; /* Number of button triggering an effect */ | |
8548 | - __u16 interval; /* Time to wait before an effect can be re-triggered */ | |
8549 | + __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */ | |
8550 | }; | |
8551 | ||
8552 | -struct ff_shape { | |
8553 | - __u16 attack_length; /* Duration of attack */ | |
8554 | - __s16 attack_level; /* Level at beginning of attack */ | |
8555 | - __u16 fade_length; /* Duration of fade */ | |
8556 | - __s16 fade_level; /* Level at end of fade */ | |
8557 | +struct ff_envelope { | |
8558 | + __u16 attack_length; /* Duration of attack (ms) */ | |
8559 | + __u16 attack_level; /* Level at beginning of attack */ | |
8560 | + __u16 fade_length; /* Duration of fade (ms) */ | |
8561 | + __u16 fade_level; /* Level at end of fade */ | |
8562 | }; | |
8563 | ||
8564 | /* FF_CONSTANT */ | |
8565 | struct ff_constant_effect { | |
8566 | - __s16 level; /* Strength of effect */ | |
8567 | - __u16 direction; /* Direction of effect (see periodic effects) */ | |
8568 | - struct ff_shape shape; | |
8569 | + __s16 level; /* Strength of effect. Negative values are OK */ | |
8570 | + struct ff_envelope envelope; | |
8571 | }; | |
8572 | ||
8573 | -/* FF_SPRING of FF_FRICTION */ | |
8574 | -struct ff_interactive_effect { | |
8575 | -/* Axis along which effect must be created. If null, the field named direction | |
8576 | - * is used | |
8577 | - * It is a bit array (ie to enable axes X and Y, use BIT(ABS_X) | BIT(ABS_Y) | |
8578 | - */ | |
8579 | - __u16 axis; | |
8580 | - __u16 direction; | |
8581 | +/* FF_RAMP */ | |
8582 | +struct ff_ramp_effect { | |
8583 | + __s16 start_level; | |
8584 | + __s16 end_level; | |
8585 | + struct ff_envelope envelope; | |
8586 | +}; | |
8587 | ||
8588 | - __s16 right_saturation; /* Max level when joystick is on the right */ | |
8589 | - __s16 left_saturation; /* Max level when joystick in on the left */ | |
8590 | +/* FF_SPRING of FF_FRICTION */ | |
8591 | +struct ff_condition_effect { | |
8592 | + __u16 right_saturation; /* Max level when joystick is on the right */ | |
8593 | + __u16 left_saturation; /* Max level when joystick in on the left */ | |
8594 | ||
8595 | __s16 right_coeff; /* Indicates how fast the force grows when the | |
8596 | joystick moves to the right */ | |
8597 | __s16 left_coeff; /* Same for left side */ | |
8598 | ||
8599 | __u16 deadband; /* Size of area where no force is produced */ | |
8600 | - __s16 center; /* Position of dead dead zone */ | |
8601 | + __s16 center; /* Position of dead zone */ | |
8602 | ||
8603 | }; | |
8604 | ||
8605 | /* FF_PERIODIC */ | |
8606 | struct ff_periodic_effect { | |
8607 | __u16 waveform; /* Kind of wave (sine, square...) */ | |
8608 | - __u16 period; | |
8609 | + __u16 period; /* in ms */ | |
8610 | __s16 magnitude; /* Peak value */ | |
8611 | __s16 offset; /* Mean value of wave (roughly) */ | |
8612 | __u16 phase; /* 'Horizontal' shift */ | |
8613 | - __u16 direction; /* Direction. 0 deg -> 0x0000 | |
8614 | - 90 deg -> 0x4000 */ | |
8615 | ||
8616 | - struct ff_shape shape; | |
8617 | + struct ff_envelope envelope; | |
8618 | + | |
8619 | +/* Only used if waveform == FF_CUSTOM */ | |
8620 | + __u32 custom_len; /* Number of samples */ | |
8621 | + __s16 *custom_data; /* Buffer of samples */ | |
8622 | +/* Note: the data pointed by custom_data is copied by the driver. You can | |
8623 | + * therefore dispose of the memory after the upload/update */ | |
8624 | +}; | |
8625 | + | |
8626 | +/* FF_RUMBLE */ | |
8627 | +/* Some rumble pads have two motors of different weight. | |
8628 | + strong_magnitude represents the magnitude of the vibration generated | |
8629 | + by the heavy motor. | |
8630 | +*/ | |
8631 | +struct ff_rumble_effect { | |
8632 | + __u16 strong_magnitude; /* Magnitude of the heavy motor */ | |
8633 | + __u16 weak_magnitude; /* Magnitude of the light one */ | |
8634 | }; | |
8635 | ||
8636 | /* | |
8637 | @@ -554,36 +603,30 @@ | |
8638 | struct ff_effect { | |
8639 | __u16 type; | |
8640 | /* Following field denotes the unique id assigned to an effect. | |
8641 | - * It is set by the driver. | |
8642 | + * If user sets if to -1, a new effect is created, and its id is returned in the same field | |
8643 | + * Else, the user sets it to the effect id it wants to update. | |
8644 | */ | |
8645 | __s16 id; | |
8646 | ||
8647 | + __u16 direction; /* Direction. 0 deg -> 0x0000 (down) | |
8648 | + 90 deg -> 0x4000 (left) | |
8649 | + 180 deg -> 0x8000 (up) | |
8650 | + 270 deg -> 0xC000 (right) | |
8651 | + */ | |
8652 | + | |
8653 | struct ff_trigger trigger; | |
8654 | struct ff_replay replay; | |
8655 | ||
8656 | union { | |
8657 | struct ff_constant_effect constant; | |
8658 | + struct ff_ramp_effect ramp; | |
8659 | struct ff_periodic_effect periodic; | |
8660 | - struct ff_interactive_effect interactive; | |
8661 | + struct ff_condition_effect condition[2]; /* One for each axis */ | |
8662 | + struct ff_rumble_effect rumble; | |
8663 | } u; | |
8664 | }; | |
8665 | ||
8666 | /* | |
8667 | - * Buttons that can trigger effects. Use for example FF_BTN(BTN_TRIGGER) to | |
8668 | - * access the bitmap. | |
8669 | - */ | |
8670 | - | |
8671 | -#define FF_BTN(x) ((x) - BTN_MISC + FF_BTN_OFFSET) | |
8672 | -#define FF_BTN_OFFSET 0x00 | |
8673 | - | |
8674 | -/* | |
8675 | - * Force feedback axis mappings. Use FF_ABS() to access the bitmap. | |
8676 | - */ | |
8677 | - | |
8678 | -#define FF_ABS(x) ((x) + FF_ABS_OFFSET) | |
8679 | -#define FF_ABS_OFFSET 0x40 | |
8680 | - | |
8681 | -/* | |
8682 | * Force feedback effect types | |
8683 | */ | |
8684 | ||
8685 | @@ -592,6 +635,9 @@ | |
8686 | #define FF_CONSTANT 0x52 | |
8687 | #define FF_SPRING 0x53 | |
8688 | #define FF_FRICTION 0x54 | |
8689 | +#define FF_DAMPER 0x55 | |
8690 | +#define FF_INERTIA 0x56 | |
8691 | +#define FF_RAMP 0x57 | |
8692 | ||
8693 | /* | |
8694 | * Force feedback periodic effect types | |
8695 | @@ -630,8 +676,9 @@ | |
8696 | ||
8697 | void *private; | |
8698 | ||
8699 | - int number; | |
8700 | char *name; | |
8701 | + char *phys; | |
8702 | + char *uniq; | |
8703 | unsigned short idbus; | |
8704 | unsigned short idvendor; | |
8705 | unsigned short idproduct; | |
8706 | @@ -654,6 +701,9 @@ | |
8707 | unsigned int repeat_key; | |
8708 | struct timer_list timer; | |
8709 | ||
8710 | + struct pm_dev *pm_dev; | |
8711 | + int state; | |
8712 | + | |
8713 | int abs[ABS_MAX + 1]; | |
8714 | int rep[REP_MAX + 1]; | |
8715 | ||
8716 | @@ -668,6 +718,8 @@ | |
8717 | ||
8718 | int (*open)(struct input_dev *dev); | |
8719 | void (*close)(struct input_dev *dev); | |
8720 | + int (*accept)(struct input_dev *dev, struct file *file); | |
8721 | + int (*flush)(struct input_dev *dev, struct file *file); | |
8722 | int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); | |
8723 | int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); | |
8724 | int (*erase_effect)(struct input_dev *dev, int effect_id); | |
8725 | @@ -676,16 +728,63 @@ | |
8726 | struct input_dev *next; | |
8727 | }; | |
8728 | ||
8729 | +/* | |
8730 | + * Structure for hotplug & device<->driver matching. | |
8731 | + */ | |
8732 | + | |
8733 | +#define INPUT_DEVICE_ID_MATCH_BUS 1 | |
8734 | +#define INPUT_DEVICE_ID_MATCH_VENDOR 2 | |
8735 | +#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 | |
8736 | +#define INPUT_DEVICE_ID_MATCH_VERSION 8 | |
8737 | + | |
8738 | +#define INPUT_DEVICE_ID_MATCH_EVBIT 0x010 | |
8739 | +#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x020 | |
8740 | +#define INPUT_DEVICE_ID_MATCH_RELBIT 0x040 | |
8741 | +#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x080 | |
8742 | +#define INPUT_DEVICE_ID_MATCH_MSCIT 0x100 | |
8743 | +#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200 | |
8744 | +#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400 | |
8745 | +#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800 | |
8746 | + | |
8747 | +#define INPUT_DEVICE_ID_MATCH_DEVICE\ | |
8748 | + (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT) | |
8749 | +#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\ | |
8750 | + (INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION) | |
8751 | + | |
8752 | +struct input_device_id { | |
8753 | + | |
8754 | + unsigned long flags; | |
8755 | + | |
8756 | + unsigned short idbus; | |
8757 | + unsigned short idvendor; | |
8758 | + unsigned short idproduct; | |
8759 | + unsigned short idversion; | |
8760 | + | |
8761 | + unsigned long evbit[NBITS(EV_MAX)]; | |
8762 | + unsigned long keybit[NBITS(KEY_MAX)]; | |
8763 | + unsigned long relbit[NBITS(REL_MAX)]; | |
8764 | + unsigned long absbit[NBITS(ABS_MAX)]; | |
8765 | + unsigned long mscbit[NBITS(MSC_MAX)]; | |
8766 | + unsigned long ledbit[NBITS(LED_MAX)]; | |
8767 | + unsigned long sndbit[NBITS(SND_MAX)]; | |
8768 | + unsigned long ffbit[NBITS(FF_MAX)]; | |
8769 | + | |
8770 | + unsigned long driver_info; | |
8771 | +}; | |
8772 | + | |
8773 | struct input_handler { | |
8774 | ||
8775 | void *private; | |
8776 | ||
8777 | void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); | |
8778 | - struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev); | |
8779 | + struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); | |
8780 | void (*disconnect)(struct input_handle *handle); | |
8781 | ||
8782 | struct file_operations *fops; | |
8783 | int minor; | |
8784 | + char *name; | |
8785 | + | |
8786 | + struct input_device_id *id_table; | |
8787 | ||
8788 | struct input_handle *handle; | |
8789 | struct input_handler *next; | |
8790 | @@ -696,6 +795,7 @@ | |
8791 | void *private; | |
8792 | ||
8793 | int open; | |
8794 | + char *name; | |
8795 | ||
8796 | struct input_dev *dev; | |
8797 | struct input_handler *handler; | |
8798 | @@ -713,6 +813,9 @@ | |
8799 | int input_open_device(struct input_handle *); | |
8800 | void input_close_device(struct input_handle *); | |
8801 | ||
8802 | +int input_accept_process(struct input_handle *handle, struct file *file); | |
8803 | +int input_flush_device(struct input_handle* handle, struct file* file); | |
8804 | + | |
8805 | devfs_handle_t input_register_minor(char *name, int minor, int minor_base); | |
8806 | void input_unregister_minor(devfs_handle_t handle); | |
8807 | ||
8808 | @@ -721,6 +824,8 @@ | |
8809 | #define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c)) | |
8810 | #define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) | |
8811 | #define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) | |
8812 | +#define input_report_ff(a,b,c) input_event(a, EV_FF, b, c) | |
8813 | +#define input_report_ff_status(a,b,c) input_event(a, EV_FF_STATUS, b, c) | |
8814 | ||
8815 | #endif | |
8816 | #endif | |
8817 | diff -u -N -r --exclude=*.rej --exclude=CVS --exclude=.* --exclude=*~ linux-vanilla/include/linux/serio.h linux-modified/include/linux/serio.h | |
8818 | --- linux-vanilla/include/linux/serio.h Fri Nov 29 01:53:15 2002 | |
8819 | +++ linux-modified/include/linux/serio.h Mon Jan 13 22:42:43 2003 | |
8820 | @@ -2,38 +2,38 @@ | |
8821 | #define _SERIO_H | |
8822 | ||
8823 | /* | |
8824 | - * $Id$ | |
8825 | + * $Id$ | |
8826 | * | |
8827 | - * Copyright (C) 1999 Vojtech Pavlik | |
8828 | - * | |
8829 | - * Sponsored by SuSE | |
8830 | + * Copyright (C) 1999-2001 Vojtech Pavlik | |
8831 | */ | |
8832 | ||
8833 | /* | |
8834 | * This program is free software; you can redistribute it and/or modify | |
8835 | * it under the terms of the GNU General Public License as published by | |
8836 | - * the Free Software Foundation; either version 2 of the License, or | |
8837 | + * the Free Software Foundation; either version 2 of the License, or | |
8838 | * (at your option) any later version. | |
8839 | - * | |
8840 | + * | |
8841 | * This program is distributed in the hope that it will be useful, | |
8842 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
8843 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
8844 | * GNU General Public License for more details. | |
8845 | - * | |
8846 | + * | |
8847 | * You should have received a copy of the GNU General Public License | |
8848 | * along with this program; if not, write to the Free Software | |
8849 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
8850 | - * | |
8851 | + * | |
8852 | * Should you need to contact me, the author, you can do so either by | |
8853 | * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail: | |
8854 | - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic | |
8855 | + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic | |
8856 | */ | |
8857 | ||
8858 | /* | |
8859 | * The serial port set type ioctl. | |
8860 | */ | |
8861 | ||
8862 | +#include <asm/errno.h> | |
8863 | #include <linux/ioctl.h> | |
8864 | + | |
8865 | #define SPIOCSTYPE _IOW('q', 0x01, unsigned long) | |
8866 | ||
8867 | struct serio; | |
8868 | @@ -42,23 +42,30 @@ | |
8869 | ||
8870 | void *private; | |
8871 | void *driver; | |
8872 | + char *name; | |
8873 | + char *phys; | |
8874 | + | |
8875 | + unsigned short idbus; | |
8876 | + unsigned short idvendor; | |
8877 | + unsigned short idproduct; | |
8878 | + unsigned short idversion; | |
8879 | ||
8880 | unsigned long type; | |
8881 | - int number; | |
8882 | ||
8883 | int (*write)(struct serio *, unsigned char); | |
8884 | int (*open)(struct serio *); | |
8885 | void (*close)(struct serio *); | |
8886 | ||
8887 | struct serio_dev *dev; | |
8888 | - | |
8889 | struct serio *next; | |
8890 | }; | |
8891 | ||
8892 | struct serio_dev { | |
8893 | ||
8894 | void *private; | |
8895 | + char *name; | |
8896 | ||
8897 | + void (*write_wakeup)(struct serio *); | |
8898 | void (*interrupt)(struct serio *, unsigned char, unsigned int); | |
8899 | void (*connect)(struct serio *, struct serio_dev *dev); | |
8900 | void (*disconnect)(struct serio *); | |
8901 | @@ -77,7 +84,14 @@ | |
8902 | ||
8903 | static __inline__ int serio_write(struct serio *serio, unsigned char data) | |
8904 | { | |
8905 | - return serio->write(serio, data); | |
8906 | + return serio->write?serio->write(serio, data):-ENOSYS; | |
8907 | +} | |
8908 | + | |
8909 | +static __inline__ void serio_dev_write_wakeup(struct serio *serio) | |
8910 | +{ | |
8911 | + if (serio->dev && serio->dev->write_wakeup) { | |
8912 | + serio->dev->write_wakeup(serio); | |
8913 | + } | |
8914 | } | |
8915 | ||
8916 | #define SERIO_TIMEOUT 1 | |
8917 | @@ -109,6 +123,8 @@ | |
8918 | #define SERIO_STOWAWAY 0x20 | |
8919 | #define SERIO_H3600 0x21 | |
8920 | #define SERIO_PS2SER 0x22 | |
8921 | +#define SERIO_TWIDKBD 0x23 | |
8922 | +#define SERIO_TWIDJOY 0x24 | |
8923 | #define SERIO_HIL 0x25 | |
8924 | ||
8925 | #define SERIO_ID 0xff00UL |