diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/Documentation/input/ff.txt linux-modified/Documentation/input/ff.txt --- linux-vanilla/Documentation/input/ff.txt 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/Documentation/input/ff.txt 2003-07-21 23:08:09.000000000 +0200 @@ -1,6 +1,7 @@ Force feedback for Linux. By Johann Deneux on 2001/04/22. - +You may redistribute this file. Please remember to include shape.fig and +interactive.fig as well. ---------------------------------------------------------------------------- 0. Introduction @@ -38,13 +39,10 @@ You then need to insert the modules into the following order: % modprobe joydev -% modprobe serport +% modprobe serport # Only for serial % modprobe iforce % modprobe evdev % ./inputattach -ifor $2 & # Only for serial -For convenience, you may use the shell script named "ff" available from -the cvs tree of the Linux Console Project at sourceforge. You can also -retrieve it from http://www.esil.univ-mrs.fr/~jdeneux/projects/ff/. If you are using USB, you don't need the inputattach step. Please check that you have all the /dev/input entries needed: @@ -68,7 +66,7 @@ 2.1 Does it work ? ~~~~~~~~~~~~~~~~~~ There is an utility called fftest that will allow you to test the driver. -% fftest /dev/eventXX +% fftest /dev/input/eventXX 3. Instructions to the developper ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -81,22 +79,30 @@ #include #include +unsigned long features[1 + FF_MAX/sizeof(unsigned long)]; int ioctl(int file_descriptor, int request, unsigned long *features); -"request" must be EVIOCGBIT(EV_FF, sizeof(unsigned long)) +"request" must be EVIOCGBIT(EV_FF, size of features array in bytes ) Returns the features supported by the device. features is a bitfield with the following bits: -- FF_X has an X axis (should allways be the case) -- FF_Y has an Y axis (usually not the case for wheels) +- FF_X has an X axis (usually joysticks) +- FF_Y has an Y axis (usually joysticks) +- FF_WHEEL has a wheel (usually sterring wheels) - FF_CONSTANT can render constant force effects -- FF_PERIODIC can render periodic effects (sine, ramp, square...) +- FF_PERIODIC can render periodic effects (sine, triangle, square...) +- FF_RAMP can render ramp effects - FF_SPRING can simulate the presence of a spring -- FF_FRICTION can simulate friction (aka drag, damper effect...) +- FF_FRICTION can simulate friction +- FF_DAMPER can simulate damper effects - FF_RUMBLE rumble effects (normally the only effect supported by rumble pads) -- 8 bits from FF_N_EFFECTS_0 containing the number of effects that can be - simultaneously played. +- FF_INERTIA can simulate inertia + + +int ioctl(int fd, EVIOCGEFFECTS, int *n); + +Returns the number of effects the device can keep in its memory. 3.2 Uploading effects to the device ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -112,7 +118,11 @@ The content of effect may be modified. In particular, its field "id" is set to the unique id assigned by the driver. This data is required for performing some operations (removing an effect, controlling the playback). -See for a description of the ff_effect stuct. +This if field must be set to -1 by the user in order to tell the driver to +allocate a new effect. +See for a description of the ff_effect stuct. You should also +find help in a few sketches, contained in files shape.fig and interactive.fig. +You need xfig to visualize these files. 3.3 Removing an effect from the device ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -187,8 +197,31 @@ 3.7 Dynamic update of an effect ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -This consists in changing some parameters of an effect while it's playing. The -driver currently does not support that. You still have the brute-force method, -which consists in erasing the effect and uploading the updated version. It -actually works pretty well. You don't need to stop-and-start the effect. +Proceed as if you wanted to upload a new effect, except that instead of +setting the id field to -1, you set it to the wanted effect id. +Normally, the effect is not stopped and restarted. However, depending on the +type of device, not all paramaters can be dynamically updated. For example, +the direction of an effect cannot be updated with iforce devices. In this +case, the driver stops the effect, up-load it, and restart it. + + +3.8 Information about the status of effects +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Every time the status of an effect is changed, an event is sent. The values +and meanings of the fields of the event are as follows: +struct input_event { +/* When the status of the effect changed */ + struct timeval time; + +/* Set to EV_FF_STATUS */ + unsigned short type; + +/* Contains the id of the effect */ + unsigned short code; + +/* Indicates the status */ + unsigned int value; +}; +FF_STATUS_STOPPED The effect stopped playing +FF_STATUS_PLAYING The effect started to play diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/Documentation/input/interactive.fig linux-modified/Documentation/input/interactive.fig --- linux-vanilla/Documentation/input/interactive.fig 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/Documentation/input/interactive.fig 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,42 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +2 1 0 2 0 7 50 0 -1 6.000 0 0 -1 0 0 6 + 1200 3600 1800 3600 2400 4800 3000 4800 4200 5700 4800 5700 +2 2 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 5 + 1200 3150 4800 3150 4800 6300 1200 6300 1200 3150 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 1200 4800 4800 4800 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4 + 2400 4800 2400 6525 1950 7125 1950 7800 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4 + 3000 4800 3000 6525 3600 7125 3600 7800 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3 + 0 0 1.00 60.00 120.00 + 3825 5400 4125 5100 5400 5100 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3 + 0 0 1.00 60.00 120.00 + 2100 4200 2400 3900 5400 3900 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 4800 5700 5400 5700 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 1800 3600 5400 3600 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 1 3 + 0 0 1.00 60.00 120.00 + 2700 4800 2700 4425 5400 4425 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 1950 7800 3600 7800 +4 1 0 50 0 0 12 0.0000 4 135 810 2775 7725 Dead band\001 +4 0 0 50 0 0 12 0.0000 4 180 1155 5400 5700 right saturation\001 +4 0 0 50 0 0 12 0.0000 4 135 1065 5400 3600 left saturation\001 +4 0 0 50 0 0 12 0.0000 4 180 2505 5400 3900 left coeff ( positive in that case )\001 +4 0 0 50 0 0 12 0.0000 4 180 2640 5475 5100 right coeff ( negative in that case )\001 +4 0 0 50 0 0 12 0.0000 4 105 480 5400 4425 center\001 diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/Documentation/input/joystick.txt linux-modified/Documentation/input/joystick.txt --- linux-vanilla/Documentation/input/joystick.txt 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/Documentation/input/joystick.txt 2003-07-21 23:08:09.000000000 +0200 @@ -1,7 +1,7 @@ Linux Joystick driver v2.0.0 - (c) 1996-2000 Vojtech Pavlik + (c) 1996-2000 Vojtech Pavlik Sponsored by SuSE - $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ ---------------------------------------------------------------------------- 0. Disclaimer @@ -21,8 +21,8 @@ Temple Place, Suite 330, Boston, MA 02111-1307 USA Should you need to contact me, the author, you can do so either by e-mail -- mail your message to , or by paper mail: Vojtech Pavlik, -Ucitelska 1576, Prague 8, 182 00 Czech Republic +- mail your message to , or by paper mail: Vojtech Pavlik, +Simunkova 1594, Prague 8, 182 00 Czech Republic For your convenience, the GNU General Public License version 2 is included in the package: See the file COPYING. @@ -111,7 +111,7 @@ alias tty-ldisc-2 serport alias char-major-13 input above input joydev ns558 analog - options analog js=gameport + options analog js=gamepad 2.5 Verifying that it works ~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -503,15 +503,16 @@ 3.21 I-Force devices ~~~~~~~~~~~~~~~~~~~~ - All I-Force devices are supported by the iforce.c module. This includes: + All I-Force devices are supported by the iforce.o module. This includes: * AVB Mag Turbo Force * AVB Top Shot Pegasus +* AVB Top Shot Force Feedback Racing Wheel * Logitech WingMan Force -* Logitech WingMan Force 3D * Logitech WingMan Force Wheel -* Logitech WingMan Strike Force 3D * Guillemot Race Leader Force Feedback +* Guillemot Force Feedback Racing Wheel +* Thrustmaster Motor Sport GT To use it, you need to attach the serial port to the driver using the @@ -525,6 +526,10 @@ The I-Force driver now supports force feedback via the event interface. + Please note that Logitech WingMan *3D devices are _not_ supported by this +module, rather by hid. Force feedback is not supported for those devices. +Logitech gamepads are also hid devices. + 3.22 Gravis Stinger gamepad ~~~~~~~~~~~~~~~~~~~~~~~~~~~ The Gravis Stinger serial port gamepad, designed for use with laptop diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/Documentation/input/shape.fig linux-modified/Documentation/input/shape.fig --- linux-vanilla/Documentation/input/shape.fig 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/Documentation/input/shape.fig 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,65 @@ +#FIG 3.2 +Landscape +Center +Inches +Letter +100.00 +Single +-2 +1200 2 +2 1 0 2 0 7 50 0 -1 0.000 0 0 -1 0 0 6 + 4200 3600 4200 3075 4950 2325 7425 2325 8250 3150 8250 3600 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 4200 3675 4200 5400 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 8250 3675 8250 5400 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 3675 3600 8700 3600 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 8775 3600 10200 3600 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 8325 3150 9075 3150 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 7500 2325 10200 2325 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 3600 3600 3000 3600 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 4125 3075 3000 3075 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 4200 5400 8175 5400 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 10125 2325 10125 3600 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 3000 3150 3000 3600 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 9075 3150 9075 3600 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 4950 2325 4950 1200 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 2 + 7425 2325 7425 1200 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4 + 4200 3075 4200 2400 3600 1800 3600 1200 +2 1 1 1 0 7 50 0 -1 4.000 0 0 -1 0 0 4 + 8250 3150 8250 2475 8775 1950 8775 1200 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 3600 1275 4950 1275 +2 1 0 1 0 7 50 0 -1 4.000 0 0 -1 1 1 2 + 0 0 1.00 60.00 120.00 + 0 0 1.00 60.00 120.00 + 7425 1275 8700 1275 +4 1 0 50 0 0 12 0.0000 4 135 1140 6075 5325 Effect duration\001 +4 0 0 50 0 0 12 0.0000 4 180 1305 10200 3000 Effect magnitude\001 +4 0 0 50 0 0 12 0.0000 4 135 780 9150 3450 Fade level\001 +4 1 0 50 0 0 12 0.0000 4 180 1035 4275 1200 Attack length\001 +4 1 0 50 0 0 12 0.0000 4 180 885 8175 1200 Fade length\001 +4 2 0 50 0 0 12 0.0000 4 135 930 2925 3375 Attack level\001 diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/Makefile linux-modified/Makefile --- linux-vanilla/Makefile 2003-06-13 16:51:39.000000000 +0200 +++ linux-modified/Makefile 2003-07-21 23:08:59.000000000 +0200 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 SUBLEVEL = 22 -EXTRAVERSION = +EXTRAVERSION = -ff KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/Config.in linux-modified/drivers/char/joystick/Config.in --- linux-vanilla/drivers/char/joystick/Config.in 2002-11-29 00:53:12.000000000 +0100 +++ linux-modified/drivers/char/joystick/Config.in 2003-07-21 23:08:09.000000000 +0200 @@ -32,8 +32,7 @@ dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT - dep_tristate ' I-Force USB joysticks and wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB - dep_tristate ' I-Force Serial joysticks and wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT $CONFIG_INPUT_SERIO + source drivers/char/joystick/iforce/Config.in dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_SERIO dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_SERIO dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_SERIO diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/Makefile linux-modified/drivers/char/joystick/Makefile --- linux-vanilla/drivers/char/joystick/Makefile 2002-11-29 00:53:12.000000000 +0100 +++ linux-modified/drivers/char/joystick/Makefile 2003-07-21 23:08:09.000000000 +0200 @@ -8,19 +8,6 @@ export-objs := serio.o gameport.o pcigame.o -# I-Force may need both USB and RS-232 - -ifeq ($(CONFIG_INPUT_IFORCE_232),m) - ifeq ($(CONFIG_INPUT_IFORCE_USB),y) - CONFIG_INPUT_IFORCE_USB := m - endif -endif -ifeq ($(CONFIG_INPUT_IFORCE_USB),m) - ifeq ($(CONFIG_INPUT_IFORCE_232),y) - CONFIG_INPUT_IFORCE_232 := m - endif -endif - # Object file lists. obj-y := @@ -46,8 +33,6 @@ obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o obj-$(CONFIG_INPUT_STINGER) += stinger.o -obj-$(CONFIG_INPUT_IFORCE_232) += iforce.o -obj-$(CONFIG_INPUT_IFORCE_USB) += iforce.o obj-$(CONFIG_INPUT_ANALOG) += analog.o obj-$(CONFIG_INPUT_A3D) += a3d.o @@ -65,6 +50,8 @@ obj-$(CONFIG_INPUT_AMIJOY) += amijoy.o +subdir-$(CONFIG_JOYSTICK_IFORCE) += iforce + # The global Rules.make. include $(TOPDIR)/Rules.make diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/a3d.c linux-modified/drivers/char/joystick/a3d.c --- linux-vanilla/drivers/char/joystick/a3d.c 2002-08-03 02:39:43.000000000 +0200 +++ linux-modified/drivers/char/joystick/a3d.c 2003-07-21 23:08:09.000000000 +0200 @@ -347,8 +347,8 @@ a3d->dev.idversion = 0x0100; input_register_device(&a3d->dev); - printk(KERN_INFO "input%d: %s on gameport%d.0\n", - a3d->dev.number, a3d_names[a3d->mode], gameport->number); + printk(KERN_INFO "input: %s on gameport%d.0\n", + a3d_names[a3d->mode], gameport->number); return; fail2: gameport_close(gameport); diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/adi.c linux-modified/drivers/char/joystick/adi.c --- linux-vanilla/drivers/char/joystick/adi.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/adi.c 2003-07-21 23:08:09.000000000 +0200 @@ -514,8 +514,8 @@ if (port->adi[i].length > 0) { adi_init_center(port->adi + i); input_register_device(&port->adi[i].dev); - printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n", - port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i); + printk(KERN_INFO "input: %s [%s] on gameport%d.%d\n", + port->adi[i].name, port->adi[i].cname, gameport->number, i); } } diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/analog.c linux-modified/drivers/char/joystick/analog.c --- linux-vanilla/drivers/char/joystick/analog.c 2002-11-29 00:53:12.000000000 +0100 +++ linux-modified/drivers/char/joystick/analog.c 2003-07-21 23:08:09.000000000 +0200 @@ -490,8 +490,8 @@ input_register_device(&analog->dev); - printk(KERN_INFO "input%d: %s at gameport%d.%d", - analog->dev.number, analog->name, port->gameport->number, index); + printk(KERN_INFO "input: %s at gameport%d.%d", + analog->name, port->gameport->number, index); if (port->cooked) printk(" [ADC port]\n"); diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/cobra.c linux-modified/drivers/char/joystick/cobra.c --- linux-vanilla/drivers/char/joystick/cobra.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/cobra.c 2003-07-21 23:08:09.000000000 +0200 @@ -208,8 +208,8 @@ cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1; input_register_device(cobra->dev + i); - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", - cobra->dev[i].number, cobra_name, gameport->number, i); + printk(KERN_INFO "input: %s on gameport%d.%d\n", + cobra_name, gameport->number, i); } diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/db9.c linux-modified/drivers/char/joystick/db9.c --- linux-vanilla/drivers/char/joystick/db9.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/db9.c 2003-07-21 23:08:09.000000000 +0200 @@ -362,8 +362,8 @@ db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1; input_register_device(db9->dev + i); - printk(KERN_INFO "input%d: %s on %s\n", - db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name); + printk(KERN_INFO "input: %s on %s\n", + db9_name[db9->mode], db9->pd->port->name); } return db9; diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/gamecon.c linux-modified/drivers/char/joystick/gamecon.c --- linux-vanilla/drivers/char/joystick/gamecon.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/gamecon.c 2003-07-21 23:08:09.000000000 +0200 @@ -608,7 +608,7 @@ for (i = 0; i < 5; i++) if (gc->pads[0] & gc_status_bit[i]) { input_register_device(gc->dev + i); - printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name); + printk(KERN_INFO "input: %s on %s\n", gc->dev[i].name, gc->pd->port->name); } return gc; diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/gf2k.c linux-modified/drivers/char/joystick/gf2k.c --- linux-vanilla/drivers/char/joystick/gf2k.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/gf2k.c 2003-07-21 23:08:09.000000000 +0200 @@ -323,8 +323,8 @@ } input_register_device(&gf2k->dev); - printk(KERN_INFO "input%d: %s on gameport%d.0\n", - gf2k->dev.number, gf2k_names[gf2k->id], gameport->number); + printk(KERN_INFO "input: %s on gameport%d.0\n", + gf2k_names[gf2k->id], gameport->number); return; fail2: gameport_close(gameport); diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/grip.c linux-modified/drivers/char/joystick/grip.c --- linux-vanilla/drivers/char/joystick/grip.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/grip.c 2003-07-21 23:08:09.000000000 +0200 @@ -382,8 +382,8 @@ input_register_device(grip->dev + i); - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", - grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i); + printk(KERN_INFO "input: %s on gameport%d.%d\n", + grip_name[grip->mode[i]], gameport->number, i); } return; diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/Config.help linux-modified/drivers/char/joystick/iforce/Config.help --- linux-vanilla/drivers/char/joystick/iforce/Config.help 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/Config.help 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,21 @@ +CONFIG_JOYSTICK_IFORCE + Say Y here if you have an I-Force joystick or steering wheel + + You also must choose at least one of the two options below. + + This driver is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you want). + The module will be called iforce.o. If you want to compile it as a + module, say M here and read . + +CONFIG_JOYSTICK_IFORCE_USB + Say Y here if you have an I-Force joystick or steering wheel + connected to your USB port. + +CONFIG_JOYSTICK_IFORCE_232 + Say Y here if you have an I-Force joystick or steering wheel + connected to your serial (COM) port. + + You will need an additional utility called inputattach, see + Documentation/input/joystick.txt and ff.txt. + diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/Config.in linux-modified/drivers/char/joystick/iforce/Config.in --- linux-vanilla/drivers/char/joystick/iforce/Config.in 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/Config.in 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,14 @@ +# +# I-Force driver configuration +# + +dep_tristate 'I-Force devices' CONFIG_JOYSTICK_IFORCE $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK + +if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_JOYSTICK_IFORCE" = "y" ]; then + if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_USB" = "y" ]; then + dep_mbool ' I-Force USB joysticks and wheels' CONFIG_JOYSTICK_IFORCE_USB $CONFIG_USB + fi + if [ "$CONFIG_JOYSTICK_IFORCE" = "m" -o "$CONFIG_INPUT_SERIO" = "y" ]; then + dep_mbool ' I-Force Serial joysticks and wheels' CONFIG_JOYSTICK_IFORCE_232 $CONFIG_INPUT_SERIO + fi +fi diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/Makefile linux-modified/drivers/char/joystick/iforce/Makefile --- linux-vanilla/drivers/char/joystick/iforce/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/Makefile 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,30 @@ +# +# Makefile for the I-Force driver +# +# By Johann Deneux +# + +# Goal definition +list-multi := iforce.o +iforce-objs := iforce-ff.o iforce-main.o iforce-packets.o + +obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o + +ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y) + iforce-objs += iforce-serio.o +endif + +ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y) + iforce-objs += iforce-usb.o +endif + +EXTRA_CFLAGS = -Werror-implicit-function-declaration + +# The global Rules.make. + +include $(TOPDIR)/Rules.make + +# Additional rules +iforce.o: $(iforce-objs) + $(LD) -r -o $@ $(iforce-objs) + diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/iforce-ff.c linux-modified/drivers/char/joystick/iforce/iforce-ff.c --- linux-vanilla/drivers/char/joystick/iforce/iforce-ff.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/iforce-ff.c 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,544 @@ +/* + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * + * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2001-2002 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +/* + * Set the magnitude of a constant force effect + * Return error code + * + * Note: caller must ensure exclusive access to device + */ + +static int make_magnitude_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, __s16 level) +{ + unsigned char data[3]; + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 2, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + data[2] = HIFIX80(level); + + iforce_send_packet(iforce, FF_CMD_MAGNITUDE, data); + +// iforce_dump_packet("magnitude: ", FF_CMD_MAGNITUDE, data); + return 0; +} + +/* + * Upload the component of an effect dealing with the period, phase and magnitude + */ + +static int make_period_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + __s16 magnitude, __s16 offset, u16 period, u16 phase) +{ + unsigned char data[7]; + + period = TIME_SCALE(period); + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = HIFIX80(magnitude); + data[3] = HIFIX80(offset); + data[4] = HI(phase); + + data[5] = LO(period); + data[6] = HI(period); + + iforce_send_packet(iforce, FF_CMD_PERIOD, data); + + return 0; +} + +/* + * Uploads the part of an effect setting the envelope of the force + */ + +static int make_envelope_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + u16 attack_duration, __s16 initial_level, + u16 fade_duration, __s16 final_level) +{ + unsigned char data[8]; + + attack_duration = TIME_SCALE(attack_duration); + fade_duration = TIME_SCALE(fade_duration); + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = LO(attack_duration); + data[3] = HI(attack_duration); + data[4] = HI(initial_level); + + data[5] = LO(fade_duration); + data[6] = HI(fade_duration); + data[7] = HI(final_level); + + iforce_send_packet(iforce, FF_CMD_ENVELOPE, data); + + return 0; +} + +/* + * Component of spring, friction, inertia... effects + */ + +static int make_condition_modifier(struct iforce* iforce, + struct resource* mod_chunk, int no_alloc, + __u16 rsat, __u16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center) +{ + unsigned char data[10]; + + if (!no_alloc) { + down(&iforce->mem_mutex); + if (allocate_resource(&(iforce->device_memory), mod_chunk, 8, + iforce->device_memory.start, iforce->device_memory.end, 2L, + NULL, NULL)) { + up(&iforce->mem_mutex); + return -ENOMEM; + } + up(&iforce->mem_mutex); + } + + data[0] = LO(mod_chunk->start); + data[1] = HI(mod_chunk->start); + + data[2] = (100*rk)>>15; /* Dangerous: the sign is extended by gcc on plateforms providing an arith shift */ + data[3] = (100*lk)>>15; /* This code is incorrect on cpus lacking arith shift */ + + center = (500*center)>>15; + data[4] = LO(center); + data[5] = HI(center); + + db = (1000*db)>>16; + data[6] = LO(db); + data[7] = HI(db); + + data[8] = (100*rsat)>>16; + data[9] = (100*lsat)>>16; + + iforce_send_packet(iforce, FF_CMD_CONDITION, data); +// iforce_dump_packet("condition", FF_CMD_CONDITION, data); + + return 0; +} + +static unsigned char find_button(struct iforce *iforce, signed short button) +{ + int i; + for (i = 1; iforce->type->btn[i] >= 0; i++) + if (iforce->type->btn[i] == button) + return i + 1; + return 0; +} + +/* + * Analyse the changes in an effect, and tell if we need to send an condition + * parameter packet + */ +static int need_condition_modifier(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + int ret=0; + int i; + + if (new->type != FF_SPRING && new->type != FF_FRICTION) { + printk(KERN_WARNING "iforce.c: bad effect type in need_condition_modifier\n"); + return FALSE; + } + + for(i=0; i<2; i++) { + ret |= old->u.condition[i].right_saturation != new->u.condition[i].right_saturation + || old->u.condition[i].left_saturation != new->u.condition[i].left_saturation + || old->u.condition[i].right_coeff != new->u.condition[i].right_coeff + || old->u.condition[i].left_coeff != new->u.condition[i].left_coeff + || old->u.condition[i].deadband != new->u.condition[i].deadband + || old->u.condition[i].center != new->u.condition[i].center; + } + return ret; +} + +/* + * Analyse the changes in an effect, and tell if we need to send a magnitude + * parameter packet + */ +static int need_magnitude_modifier(struct iforce* iforce, struct ff_effect* effect) +{ + int id = effect->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (effect->type != FF_CONSTANT) { + printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); + return FALSE; + } + + return (old->u.constant.level != effect->u.constant.level); +} + +/* + * Analyse the changes in an effect, and tell if we need to send an envelope + * parameter packet + */ +static int need_envelope_modifier(struct iforce* iforce, struct ff_effect* effect) +{ + int id = effect->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + switch (effect->type) { + case FF_CONSTANT: + if (old->u.constant.envelope.attack_length != effect->u.constant.envelope.attack_length + || old->u.constant.envelope.attack_level != effect->u.constant.envelope.attack_level + || old->u.constant.envelope.fade_length != effect->u.constant.envelope.fade_length + || old->u.constant.envelope.fade_level != effect->u.constant.envelope.fade_level) + return TRUE; + break; + + case FF_PERIODIC: + if (old->u.periodic.envelope.attack_length != effect->u.periodic.envelope.attack_length + || old->u.periodic.envelope.attack_level != effect->u.periodic.envelope.attack_level + || old->u.periodic.envelope.fade_length != effect->u.periodic.envelope.fade_length + || old->u.periodic.envelope.fade_level != effect->u.periodic.envelope.fade_level) + return TRUE; + break; + + default: + printk(KERN_WARNING "iforce.c: bad effect type in need_envelope_modifier\n"); + } + + return FALSE; +} + +/* + * Analyse the changes in an effect, and tell if we need to send a periodic + * parameter effect + */ +static int need_period_modifier(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (new->type != FF_PERIODIC) { + printk(KERN_WARNING "iforce.c: bad effect type in need_periodic_modifier\n"); + return FALSE; + } + + return (old->u.periodic.period != new->u.periodic.period + || old->u.periodic.magnitude != new->u.periodic.magnitude + || old->u.periodic.offset != new->u.periodic.offset + || old->u.periodic.phase != new->u.periodic.phase); +} + +/* + * Analyse the changes in an effect, and tell if we need to send an effect + * packet + */ +static int need_core(struct iforce* iforce, struct ff_effect* new) +{ + int id = new->id; + struct ff_effect* old = &iforce->core_effects[id].effect; + + if (old->direction != new->direction + || old->trigger.button != new->trigger.button + || old->trigger.interval != new->trigger.interval + || old->replay.length != new->replay.length + || old->replay.delay != new->replay.delay) + return TRUE; + + return FALSE; +} +/* + * Send the part common to all effects to the device + */ +static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2, + u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button, + u16 interval, u16 direction) +{ + unsigned char data[14]; + + duration = TIME_SCALE(duration); + delay = TIME_SCALE(delay); + interval = TIME_SCALE(interval); + + data[0] = LO(id); + data[1] = effect_type; + data[2] = LO(axes) | find_button(iforce, button); + + if (!duration) duration = 0xFFFF; + data[3] = LO(duration); + data[4] = HI(duration); + + data[5] = HI(direction); + + data[6] = LO(interval); + data[7] = HI(interval); + + data[8] = LO(mod_id1); + data[9] = HI(mod_id1); + data[10] = LO(mod_id2); + data[11] = HI(mod_id2); + + data[12] = LO(delay); + data[13] = HI(delay); + + /* Stop effect */ +/* iforce_control_playback(iforce, id, 0);*/ + + iforce_send_packet(iforce, FF_CMD_EFFECT, data); + + /* If needed, restart effect */ + if (test_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[id].flags)) { + /* BUG: perhaps we should replay n times, instead of 1. But we do not know n */ + iforce_control_playback(iforce, id, 1); + } + + return 0; +} + +/* + * Upload a periodic effect to the device + * See also iforce_upload_constant. + */ +int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + u8 wave_code; + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); + struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); + int param1_err = 1; + int param2_err = 1; + int core_err = 0; + + if (!is_update || need_period_modifier(iforce, effect)) { + param1_err = make_period_modifier(iforce, mod1_chunk, + is_update, + effect->u.periodic.magnitude, effect->u.periodic.offset, + effect->u.periodic.period, effect->u.periodic.phase); + if (param1_err) return param1_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + } + + if (!is_update || need_envelope_modifier(iforce, effect)) { + param2_err = make_envelope_modifier(iforce, mod2_chunk, + is_update, + effect->u.periodic.envelope.attack_length, + effect->u.periodic.envelope.attack_level, + effect->u.periodic.envelope.fade_length, + effect->u.periodic.envelope.fade_level); + if (param2_err) return param2_err; + set_bit(FF_MOD2_IS_USED, core_effect->flags); + } + + switch (effect->u.periodic.waveform) { + case FF_SQUARE: wave_code = 0x20; break; + case FF_TRIANGLE: wave_code = 0x21; break; + case FF_SINE: wave_code = 0x22; break; + case FF_SAW_UP: wave_code = 0x23; break; + case FF_SAW_DOWN: wave_code = 0x24; break; + default: wave_code = 0x20; break; + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1_chunk->start, + mod2_chunk->start, + wave_code, + 0x20, + effect->replay.length, + effect->replay.delay, + effect->trigger.button, + effect->trigger.interval, + effect->direction); + } + + /* If one of the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if one parameter at least was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : (param1_err && param2_err); +} + +/* + * Upload a constant force effect + * Return value: + * <0 Error code + * 0 Ok, effect created or updated + * 1 effect did not change since last upload, and no packet was therefore sent + */ +int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk); + struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk); + int param1_err = 1; + int param2_err = 1; + int core_err = 0; + + if (!is_update || need_magnitude_modifier(iforce, effect)) { + param1_err = make_magnitude_modifier(iforce, mod1_chunk, + is_update, + effect->u.constant.level); + if (param1_err) return param1_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + } + + if (!is_update || need_envelope_modifier(iforce, effect)) { + param2_err = make_envelope_modifier(iforce, mod2_chunk, + is_update, + effect->u.constant.envelope.attack_length, + effect->u.constant.envelope.attack_level, + effect->u.constant.envelope.fade_length, + effect->u.constant.envelope.fade_level); + if (param2_err) return param2_err; + set_bit(FF_MOD2_IS_USED, core_effect->flags); + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1_chunk->start, + mod2_chunk->start, + 0x00, + 0x20, + effect->replay.length, + effect->replay.delay, + effect->trigger.button, + effect->trigger.interval, + effect->direction); + } + + /* If one of the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if one parameter at least was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : (param1_err && param2_err); +} + +/* + * Upload an condition effect. Those are for example friction, inertia, springs... + */ +int iforce_upload_condition(struct iforce* iforce, struct ff_effect* effect, int is_update) +{ + int core_id = effect->id; + struct iforce_core_effect* core_effect = iforce->core_effects + core_id; + struct resource* mod1_chunk = &(core_effect->mod1_chunk); + struct resource* mod2_chunk = &(core_effect->mod2_chunk); + u8 type; + int param_err = 1; + int core_err = 0; + + switch (effect->type) { + case FF_SPRING: type = 0x40; break; + case FF_DAMPER: type = 0x41; break; + default: return -1; + } + + if (!is_update || need_condition_modifier(iforce, effect)) { + param_err = make_condition_modifier(iforce, mod1_chunk, + is_update, + effect->u.condition[0].right_saturation, + effect->u.condition[0].left_saturation, + effect->u.condition[0].right_coeff, + effect->u.condition[0].left_coeff, + effect->u.condition[0].deadband, + effect->u.condition[0].center); + if (param_err) return param_err; + set_bit(FF_MOD1_IS_USED, core_effect->flags); + + param_err = make_condition_modifier(iforce, mod2_chunk, + is_update, + effect->u.condition[1].right_saturation, + effect->u.condition[1].left_saturation, + effect->u.condition[1].right_coeff, + effect->u.condition[1].left_coeff, + effect->u.condition[1].deadband, + effect->u.condition[1].center); + if (param_err) return param_err; + set_bit(FF_MOD2_IS_USED, core_effect->flags); + + } + + if (!is_update || need_core(iforce, effect)) { + core_err = make_core(iforce, effect->id, + mod1_chunk->start, mod2_chunk->start, + type, 0xc0, + effect->replay.length, effect->replay.delay, + effect->trigger.button, effect->trigger.interval, + effect->direction); + } + + /* If the parameter creation failed, we already returned an + * error code. + * If the core creation failed, we return its error code. + * Else: if a parameter was created, we return 0 + * else we return 1; + */ + return core_err < 0 ? core_err : param_err; +} diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/iforce-main.c linux-modified/drivers/char/joystick/iforce/iforce-main.c --- linux-vanilla/drivers/char/joystick/iforce/iforce-main.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/iforce-main.c 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,562 @@ +/* + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * + * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2001-2002 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +MODULE_AUTHOR("Vojtech Pavlik , Johann Deneux "); +MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver"); +MODULE_LICENSE("GPL"); + +#define USB_VENDOR_ID_SAITEK 0x06a3 +#define USB_PRODUCT_ID_CYBORGFORCE 0xff12 + + +static signed short btn_joystick[] = +{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; + +static signed short btn_avb_pegasus[] = +{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; + +static signed short btn_wheel[] = +{ BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 }; + +static signed short btn_avb_tw[] = +{ BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, + BTN_BASE2, BTN_BASE3, BTN_BASE4, -1 }; + +static signed short btn_avb_wheel[] = +{ BTN_GEAR_DOWN, BTN_GEAR_UP, BTN_BASE, BTN_BASE2, BTN_BASE3, + BTN_BASE4, BTN_BASE5, BTN_BASE6, -1 }; + +static signed short abs_joystick[] = +{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 }; + +static signed short abs_avb_pegasus[] = +{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_HAT0X, ABS_HAT0Y, + ABS_HAT1X, ABS_HAT1Y, -1 }; + +static signed short abs_wheel[] = +{ ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 }; + +static signed short btn_saitek_joystick[] = +{ BTN_TRIGGER, BTN_TOP2, BTN_THUMB,BTN_THUMB2, BTN_TOP, + BTN_BASE, BTN_BASE2, BTN_BASE4, BTN_BASE3, -1 }; + +static signed short abs_saitek_joystick[] = +{ ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER,ABS_HAT0X, ABS_HAT0Y, -1 }; + + + +static signed short ff_iforce[] = +{ FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_DAMPER, + FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, + FF_AUTOCENTER, -1 }; + +static struct iforce_device iforce_device[] = { + { 0x044f, 0xa01c, "Thrustmaster Motor Sport GT", btn_wheel, abs_wheel, ff_iforce }, + { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce }, + { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce }, + { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_avb_pegasus, abs_avb_pegasus, ff_iforce }, + { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_avb_wheel, abs_wheel, ff_iforce }, + { 0x05ef, 0x8888, "AVB Top Shot Force Feedback Racing Wheel", btn_avb_tw, abs_wheel, ff_iforce }, //? + { 0x061c, 0xc084, "ACT LABS Force RS", btn_wheel, abs_wheel, ff_iforce }, //? + { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce }, //? + { 0x06f8, 0x0004, "Guillemot Force Feedback Racing Wheel", btn_wheel, abs_wheel, ff_iforce }, //? + { 0x06a3, 0xff12, "Saitek Cyborgforce", btn_saitek_joystick, abs_saitek_joystick, ff_iforce }, + { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce } +}; + + + +static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + unsigned char data[3]; + + if (type != EV_FF) + return -1; + + switch (code) { + + case FF_GAIN: + + data[0] = value >> 9; + iforce_send_packet(iforce, FF_CMD_GAIN, data); + + return 0; + + case FF_AUTOCENTER: + + data[0] = 0x03; + data[1] = value >> 9; + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); + + data[0] = 0x04; + data[1] = 0x01; + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, data); + + return 0; + + default: /* Play or stop an effect */ + + if (value > 0) { + set_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); + } + else { + clear_bit(FF_CORE_SHOULD_PLAY, iforce->core_effects[code].flags); + } + + iforce_control_playback(iforce, code, value); + return 0; + } + + return -1; +} + +/* + * Function called when an ioctl is performed on the event dev entry. + * It uploads an effect to the device + */ +static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + int id; + int ret; + int is_update; + +/* Check this effect type is supported by this device */ + if (!test_bit(effect->type, iforce->dev.ffbit)) + return -EINVAL; + +/* + * If we want to create a new effect, get a free id + */ + if (effect->id == -1) { + + for (id=0; id < FF_EFFECTS_MAX; ++id) + if (!test_and_set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break; + + if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max) + return -ENOMEM; + + effect->id = id; + iforce->core_effects[id].owner = current->pid; + iforce->core_effects[id].flags[0] = (1<type != iforce->core_effects[effect->id].effect.type) + return -EINVAL; + + /* Check the effect is not already being updated */ + if (test_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags)) { + return -EAGAIN; + } + + is_update = TRUE; + } + +/* + * Upload the effect + */ + switch (effect->type) { + + case FF_PERIODIC: + ret = iforce_upload_periodic(iforce, effect, is_update); + break; + + case FF_CONSTANT: + ret = iforce_upload_constant(iforce, effect, is_update); + break; + + case FF_SPRING: + case FF_DAMPER: + ret = iforce_upload_condition(iforce, effect, is_update); + break; + + default: + return -EINVAL; + } + if (ret == 0) { + /* A packet was sent, forbid new updates until we are notified + * that the packet was updated + */ + set_bit(FF_CORE_UPDATE, iforce->core_effects[effect->id].flags); + } + iforce->core_effects[effect->id].effect = *effect; + return ret; +} + +/* + * Erases an effect: it frees the effect id and mark as unused the memory + * allocated for the parameters + */ +static int iforce_erase_effect(struct input_dev *dev, int effect_id) +{ + struct iforce* iforce = (struct iforce*)(dev->private); + int err = 0; + struct iforce_core_effect* core_effect; + + if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX) + return -EINVAL; + + core_effect = iforce->core_effects + effect_id; + + if (test_bit(FF_MOD1_IS_USED, core_effect->flags)) + err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk)); + + if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags)) + err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk)); + + /*TODO: remember to change that if more FF_MOD* bits are added */ + core_effect->flags[0] = 0; + + return err; +} + +static int iforce_open(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + + switch (iforce->bus) { +#ifdef CONFIG_JOYSTICK_IFORCE_USB + case IFORCE_USB: + iforce->irq->dev = iforce->usbdev; + if (usb_submit_urb(iforce->irq)) + return -EIO; + break; +#endif + } + + /* Enable force feedback */ + iforce_send_packet(iforce, FF_CMD_ENABLE, "\004"); + + return 0; +} + +static int iforce_flush(struct input_dev *dev, struct file *file) +{ + struct iforce *iforce = dev->private; + int i; + + /* Erase all effects this process owns */ + for (i=0; iff_effects_max; ++i) { + + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && + current->pid == iforce->core_effects[i].owner) { + + /* Stop effect */ + input_report_ff(dev, i, 0); + + /* Free ressources assigned to effect */ + if (iforce_erase_effect(dev, i)) { + printk(KERN_WARNING "iforce_flush: erase effect %d failed\n", i); + } + } + + } + return 0; +} + +static void iforce_release(struct input_dev *dev) +{ + struct iforce *iforce = dev->private; + int i; + + /* Check: no effect should be present in memory */ + for (i=0; iff_effects_max; ++i) { + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags)) + break; + } + if (iff_effects_max) { + printk(KERN_WARNING "iforce_release: Device still owns effects\n"); + } + + /* Disable force feedback playback */ + iforce_send_packet(iforce, FF_CMD_ENABLE, "\001"); + + switch (iforce->bus) { +#ifdef CONFIG_JOYSTICK_IFORCE_USB + case IFORCE_USB: + usb_unlink_urb(iforce->irq); + + /* The device was unplugged before the file + * was released */ + if (iforce->usbdev == NULL) { + iforce_delete_device(iforce); + kfree(iforce); + } + break; +#endif + } +} + +void iforce_delete_device(struct iforce *iforce) +{ + switch (iforce->bus) { +#ifdef CONFIG_JOYSTICK_IFORCE_USB + case IFORCE_USB: + iforce_usb_delete(iforce); + break; +#endif +#ifdef CONFIG_JOYSTICK_IFORCE_232 + case IFORCE_232: + //TODO: Wait for the last packets to be sent + break; +#endif + } +} + +int iforce_init_device(struct iforce *iforce) +{ + unsigned char c[] = "CEOV"; + int i; + + init_waitqueue_head(&iforce->wait); + spin_lock_init(&iforce->xmit_lock); + init_MUTEX(&iforce->mem_mutex); + iforce->xmit.buf = iforce->xmit_data; + + iforce->dev.ff_effects_max = 10; + +/* + * Input device fields. + */ + + iforce->dev.idbus = BUS_USB; + iforce->dev.private = iforce; + iforce->dev.name = "Unknown I-Force device"; + iforce->dev.open = iforce_open; + iforce->dev.close = iforce_release; + iforce->dev.flush = iforce_flush; + iforce->dev.event = iforce_input_event; + iforce->dev.upload_effect = iforce_upload_effect; + iforce->dev.erase_effect = iforce_erase_effect; + +/* + * On-device memory allocation. + */ + + iforce->device_memory.name = "I-Force device effect memory"; + iforce->device_memory.start = 0; + iforce->device_memory.end = 200; + iforce->device_memory.flags = IORESOURCE_MEM; + iforce->device_memory.parent = NULL; + iforce->device_memory.child = NULL; + iforce->device_memory.sibling = NULL; + +/* + * Wait until device ready - until it sends its first response. + */ + + for (i = 0; i < 20; i++) + if (!iforce_get_id_packet(iforce, "O")) + break; + + if (i == 20) { /* 5 seconds */ + printk(KERN_ERR "iforce-main.c: Timeout waiting for response from device.\n"); + return -1; + } + +/* + * Get device info. + */ + + if (!iforce_get_id_packet(iforce, "M")) + iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1]; + else + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet M\n"); + + if (!iforce_get_id_packet(iforce, "P")) + iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1]; + else + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet P\n"); + + if (!iforce_get_id_packet(iforce, "B")) + iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1]; + else + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet B\n"); + + if (!iforce_get_id_packet(iforce, "N")) + iforce->dev.ff_effects_max = iforce->edata[1]; + else + printk(KERN_WARNING "iforce-main.c: Device does not respond to id packet N\n"); + + /* Check if the device can store more effects than the driver can really handle */ + if (iforce->dev.ff_effects_max > FF_EFFECTS_MAX) { + printk(KERN_WARNING "input??: Device can handle %d effects, but N_EFFECTS_MAX is set to %d in iforce.h\n", + iforce->dev.ff_effects_max, FF_EFFECTS_MAX); + iforce->dev.ff_effects_max = FF_EFFECTS_MAX; + } + +/* + * Display additional info. + */ + + for (i = 0; c[i]; i++) + if (!iforce_get_id_packet(iforce, c + i)) + iforce_dump_packet("info", iforce->ecmd, iforce->edata); + +/* + * Disable spring, enable force feedback. + * FIXME: We should use iforce_set_autocenter() et al here. + */ + + iforce_send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000"); + +/* + * Find appropriate device entry + */ + + for (i = 0; iforce_device[i].idvendor; i++) + if (iforce_device[i].idvendor == iforce->dev.idvendor && + iforce_device[i].idproduct == iforce->dev.idproduct) + break; + + iforce->type = iforce_device + i; + iforce->dev.name = iforce->type->name; + +/* + * Set input device bitfields and ranges. + */ + + iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF) | BIT(EV_FF_STATUS); + + for (i = 0; iforce->type->btn[i] >= 0; i++) { + signed short t = iforce->type->btn[i]; + set_bit(t, iforce->dev.keybit); + } + set_bit(BTN_DEAD, iforce->dev.keybit); + + for (i = 0; iforce->type->abs[i] >= 0; i++) { + + signed short t = iforce->type->abs[i]; + set_bit(t, iforce->dev.absbit); + + switch (t) { + + case ABS_X: + case ABS_Y: + case ABS_WHEEL: + if (iforce->dev.idvendor == USB_VENDOR_ID_SAITEK && iforce->dev.idproduct == USB_PRODUCT_ID_CYBORGFORCE) + { + iforce->dev.absmax[t] = 0x1000; + iforce->dev.absmin[t] = 0; + } + else { + iforce->dev.absmax[t] = 1920; + iforce->dev.absmin[t] = -1920; + } + iforce->dev.absflat[t] = 128; + iforce->dev.absfuzz[t] = 16; + set_bit(t, iforce->dev.ffbit); + break; + + case ABS_THROTTLE: + case ABS_GAS: + case ABS_BRAKE: + + iforce->dev.absmax[t] = 255; + iforce->dev.absmin[t] = 0; + break; + + case ABS_RUDDER: + if (iforce->dev.idvendor == USB_VENDOR_ID_SAITEK && iforce->dev.idproduct == USB_PRODUCT_ID_CYBORGFORCE) + { + iforce->dev.absmax[t] = 255; + iforce->dev.absmin[t] = 0; + iforce->dev.absflat[t] = 10; + iforce->dev.absfuzz[t] = 4; + + } + else + { + iforce->dev.absmax[t] = 127; + iforce->dev.absmin[t] = -128; + + } + break; + + case ABS_HAT0X: + case ABS_HAT0Y: + case ABS_HAT1X: + case ABS_HAT1Y: + iforce->dev.absmax[t] = 1; + iforce->dev.absmin[t] = -1; + break; + } + } + + for (i = 0; iforce->type->ff[i] >= 0; i++) + set_bit(iforce->type->ff[i], iforce->dev.ffbit); + +/* + * Register input device. + */ + + input_register_device(&iforce->dev); + + printk(KERN_DEBUG "iforce->dev.open = %p\n", iforce->dev.open); + + printk(KERN_INFO "input: %s [%d effects, %ld bytes memory]\n", + iforce->dev.name, iforce->dev.ff_effects_max, + iforce->device_memory.end); + + return 0; +} + +static int __init iforce_init(void) +{ +#ifdef CONFIG_JOYSTICK_IFORCE_USB + usb_register(&iforce_usb_driver); +#endif +#ifdef CONFIG_JOYSTICK_IFORCE_232 + serio_register_device(&iforce_serio_dev); +#endif + return 0; +} + +static void __exit iforce_exit(void) +{ +#ifdef CONFIG_JOYSTICK_IFORCE_USB + usb_deregister(&iforce_usb_driver); +#endif +#ifdef CONFIG_JOYSTICK_IFORCE_232 + serio_unregister_device(&iforce_serio_dev); +#endif +} + +module_init(iforce_init); +module_exit(iforce_exit); diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/iforce-packets.c linux-modified/drivers/char/joystick/iforce/iforce-packets.c --- linux-vanilla/drivers/char/joystick/iforce/iforce-packets.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/iforce-packets.c 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,320 @@ +/* + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * + * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2001-2002 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +static struct { + __s32 x; + __s32 y; +} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}}; + + +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) +{ + int i; + + printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd); + for (i = 0; i < LO(cmd); i++) + printk("%02x ", data[i]); + printk(")\n"); +} + +/* + * Send a packet of bytes to the device + */ +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data) +{ + /* Copy data to buffer */ + int n = LO(cmd); + int c; + int empty; + int head, tail; + unsigned long flags; + +/* + * Update head and tail of xmit buffer + */ + spin_lock_irqsave(&iforce->xmit_lock, flags); + + head = iforce->xmit.head; + tail = iforce->xmit.tail; + + if (CIRC_SPACE(head, tail, XMIT_SIZE) < n+2) { + printk(KERN_WARNING "iforce.c: not enough space in xmit buffer to send new packet\n"); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return -1; + } + + empty = head == tail; + XMIT_INC(iforce->xmit.head, n+2); + +/* + * Store packet in xmit buffer + */ + iforce->xmit.buf[head] = HI(cmd); + XMIT_INC(head, 1); + iforce->xmit.buf[head] = LO(cmd); + XMIT_INC(head, 1); + + c = CIRC_SPACE_TO_END(head, tail, XMIT_SIZE); + if (n < c) c=n; + + memcpy(&iforce->xmit.buf[head], + data, + c); + if (n != c) { + memcpy(&iforce->xmit.buf[0], + data + c, + n - c); + } + XMIT_INC(head, n); + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); +/* + * If necessary, start the transmission + */ + switch (iforce->bus) { + +#ifdef CONFIG_JOYSTICK_IFORCE_232 + case IFORCE_232: + if (empty) + iforce_serial_xmit(iforce); + break; +#endif +#ifdef CONFIG_JOYSTICK_IFORCE_USB + case IFORCE_USB: + + if (iforce->usbdev && empty && + !test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { + + iforce_usb_xmit(iforce); + } + break; +#endif + } + return 0; +} + +/* Start or stop an effect */ +int iforce_control_playback(struct iforce* iforce, u16 id, unsigned int value) +{ + unsigned char data[3]; + +//printk(KERN_DEBUG "iforce-packets.c: control_playback %d %d\n", id, value); + + data[0] = LO(id); + data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0; + data[2] = LO(value); + return iforce_send_packet(iforce, FF_CMD_PLAY, data); +} + +/* Mark an effect that was being updated as ready. That means it can be updated + * again */ +static int mark_core_as_ready(struct iforce *iforce, unsigned short addr) +{ + int i; + for (i=0; idev.ff_effects_max; ++i) { + if (test_bit(FF_CORE_IS_USED, iforce->core_effects[i].flags) && + (iforce->core_effects[i].mod1_chunk.start == addr || + iforce->core_effects[i].mod2_chunk.start == addr)) { + clear_bit(FF_CORE_UPDATE, iforce->core_effects[i].flags); + return 0; + } + } + printk(KERN_WARNING "iforce-packets.c: unused effect %04x updated !!!\n", addr); + return -1; +} + +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data) +{ + struct input_dev *dev = &iforce->dev; + int i; + static int being_used = 0; + + if (being_used) + printk(KERN_WARNING "iforce-packets.c: re-entrant call to iforce_process %d\n", being_used); + being_used++; + +#ifdef CONFIG_JOYSTICK_IFORCE_232 + if (HI(iforce->expect_packet) == HI(cmd)) { + iforce->expect_packet = 0; + iforce->ecmd = cmd; + memcpy(iforce->edata, data, IFORCE_MAX_LENGTH); + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); + } +#endif + + if (!iforce->type) { + being_used--; + return; + } + + switch (HI(cmd)) { + + case 0x01: /* joystick position data */ + case 0x03: /* wheel position data */ + case 0x06: /*saitek cyborgforve data */ + if (HI(cmd) == 6) { + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); + input_report_abs(dev, ABS_RUDDER, 255 - data[7]); + } + else if (HI(cmd) == 1) { + input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2])); + input_report_abs(dev, ABS_THROTTLE, 255 - data[4]); + if (LO(cmd) >= 8 && test_bit(ABS_RUDDER ,dev->absbit)) + input_report_abs(dev, ABS_RUDDER, (__s8)data[7]); + } else { + input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0])); + input_report_abs(dev, ABS_GAS, 255 - data[2]); + input_report_abs(dev, ABS_BRAKE, 255 - data[3]); + } + + input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x); + input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y); + + for (i = 0; iforce->type->btn[i] >= 0; i++) + input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7))); + + /* If there are untouched bits left, interpret them as the second hat */ + if (i <= 8) { + int btns = data[6]; + if (test_bit(ABS_HAT1X, dev->absbit)) { + if (btns & 8) input_report_abs(dev, ABS_HAT1X, -1); + else if (btns & 2) input_report_abs(dev, ABS_HAT1X, 1); + else input_report_abs(dev, ABS_HAT1X, 0); + } + if (test_bit(ABS_HAT1Y, dev->absbit)) { + if (btns & 1) input_report_abs(dev, ABS_HAT1Y, -1); + else if (btns & 4) input_report_abs(dev, ABS_HAT1Y, 1); + else input_report_abs(dev, ABS_HAT1Y, 0); + } + } + + break; + + case 0x02: /* status report */ + input_report_key(dev, BTN_DEAD, data[0] & 0x02); + + /* Check if an effect was just started or stopped */ + i = data[1] & 0x7f; + if (data[1] & 0x80) { + if (!test_and_set_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report play event */ + input_report_ff_status(dev, i, FF_STATUS_PLAYING); + } + } + else if (test_and_clear_bit(FF_CORE_IS_PLAYED, iforce->core_effects[i].flags)) { + /* Report stop event */ + input_report_ff_status(dev, i, FF_STATUS_STOPPED); + } + if (LO(cmd) > 3) { + int j; + for (j=3; jbus) { + + case IFORCE_USB: + +#ifdef CONFIG_JOYSTICK_IFORCE_USB + iforce->dr.bRequest = packet[0]; + iforce->ctrl->dev = iforce->usbdev; + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&iforce->wait, &wait); + + if (usb_submit_urb(iforce->ctrl)) { + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + return -1; + } + + while (timeout && iforce->ctrl->status == -EINPROGRESS) + timeout = schedule_timeout(timeout); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + + if (!timeout) { + usb_unlink_urb(iforce->ctrl); + return -1; + } +#else + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = USB!\n"); +#endif + break; + + case IFORCE_232: + +#ifdef CONFIG_JOYSTICK_IFORCE_232 + iforce->expect_packet = FF_CMD_QUERY; + iforce_send_packet(iforce, FF_CMD_QUERY, packet); + + set_current_state(TASK_INTERRUPTIBLE); + add_wait_queue(&iforce->wait, &wait); + + while (timeout && iforce->expect_packet) + timeout = schedule_timeout(timeout); + + set_current_state(TASK_RUNNING); + remove_wait_queue(&iforce->wait, &wait); + + if (!timeout) { + iforce->expect_packet = 0; + return -1; + } +#else + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = SERIO!\n"); +#endif + break; + + default: + printk(KERN_ERR "iforce_get_id_packet: iforce->bus = %d\n", + iforce->bus); + break; + } + + return -(iforce->edata[0] != packet[0]); +} + diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/iforce-serio.c linux-modified/drivers/char/joystick/iforce/iforce-serio.c --- linux-vanilla/drivers/char/joystick/iforce/iforce-serio.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/iforce-serio.c 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,166 @@ +/* + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * + * Copyright (c) 2000-2001 Vojtech Pavlik + * Copyright (c) 2001 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +void iforce_serial_xmit(struct iforce *iforce) +{ + unsigned char cs; + int i; + unsigned long flags; + + if (test_and_set_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags)) { + set_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags); + return; + } + + spin_lock_irqsave(&iforce->xmit_lock, flags); + +again: + if (iforce->xmit.head == iforce->xmit.tail) { + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return; + } + + cs = 0x2b; + + serio_write(iforce->serio, 0x2b); + + serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + cs ^= iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + + for (i=iforce->xmit.buf[iforce->xmit.tail]; i >= 0; --i) { + serio_write(iforce->serio, iforce->xmit.buf[iforce->xmit.tail]); + cs ^= iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + } + + serio_write(iforce->serio, cs); + + if (test_and_clear_bit(IFORCE_XMIT_AGAIN, iforce->xmit_flags)) + goto again; + + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); +} + +static void iforce_serio_write_wakeup(struct serio *serio) +{ + iforce_serial_xmit((struct iforce *)serio->private); +} + +static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags) +{ + struct iforce* iforce = serio->private; + + if (!iforce->pkt) { + if (data != 0x2b) { + return; + } + iforce->pkt = 1; + return; + } + + if (!iforce->id) { + if (data > 3 && data != 0xff) { + iforce->pkt = 0; + return; + } + iforce->id = data; + return; + } + + if (!iforce->len) { + if (data > IFORCE_MAX_LENGTH) { + iforce->pkt = 0; + iforce->id = 0; + return; + } + iforce->len = data; + return; + } + + if (iforce->idx < iforce->len) { + iforce->csum += iforce->data[iforce->idx++] = data; + return; + } + + if (iforce->idx == iforce->len) { + iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data); + iforce->pkt = 0; + iforce->id = 0; + iforce->len = 0; + iforce->idx = 0; + iforce->csum = 0; + } +} + +static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev) +{ + struct iforce *iforce; + if (serio->type != (SERIO_RS232 | SERIO_IFORCE)) + return; + + if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return; + memset(iforce, 0, sizeof(struct iforce)); + + iforce->bus = IFORCE_232; + iforce->serio = serio; + serio->private = iforce; + + if (serio_open(serio, dev)) { + kfree(iforce); + return; + } + + if (iforce_init_device(iforce)) { + serio_close(serio); + kfree(iforce); + return; + } +} + +static void iforce_serio_disconnect(struct serio *serio) +{ + struct iforce* iforce = serio->private; + + input_unregister_device(&iforce->dev); + serio_close(serio); + kfree(iforce); +} + +struct serio_dev iforce_serio_dev = { + write_wakeup: iforce_serio_write_wakeup, + interrupt: iforce_serio_irq, + connect: iforce_serio_connect, + disconnect: iforce_serio_disconnect, +}; diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/iforce-usb.c linux-modified/drivers/char/joystick/iforce/iforce-usb.c --- linux-vanilla/drivers/char/joystick/iforce/iforce-usb.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/iforce-usb.c 2003-07-21 23:08:09.000000000 +0200 @@ -0,0 +1,211 @@ + /* + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * + * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2001-2002 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include "iforce.h" + +void iforce_usb_xmit(struct iforce *iforce) +{ + int n, c; + unsigned long flags; + + spin_lock_irqsave(&iforce->xmit_lock, flags); + + if (iforce->xmit.head == iforce->xmit.tail) { + clear_bit(IFORCE_XMIT_RUNNING, iforce->xmit_flags); + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + return; + } + + ((char *)iforce->out->transfer_buffer)[0] = iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + n = iforce->xmit.buf[iforce->xmit.tail]; + XMIT_INC(iforce->xmit.tail, 1); + + iforce->out->transfer_buffer_length = n + 1; + iforce->out->dev = iforce->usbdev; + + /* Copy rest of data then */ + c = CIRC_CNT_TO_END(iforce->xmit.head, iforce->xmit.tail, XMIT_SIZE); + if (n < c) c=n; + + memcpy(iforce->out->transfer_buffer + 1, + &iforce->xmit.buf[iforce->xmit.tail], + c); + if (n != c) { + memcpy(iforce->out->transfer_buffer + 1 + c, + &iforce->xmit.buf[0], + n-c); + } + XMIT_INC(iforce->xmit.tail, n); + + spin_unlock_irqrestore(&iforce->xmit_lock, flags); + + if ( (n=usb_submit_urb(iforce->out)) ) { + printk(KERN_WARNING "iforce.c: iforce_usb_xmit: usb_submit_urb failed %d\n", n); + } +} + +static void iforce_usb_irq(struct urb *urb) +{ + struct iforce *iforce = urb->context; + if (urb->status) return; + iforce_process_packet(iforce, + (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1); +} + +static void iforce_usb_out(struct urb *urb) +{ + struct iforce *iforce = urb->context; + + if (urb->status) { + printk(KERN_DEBUG "iforce_usb_out: urb->status %d, exiting", urb->status); + return; + } + + iforce_usb_xmit(iforce); + + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); +} + +static void iforce_usb_ctrl(struct urb *urb) +{ + struct iforce *iforce = urb->context; + if (urb->status) return; + iforce->ecmd = 0xff00 | urb->actual_length; + if (waitqueue_active(&iforce->wait)) + wake_up(&iforce->wait); +} + +static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum, + const struct usb_device_id *id) +{ + struct usb_endpoint_descriptor *epirq, *epout; + struct iforce *iforce; + + epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0; + epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1; + + if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) + goto fail; + + memset(iforce, 0, sizeof(struct iforce)); + + if (!(iforce->irq = usb_alloc_urb(0))) { + goto fail; + } + + if (!(iforce->out = usb_alloc_urb(0))) { + goto fail; + } + + if (!(iforce->ctrl = usb_alloc_urb(0))) { + goto fail; + } + + iforce->bus = IFORCE_USB; + iforce->usbdev = dev; + + iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE; + iforce->dr.wIndex = 0; + iforce->dr.wLength = 16; + + usb_fill_int_urb(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress), + iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval); + + usb_fill_bulk_urb(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress), + iforce + 1, 32, iforce_usb_out, iforce); + + usb_fill_control_urb(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0), + (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce); + + if (iforce_init_device(iforce)) goto fail; + + return iforce; + +fail: + if (iforce) { + if (iforce->irq) usb_free_urb(iforce->irq); + if (iforce->out) usb_free_urb(iforce->out); + if (iforce->ctrl) usb_free_urb(iforce->ctrl); + kfree(iforce); + } + + return NULL; +} + +/* Called by iforce_delete() */ +void iforce_usb_delete(struct iforce* iforce) +{ + usb_unlink_urb(iforce->irq); + usb_unlink_urb(iforce->out); + usb_unlink_urb(iforce->ctrl); + + usb_free_urb(iforce->irq); + usb_free_urb(iforce->out); + usb_free_urb(iforce->ctrl); +} + +static void iforce_usb_disconnect(struct usb_device *dev, void *ptr) +{ + struct iforce *iforce = ptr; + int open = iforce->dev.handle->open; + + iforce->usbdev = NULL; + input_unregister_device(&iforce->dev); + + if (!open) { + iforce_delete_device(iforce); + kfree(iforce); + } +} + +static struct usb_device_id iforce_usb_ids [] = { + { USB_DEVICE(0x044f, 0xa01c) }, /* Thrustmaster Motor Sport GT */ + { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */ + { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */ + { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */ + { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */ + { USB_DEVICE(0x05ef, 0x8888) }, /* AVB Top Shot FFB Racing Wheel */ + { USB_DEVICE(0x061c, 0xc084) }, /* ACT LABS Force RS */ + { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */ + { USB_DEVICE(0x06f8, 0x0004) }, /* Guillemot Force Feedback Racing Wheel */ + { USB_DEVICE(0x06a3, 0xff12) }, /* Saitek Cyborgforce 3d */ + { } /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE (usb, iforce_usb_ids); + +struct usb_driver iforce_usb_driver = { +// owner: THIS_MODULE, + name: "iforce", + probe: iforce_usb_probe, + disconnect: iforce_usb_disconnect, + id_table: iforce_usb_ids, +}; diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/iforce/iforce.h linux-modified/drivers/char/joystick/iforce/iforce.h --- linux-vanilla/drivers/char/joystick/iforce/iforce.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-modified/drivers/char/joystick/iforce/iforce.h 2003-07-21 23:34:43.000000000 +0200 @@ -0,0 +1,184 @@ +/* + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * + * Copyright (c) 2000-2002 Vojtech Pavlik + * Copyright (c) 2001-2002 Johann Deneux + * + * USB/RS232 I-Force joysticks and wheels. + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Should you need to contact me, the author, you can do so either by + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* FF: This module provides arbitrary resource management routines. + * I use it to manage the device's memory. + * Despite the name of this module, I am *not* going to access the ioports. + */ +#include + +#define IFORCE_MAX_LENGTH 16 + +#define IFORCE_232 1 +#define IFORCE_USB 2 + +#define FALSE 0 +#define TRUE 1 + +#define FF_EFFECTS_MAX 32 + +/* Each force feedback effect is made of one core effect, which can be + * associated to at most to effect modifiers + */ +#define FF_MOD1_IS_USED 0 +#define FF_MOD2_IS_USED 1 +#define FF_CORE_IS_USED 2 +#define FF_CORE_IS_PLAYED 3 /* Effect is currently being played */ +#define FF_CORE_SHOULD_PLAY 4 /* User wants the effect to be played */ +#define FF_CORE_UPDATE 5 /* Effect is being updated */ +#define FF_MODCORE_MAX 5 + +struct iforce_core_effect { + /* Information about where modifiers are stored in the device's memory */ + struct resource mod1_chunk; + struct resource mod2_chunk; + unsigned long flags[NBITS(FF_MODCORE_MAX)]; + pid_t owner; + /* Used to keep track of parameters of an effect. They are needed + * to know what parts of an effect changed in an update operation. + * We try to send only parameter packets if possible, as sending + * effect parameter requires the effect to be stoped and restarted + */ + struct ff_effect effect; +}; + +#define FF_CMD_EFFECT 0x010e +#define FF_CMD_ENVELOPE 0x0208 +#define FF_CMD_MAGNITUDE 0x0303 +#define FF_CMD_PERIOD 0x0407 +#define FF_CMD_CONDITION 0x050a + +#define FF_CMD_AUTOCENTER 0x4002 +#define FF_CMD_PLAY 0x4103 +#define FF_CMD_ENABLE 0x4201 +#define FF_CMD_GAIN 0x4301 + +#define FF_CMD_QUERY 0xff01 + +/* Buffer for async write */ +#define XMIT_SIZE 256 +#define XMIT_INC(var, n) (var)+=n; (var)&= XMIT_SIZE -1 +/* iforce::xmit_flags */ +#define IFORCE_XMIT_RUNNING 0 +#define IFORCE_XMIT_AGAIN 1 + +struct iforce_device { + u16 idvendor; + u16 idproduct; + char *name; + signed short *btn; + signed short *abs; + signed short *ff; +}; + +struct iforce { + struct input_dev dev; /* Input device interface */ + struct iforce_device *type; + int bus; + + unsigned char data[IFORCE_MAX_LENGTH]; + unsigned char edata[IFORCE_MAX_LENGTH]; + u16 ecmd; + u16 expect_packet; + +#ifdef CONFIG_JOYSTICK_IFORCE_232 + struct serio *serio; /* RS232 transfer */ + int idx, pkt, len, id; + unsigned char csum; +#endif +#ifdef CONFIG_JOYSTICK_IFORCE_USB + struct usb_device *usbdev; /* USB transfer */ + struct urb *irq, *out, *ctrl; + struct usb_ctrlrequest dr; +#endif + spinlock_t xmit_lock; + /* Buffer used for asynchronous sending of bytes to the device */ + struct circ_buf xmit; + unsigned char xmit_data[XMIT_SIZE]; + long xmit_flags[1]; + + /* Force Feedback */ + wait_queue_head_t wait; + struct resource device_memory; + struct iforce_core_effect core_effects[FF_EFFECTS_MAX]; + struct semaphore mem_mutex; +}; + +/* Get hi and low bytes of a 16-bits int */ +#define HI(a) ((unsigned char)((a) >> 8)) +#define LO(a) ((unsigned char)((a) & 0xff)) + +/* For many parameters, it seems that 0x80 is a special value that should + * be avoided. Instead, we replace this value by 0x7f + */ +#define HIFIX80(a) ((unsigned char)(((a)<0? (a)+255 : (a))>>8)) + +/* Encode a time value */ +#define TIME_SCALE(a) (a) + + +/* Public functions */ +/* iforce-serio.c */ +void iforce_serial_xmit(struct iforce *iforce); + +/* iforce-usb.c */ +void iforce_usb_xmit(struct iforce *iforce); +void iforce_usb_delete(struct iforce *iforce); + +/* iforce-main.c */ +int iforce_init_device(struct iforce *iforce); +void iforce_delete_device(struct iforce *iforce); + +/* iforce-packets.c */ +int iforce_control_playback(struct iforce*, u16 id, unsigned int); +void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data); +int iforce_send_packet(struct iforce *iforce, u16 cmd, unsigned char* data); +void iforce_dump_packet(char *msg, u16 cmd, unsigned char *data) ; +int iforce_get_id_packet(struct iforce *iforce, char *packet); + +/* iforce-ff.c */ +int iforce_upload_periodic(struct iforce*, struct ff_effect*, int is_update); +int iforce_upload_constant(struct iforce*, struct ff_effect*, int is_update); +int iforce_upload_condition(struct iforce*, struct ff_effect*, int is_update); + +/* Public variables */ +extern struct serio_dev iforce_serio_dev; +extern struct usb_driver iforce_usb_driver; diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/interact.c linux-modified/drivers/char/joystick/interact.c --- linux-vanilla/drivers/char/joystick/interact.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/interact.c 2003-07-21 23:08:09.000000000 +0200 @@ -270,8 +270,8 @@ set_bit(t, interact->dev.keybit); input_register_device(&interact->dev); - printk(KERN_INFO "input%d: %s on gameport%d.0\n", - interact->dev.number, interact_type[interact->type].name, gameport->number); + printk(KERN_INFO "input: %s on gameport%d.0\n", + interact_type[interact->type].name, gameport->number); return; fail2: gameport_close(gameport); diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/magellan.c linux-modified/drivers/char/joystick/magellan.c --- linux-vanilla/drivers/char/joystick/magellan.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/magellan.c 2003-07-21 23:08:09.000000000 +0200 @@ -178,7 +178,7 @@ input_register_device(&magellan->dev); - printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number); + printk(KERN_INFO "input: %s on serio %s\n", magellan_name, serio->name); } /* diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/serio.c linux-modified/drivers/char/joystick/serio.c --- linux-vanilla/drivers/char/joystick/serio.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/serio.c 2003-07-21 23:08:09.000000000 +0200 @@ -1,9 +1,7 @@ /* - * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* @@ -27,14 +25,16 @@ * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include #include #include +#include MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Serio abstraction core"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(serio_register_port); @@ -47,7 +47,6 @@ static struct serio *serio_list; static struct serio_dev *serio_dev; -static int serio_number; static void serio_find_dev(struct serio *serio) { @@ -69,7 +68,6 @@ void serio_register_port(struct serio *serio) { - serio->number = serio_number++; serio->next = serio_list; serio_list = serio; serio_find_dev(serio); @@ -84,8 +82,6 @@ if (serio->dev && serio->dev->disconnect) serio->dev->disconnect(serio); - - serio_number--; } void serio_register_device(struct serio_dev *dev) diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/serport.c linux-modified/drivers/char/joystick/serport.c --- linux-vanilla/drivers/char/joystick/serport.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/serport.c 2003-07-21 23:08:09.000000000 +0200 @@ -1,9 +1,7 @@ /* - * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik - * - * Sponsored by SuSE */ /* @@ -28,7 +26,7 @@ * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -39,12 +37,19 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input device TTY line discipline"); +MODULE_LICENSE("GPL"); + struct serport { struct tty_struct *tty; wait_queue_head_t wait; struct serio serio; + char phys[32]; }; +char serport_name[] = "Serial port"; + /* * Callback functions from the serio code. */ @@ -75,6 +80,8 @@ static int serport_ldisc_open(struct tty_struct *tty) { struct serport *serport; + char ttyname[64]; + int i; MOD_INC_USE_COUNT; @@ -85,9 +92,19 @@ memset(serport, 0, sizeof(struct serport)); + set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags); serport->tty = tty; tty->disc_data = serport; + strcpy(ttyname, tty->driver.name); + for (i = 0; ttyname[i] != 0 && ttyname[i] != '/'; i++); + ttyname[i] = 0; + + sprintf(serport->phys, "%s%d/serio0", ttyname, MINOR(tty->device) - tty->driver.minor_start); + + serport->serio.name = serport_name; + serport->serio.phys = serport->phys; + serport->serio.type = SERIO_RS232; serport->serio.write = serport_serio_write; serport->serio.open = serport_serio_open; @@ -156,14 +173,14 @@ serio_register_port(&serport->serio); - printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name); + printk(KERN_INFO "serio: Serial port %s\n", name); add_wait_queue(&serport->wait, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); while(serport->serio.type && !signal_pending(current)) schedule(); - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&serport->wait, &wait); serio_unregister_port(&serport->serio); @@ -187,6 +204,14 @@ return -EINVAL; } +static void serport_ldisc_write_wakeup(struct tty_struct * tty) +{ + struct serport *sp = (struct serport *) tty->disc_data; + + serio_dev_write_wakeup(&sp->serio); + +} + /* * The line discipline structure. */ @@ -199,6 +224,7 @@ ioctl: serport_ldisc_ioctl, receive_buf: serport_ldisc_receive, receive_room: serport_ldisc_room, + write_wakeup: serport_ldisc_write_wakeup }; /* @@ -222,5 +248,3 @@ module_init(serport_init); module_exit(serport_exit); - -MODULE_LICENSE("GPL"); diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/sidewinder.c linux-modified/drivers/char/joystick/sidewinder.c --- linux-vanilla/drivers/char/joystick/sidewinder.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/sidewinder.c 2003-07-21 23:08:09.000000000 +0200 @@ -719,8 +719,8 @@ set_bit(code, sw->dev[i].keybit); input_register_device(sw->dev + i); - printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n", - sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k); + printk(KERN_INFO "input: %s%s on gameport%d.%d [%d-bit id %d data %d]\n", + sw->name, comment, gameport->number, i, m, l, k); } return; diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/spaceball.c linux-modified/drivers/char/joystick/spaceball.c --- linux-vanilla/drivers/char/joystick/spaceball.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/spaceball.c 2003-07-21 23:08:09.000000000 +0200 @@ -81,8 +81,8 @@ case '@': /* Reset packet */ spaceball->data[spaceball->idx - 1] = 0; for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++); - printk(KERN_INFO "input%d: %s [%s] on serio%d\n", - spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number); + printk(KERN_INFO "input: %s [%s] on serio %s\n", + spaceball_name, spaceball->data + i, spaceball->serio->name); break; case 'D': /* Ball data */ diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/spaceorb.c linux-modified/drivers/char/joystick/spaceorb.c --- linux-vanilla/drivers/char/joystick/spaceorb.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/spaceorb.c 2003-07-21 23:08:09.000000000 +0200 @@ -88,8 +88,8 @@ case 'R': /* Reset packet */ spaceorb->data[spaceorb->idx - 1] = 0; for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++); - printk(KERN_INFO "input%d: %s [%s] on serio%d\n", - spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number); + printk(KERN_INFO "input: %s [%s] on serio %s\n", + spaceorb_name, spaceorb->data + i, spaceorb->serio->name); break; case 'D': /* Ball + button data */ diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/stinger.c linux-modified/drivers/char/joystick/stinger.c --- linux-vanilla/drivers/char/joystick/stinger.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/stinger.c 2003-07-21 23:08:09.000000000 +0200 @@ -168,7 +168,7 @@ input_register_device(&stinger->dev); - printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number); + printk(KERN_INFO "input: %s on serio %s\n", stinger_name, serio->name); } /* diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/tmdc.c linux-modified/drivers/char/joystick/tmdc.c --- linux-vanilla/drivers/char/joystick/tmdc.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/tmdc.c 2003-07-21 23:08:09.000000000 +0200 @@ -336,8 +336,8 @@ } input_register_device(tmdc->dev + j); - printk(KERN_INFO "input%d: %s on gameport%d.%d\n", - tmdc->dev[j].number, tmdc->name[j], gameport->number, j); + printk(KERN_INFO "input: %s on gameport%d.%d\n", + tmdc->name[j], gameport->number, j); } return; diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/turbografx.c linux-modified/drivers/char/joystick/turbografx.c --- linux-vanilla/drivers/char/joystick/turbografx.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/turbografx.c 2003-07-21 23:08:09.000000000 +0200 @@ -190,8 +190,8 @@ tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1; input_register_device(tgfx->dev + i); - printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n", - tgfx->dev[i].number, config[i+1], tgfx->pd->port->name); + printk(KERN_INFO "input: %d-button Multisystem joystick on %s\n", + config[i+1], tgfx->pd->port->name); } if (!tgfx->sticks) { diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/char/joystick/warrior.c linux-modified/drivers/char/joystick/warrior.c --- linux-vanilla/drivers/char/joystick/warrior.c 2001-09-13 00:34:06.000000000 +0200 +++ linux-modified/drivers/char/joystick/warrior.c 2003-07-21 23:08:09.000000000 +0200 @@ -180,7 +180,7 @@ input_register_device(&warrior->dev); - printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number); + printk(KERN_INFO "input: Logitech WingMan Warrior on serio %s\n", serio->name); } /* diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/input/evdev.c linux-modified/drivers/input/evdev.c --- linux-vanilla/drivers/input/evdev.c 2003-06-13 16:51:34.000000000 +0200 +++ linux-modified/drivers/input/evdev.c 2003-07-21 23:08:09.000000000 +0200 @@ -1,11 +1,9 @@ /* - * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * * Event char devices, giving access to raw input device events. - * - * Sponsored by SuSE */ /* @@ -24,8 +22,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #define EVDEV_MINOR_BASE 64 @@ -43,6 +41,7 @@ int exist; int open; int minor; + char name[16]; struct input_handle handle; wait_queue_head_t wait; devfs_handle_t devfs; @@ -89,12 +88,20 @@ return retval < 0 ? retval : 0; } +static int evdev_flush(struct file * file) +{ + struct evdev_list *list = (struct evdev_list*)file->private_data; + + if (!list->evdev->exist) return -ENODEV; + + return input_flush_device(&list->evdev->handle, file); +} + static int evdev_release(struct inode * inode, struct file * file) { struct evdev_list *list = file->private_data; struct evdev_list **listptr; - lock_kernel(); listptr = &list->evdev->list; evdev_fasync(-1, file, 0); @@ -113,8 +120,7 @@ } kfree(list); - unlock_kernel(); - + return 0; } @@ -122,10 +128,16 @@ { struct evdev_list *list; int i = MINOR(inode->i_rdev) - EVDEV_MINOR_BASE; + int accept_err; if (i >= EVDEV_MINORS || !evdev_table[i]) return -ENODEV; + /* Ask the driver if he wishes to accept the open() */ + if ((accept_err = input_accept_process(&(evdev_table[i]->handle), file))) { + return accept_err; + } + if (!(list = kmalloc(sizeof(struct evdev_list), GFP_KERNEL))) return -ENOMEM; memset(list, 0, sizeof(struct evdev_list)); @@ -149,6 +161,8 @@ struct input_event event; int retval = 0; + if (!list->evdev->exist) return -ENODEV; + while (retval < count) { if (copy_from_user(&event, buffer + retval, sizeof(struct input_event))) @@ -169,7 +183,7 @@ if (list->head == list->tail) { add_wait_queue(&list->evdev->wait, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); while (list->head == list->tail) { @@ -189,7 +203,7 @@ schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&list->evdev->wait, &wait); } @@ -221,7 +235,9 @@ struct evdev_list *list = file->private_data; struct evdev *evdev = list->evdev; struct input_dev *dev = evdev->handle.dev; - int retval; + int retval, t, u; + + if (!evdev->exist) return -ENODEV; if (!evdev->exist) return -ENODEV; @@ -237,6 +253,40 @@ if ((retval = put_user(dev->idproduct, ((short *) arg) + 2))) return retval; if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval; return 0; + + case EVIOCGREP: + if ((retval = put_user(dev->rep[0], ((int *) arg) + 0))) return retval; + if ((retval = put_user(dev->rep[1], ((int *) arg) + 1))) return retval; + return 0; + + case EVIOCSREP: + if ((retval = get_user(dev->rep[0], ((int *) arg) + 0))) return retval; + if ((retval = get_user(dev->rep[1], ((int *) arg) + 1))) return retval; + return 0; + + case EVIOCGKEYCODE: + if ((retval = get_user(t, ((int *) arg) + 0))) return retval; + if (t < 0 || t > dev->keycodemax) return -EINVAL; + switch (dev->keycodesize) { + case 1: u = *(u8*)(dev->keycode + t); break; + case 2: u = *(u16*)(dev->keycode + t * 2); break; + case 4: u = *(u32*)(dev->keycode + t * 4); break; + default: return -EINVAL; + } + if ((retval = put_user(u, ((int *) arg) + 1))) return retval; + return 0; + + case EVIOCSKEYCODE: + if ((retval = get_user(t, ((int *) arg) + 0))) return retval; + if (t < 0 || t > dev->keycodemax) return -EINVAL; + if ((retval = get_user(u, ((int *) arg) + 1))) return retval; + switch (dev->keycodesize) { + case 1: *(u8*)(dev->keycode + t) = u; break; + case 2: *(u16*)(dev->keycode + t * 2) = u; break; + case 4: *(u32*)(dev->keycode + t * 4) = u; break; + default: return -EINVAL; + } + return 0; case EVIOCSFF: if (dev->upload_effect) { @@ -285,22 +335,55 @@ default: return -EINVAL; } len = NBITS(len) * sizeof(long); - if (len > _IOC_SIZE(cmd)) { - printk(KERN_WARNING "evdev.c: Truncating bitfield length from %d to %d\n", - len, _IOC_SIZE(cmd)); - len = _IOC_SIZE(cmd); - } + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); return copy_to_user((char *) arg, bits, len) ? -EFAULT : len; } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) { + int len; + len = NBITS(KEY_MAX) * sizeof(long); + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user((char *) arg, dev->key, len) ? -EFAULT : len; + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGLED(0))) { + int len; + len = NBITS(LED_MAX) * sizeof(long); + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user((char *) arg, dev->led, len) ? -EFAULT : len; + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGSND(0))) { + int len; + len = NBITS(SND_MAX) * sizeof(long); + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user((char *) arg, dev->snd, len) ? -EFAULT : len; + } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGNAME(0))) { int len; - if (!dev->name) return 0; + if (!dev->name) return -ENOENT; len = strlen(dev->name) + 1; if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); return copy_to_user((char *) arg, dev->name, len) ? -EFAULT : len; } + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGPHYS(0))) { + int len; + if (!dev->phys) return -ENOENT; + len = strlen(dev->phys) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user((char *) arg, dev->phys, len) ? -EFAULT : len; + } + + if (_IOC_NR(cmd) == _IOC_NR(EVIOCGUNIQ(0))) { + int len; + if (!dev->uniq) return -ENOENT; + len = strlen(dev->uniq) + 1; + if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd); + return copy_to_user((char *) arg, dev->uniq, len) ? -EFAULT : len; + } + if ((_IOC_NR(cmd) & ~ABS_MAX) == _IOC_NR(EVIOCGABS(0))) { int t = _IOC_NR(cmd) & ABS_MAX; @@ -326,9 +409,10 @@ release: evdev_release, ioctl: evdev_ioctl, fasync: evdev_fasync, + flush: evdev_flush }; -static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev) +static struct input_handle *evdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct evdev *evdev; int minor; @@ -347,16 +431,17 @@ evdev->minor = minor; evdev_table[minor] = evdev; + + sprintf(evdev->name, "event%d", minor); evdev->handle.dev = dev; + evdev->handle.name = evdev->name; evdev->handle.handler = handler; evdev->handle.private = evdev; - evdev->exist = 1; - evdev->devfs = input_register_minor("event%d", minor, EVDEV_MINOR_BASE); -// printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number); + evdev->exist = 1; return &evdev->handle; } @@ -377,12 +462,21 @@ } } +static struct input_device_id evdev_ids[] = { + { driver_info: 1 }, /* Matches all devices */ + { }, /* Terminating zero entry */ +}; + +MODULE_DEVICE_TABLE(input, evdev_ids); + static struct input_handler evdev_handler = { event: evdev_event, connect: evdev_connect, disconnect: evdev_disconnect, fops: &evdev_fops, minor: EVDEV_MINOR_BASE, + name: "evdev", + id_table: evdev_ids, }; static int __init evdev_init(void) @@ -399,7 +493,6 @@ module_init(evdev_init); module_exit(evdev_exit); -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Event character device driver"); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input driver event char devices"); MODULE_LICENSE("GPL"); - diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/input/input.c linux-modified/drivers/input/input.c --- linux-vanilla/drivers/input/input.c 2003-06-13 16:51:34.000000000 +0200 +++ linux-modified/drivers/input/input.c 2003-07-21 23:08:09.000000000 +0200 @@ -1,11 +1,9 @@ /* - * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ * * Copyright (c) 1999-2001 Vojtech Pavlik * - * The input layer module itself - * - * Sponsored by SuSE + * The input core */ /* @@ -24,8 +22,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -34,12 +32,16 @@ #include #include #include +#include +#include +#include +#include +#include -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Input layer module"); +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Input core"); MODULE_LICENSE("GPL"); - EXPORT_SYMBOL(input_register_device); EXPORT_SYMBOL(input_unregister_device); EXPORT_SYMBOL(input_register_handler); @@ -48,6 +50,8 @@ EXPORT_SYMBOL(input_unregister_minor); EXPORT_SYMBOL(input_open_device); EXPORT_SYMBOL(input_close_device); +EXPORT_SYMBOL(input_accept_process); +EXPORT_SYMBOL(input_flush_device); EXPORT_SYMBOL(input_event); #define INPUT_MAJOR 13 @@ -57,20 +61,32 @@ static struct input_handler *input_handler; static struct input_handler *input_table[8]; static devfs_handle_t input_devfs_handle; -static int input_number; -static long input_devices[NBITS(INPUT_DEVICES)]; + +#ifdef CONFIG_PROC_FS +static struct proc_dir_entry *proc_bus_input_dir; +DECLARE_WAIT_QUEUE_HEAD(input_devices_poll_wait); +static int input_devices_state; +#endif void input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value) { struct input_handle *handle = dev->handle; /* + * Wake up the device if it is sleeping. + */ + if (dev->pm_dev) + pm_access(dev->pm_dev); + +/* * Filter non-events, and bad input values out. */ if (type > EV_MAX || !test_bit(type, dev->evbit)) return; + add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value); + switch (type) { case EV_KEY: @@ -187,16 +203,36 @@ mod_timer(&dev->timer, jiffies + dev->rep[REP_PERIOD]); } +int input_accept_process(struct input_handle *handle, struct file *file) +{ + if (handle->dev->accept) + return handle->dev->accept(handle->dev, file); + + return 0; +} + int input_open_device(struct input_handle *handle) { + if (handle->dev->pm_dev) + pm_access(handle->dev->pm_dev); handle->open++; if (handle->dev->open) return handle->dev->open(handle->dev); return 0; } +int input_flush_device(struct input_handle* handle, struct file* file) +{ + if (handle->dev->flush) + return handle->dev->flush(handle->dev, file); + + return 0; +} + void input_close_device(struct input_handle *handle) { + if (handle->dev->pm_dev) + pm_dev_idle(handle->dev->pm_dev); if (handle->dev->close) handle->dev->close(handle->dev); handle->open--; @@ -210,25 +246,197 @@ handle->handler->handle = handle; } +/** + * input_find_and_remove - Find and remove node + * + * @type: data type + * @initval: initial value + * @targ: node to find + * @next: next node in the list + * + * Searches the linked list for the target node @targ. If the node + * is found, it is removed from the list. + * + * If the node is not found, the end of the list will be hit, + * indicating that it wasn't in the list to begin with. + * + * Returns nothing. + */ +#define input_find_and_remove(type, initval, targ, next) \ + do { \ + type **ptr; \ + for (ptr = &initval; *ptr; ptr = &((*ptr)->next)) \ + if (*ptr == targ) break; \ + if (*ptr) *ptr = (*ptr)->next; \ + } while (0) + static void input_unlink_handle(struct input_handle *handle) { - struct input_handle **handleptr; + input_find_and_remove(struct input_handle, handle->dev->handle, handle, dnext); + input_find_and_remove(struct input_handle, handle->handler->handle, handle, hnext); +} + +#define MATCH_BIT(bit, max) \ + for (i = 0; i < NBITS(max); i++) \ + if ((id->bit[i] & dev->bit[i]) != id->bit[i]) \ + break; \ + if (i != NBITS(max)) \ + continue; + +static struct input_device_id *input_match_device(struct input_device_id *id, struct input_dev *dev) +{ + int i; + + for (; id->flags || id->driver_info; id++) { + + if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) + if (id->idbus != dev->idbus) + continue; - handleptr = &handle->dev->handle; - while (*handleptr && (*handleptr != handle)) - handleptr = &((*handleptr)->dnext); - *handleptr = (*handleptr)->dnext; - - handleptr = &handle->handler->handle; - while (*handleptr && (*handleptr != handle)) - handleptr = &((*handleptr)->hnext); - *handleptr = (*handleptr)->hnext; + if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) + if (id->idvendor != dev->idvendor) + continue; + + if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) + if (id->idproduct != dev->idproduct) + continue; + + if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) + if (id->idversion != dev->idversion) + continue; + + MATCH_BIT(evbit, EV_MAX); + MATCH_BIT(keybit, KEY_MAX); + MATCH_BIT(relbit, REL_MAX); + MATCH_BIT(absbit, ABS_MAX); + MATCH_BIT(mscbit, MSC_MAX); + MATCH_BIT(ledbit, LED_MAX); + MATCH_BIT(sndbit, SND_MAX); + MATCH_BIT(ffbit, FF_MAX); + + return id; + } + + return NULL; } +/* + * Input hotplugging interface - loading event handlers based on + * device bitfields. + */ + +#ifdef CONFIG_HOTPLUG + +/* + * Input hotplugging invokes what /proc/sys/kernel/hotplug says + * (normally /sbin/hotplug) when input devices get added or removed. + * + * This invokes a user mode policy agent, typically helping to load driver + * or other modules, configure the device, and more. Drivers can provide + * a MODULE_DEVICE_TABLE to help with module loading subtasks. + * + */ + +#define SPRINTF_BIT_A(bit, name, max) \ + do { \ + envp[i++] = scratch; \ + scratch += sprintf(scratch, name); \ + for (j = NBITS(max) - 1; j >= 0; j--) \ + if (dev->bit[j]) break; \ + for (; j >= 0; j--) \ + scratch += sprintf(scratch, "%lx ", dev->bit[j]); \ + scratch++; \ + } while (0) + +#define SPRINTF_BIT_A2(bit, name, max, ev) \ + do { \ + if (test_bit(ev, dev->evbit)) \ + SPRINTF_BIT_A(bit, name, max); \ + } while (0) + +static void input_call_hotplug(char *verb, struct input_dev *dev) +{ + char *argv[3], **envp, *buf, *scratch; + int i = 0, j, value; + + if (!hotplug_path[0]) { + printk(KERN_ERR "input.c: calling hotplug a hotplug agent defined\n"); + return; + } + if (in_interrupt()) { + printk(KERN_ERR "input.c: calling hotplug from interrupt\n"); + return; + } + if (!current->fs->root) { + printk(KERN_WARNING "input.c: calling hotplug without valid filesystem\n"); + return; + } + if (!(envp = (char **) kmalloc(20 * sizeof(char *), GFP_KERNEL))) { + printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); + return; + } + if (!(buf = kmalloc(1024, GFP_KERNEL))) { + kfree (envp); + printk(KERN_ERR "input.c: not enough memory allocating hotplug environment\n"); + return; + } + + argv[0] = hotplug_path; + argv[1] = "input"; + argv[2] = 0; + + envp[i++] = "HOME=/"; + envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin"; + + scratch = buf; + + envp[i++] = scratch; + scratch += sprintf(scratch, "ACTION=%s", verb) + 1; + + envp[i++] = scratch; + scratch += sprintf(scratch, "PRODUCT=%x/%x/%x/%x", + dev->idbus, dev->idvendor, dev->idproduct, dev->idversion) + 1; + + if (dev->name) { + envp[i++] = scratch; + scratch += sprintf(scratch, "NAME=%s", dev->name) + 1; + } + + if (dev->phys) { + envp[i++] = scratch; + scratch += sprintf(scratch, "PHYS=%s", dev->phys) + 1; + } + + SPRINTF_BIT_A(evbit, "EV=", EV_MAX); + SPRINTF_BIT_A2(keybit, "KEY=", KEY_MAX, EV_KEY); + SPRINTF_BIT_A2(relbit, "REL=", REL_MAX, EV_REL); + SPRINTF_BIT_A2(absbit, "ABS=", ABS_MAX, EV_ABS); + SPRINTF_BIT_A2(mscbit, "MSC=", MSC_MAX, EV_MSC); + SPRINTF_BIT_A2(ledbit, "LED=", LED_MAX, EV_LED); + SPRINTF_BIT_A2(sndbit, "SND=", SND_MAX, EV_SND); + SPRINTF_BIT_A2(ffbit, "FF=", FF_MAX, EV_FF); + + envp[i++] = 0; + + printk(KERN_DEBUG "input.c: calling %s %s [%s %s %s %s %s]\n", + argv[0], argv[1], envp[0], envp[1], envp[2], envp[3], envp[4]); + + value = call_usermodehelper(argv [0], argv, envp); + + kfree(buf); + kfree(envp); + + if (value != 0) + printk(KERN_WARNING "input.c: hotplug returned %d\n", value); +} + +#endif + void input_register_device(struct input_dev *dev) { struct input_handler *handler = input_handler; struct input_handle *handle; + struct input_device_id *id; /* * Initialize repeat timer to default values. @@ -244,35 +452,70 @@ * Add the device. */ - if (input_number >= INPUT_DEVICES) { - printk(KERN_WARNING "input: ran out of input device numbers!\n"); - dev->number = input_number; - } else { - dev->number = find_first_zero_bit(input_devices, INPUT_DEVICES); - set_bit(dev->number, input_devices); - } - dev->next = input_dev; input_dev = dev; - input_number++; /* * Notify handlers. */ while (handler) { - if ((handle = handler->connect(handler, dev))) - input_link_handle(handle); + if ((id = input_match_device(handler->id_table, dev))) + if ((handle = handler->connect(handler, dev, id))) + input_link_handle(handle); handler = handler->next; } + +/* + * Notify the hotplug agent. + */ + +#ifdef CONFIG_HOTPLUG + input_call_hotplug("add", dev); +#endif + +/* + * Notify /proc. + */ + +#ifdef CONFIG_PROC_FS + input_devices_state++; + wake_up(&input_devices_poll_wait); +#endif +} + +#define DUMP_ARRAY(n, array) \ +printk(KERN_DEBUG " ");\ +for (i=0; iflags); + if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT) { + DUMP_ARRAY(NBITS(EV_MAX), id->evbit); + } + if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT) { + DUMP_ARRAY(NBITS(KEY_MAX), id->keybit); + } } void input_unregister_device(struct input_dev *dev) { struct input_handle *handle = dev->handle; - struct input_dev **devptr = &input_dev; struct input_handle *dnext; + if (!dev) return; + +/* + * Turn off power management for the device. + */ + if (dev->pm_dev) + pm_unregister(dev->pm_dev); + /* * Kill any pending repeat timers. */ @@ -291,23 +534,35 @@ } /* - * Remove the device. + * Notify the hotplug agent. */ - while (*devptr && (*devptr != dev)) - devptr = &((*devptr)->next); - *devptr = (*devptr)->next; +#ifdef CONFIG_HOTPLUG + input_call_hotplug("remove", dev); +#endif + +/* + * Remove the device. + */ + input_find_and_remove(struct input_dev, input_dev, dev, next); - input_number--; +/* + * Notify /proc. + */ - if (dev->number < INPUT_DEVICES) - clear_bit(dev->number, input_devices); +#ifdef CONFIG_PROC_FS + input_devices_state++; + wake_up(&input_devices_poll_wait); +#endif } void input_register_handler(struct input_handler *handler) { struct input_dev *dev = input_dev; struct input_handle *handle; + struct input_device_id *id; + + if (!handler) return; /* * Add minors if needed. @@ -326,17 +581,27 @@ /* * Notify it about all existing devices. */ +// dump_id_table(handler->id_table); while (dev) { - if ((handle = handler->connect(handler, dev))) - input_link_handle(handle); + if ((id = input_match_device(handler->id_table, dev))) + if ((handle = handler->connect(handler, dev, id))) + input_link_handle(handle); dev = dev->next; } + +/* + * Notify /proc. + */ + +#ifdef CONFIG_PROC_FS + input_devices_state++; + wake_up(&input_devices_poll_wait); +#endif } void input_unregister_handler(struct input_handler *handler) { - struct input_handler **handlerptr = &input_handler; struct input_handle *handle = handler->handle; struct input_handle *hnext; @@ -354,18 +619,23 @@ /* * Remove it. */ - - while (*handlerptr && (*handlerptr != handler)) - handlerptr = &((*handlerptr)->next); - - *handlerptr = (*handlerptr)->next; + input_find_and_remove(struct input_handler, input_handler, handler, + next); /* * Remove minors. */ - if (handler->fops != NULL) input_table[handler->minor >> 5] = NULL; + +/* + * Notify /proc. + */ + +#ifdef CONFIG_PROC_FS + input_devices_state++; + wake_up(&input_devices_poll_wait); +#endif } static int input_open_file(struct inode *inode, struct file *file) @@ -389,9 +659,7 @@ old_fops = file->f_op; file->f_op = new_fops; - lock_kernel(); err = new_fops->open(inode, file); - unlock_kernel(); if (err) { fops_put(file->f_op); @@ -419,18 +687,164 @@ devfs_unregister(handle); } +/* + * ProcFS interface for the input drivers. + */ + +#ifdef CONFIG_PROC_FS + +#define SPRINTF_BIT_B(bit, name, max) \ + do { \ + len += sprintf(buf + len, "B: %s", name); \ + for (i = NBITS(max) - 1; i >= 0; i--) \ + if (dev->bit[i]) break; \ + for (; i >= 0; i--) \ + len += sprintf(buf + len, "%lx ", dev->bit[i]); \ + len += sprintf(buf + len, "\n"); \ + } while (0) + +#define SPRINTF_BIT_B2(bit, name, max, ev) \ + do { \ + if (test_bit(ev, dev->evbit)) \ + SPRINTF_BIT_B(bit, name, max); \ + } while (0) + + +static unsigned int input_devices_poll(struct file *file, poll_table *wait) +{ + int state = input_devices_state; + poll_wait(file, &input_devices_poll_wait, wait); + if (state != input_devices_state) + return POLLIN | POLLRDNORM; + return 0; +} + +static int input_devices_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +{ + struct input_dev *dev = input_dev; + struct input_handle *handle; + + off_t at = 0; + int i, len, cnt = 0; + + while (dev) { + + len = sprintf(buf, "I: Bus=%04x Vendor=%04x Product=%04x Version=%04x\n", + dev->idbus, dev->idvendor, dev->idproduct, dev->idversion); + + len += sprintf(buf + len, "N: Name=\"%s\"\n", dev->name ? dev->name : ""); + len += sprintf(buf + len, "P: Phys=%s\n", dev->phys ? dev->phys : ""); + len += sprintf(buf + len, "D: Drivers="); + + handle = dev->handle; + + while (handle) { + len += sprintf(buf + len, "%s ", handle->name); + handle = handle->dnext; + } + + len += sprintf(buf + len, "\n"); + + SPRINTF_BIT_B(evbit, "EV=", EV_MAX); + SPRINTF_BIT_B2(keybit, "KEY=", KEY_MAX, EV_KEY); + SPRINTF_BIT_B2(relbit, "REL=", REL_MAX, EV_REL); + SPRINTF_BIT_B2(absbit, "ABS=", ABS_MAX, EV_ABS); + SPRINTF_BIT_B2(mscbit, "MSC=", MSC_MAX, EV_MSC); + SPRINTF_BIT_B2(ledbit, "LED=", LED_MAX, EV_LED); + SPRINTF_BIT_B2(sndbit, "SND=", SND_MAX, EV_SND); + SPRINTF_BIT_B2(ffbit, "FF=", FF_MAX, EV_FF); + + len += sprintf(buf + len, "\n"); + + at += len; + + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else cnt += len; + buf += len; + if (cnt >= count) + break; + } + + dev = dev->next; + } + + if (!dev) *eof = 1; + + return (count > cnt) ? cnt : count; +} + +static int input_handlers_read(char *buf, char **start, off_t pos, int count, int *eof, void *data) +{ + struct input_handler *handler = input_handler; + + off_t at = 0; + int len = 0, cnt = 0; + int i = 0; + + while (handler) { + + if (handler->fops) + len = sprintf(buf, "N: Number=%d Name=%s Minor=%d\n", + i++, handler->name, handler->minor); + else + len = sprintf(buf, "N: Number=%d Name=%s\n", + i++, handler->name); + + at += len; + + if (at >= pos) { + if (!*start) { + *start = buf + (pos - (at - len)); + cnt = at - pos; + } else cnt += len; + buf += len; + if (cnt >= count) + break; + } + + handler = handler->next; + } + + if (!handler) *eof = 1; + + return (count > cnt) ? cnt : count; +} + +#endif + static int __init input_init(void) { + struct proc_dir_entry *entry; + +#ifdef CONFIG_PROC_FS + proc_bus_input_dir = proc_mkdir("input", proc_bus); + proc_bus_input_dir->owner = THIS_MODULE; + entry = create_proc_read_entry("devices", 0, proc_bus_input_dir, input_devices_read, NULL); + entry->owner = THIS_MODULE; + entry->proc_fops->poll = input_devices_poll; + entry = create_proc_read_entry("handlers", 0, proc_bus_input_dir, input_handlers_read, NULL); + entry->owner = THIS_MODULE; +#endif if (devfs_register_chrdev(INPUT_MAJOR, "input", &input_fops)) { printk(KERN_ERR "input: unable to register char major %d", INPUT_MAJOR); return -EBUSY; } + input_devfs_handle = devfs_mk_dir(NULL, "input", NULL); + return 0; } static void __exit input_exit(void) { +#ifdef CONFIG_PROC_FS + remove_proc_entry("devices", proc_bus_input_dir); + remove_proc_entry("handlers", proc_bus_input_dir); + remove_proc_entry("input", proc_bus); +#endif devfs_unregister(input_devfs_handle); if (devfs_unregister_chrdev(INPUT_MAJOR, "input")) printk(KERN_ERR "input: can't unregister char major %d", INPUT_MAJOR); diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/input/joydev.c linux-modified/drivers/input/joydev.c --- linux-vanilla/drivers/input/joydev.c 2003-06-13 16:51:34.000000000 +0200 +++ linux-modified/drivers/input/joydev.c 2003-07-21 23:12:04.000000000 +0200 @@ -1,12 +1,10 @@ /* - * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 1999-2001 Vojtech Pavlik * Copyright (c) 1999 Colin Van Dyke * * Joystick device driver for the input driver suite. - * - * Sponsored by SuSE and Intel */ /* @@ -25,8 +23,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #include @@ -46,6 +44,11 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Joystick device interfaces"); +MODULE_SUPPORTED_DEVICE("input/js"); +MODULE_LICENSE("GPL"); + #define JOYDEV_MINOR_BASE 0 #define JOYDEV_MINORS 32 #define JOYDEV_BUFFER_SIZE 64 @@ -56,6 +59,7 @@ int exist; int open; int minor; + char name[16]; struct input_handle handle; wait_queue_head_t wait; devfs_handle_t devfs; @@ -84,11 +88,6 @@ static struct joydev *joydev_table[JOYDEV_MINORS]; -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Joystick device driver"); -MODULE_LICENSE("GPL"); -MODULE_SUPPORTED_DEVICE("input/js"); - static int joydev_correct(int value, struct js_corr *corr) { switch (corr->type) { @@ -167,7 +166,6 @@ struct joydev_list *list = file->private_data; struct joydev_list **listptr; - lock_kernel(); listptr = &list->joydev->list; joydev_fasync(-1, file, 0); @@ -186,7 +184,6 @@ } kfree(list); - unlock_kernel(); return 0; } @@ -257,7 +254,7 @@ if (list->head == list->tail && list->startup == joydev->nabs + joydev->nkey) { add_wait_queue(&list->joydev->wait, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); while (list->head == list->tail) { @@ -277,7 +274,7 @@ schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&list->joydev->wait, &wait); } @@ -339,6 +336,8 @@ if (!joydev->exist) return -ENODEV; + if (!joydev->exist) return -ENODEV; + switch (cmd) { case JS_SET_CAL: @@ -420,16 +419,11 @@ fasync: joydev_fasync, }; -static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev) +static struct input_handle *joydev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct joydev *joydev; int i, j, t, minor; - if (!(test_bit(EV_KEY, dev->evbit) && test_bit(EV_ABS, dev->evbit) && - (test_bit(ABS_X, dev->absbit) || test_bit(ABS_Y, dev->absbit)) && - (test_bit(BTN_TRIGGER, dev->keybit) || test_bit(BTN_A, dev->keybit) - || test_bit(BTN_1, dev->keybit)))) return NULL; - for (minor = 0; minor < JOYDEV_MINORS && joydev_table[minor]; minor++); if (minor == JOYDEV_MINORS) { printk(KERN_ERR "joydev: no more free joydev devices\n"); @@ -445,12 +439,13 @@ joydev->minor = minor; joydev_table[minor] = joydev; + sprintf(joydev->name, "js%d", minor); + joydev->handle.dev = dev; + joydev->handle.name = joydev->name; joydev->handle.handler = handler; joydev->handle.private = joydev; - joydev->exist = 1; - for (i = 0; i < ABS_MAX; i++) if (test_bit(i, dev->absbit)) { joydev->absmap[i] = joydev->nabs; @@ -494,6 +489,8 @@ // printk(KERN_INFO "js%d: Joystick device for input%d\n", minor, dev->number); + joydev->exist = 1; + return &joydev->handle; } @@ -512,12 +509,35 @@ } } +static struct input_device_id joydev_ids[] = { + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, + absbit: { BIT(ABS_X) }, + }, + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, + absbit: { BIT(ABS_WHEEL) }, + }, + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, + absbit: { BIT(ABS_THROTTLE) }, + }, + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, joydev_ids); + static struct input_handler joydev_handler = { event: joydev_event, connect: joydev_connect, disconnect: joydev_disconnect, fops: &joydev_fops, minor: JOYDEV_MINOR_BASE, + name: "joydev", + id_table: joydev_ids, }; static int __init joydev_init(void) diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/input/keybdev.c linux-modified/drivers/input/keybdev.c --- linux-vanilla/drivers/input/keybdev.c 2003-06-13 16:51:34.000000000 +0200 +++ linux-modified/drivers/input/keybdev.c 2003-07-21 23:08:09.000000000 +0200 @@ -177,20 +177,11 @@ tasklet_schedule(&keyboard_tasklet); } -static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev) +static struct input_handle *keybdev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id* id) { struct input_handle *handle; int i; - if (!test_bit(EV_KEY, dev->evbit)) - return NULL; - - for (i = KEY_RESERVED; i < BTN_MISC; i++) - if (test_bit(i, dev->keybit)) break; - - if (i == BTN_MISC) - return NULL; - if (!(handle = kmalloc(sizeof(struct input_handle), GFP_KERNEL))) return NULL; memset(handle, 0, sizeof(struct input_handle)); @@ -213,10 +204,25 @@ kfree(handle); } +static struct input_device_id keybdev_ids[] = { + /* If it's got an "esc" key, it's a keyboard */ + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT, + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { BIT(KEY_ESC) }, + }, + + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, keybdev_ids); + static struct input_handler keybdev_handler = { event: keybdev_event, connect: keybdev_connect, disconnect: keybdev_disconnect, + name: "keybdev", + id_table: keybdev_ids, }; static int __init keybdev_init(void) diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/input/mousedev.c linux-modified/drivers/input/mousedev.c --- linux-vanilla/drivers/input/mousedev.c 2003-06-13 16:51:34.000000000 +0200 +++ linux-modified/drivers/input/mousedev.c 2003-07-21 23:15:09.000000000 +0200 @@ -1,11 +1,9 @@ /* - * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik + * Copyright (c) 1999-2001 Vojtech Pavlik * - * Input driver to ImExPS/2 device driver module. - * - * Sponsored by SuSE + * Input driver to ExplorerPS/2 device driver module. */ /* @@ -24,8 +22,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #define MOUSEDEV_MINOR_BASE 32 @@ -41,6 +39,10 @@ #include #include +MODULE_AUTHOR("Vojtech Pavlik "); +MODULE_DESCRIPTION("Mouse (ExplorerPS/2) device interfaces"); +MODULE_LICENSE("GPL"); + #ifndef CONFIG_INPUT_MOUSEDEV_SCREEN_X #define CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 #endif @@ -52,6 +54,7 @@ int exist; int open; int minor; + char name[16]; wait_queue_head_t wait; struct mousedev_list *list; struct input_handle handle; @@ -89,8 +92,6 @@ struct mousedev_list *list; int index, size; - add_mouse_randomness((type << 4) ^ code ^ (code >> 4) ^ value); - while (*mousedev) { list = (*mousedev)->list; while (list) { @@ -101,13 +102,23 @@ switch (code) { case ABS_X: size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X]; - list->dx += (value * xres - list->oldx) / size; - list->oldx += list->dx * size; + if (size != 0) { + list->dx += (value * xres - list->oldx) / size; + list->oldx += list->dx * size; + } else { + list->dx += value - list->oldx; + list->oldx += list->dx; + } break; case ABS_Y: size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y]; - list->dy -= (value * yres - list->oldy) / size; - list->oldy -= list->dy * size; + if (size != 0) { + list->dy -= (value * yres - list->oldy) / size; + list->oldy -= list->dy * size; + } else { + list->dy -= value - list->oldy; + list->oldy -= list->dy; + } break; } break; @@ -170,7 +181,6 @@ struct mousedev_list *list = file->private_data; struct mousedev_list **listptr; - lock_kernel(); listptr = &list->mousedev->list; mousedev_fasync(-1, file, 0); @@ -208,7 +218,6 @@ } kfree(list); - unlock_kernel(); return 0; } @@ -216,7 +225,14 @@ static int mousedev_open(struct inode * inode, struct file * file) { struct mousedev_list *list; - int i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; + int i; + +#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX + if (major(inode->i_rdev) == MISC_MAJOR)) + i = MOUSEDEV_MIX; + else +#endif + i = MINOR(inode->i_rdev) - MOUSEDEV_MINOR_BASE; if (i >= MOUSEDEV_MINORS || !mousedev_table[i]) return -ENODEV; @@ -346,7 +362,7 @@ if (!list->ready && !list->buffer) { add_wait_queue(&list->mousedev->wait, &wait); - current->state = TASK_INTERRUPTIBLE; + set_current_state(TASK_INTERRUPTIBLE); while (!list->ready) { @@ -362,7 +378,7 @@ schedule(); } - current->state = TASK_RUNNING; + set_current_state(TASK_RUNNING); remove_wait_queue(&list->mousedev->wait, &wait); } @@ -403,7 +419,7 @@ fasync: mousedev_fasync, }; -static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev) +static struct input_handle *mousedev_connect(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id) { struct mousedev *mousedev; int minor = 0; @@ -430,11 +446,12 @@ memset(mousedev, 0, sizeof(struct mousedev)); init_waitqueue_head(&mousedev->wait); - mousedev->exist = 1; mousedev->minor = minor; mousedev_table[minor] = mousedev; + sprintf(mousedev->name, "mouse%d", minor); mousedev->handle.dev = dev; + mousedev->handle.name = mousedev->name; mousedev->handle.handler = handler; mousedev->handle.private = mousedev; @@ -443,7 +460,7 @@ if (mousedev_mix.open) input_open_device(&mousedev->handle); -// printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number); + mousedev->exist = 1; return &mousedev->handle; } @@ -464,6 +481,26 @@ kfree(mousedev); } } + +static struct input_device_id mousedev_ids[] = { + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_RELBIT, + evbit: { BIT(EV_KEY) | BIT(EV_REL) }, + keybit: { [LONG(BTN_LEFT)] = BIT(BTN_LEFT) }, + relbit: { BIT(REL_X) | BIT(REL_Y) }, + }, /* A mouse like device, at least one button, two relative axes */ + + { + flags: INPUT_DEVICE_ID_MATCH_EVBIT | INPUT_DEVICE_ID_MATCH_KEYBIT | INPUT_DEVICE_ID_MATCH_ABSBIT, + evbit: { BIT(EV_KEY) | BIT(EV_ABS) }, + keybit: { [LONG(BTN_TOUCH)] = BIT(BTN_TOUCH) }, + absbit: { BIT(ABS_X) | BIT(ABS_Y) }, + }, /* A tablet like device, at least touch detection, two absolute axes */ + + { }, /* Terminating entry */ +}; + +MODULE_DEVICE_TABLE(input, mousedev_ids); static struct input_handler mousedev_handler = { event: mousedev_event, @@ -471,7 +508,15 @@ disconnect: mousedev_disconnect, fops: &mousedev_fops, minor: MOUSEDEV_MINOR_BASE, + name: "mousedev", + id_table: mousedev_ids, +}; + +#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX +static struct miscdevice psaux_mouse = { + PSMOUSE_MINOR, "psaux", &mousedev_fops }; +#endif static int __init mousedev_init(void) { @@ -483,6 +528,9 @@ mousedev_mix.exist = 1; mousedev_mix.minor = MOUSEDEV_MIX; mousedev_mix.devfs = input_register_minor("mice", MOUSEDEV_MIX, MOUSEDEV_MINOR_BASE); +#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX + misc_register(&psaux_mouse) +#endif printk(KERN_INFO "mice: PS/2 mouse device common for all mice\n"); @@ -491,6 +539,9 @@ static void __exit mousedev_exit(void) { +#ifdef CONFIG_INPUT_MOUSEDEV_PSAUX + misc_deregister(&psaux_mouse) +#endif input_unregister_minor(mousedev_mix.devfs); input_unregister_handler(&mousedev_handler); } @@ -498,10 +549,6 @@ module_init(mousedev_init); module_exit(mousedev_exit); -MODULE_AUTHOR("Vojtech Pavlik "); -MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver"); -MODULE_LICENSE("GPL"); - MODULE_PARM(xres, "i"); MODULE_PARM_DESC(xres, "Horizontal screen resolution"); MODULE_PARM(yres, "i"); diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/include/linux/input.h linux-modified/include/linux/input.h --- linux-vanilla/include/linux/input.h 2003-06-13 16:51:38.000000000 +0200 +++ linux-modified/include/linux/input.h 2003-07-21 23:34:43.000000000 +0200 @@ -2,11 +2,9 @@ #define _INPUT_H /* - * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ * - * Copyright (c) 1999-2000 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (c) 1999-2001 Vojtech Pavlik */ /* @@ -17,7 +15,7 @@ * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License @@ -25,8 +23,8 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Should you need to contact me, the author, you can do so either by - * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * e-mail - mail your message to , or by paper mail: + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ #ifdef __KERNEL__ @@ -64,17 +62,20 @@ #define EVIOCSREP _IOW('E', 0x03, int[2]) /* get repeat settings */ #define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ #define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */ -#define EVIOCGKEY _IOR('E', 0x05, int[2]) /* get key value */ + #define EVIOCGNAME(len) _IOC(_IOC_READ, 'E', 0x06, len) /* get device name */ -#define EVIOCGBUS _IOR('E', 0x07, short[4]) /* get bus address */ +#define EVIOCGPHYS(len) _IOC(_IOC_READ, 'E', 0x07, len) /* get physical location */ +#define EVIOCGUNIQ(len) _IOC(_IOC_READ, 'E', 0x08, len) /* get unique identifier */ + +#define EVIOCGKEY(len) _IOC(_IOC_READ, 'E', 0x18, len) /* get global keystate */ +#define EVIOCGLED(len) _IOC(_IOC_READ, 'E', 0x19, len) /* get all LEDs */ +#define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ #define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ #define EVIOCGABS(abs) _IOR('E', 0x40 + abs, int[5]) /* get abs value/limits */ #define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ -#define EVIOCSGAIN _IOW('E', 0x82, unsigned short) /* Set overall gain */ -#define EVIOCSAUTOCENTER _IOW('E', 0x83, unsigned short) /* Enable or disable auto-centering */ #define EVIOCGEFFECTS _IOR('E', 0x84, int) /* Report number of effects playable at the same time */ /* @@ -90,6 +91,8 @@ #define EV_SND 0x12 #define EV_REP 0x14 #define EV_FF 0x15 +#define EV_PWR 0x16 +#define EV_FF_STATUS 0x17 #define EV_MAX 0x1f /* @@ -304,8 +307,27 @@ #define KEY_PROG4 203 #define KEY_SUSPEND 205 #define KEY_CLOSE 206 +#define KEY_PLAY 207 +#define KEY_FASTFORWARD 208 +#define KEY_BASSBOOST 209 +#define KEY_PRINT 210 +#define KEY_HP 211 +#define KEY_CAMERA 212 +#define KEY_SOUND 213 +#define KEY_QUESTION 214 +#define KEY_EMAIL 215 +#define KEY_CHAT 216 +#define KEY_SEARCH 217 +#define KEY_CONNECT 218 +#define KEY_FINANCE 219 +#define KEY_SPORT 220 +#define KEY_SHOP 221 +#define KEY_ALTERASE 222 +#define KEY_CANCEL 223 +#define KEY_BRIGHTNESSDOWN 224 +#define KEY_BRIGHTNESSUP 225 -#define KEY_UNKNOWN 220 +#define KEY_UNKNOWN 240 #define KEY_BRIGHTNESSDOWN 224 #define KEY_BRIGHTNESSUP 225 @@ -376,6 +398,10 @@ #define BTN_STYLUS 0x14b #define BTN_STYLUS2 0x14c +#define BTN_WHEEL 0x150 +#define BTN_GEAR_DOWN 0x150 +#define BTN_GEAR_UP 0x151 + #define KEY_MAX 0x1ff /* @@ -419,7 +445,8 @@ #define ABS_TILT_X 0x1a #define ABS_TILT_Y 0x1b #define ABS_MISC 0x1c -#define ABS_MAX 0x1f +#define ABS_VOLUME 0x20 +#define ABS_MAX 0x3f /* * Misc events @@ -485,67 +512,89 @@ #define BUS_I2C 0x18 /* + * Values describing the status of an effect + */ +#define FF_STATUS_STOPPED 0x00 +#define FF_STATUS_PLAYING 0x01 +#define FF_STATUS_MAX 0x01 + +/* * Structures used in ioctls to upload effects to a device * The first structures are not passed directly by using ioctls. * They are sub-structures of the actually sent structure (called ff_effect) */ struct ff_replay { - __u16 length; /* Duration of an effect */ + __u16 length; /* Duration of an effect in ms. + All other times are also expressed in ms. + 0 means "play for ever" */ __u16 delay; /* Time to wait before to start playing an effect */ }; struct ff_trigger { __u16 button; /* Number of button triggering an effect */ - __u16 interval; /* Time to wait before an effect can be re-triggered */ + __u16 interval; /* Time to wait before an effect can be re-triggered (ms) */ }; -struct ff_shape { - __u16 attack_length; /* Duration of attack */ - __s16 attack_level; /* Level at beginning of attack */ - __u16 fade_length; /* Duration of fade */ - __s16 fade_level; /* Level at end of fade */ +struct ff_envelope { + __u16 attack_length; /* Duration of attack (ms) */ + __u16 attack_level; /* Level at beginning of attack */ + __u16 fade_length; /* Duration of fade (ms) */ + __u16 fade_level; /* Level at end of fade */ }; /* FF_CONSTANT */ struct ff_constant_effect { - __s16 level; /* Strength of effect */ - __u16 direction; /* Direction of effect (see periodic effects) */ - struct ff_shape shape; + __s16 level; /* Strength of effect. Negative values are OK */ + struct ff_envelope envelope; }; -/* FF_SPRING of FF_FRICTION */ -struct ff_interactive_effect { -/* Axis along which effect must be created. If null, the field named direction - * is used - * It is a bit array (ie to enable axes X and Y, use BIT(ABS_X) | BIT(ABS_Y) - */ - __u16 axis; - __u16 direction; +/* FF_RAMP */ +struct ff_ramp_effect { + __s16 start_level; + __s16 end_level; + struct ff_envelope envelope; +}; - __s16 right_saturation; /* Max level when joystick is on the right */ - __s16 left_saturation; /* Max level when joystick in on the left */ +/* FF_SPRING of FF_FRICTION */ +struct ff_condition_effect { + __u16 right_saturation; /* Max level when joystick is on the right */ + __u16 left_saturation; /* Max level when joystick in on the left */ __s16 right_coeff; /* Indicates how fast the force grows when the joystick moves to the right */ __s16 left_coeff; /* Same for left side */ __u16 deadband; /* Size of area where no force is produced */ - __s16 center; /* Position of dead dead zone */ + __s16 center; /* Position of dead zone */ }; /* FF_PERIODIC */ struct ff_periodic_effect { __u16 waveform; /* Kind of wave (sine, square...) */ - __u16 period; + __u16 period; /* in ms */ __s16 magnitude; /* Peak value */ __s16 offset; /* Mean value of wave (roughly) */ __u16 phase; /* 'Horizontal' shift */ - __u16 direction; /* Direction. 0 deg -> 0x0000 - 90 deg -> 0x4000 */ - struct ff_shape shape; + struct ff_envelope envelope; + +/* Only used if waveform == FF_CUSTOM */ + __u32 custom_len; /* Number of samples */ + __s16 *custom_data; /* Buffer of samples */ +/* Note: the data pointed by custom_data is copied by the driver. You can + * therefore dispose of the memory after the upload/update */ +}; + +/* FF_RUMBLE */ +/* Some rumble pads have two motors of different weight. + strong_magnitude represents the magnitude of the vibration generated + by the heavy motor. +*/ +struct ff_rumble_effect { + __u16 strong_magnitude; /* Magnitude of the heavy motor */ + __u16 weak_magnitude; /* Magnitude of the light one */ }; /* @@ -554,36 +603,30 @@ struct ff_effect { __u16 type; /* Following field denotes the unique id assigned to an effect. - * It is set by the driver. + * If user sets if to -1, a new effect is created, and its id is returned in the same field + * Else, the user sets it to the effect id it wants to update. */ __s16 id; + __u16 direction; /* Direction. 0 deg -> 0x0000 (down) + 90 deg -> 0x4000 (left) + 180 deg -> 0x8000 (up) + 270 deg -> 0xC000 (right) + */ + struct ff_trigger trigger; struct ff_replay replay; union { struct ff_constant_effect constant; + struct ff_ramp_effect ramp; struct ff_periodic_effect periodic; - struct ff_interactive_effect interactive; + struct ff_condition_effect condition[2]; /* One for each axis */ + struct ff_rumble_effect rumble; } u; }; /* - * Buttons that can trigger effects. Use for example FF_BTN(BTN_TRIGGER) to - * access the bitmap. - */ - -#define FF_BTN(x) ((x) - BTN_MISC + FF_BTN_OFFSET) -#define FF_BTN_OFFSET 0x00 - -/* - * Force feedback axis mappings. Use FF_ABS() to access the bitmap. - */ - -#define FF_ABS(x) ((x) + FF_ABS_OFFSET) -#define FF_ABS_OFFSET 0x40 - -/* * Force feedback effect types */ @@ -592,6 +635,9 @@ #define FF_CONSTANT 0x52 #define FF_SPRING 0x53 #define FF_FRICTION 0x54 +#define FF_DAMPER 0x55 +#define FF_INERTIA 0x56 +#define FF_RAMP 0x57 /* * Force feedback periodic effect types @@ -630,8 +676,9 @@ void *private; - int number; char *name; + char *phys; + char *uniq; unsigned short idbus; unsigned short idvendor; unsigned short idproduct; @@ -654,6 +701,9 @@ unsigned int repeat_key; struct timer_list timer; + struct pm_dev *pm_dev; + int state; + int abs[ABS_MAX + 1]; int rep[REP_MAX + 1]; @@ -668,6 +718,8 @@ int (*open)(struct input_dev *dev); void (*close)(struct input_dev *dev); + int (*accept)(struct input_dev *dev, struct file *file); + int (*flush)(struct input_dev *dev, struct file *file); int (*event)(struct input_dev *dev, unsigned int type, unsigned int code, int value); int (*upload_effect)(struct input_dev *dev, struct ff_effect *effect); int (*erase_effect)(struct input_dev *dev, int effect_id); @@ -676,16 +728,63 @@ struct input_dev *next; }; +/* + * Structure for hotplug & device<->driver matching. + */ + +#define INPUT_DEVICE_ID_MATCH_BUS 1 +#define INPUT_DEVICE_ID_MATCH_VENDOR 2 +#define INPUT_DEVICE_ID_MATCH_PRODUCT 4 +#define INPUT_DEVICE_ID_MATCH_VERSION 8 + +#define INPUT_DEVICE_ID_MATCH_EVBIT 0x010 +#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x020 +#define INPUT_DEVICE_ID_MATCH_RELBIT 0x040 +#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x080 +#define INPUT_DEVICE_ID_MATCH_MSCIT 0x100 +#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200 +#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400 +#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800 + +#define INPUT_DEVICE_ID_MATCH_DEVICE\ + (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT) +#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\ + (INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION) + +struct input_device_id { + + unsigned long flags; + + unsigned short idbus; + unsigned short idvendor; + unsigned short idproduct; + unsigned short idversion; + + unsigned long evbit[NBITS(EV_MAX)]; + unsigned long keybit[NBITS(KEY_MAX)]; + unsigned long relbit[NBITS(REL_MAX)]; + unsigned long absbit[NBITS(ABS_MAX)]; + unsigned long mscbit[NBITS(MSC_MAX)]; + unsigned long ledbit[NBITS(LED_MAX)]; + unsigned long sndbit[NBITS(SND_MAX)]; + unsigned long ffbit[NBITS(FF_MAX)]; + + unsigned long driver_info; +}; + struct input_handler { void *private; void (*event)(struct input_handle *handle, unsigned int type, unsigned int code, int value); - struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev); + struct input_handle* (*connect)(struct input_handler *handler, struct input_dev *dev, struct input_device_id *id); void (*disconnect)(struct input_handle *handle); struct file_operations *fops; int minor; + char *name; + + struct input_device_id *id_table; struct input_handle *handle; struct input_handler *next; @@ -696,6 +795,7 @@ void *private; int open; + char *name; struct input_dev *dev; struct input_handler *handler; @@ -713,6 +813,9 @@ int input_open_device(struct input_handle *); void input_close_device(struct input_handle *); +int input_accept_process(struct input_handle *handle, struct file *file); +int input_flush_device(struct input_handle* handle, struct file* file); + devfs_handle_t input_register_minor(char *name, int minor, int minor_base); void input_unregister_minor(devfs_handle_t handle); @@ -721,6 +824,8 @@ #define input_report_key(a,b,c) input_event(a, EV_KEY, b, !!(c)) #define input_report_rel(a,b,c) input_event(a, EV_REL, b, c) #define input_report_abs(a,b,c) input_event(a, EV_ABS, b, c) +#define input_report_ff(a,b,c) input_event(a, EV_FF, b, c) +#define input_report_ff_status(a,b,c) input_event(a, EV_FF_STATUS, b, c) #endif #endif diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/include/linux/serio.h linux-modified/include/linux/serio.h --- linux-vanilla/include/linux/serio.h 2002-11-29 00:53:15.000000000 +0100 +++ linux-modified/include/linux/serio.h 2003-07-21 23:08:09.000000000 +0200 @@ -2,38 +2,38 @@ #define _SERIO_H /* - * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ + * $Id: patch-2.4.22-iforce,v 1.1 2004/06/01 05:43:10 hans Exp $ * - * Copyright (C) 1999 Vojtech Pavlik - * - * Sponsored by SuSE + * Copyright (C) 1999-2001 Vojtech Pavlik */ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or + * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * + * * Should you need to contact me, the author, you can do so either by * e-mail - mail your message to , or by paper mail: - * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic + * Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic */ /* * The serial port set type ioctl. */ +#include #include + #define SPIOCSTYPE _IOW('q', 0x01, unsigned long) struct serio; @@ -42,23 +42,30 @@ void *private; void *driver; + char *name; + char *phys; + + unsigned short idbus; + unsigned short idvendor; + unsigned short idproduct; + unsigned short idversion; unsigned long type; - int number; int (*write)(struct serio *, unsigned char); int (*open)(struct serio *); void (*close)(struct serio *); struct serio_dev *dev; - struct serio *next; }; struct serio_dev { void *private; + char *name; + void (*write_wakeup)(struct serio *); void (*interrupt)(struct serio *, unsigned char, unsigned int); void (*connect)(struct serio *, struct serio_dev *dev); void (*disconnect)(struct serio *); @@ -77,7 +84,14 @@ static __inline__ int serio_write(struct serio *serio, unsigned char data) { - return serio->write(serio, data); + return serio->write?serio->write(serio, data):-ENOSYS; +} + +static __inline__ void serio_dev_write_wakeup(struct serio *serio) +{ + if (serio->dev && serio->dev->write_wakeup) { + serio->dev->write_wakeup(serio); + } } #define SERIO_TIMEOUT 1 @@ -109,6 +123,8 @@ #define SERIO_STOWAWAY 0x20 #define SERIO_H3600 0x21 #define SERIO_PS2SER 0x22 +#define SERIO_TWIDKBD 0x23 +#define SERIO_TWIDJOY 0x24 #define SERIO_HIL 0x25 #define SERIO_ID 0xff00UL diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/usb/usbkbd.c linux-modified/drivers/usb/usbkbd.c --- linux-vanilla/drivers/usb/usbkbd.c 2003-06-13 16:51:37.000000000 +0200 +++ linux-modified/drivers/usb/usbkbd.c 2003-07-21 23:08:09.000000000 +0200 @@ -250,8 +250,8 @@ input_register_device(&kbd->dev); - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", - kbd->dev.number, kbd->name, dev->bus->busnum, dev->devnum, ifnum); + printk(KERN_INFO "input: %s on usb%d:%d.%d\n", + kbd->name, dev->bus->busnum, dev->devnum, ifnum); return kbd; } diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/usb/usbmouse.c linux-modified/drivers/usb/usbmouse.c --- linux-vanilla/drivers/usb/usbmouse.c 2003-06-13 16:51:37.000000000 +0200 +++ linux-modified/drivers/usb/usbmouse.c 2003-07-21 23:08:09.000000000 +0200 @@ -166,8 +166,8 @@ input_register_device(&mouse->dev); - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", - mouse->dev.number, mouse->name, dev->bus->busnum, dev->devnum, ifnum); + printk(KERN_INFO "input: %s on usb%d:%d.%d\n", + mouse->name, dev->bus->busnum, dev->devnum, ifnum); return mouse; } diff -u -r -N -x '*.rej' -x '*.~' linux-vanilla/drivers/usb/wacom.c linux-modified/drivers/usb/wacom.c --- linux-vanilla/drivers/usb/wacom.c 2002-11-29 00:53:15.000000000 +0100 +++ linux-modified/drivers/usb/wacom.c 2003-07-21 23:08:09.000000000 +0200 @@ -491,8 +491,8 @@ usb_set_report(dev, ifnum, 3, 5, rep_data, 0); usb_set_report(dev, ifnum, 3, 6, rep_data, 0); - printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n", - wacom->dev.number, wacom->features->name, dev->bus->busnum, dev->devnum, ifnum); + printk(KERN_INFO "input: %s on usb%d:%d.%d\n", + wacom->features->name, dev->bus->busnum, dev->devnum, ifnum); return wacom; }