## Automatically generated incremental diff
## From:   linux-2.4.10-pre8
## To:     linux-2.4.10-pre9
## Robot:  $Id: make-incremental-diff,v 1.8 2001/12/04 06:05:04 hpa Exp $

diff -urN linux-2.4.10-pre8/Documentation/filesystems/ntfs.txt linux/Documentation/filesystems/ntfs.txt
--- linux-2.4.10-pre8/Documentation/filesystems/ntfs.txt	Mon Dec  3 23:09:37 2001
+++ linux/Documentation/filesystems/ntfs.txt	Mon Dec  3 23:09:47 2001
@@ -98,6 +98,16 @@
 ChangeLog
 =========
 
+NTFS 1.1.19:
+	- Fixed ntfs_getdir_unsorted(), ntfs_readdir() and ntfs_printcb() to
+	  cope with arbitrary cluster sizes. Very important for Win2k+. Also,
+	  make them detect directories which are too large and truncate the
+	  enumeration pretending end of directory was reached. Detect more
+	  error conditions and overflows. All this fixes the problem where the
+	  driver could end up in an infinite loop under certain circumstances.
+	- Fixed potential memory leaks in Unicode conversion functions and
+	  setup correct NULL return values.
+
 NTFS 1.1.18:
 
 	- Enhanced & bug fixed cluster deallocation (race fixes, etc.)
diff -urN linux-2.4.10-pre8/Documentation/input/cs461x.txt linux/Documentation/input/cs461x.txt
--- linux-2.4.10-pre8/Documentation/input/cs461x.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/input/cs461x.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,45 @@
+Preface.
+
+This is a new low-level driver to support analog joystick attached to
+Crystal SoundFusion CS4610/CS4612/CS4615. This code is based upon 
+Vortex/Solo drivers as an example of decoration style, and ALSA
+0.5.8a kernel drivers as an chipset documentation and samples.
+
+This version does not have cooked mode support; the basic code 
+is present here, but have not tested completely. The button analysis 
+is completed in this mode, but the axis movement is not. 
+
+Raw mode works fine with analog joystick front-end driver and cs461x
+driver as a backend. I've tested this driver with CS4610, 4-axis and 
+4-button joystick; I mean the jstest utility. Also I've tried to
+play in xracer game using joystick, and the result is better than
+keyboard only mode.
+
+The sensitivity and calibrate quality have not been tested; the two
+reasons are performed: the same hardware cannot work under Win95 (blue 
+screen in VJOYD); I have no documentation on my chip; and the existing 
+behavior in my case was not raised the requirement of joystick calibration. 
+So the driver have no code to perform hardware related calibration.
+
+The patch contains minor changes of Config.in and Makefile files. All
+needed code have been moved to one separate file cs461x.c like ns558.c
+This driver have the basic support for PCI devices only; there is no
+ISA or PnP ISA cards supported. AFAIK the ns558 have support for Crystal 
+ISA and PnP ISA series.
+
+The driver works witn ALSA drivers simultaneously. For exmple, the xracer
+uses joystick as input device and PCM device as sound output in one time.
+There are no sound or input collisions detected. The source code have
+comments about them; but I've found the joystick can be initialized 
+separately of ALSA modules. So, you canm use only one joystick driver
+without ALSA drivers. The ALSA drivers are not needed to compile or
+run this driver.
+
+There are no debug information print have been placed in source, and no
+specific options required to work this driver. The found chipset parameters
+are printed via printk(KERN_INFO "..."), see the /var/log/messages to
+inspect cs461x: prefixed messages to determine possible card detection 
+errors.
+
+Regards,
+Viktor
diff -urN linux-2.4.10-pre8/Documentation/input/ff.txt linux/Documentation/input/ff.txt
--- linux-2.4.10-pre8/Documentation/input/ff.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/input/ff.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,194 @@
+Force feedback for Linux.
+By Johann Deneux <deneux@ifrance.com> on 2001/04/22.
+
+----------------------------------------------------------------------------
+
+0. Introduction
+~~~~~~~~~~~~~~~
+This document describes how to use force feedback devices under Linux. The
+goal is not to support these devices as if they were simple input-only devices
+(as it is already the case), but to really enable the rendering of force
+effects.
+At the moment, only I-Force devices are supported, and not officially. That
+means I had to find out how the protocol works on my own. Of course, the
+information I managed to grasp is far from being complete, and I can not
+guarranty that this driver will work for you.
+This document only describes the force feedback part of the driver for I-Force
+devices. Please read joystick.txt before reading further this document.
+
+2. Instructions to the user
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Here are instructions on how to compile and use the driver. In fact, this
+driver is the normal iforce.o, input.o and evdev.o drivers written by Vojtech
+Pavlik, plus additions to support force feedback.
+
+Before you start, let me WARN you that some devices shake violently during the
+initialisation phase. This happens for example with my "AVB Top Shot Pegasus".
+To stop this annoying behaviour, move you joystick to its limits. Anyway, you
+should keep a hand on your device, in order to avoid it to brake down if
+something goes wrong.
+
+At the kernel's compilation:
+	- Enable IForce/Serial
+	- Enable Event interface
+
+Compile the modules, install them.
+
+You also need inputattach.
+
+You then need to insert the modules into the following order:
+% modprobe joydev
+% modprobe serport
+% 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:
+cd /dev
+rm js*
+mkdir input
+mknod input/js0 c 13 0
+mknod input/js1 c 13 1
+mknod input/js2 c 13 2
+mknod input/js3 c 13 3
+ln -s input/js0 js0
+ln -s input/js1 js1
+ln -s input/js2 js2
+ln -s input/js3 js3
+
+mknod input/event0 c 13 64
+mknod input/event1 c 13 65
+mknod input/event2 c 13 66
+mknod input/event3 c 13 67
+
+2.1 Does it work ?
+~~~~~~~~~~~~~~~~~~
+There is an utility called fftest that will allow you to test the driver.
+% fftest /dev/eventXX
+
+3. Instructions to the developper
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  All interactions are done using the event API. That is, you can use ioctl()
+and write() on /dev/input/eventXX.
+  This information is subject to change.
+
+3.1 Querying device capabilities
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#include <linux/input.h>
+#include <sys/ioctl.h>
+
+int ioctl(int file_descriptor, int request, unsigned long *features);
+
+"request" must be EVIOCGBIT(EV_FF, sizeof(unsigned long))
+
+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_CONSTANT	can render constant force effects
+- FF_PERIODIC	can render periodic effects (sine, ramp, square...)
+- FF_SPRING	can simulate the presence of a spring
+- FF_FRICTION	can simulate friction (aka drag, damper effect...)
+- 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.
+
+3.2 Uploading effects to the device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+#include <linux/input.h>
+#include <sys/ioctl.h>
+ 
+int ioctl(int file_descriptor, int request, struct ff_effect *effect);
+
+"request" must be EVIOCSFF.
+
+"effect" points to a structure describing the effect to upload. The effect is
+uploaded, but not played.
+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 <linux/input.h> for a description of the ff_effect stuct.
+
+3.3 Removing an effect from the device
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+int ioctl(int fd, EVIOCRMFF, effect.id);
+
+This makes room for new effects in the device's memory. Please note this won't
+stop the effect if it was playing.
+
+3.4 Controlling the playback of effects
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Control of playing is done with write(). Below is an example:
+
+#include <linux/input.h>
+#include <unistd.h>
+
+	struct input_event play;
+	struct input_event stop;
+	struct ff_effect effect;
+	int fd;
+...
+	fd = open("/dev/input/eventXX", O_RDWR);
+...
+	/* Play three times */
+	play.type = EV_FF;
+	play.code = effect.id;
+	play.value = 3;
+	
+	write(fd, (const void*) &play, sizeof(play));
+...
+	/* Stop an effect */
+	stop.type = EV_FF;
+	stop.code = effect.id;
+	stop.value = 0;
+	
+	write(fd, (const void*) &play, sizeof(stop));
+
+3.5 Setting the gain
+~~~~~~~~~~~~~~~~~~~~
+Not all devices have the same strength. Therefore, users should set a gain
+factor depending on how strong they want effects to be. This setting is
+persistent accross access to the driver, so you should not care about it if
+you are writing games, as another utility probably already set this for you.
+
+/* Set the gain of the device
+int gain;		/* between 0 and 100 */
+struct input_event ie;	/* structure used to communicate with the driver */
+
+ie.type = EV_FF;
+ie.code = FF_GAIN;
+ie.value = 0xFFFFUL * gain / 100;
+
+if (write(fd, &ie, sizeof(ie)) == -1)
+	perror("set gain");
+
+3.6 Enabling/Disabling autocenter
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+The autocenter feature quite disturbs the rendering of effects in my opinion,
+and I think it should be an effect, which computation depends on the game
+type. But you can enable it if you want.
+
+int autocenter;		/* between 0 and 100 */
+struct input_event ie;
+
+ie.type = EV_FF;
+ie.code = FF_AUTOCENTER;
+ie.value = 0xFFFFUL * autocenter / 100;
+
+if (write(fd, &ie, sizeof(ie)) == -1)
+	perror("set auto-center");
+
+A value of 0 means "no auto-center".
+
+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.
+
diff -urN linux-2.4.10-pre8/Documentation/input/gameport-programming.txt linux/Documentation/input/gameport-programming.txt
--- linux-2.4.10-pre8/Documentation/input/gameport-programming.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/input/gameport-programming.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,189 @@
+$Id: gameport-programming.txt,v 1.3 2001/04/24 13:51:37 vojtech Exp $
+
+Programming gameport drivers
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. A basic classic gameport
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+If the gameport doesn't provide more than the inb()/outb() functionality,
+the code needed to register it with the joystick drivers is simple:
+
+	struct gameport gameport;
+
+	gameport.io = MY_IO_ADDRESS;
+	gameport_register_port(&gameport);
+
+Make sure struct gameport is initialized to 0 in all other fields. The
+gameport generic code will take care of the rest.
+
+If your hardware supports more than one io address, and your driver can
+choose which one program the hardware to, starting from the more exotic
+addresses is preferred, because the likelyhood of clashing with the standard
+0x201 address is smaller.
+
+Eg. if your driver supports addresses 0x200, 0x208, 0x210 and 0x218, then
+0x218 would be the address of first choice.
+
+If your hardware supports a gameport address that is not mapped to ISA io
+space (is above 0x1000), use that one, and don't map the ISA mirror.
+
+Also, always request_region() on the whole io space occupied by the
+gameport. Although only one ioport is really used, the gameport usually
+occupies from one to sixteen addresses in the io space.
+
+Please also consider enabling the gameport on the card in the ->open()
+callback if the io is mapped to ISA space - this way it'll occupy the io
+space only when something really is using it. Disable it again in the
+->close() callback. You also can select the io address in the ->open()
+callback, so that it doesn't fail if some of the possible addresses are
+already occupied by other gameports.
+
+2. Memory mapped gameport
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+When a gameport can be accessed through MMIO, this way is preferred, because
+it is faster, allowing more reads per second. Registering such a gameport
+isn't as easy as a basic IO one, but not so much complex:
+
+	struct gameport gameport;
+
+	void my_trigger(struct gameport *gameport)
+	{
+		my_mmio = 0xff;
+	}
+
+	unsigned char my_read(struct gameport *gameport)
+	{
+		return my_mmio;	
+	}
+
+	gameport.read = my_read;
+	gameport.trigger = my_trigger;
+	gameport_register_port(&gameport);
+
+3. Cooked mode gameport
+~~~~~~~~~~~~~~~~~~~~~~~
+
+There are gameports that can report the axis values as numbers, that means
+the driver doesn't have to measure them the old way - an ADC is built into
+the gameport. To register a cooked gameport:
+
+	struct gameport gameport;
+
+	int my_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+	{
+		int i;
+
+		for (i = 0; i < 4; i++)
+			axes[i] = my_mmio[i];
+		buttons[i] = my_mmio[4];
+	}
+
+	int my_open(struct gameport *gameport, int mode)
+	{
+		return -(mode != GAMEPORT_MODE_COOKED);
+	}
+
+	gameport.cooked_read = my_cooked_read;
+	gameport.open = my_open;
+	gameport.fuzz = 8;
+	gameport_register_port(&gameport);
+
+The only confusing thing here is the fuzz value. Best determined by
+experimentation, it is the amount of noise in the ADC data. Perfect
+gameports can set this to zero, most common have fuzz between 8 and 32.
+See analog.c and input.c for handling of fuzz - the fuzz value determines
+the size of a gaussian filter window that is used to eliminate the noise
+in the data.
+
+4. More complex gameports
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Gameports can support both raw and cooked modes. In that case combine either
+examples 1+2 or 1+3. Gameports can support internal calibration - see below,
+and also lightning.c and analog.c on how that works. If your driver supports
+more than one gameport instance simultaneously, use the ->private member of
+the gameport struct to point to your data.
+
+5. Unregistering a gameport
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Simple:
+
+gameport_unregister_port(&gameport);
+
+6. The gameport structure
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+struct gameport {
+
+	void *private;
+
+A private pointer for free use in the gameport driver. (Not the joystick
+driver!)
+
+	int number;
+
+Number assigned to the gameport when registered. Informational purpose only.
+
+	int io;
+
+I/O address for use with raw mode. You have to either set this, or ->read()
+to some value if your gameport supports raw mode.
+
+	int speed;
+
+Raw mode speed of the gameport reads in thousands of reads per second.
+
+	int fuzz;
+
+If the gameport supports cooked mode, this should be set to a value that
+represents the amount of noise in the data. See section 3.
+
+	void (*trigger)(struct gameport *);
+
+Trigger. This function should trigger the ns558 oneshots. If set to NULL,
+outb(0xff, io) will be used.
+
+	unsigned char (*read)(struct gameport *);
+
+Read the buttons and ns558 oneshot bits. If set to NULL, inb(io) will be
+used instead.
+
+	int (*cooked_read)(struct gameport *, int *axes, int *buttons);	
+
+If the gameport supports cooked mode, it should point this to its cooked
+read function. It should fill axes[0..3] with four values of the joystick axes
+and buttons[0] with four bits representing the buttons.
+
+	int (*calibrate)(struct gameport *, int *axes, int *max); 
+
+Function for calibrating the ADC hardware. When called, axes[0..3] should be
+pre-filled by cooked data by the caller, max[0..3] should be pre-filled with
+expected maximums for each axis. The calibrate() function should set the
+sensitivity of the ADC hardware so that the maximums fit in its range and
+recompute the axes[] values to match the new sensitivity or re-read them from
+the hardware so that they give valid values. 
+
+	int (*open)(struct gameport *, int mode);
+
+Open() serves two purposes. First a driver either opens the port in raw or
+in cooked mode, the open() callback can decide which modes are supported.
+Second, resource allocation can happen here. The port can also be enabled
+here. Prior to this call, other fields of the gameport struct (namely the io
+member) need not to be valid.
+
+	void (*close)(struct gameport *);
+
+Close() should free the resources allocated by open, possibly disabling the
+gameport.
+
+	struct gameport_dev *dev;
+	struct gameport *next;
+
+For internal use by the gameport layer.
+
+};
+
+Enjoy!
diff -urN linux-2.4.10-pre8/Documentation/input/input-programming.txt linux/Documentation/input/input-programming.txt
--- linux-2.4.10-pre8/Documentation/input/input-programming.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/input/input-programming.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,271 @@
+$Id: input-programming.txt,v 1.4 2001/05/04 09:47:14 vojtech Exp $
+
+Programming input drivers
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1. Creating an input device driver
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+1.0 The simplest example
+~~~~~~~~~~~~~~~~~~~~~~~~
+
+Here comes a very simple example of an input device driver. The device has
+just one button and the button is accessible at i/o port BUTTON_PORT. When
+pressed or released a BUTTON_IRQ happens. The driver could look like:
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+#include <asm/io.h>
+
+static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+	input_report_key(&button_dev, BTN_1, inb(BUTTON_PORT) & 1);
+}
+
+static int __init button_init(void)
+{
+	if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
+                printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
+                return -EBUSY;
+        }
+	
+	button_dev.evbit[0] = BIT(EV_KEY);
+	button_dev.keybit[LONG(BTN_0)] = BIT(BTN_0);
+	
+	input_register_device(&button_dev);
+}
+
+static void __exit button_exit(void)
+{
+        input_unregister_device(&button_dev);
+	free_irq(BUTTON_IRQ, button_interrupt);
+}
+
+module_init(button_init);
+module_exit(button_exit);
+
+1.1 What the example does
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+First it has to include the <linux/input.h> file, which interfaces to the
+input subsystem. This provides all the definitions needed.
+
+In the _init function, which is called either upon module load or when
+booting the kernel, it grabs the required resources (it should also check
+for the presence of the device).
+
+Then it sets the input bitfields. This way the device driver tells the other
+parts of the input systems what it is - what events can be generated or
+accepted by this input device. Our example device can only generate EV_KEY type
+events, and from those only BTN_0 event code. Thus we only set these two
+bits. We could have used
+
+	set_bit(EV_KEY, button_dev.evbit);
+	set_bit(BTN_0, button_dev.keybit);
+
+as well, but with more than single bits the first approach tends to be
+shorter. 
+
+Then the example driver registers the input device structure by calling
+
+	input_register_device(&button_dev);
+
+This adds the button_dev structure to linked lists of the input driver and
+calls device handler modules _connect functions to tell them a new input
+device has appeared. Because the _connect functions may call kmalloc(,
+GFP_KERNEL), which can sleep, input_register_device() must not be called
+from an interrupt or with a spinlock held.
+
+While in use, the only used function of the driver is
+
+	button_interrupt()
+
+which upon every interrupt from the button checks its state and reports it
+via the 
+
+	input_report_btn()
+
+call to the input system. There is no need to check whether the interrupt
+routine isn't reporting two same value events (press, press for example) to
+the input system, because the input_report_* functions check that
+themselves.
+
+1.2 dev->open() and dev->close()
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+In case the driver has to repeatedly poll the device, because it doesn't
+have an interrupt coming from it and the polling is too expensive to be done
+all the time, or if the device uses a valuable resource (eg. interrupt), it
+can use the open and close callback to know when it can stop polling or
+release the interrupt and when it must resume polling or grab the interrupt
+again. To do that, we would add this to our example driver:
+
+int button_used = 0;
+
+static int button_open(struct input_dev *dev)
+{
+        if (button_used++)
+                return 0;
+
+	if (request_irq(BUTTON_IRQ, button_interrupt, 0, "button", NULL)) {
+                printk(KERN_ERR "button.c: Can't allocate irq %d\n", button_irq);
+                button_used--;
+                return -EBUSY;
+        }
+
+        return 0;
+}
+
+static void button_close(struct input_dev *dev)
+{
+        if (!--button_used)
+                free_irq(IRQ_AMIGA_VERTB, button_interrupt);
+}
+
+static int __init button_init(void)
+{
+	...
+	button_dev.open = button_open;
+	button_dev.close = button_close;
+	...
+}
+
+Note the button_used variable - we have to track how many times the open
+function was called to know when exactly our device stops being used.
+
+The open() callback should return a 0 in case of succes or any nonzero value
+in case of failure. The close() callback (which is void) must always succeed.
+
+1.3 Basic event types
+~~~~~~~~~~~~~~~~~~~~~
+
+The most simple event type is EV_KEY, which is used for keys and buttons.
+It's reported to the input system via:
+
+	input_report_key(struct input_dev *dev, int code, int value)
+
+See linux/input.h for the allowable values of code (from 0 to KEY_MAX).
+Value is interpreted as a truth value, ie any nonzero value means key
+pressed, zero value means key released. The input code generates events only
+in case the value is different from before.
+
+In addition to EV_KEY, there are two more basic event types: EV_REL and
+EV_ABS. They are used for relative and absolute values supplied by the
+device. A relative value may be for example a mouse movement in the X axis.
+The mouse reports it as a relative difference from the last position,
+because it doesn't have any absolute coordinate system to work in. Absolute
+events are namely for joysticks and digitizers - devices that do work in an
+absolute coordinate systems.
+
+Having the device report EV_REL buttons is as simple as with EV_KEY, simply
+set the corresponding bits and call the
+
+	input_report_rel(struct input_dev *dev, int code, int value)
+
+function. Events are generated only for nonzero value. 
+
+However EV_ABS requires a little special care. Before calling
+input_register_devices, you have to fill additional fields in the input_dev
+struct for each absolute axis your device has. If our button device had also
+the ABS_X axis:
+
+	button_dev.absmin[ABS_X] = 0;
+	button_dev.absmax[ABS_X] = 255;
+	button_dev.absfuzz[ABS_X] = 4;
+	button_dev.absflat[ABS_X] = 8;
+
+This setting would be appropriate for a joystick X axis, with the minimum of
+0, maximum of 255 (which the joystick *must* be able to reach, no problem if
+it sometimes reports more, but it must be able to always reach the min and
+max values), with noise in the data up to +- 4, and with a center flat
+position of size 8.
+
+If you don't need absfuzz and absflat, you can set them to zero, which mean
+that the thing is precise and always returns to exactly the center position
+(if it has any).
+
+1.4 The void *private field
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+This field in the input structure can be used to point to any private data
+structures in the input device driver, in case the driver handles more than
+one device. You'll need it in the open and close callbacks.
+
+1.5 NBITS(), LONG(), BIT()
+~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These three macros frin input.h help some bitfield computations:
+
+	NBITS(x) - returns the length of a bitfield array in longs for x bits
+	LONG(x)  - returns the index in the array in longs for bit x
+	BIT(x)   - returns the indes in a long for bit x
+
+1.6 The number, id* and name fields
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The dev->number is assigned by the input system to the input device when it
+is registered. It has no use except for identifying the device to the user
+in system messages.
+
+The dev->name should be set before registering the input device by the input
+device driver. It's a string like 'Generic button device' containing an
+user friendly name of the device.
+
+The id* fields contain the bus ID (PCI, USB, ...), vendor ID and device ID
+of the device. The bus IDs are defined in input.h. The vendor and device ids
+are defined in pci_ids.h, usb_ids.h and similar include files. These fields
+should be set by the input device driver before registering it.
+
+The idtype field can be used for specific information for the input device
+driver.
+
+The id and name fields can be passed to userland via the evdev interface.
+
+1.7 The keycode, keycodemax, keycodesize fields
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+These two fields will be used for any inpur devices that report their data
+as scancodes. If not all scancodes can be known by autodetection, they may
+need to be set by userland utilities. The keycode array then is an array
+used to map from scancodes to input system keycodes. The keycode max will
+contain the size of the array and keycodesize the size of each entry in it
+(in bytes).
+
+1.8 Key autorepeat
+~~~~~~~~~~~~~~~~~~
+
+... is simple. It is handled by the input.c module. Hardware autorepeat is
+not used, because it's not present in many devices and even where it is
+present, it is broken sometimes (at keyboards: Toshiba notebooks). To enable
+autorepeat for your device, just set EV_REP in dev->evbit. All will be
+handled by the input system.
+
+1.9 Other event types, handling output events
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The other event types up to now are:
+
+EV_LED - used for the keyboad LEDs.
+EV_SND - used for keyboard beeps.
+
+They are very similar to for example key events, but they go in the other
+direction - from the system to the input device driver. If your input device
+driver can handle these events, it has to set the respective bits in evbit,
+*and* also the callback routine:
+
+	button_dev.event = button_event;
+
+int button_event(struct input_dev *dev, unsigned int type, unsigned int code, int value);
+{
+	if (type == EV_SND && code == EV_BELL) {
+		outb(value, BUTTON_BELL);
+		return 0;
+	}
+	return -1;
+}
+
+This callback routine can be called from an interrupt or a BH (although that
+isn't a rule), and thus must not sleep, and must not take too long to finish.
diff -urN linux-2.4.10-pre8/Documentation/input/input.txt linux/Documentation/input/input.txt
--- linux-2.4.10-pre8/Documentation/input/input.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/input/input.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,297 @@
+			  Linux Input drivers v1.0
+	       (c) 1999-2001 Vojtech Pavlik <vojtech@suse.cz>
+			     Sponsored by SuSE
+	    $Id: input.txt,v 1.5 2001/06/06 11:05:33 vojtech Exp $
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+  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 <vojtech@suse.cz>, 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.
+
+1. Introduction
+~~~~~~~~~~~~~~~
+  This is a collection of drivers that is designed to support all input
+devices under Linux. However, in the current kernels, although it's
+possibilities are much bigger, it's limited to USB devices only. This is
+also why it resides in the drivers/usb subdirectory.
+
+  The center of the input drivers is the input.o module, which must be
+loaded before any other of the input modules - it serves as a way of
+communication between two groups of modules:
+
+1.1 Device drivers
+~~~~~~~~~~~~~~~~~~
+  These modules talk to the hardware (for example via USB), and provide
+events (keystrokes, mouse movements) to the input.o module.
+
+1.2 Event handlers
+~~~~~~~~~~~~~~~~~~
+  These modules get events from input.o and pass them where needed via
+various interfaces - keystrokes to the kernel, mouse movements via a
+simulated PS/2 interface to GPM and X and so on.
+
+2. Simple Usage
+~~~~~~~~~~~~~~~
+  For the most usual configuration, with one USB mouse and one USB keyboard,
+you'll have to load the following modules (or have them built in to the
+kernel):
+
+	input.o
+	mousedev.o
+	keybdev.o
+	usbcore.o
+	usb-[uo]hci.o
+	hid.o
+
+  After this, the USB keyboard will work straight away, and the USB mouse
+will be available as a character device on major 13, minor 63:
+
+	crw-r--r--   1 root     root      13,  63 Mar 28 22:45 mice
+
+  This device, has to be created, unless you use devfs, in which case it's
+created automatically. The commands to do that are:
+
+	cd /dev
+	mkdir input
+	mknod input/mice c 13 63
+
+  After that you have to point GPM (the textmode mouse cut&paste tool) and
+XFree to this device to use it - GPM should be called like:
+
+	gpm -t ps2 -m /dev/input/mice
+
+  And in X:
+
+	Section "Pointer"
+	    Protocol    "ImPS/2"
+	    Device      "/dev/input/mice"
+	    ZAxisMapping 4 5
+	EndSection
+
+  When you do all of the above, you can use your USB mouse and keyboard.
+
+3. Detailed Description
+~~~~~~~~~~~~~~~~~~~~~~~
+3.1 Device drivers
+~~~~~~~~~~~~~~~~~~
+  Device drivers are the modules that generate events. The events are
+however not useful without being handled, so you also will need to use some
+of the modules from section 3.2.
+
+3.1.1 hid.c
+~~~~~~~~~~~
+  Hid.c is the largest and most complex driver of the whole suite. It
+handles all HID devices, and because there is a very wide variety of them,
+and because the USB HID specification isn't simple, it needs to be this big.
+
+  Currently, it handles USB mice, joysticks, gamepads, steering wheels
+keyboards, trackballs and digitizers.
+
+ However, USB uses HID also for monitor controls, speaker controls, UPSs,
+LCDs and many other purposes.
+
+ The monitor and speaker controls should be easy to add to the hid/input
+interface, but for the UPSs and LCDs it doesn't make much sense. For this,
+the hiddev interface was designed. See Documentation/usb/hiddev.txt
+for more information about it.
+
+  The usage of the hid.o module is very simple, it takes no parameters,
+detects everything automatically and when a HID device is inserted, it
+detects it appropriately.
+
+  However, because the devices vary wildly, you might happen to have a
+device that doesn't work well. In that case #define DEBUG at the beginning
+of hid.c and send me the syslog traces.
+
+3.1.2 usbmouse.c
+~~~~~~~~~~~~~~~~
+  For embedded systems, for mice with broken HID descriptors and just any
+other use when the big hid.c wouldn't be a good choice, there is the
+usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP
+protocol. This also means the mice must support this simpler protocol. Not
+all do. If you don't have any strong reason to use this module, use hid.c
+instead.
+
+3.1.3 usbkbd.c
+~~~~~~~~~~~~~~
+  Much like usbmouse.c, this module talks to keyboards with a simpplified
+HIDBP protocol. It's smaller, but doesn't support any extra special keys.
+Use hid.c instead if there isn't any special reason to use this.
+
+3.1.4 wacom.c
+~~~~~~~~~~~~~
+  This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom
+PenPartner, that one is handled by the HID driver. Although the Intuos and
+Graphire tablets claim that they are HID tablets as well, they are not and
+thus need this specific driver.
+
+3.1.5 iforce.c
+~~~~~~~~~~~~~~~
+  A driver for I-Force joysticks and wheels, both over USB and RS232. 
+It includes ForceFeedback support now, even though Immersion Corp. considers
+the protocol a trade secret and won't disclose a word about it.
+
+3.2 Event handlers
+~~~~~~~~~~~~~~~~~~
+  Event handlers distrubite the events from the devices to userland and
+kernel, as needed.
+
+3.2.1 keybdev.c
+~~~~~~~~~~~~~~~
+  Keybdev is currently a rather ugly hack that translates the input events
+into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and
+passes them into the handle_scancode function of the keyboard.c module. This
+works well enough on all architectures that keybdev can generate rawmode on,
+other architectures can be added to it.
+
+  The right way would be to pass the events to keyboard.c directly, best if
+keyboard.c would itself be an event handler. This is done in the input
+patch, available on the webpage mentioned below.
+
+3.2.2 mousedev.c
+~~~~~~~~~~~~~~~~
+  Mousedev is also a hack to make programs that use mouse input work. It
+takes events from either mice or digitizers/tablets and makes a PS/2-style
+(a la /dev/psaux) mouse device available to the userland. Ideally, the
+programs could use a more reasonable interface, for example evdev.c
+
+  Mousedev devices in /dev/input (as shown above) are:
+
+	crw-r--r--   1 root     root      13,  32 Mar 28 22:45 mouse0
+	crw-r--r--   1 root     root      13,  33 Mar 29 00:41 mouse1
+	crw-r--r--   1 root     root      13,  34 Mar 29 00:41 mouse2
+	crw-r--r--   1 root     root      13,  35 Apr  1 10:50 mouse3
+	...
+	...
+	crw-r--r--   1 root     root      13,  62 Apr  1 10:50 mouse30
+	crw-r--r--   1 root     root      13,  63 Apr  1 10:50 mice
+
+Each 'mouse' device is assigned to a single mouse or digitizer, except the last
+one - 'mice'. This single character device is shared by all mice and
+digitizers, and even if none are connected, the device is present.  This is
+useful for hotplugging USB mice, so that programs can open the device even when
+no mice are present.
+
+  CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size
+of your screen (in pixels) in XFree86. This is needed if you want to use
+your digitizer in X, because it's movement is sent to X via a virtual PS/2
+mouse and thus needs to be scaled accordingly. These values won't be used if
+you use a mouse only.
+
+  Mousedev will generate either PS/2, ImPS/2 (Microsoft IntelliMouse) or
+ExplorerPS/2 (IntelliMouse Explorer) protocols, depending on what the program
+reading the data wishes. You can set GPM and X to any of these. You'll need
+ImPS/2 if you want to make use of a wheel on a USB mouse and ExplorerPS/2 if you
+want to use extra (up to 5) buttons. 
+
+3.2.3 joydev.c
+~~~~~~~~~~~~~~
+  Joydev implements v0.x and v1.x Linux joystick api, much like
+drivers/char/joystick/joystick.c used to in earlier versions. See
+joystick-api.txt in the Documentation subdirectory for details.  As soon as
+any joystick is connected, it can be accessed in /dev/input on:
+
+	crw-r--r--   1 root     root      13,   0 Apr  1 10:50 js0
+	crw-r--r--   1 root     root      13,   1 Apr  1 10:50 js1
+	crw-r--r--   1 root     root      13,   2 Apr  1 10:50 js2
+	crw-r--r--   1 root     root      13,   3 Apr  1 10:50 js3
+	...
+
+And so on up to js31.
+
+3.2.4 evdev.c
+~~~~~~~~~~~~~
+  Evdev is the generic input event interface. It passes the events generated
+in the kernel straight to the program, with timestamps. The API is still
+evolving, but should be useable now. It's described in section 5.
+
+  This should be the way for GPM and X to get keyboard and mouse mouse
+events. It allows for multihead in X without any specific multihead kernel
+support. The event codes are the same on all architectures and are hardware
+independent.
+
+  The devices are in /dev/input:
+
+	crw-r--r--   1 root     root      13,  64 Apr  1 10:49 event0
+	crw-r--r--   1 root     root      13,  65 Apr  1 10:50 event1
+	crw-r--r--   1 root     root      13,  66 Apr  1 10:50 event2
+	crw-r--r--   1 root     root      13,  67 Apr  1 10:50 event3
+	...
+
+3. Contacts
+~~~~~~~~~~~
+  This effort has it's home page at:
+
+	http://www.suse.cz/development/input/
+
+You'll find both the latest HID driver and the complete Input driver there
+as well as information how to access the CVS repository for latest revisions
+of the drivers.
+
+  There is also a mailing list for this:
+
+	majordomo@atrey.karlin.mff.cuni.cz
+
+Send "subscribe linux-input" to subscribe to it.
+
+4. Verifying if it works
+~~~~~~~~~~~~~~~~~~~~~~~~
+  Typing a couple keys on the keyboard should be enough to check that a USB
+keyboard works and is correctly connected to the kernel keyboard driver.
+
+  Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse is also
+emulated, characters should appear if you move it.
+
+  You can test the joystick emulation with the 'jstest' utility, available
+in the joystick package (see Documentation/joystick.txt).
+
+  You can test the event devics with the 'evtest' utitily available on the
+input driver homepage (see the URL above).
+
+5. Event interface
+~~~~~~~~~~~~~~~~~~
+  Should you want to add event device support into any application (X, gpm,
+svgalib ...) I <vojtech@suse.cz> will be happy to provide you any help I
+can. Here goes a description of the current state of things, which is going
+to be extended, but not changed incompatibly as time goes:
+
+  You can use blocking and nonblocking reads, also select() on the
+/dev/input/eventX devices, and you'll always get a whole number of input
+events on a read. Their layout is:
+
+struct input_event {
+	struct timeval time;
+	unsigned short type;
+	unsigned short code;
+	unsigned int value;
+};
+
+  'time' is the timestamp, it returns the time at which the event happened.
+Type is for example EV_REL for relative momement, REL_KEY for a keypress or
+release. More types are defined in include/linux/input.h.
+
+  'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
+list is in include/linux/input.h.
+
+  'value' is the value the event carries. Either a relative change for
+EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
+release, 1 for keypress and 2 for autorepeat.
diff -urN linux-2.4.10-pre8/Documentation/input/joystick-api.txt linux/Documentation/input/joystick-api.txt
--- linux-2.4.10-pre8/Documentation/input/joystick-api.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/input/joystick-api.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,316 @@
+		      Joystick API Documentation                -*-Text-*-
+
+		        Ragnar Hojland Espinosa
+			  <ragnar@macula.net>
+
+			      7 Aug 1998
+
+	$Id: joystick-api.txt,v 1.2 2001/05/08 21:21:23 vojtech Exp $
+
+1. Initialization
+~~~~~~~~~~~~~~~~~
+
+Open the joystick device following the usual semantics (that is, with open).
+Since the driver now reports events instead of polling for changes,
+immediately after the open it will issue a series of synthetic events
+(JS_EVENT_INIT) that you can read to check the initial state of the
+joystick.
+
+By default, the device is opened in blocking mode.
+
+	int fd = open ("/dev/js0", O_RDONLY);
+
+
+2. Event Reading
+~~~~~~~~~~~~~~~~
+
+	struct js_event e;
+	read (fd, &e, sizeof(struct js_event));
+
+where js_event is defined as
+
+	struct js_event {
+		__u32 time;     /* event timestamp in milliseconds */
+		__s16 value;    /* value */
+		__u8 type;      /* event type */
+		__u8 number;    /* axis/button number */
+	};
+
+If the read is successful, it will return sizeof(struct js_event), unless
+you wanted to read more than one event per read as described in section 3.1.
+
+
+2.1 js_event.type
+~~~~~~~~~~~~~~~~~
+
+The possible values of ``type'' are
+
+	#define JS_EVENT_BUTTON         0x01    /* button pressed/released */
+	#define JS_EVENT_AXIS           0x02    /* joystick moved */
+	#define JS_EVENT_INIT           0x80    /* initial state of device */
+
+As mentioned above, the driver will issue synthetic JS_EVENT_INIT ORed
+events on open. That is, if it's issuing a INIT BUTTON event, the
+current type value will be
+
+	int type = JS_EVENT_BUTTON | JS_EVENT_INIT;	/* 0x81 */
+
+If you choose not to differentiate between synthetic or real events
+you can turn off the JS_EVENT_INIT bits
+
+	type &= ~JS_EVENT_INIT;				/* 0x01 */
+
+
+2.2 js_event.number
+~~~~~~~~~~~~~~~~~~~
+
+The values of ``number'' correspond to the axis or button that
+generated the event. Note that they carry separate numeration (that
+is, you have both an axis 0 and a button 0). Generally,
+
+			number
+	1st Axis X	0
+	1st Axis Y	1
+	2nd Axis X	2
+	2nd Axis Y	3
+	...and so on
+
+Hats vary from one joystick type to another. Some can be moved in 8
+directions, some only in 4, The driver, however, always reports a hat as two
+independent axis, even if the hardware doesn't allow independent movement.
+
+
+2.3 js_event.value
+~~~~~~~~~~~~~~~~~~
+
+For an axis, ``value'' is a signed integer between -32767 and +32767
+representing the position of the joystick along that axis. If you
+don't read a 0 when the joystick is `dead', or if it doesn't span the
+full range, you should recalibrate it (with, for example, jscal).
+
+For a button, ``value'' for a press button event is 1 and for a release
+button event is 0.
+
+Though this
+
+	if (js_event.type == JS_EVENT_BUTTON) {
+		buttons_state ^= (1 << js_event.number);
+	}
+
+may work well if you handle JS_EVENT_INIT events separately,
+
+	if ((js_event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) {
+		if (js_event.value)
+	        	buttons_state |= (1 << js_event.number);
+	   	else
+	      		buttons_state &= ~(1 << js_event.number);
+	}
+
+is much safer since it can't lose sync with the driver. As you would
+have to write a separate handler for JS_EVENT_INIT events in the first
+snippet, this ends up being shorter.
+
+
+2.4 js_event.time
+~~~~~~~~~~~~~~~~~
+
+The time an event was generated is stored in ``js_event.time''. It's a time
+in milliseconds since ... well, since sometime in the past.  This eases the
+task of detecting double clicks, figuring out if movement of axis and button
+presses happened at the same time, and similar.
+
+
+3. Reading
+~~~~~~~~~~
+
+If you open the device in blocking mode, a read will block (that is,
+wait) forever until an event is generated and effectively read. There
+are two alternatives if you can't afford to wait forever (which is,
+admittedly, a long time;)
+
+	a) use select to wait until there's data to be read on fd, or
+	   until it timeouts. There's a good example on the select(2)
+	   man page.
+
+	b) open the device in non-blocking mode (O_NONBLOCK)
+
+
+3.1 O_NONBLOCK
+~~~~~~~~~~~~~~
+
+If read returns -1 when reading in O_NONBLOCK mode, this isn't
+necessarily a "real" error (check errno(3)); it can just mean there
+are no events pending to be read on the driver queue. You should read
+all events on the queue (that is, until you get a -1).
+
+For example,
+
+	while (1) {
+		while (read (fd, &e, sizeof(struct js_event)) > 0) {
+	        	process_event (e);
+	   	}
+	   	/* EAGAIN is returned when the queue is empty */
+	   	if (errno != EAGAIN) {
+	      		/* error */
+	   	}
+	   	/* do something interesting with processed events */
+	}
+
+One reason for emptying the queue is that if it gets full you'll start
+missing events since the queue is finite, and older events will get
+overwritten.
+
+The other reason is that you want to know all what happened, and not
+delay the processing till later.
+
+Why can get the queue full? Because you don't empty the queue as
+mentioned, or because too much time elapses from one read to another
+and too many events to store in the queue get generated. Note that
+high system load may contribute to space those reads even more.
+
+If time between reads is enough to fill the queue and loose an event,
+the driver will switch to startup mode and next time you read it,
+synthetic events (JS_EVENT_INIT) will be generated to inform you of
+the actual state of the joystick.
+
+[As for version 1.2.8, the queue is circular and able to hold 64
+ events. You can increment this size bumping up JS_BUFF_SIZE in
+ joystick.h and recompiling the driver.]
+
+
+In the above code, you might as well want to read more than one event
+at a time using the typical read(2) functionality. For that, you would
+replace the read above with something like
+
+	struct js_event mybuffer[0xff];
+	int i = read (fd, mybuffer, sizeof(struct mybuffer));
+
+In this case, read would return -1 if the queue was empty, or some
+other value in which the number of events read would be i /
+sizeof(js_event)  Again, if the buffer was full, it's a good idea to
+process the events and keep reading it until you empty the driver queue.
+
+
+4. IOCTLs
+~~~~~~~~~
+
+The joystick driver defines the following ioctl(2) operations.
+
+				/* function			3rd arg  */
+	#define JSIOCGAXES	/* get number of axes		char	 */
+	#define JSIOCGBUTTONS	/* get number of buttons	char	 */
+	#define JSIOCGVERSION	/* get driver version		int	 */
+	#define JSIOCGNAME(len) /* get identifier string	char	 */
+	#define JSIOCSCORR	/* set correction values	&js_corr */
+	#define JSIOCGCORR	/* get correction values	&js_corr */
+
+For example, to read the number of axes
+
+	char number_of_axes;
+	ioctl (fd, JSIOCGAXES, &number_of_axes);
+
+
+4.1 JSIOGCVERSION
+~~~~~~~~~~~~~~~~~
+
+JSIOGCVERSION is a good way to check in run-time whether the running
+driver is 1.0+ and supports the event interface. If it is not, the
+IOCTL will fail. For a compile-time decision, you can test the
+JS_VERSION symbol
+
+	#ifdef JS_VERSION
+	#if JS_VERSION > 0xsomething
+
+
+4.2 JSIOCGNAME
+~~~~~~~~~~~~~~
+
+JSIOCGNAME(len) allows you to get the name string of the joystick - the same
+as is being printed at boot time. The 'len' argument is the length of the
+buffer provided by the application asking for the name. It is used to avoid
+possible overrun should the name be too long.
+
+	char name[128];
+	if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
+		strncpy(name, "Unknown", sizeof(name));
+	printf("Name: %s\n", name);
+
+
+4.3 JSIOC[SG]CORR
+~~~~~~~~~~~~~~~~~
+
+For usage on JSIOC[SG]CORR I suggest you to look into jscal.c  They are
+not needed in a normal program, only in joystick calibration software
+such as jscal or kcmjoy. These IOCTLs and data types aren't considered
+to be in the stable part of the API, and therefore may change without
+warning in following releases of the driver.
+
+Both JSIOCSCORR and JSIOCGCORR expect &js_corr to be able to hold
+information for all axis. That is, struct js_corr corr[MAX_AXIS];
+
+struct js_corr is defined as
+
+	struct js_corr {
+		__s32 coef[8];
+		__u16 prec;
+		__u16 type;
+	};
+
+and ``type''
+
+	#define JS_CORR_NONE            0x00    /* returns raw values */
+	#define JS_CORR_BROKEN          0x01    /* broken line */
+
+
+5. Backward compatibility
+~~~~~~~~~~~~~~~~~~~~~~~~~
+
+The 0.x joystick driver API is quite limited and its usage is deprecated.
+The driver offers backward compatibility, though. Here's a quick summary:
+
+	struct JS_DATA_TYPE js;
+	while (1) {
+		if (read (fd, &js, JS_RETURN) != JS_RETURN) {
+	      		/* error */
+	   	}
+	   	usleep (1000);
+	}
+
+As you can figure out from the example, the read returns immediately,
+with the actual state of the joystick.
+
+	struct JS_DATA_TYPE {
+		int buttons;    /* immediate button state */
+		int x;          /* immediate x axis value */
+		int y;          /* immediate y axis value */
+	};
+
+and JS_RETURN is defined as
+
+	#define JS_RETURN       sizeof(struct JS_DATA_TYPE)
+
+To test the state of the buttons,
+
+	first_button_state  = js.buttons & 1;
+	second_button_state = js.buttons & 2;
+
+The axis values do not have a defined range in the original 0.x driver,
+except for that the values are non-negative. The 1.2.8+ drivers use a
+fixed range for reporting the values, 1 being the minimum, 128 the
+center, and 255 maximum value.
+
+The v0.8.0.2 driver also had an interface for 'digital joysticks', (now
+called Multisystem joysticks in this driver), under /dev/djsX. This driver
+doesn't try to be compatible with that interface.
+
+
+6. Final Notes
+~~~~~~~~~~~~~~
+
+____/|	Comments, additions, and specially corrections are welcome.
+\ o.O|	Documentation valid for at least version 1.2.8 of the joystick
+ =(_)=	driver and as usual, the ultimate source for documentation is
+   U	to "Use The Source Luke" or, at your convenience, Vojtech ;)
+
+					- Ragnar
+EOF
diff -urN linux-2.4.10-pre8/Documentation/input/joystick-parport.txt linux/Documentation/input/joystick-parport.txt
--- linux-2.4.10-pre8/Documentation/input/joystick-parport.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/input/joystick-parport.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,533 @@
+		    Linux Joystick parport drivers v2.0
+	       (c) 1998-2000 Vojtech Pavlik <vojtech@suse.cz>
+	       (c) 1998 Andree Borrmann <a.borrmann@tu-bs.de>
+			     Sponsored by SuSE
+	$Id: joystick-parport.txt,v 1.5 2001/05/15 06:41:00 vojtech Exp $
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+  Any information in this file is provided as-is, without any guarantee that
+it will be true. So, use it at your own risk. The possible damages that can
+happen include burning your parallel port, and/or the sticks and joystick
+and maybe even more. Like when a lightning kills you it is not our problem.
+
+1. Intro
+~~~~~~~~
+  The joystick parport drivers are used for joysticks and gamepads not
+originally designed for PCs and other computers Linux runs on. Because of
+that, PCs usually lack the right ports to connect these devices to. Parallel
+port, because of its ability to change single bits at will, and providing
+both output and input bits is the most suitable port on the PC for
+connecting such devices.
+
+2. Devices supported
+~~~~~~~~~~~~~~~~~~~~
+  Many console and 8-bit computer gamepads and joysticks are supported. The
+following subsections discuss usage of each.
+
+2.1 NES and SNES
+~~~~~~~~~~~~~~~~
+  The Nintendo Entertainment System and Super Nintendo Entertainment System
+gamepads are widely available, and easy to get. Also, they are quite easy to
+connect to a PC, and don't need much processing speed (108 us for NES and
+165 us for SNES, compared to about 1000 us for PC gamepads) to communicate
+with them.
+
+  All NES and SNES use the same synchronous serial protocol, clocked from
+the computer's side (and thus timing insensitive). To allow up to 5 NES
+and/or SNES gamepads connected to the parallel port at once, the output
+lines of the parallel port are shared, while one of 5 available input lines
+is assigned to each gamepad.
+
+  This protocol is handled by the gamecon.c driver, so that's the one
+you'll use for NES and SNES gamepads.
+
+  The main problem with PC parallel ports is that they don't have +5V power
+source on any of their pins. So, if you want a reliable source of power
+for your pads, use either keyboard or joystick port, and make a pass-through
+cable. You can also pull the power directly from the power supply (the red
+wire is +5V).
+
+  If you want to use the parallel port only, you can take the power is from
+some data pin. For most gamepad and parport implementations only one pin is
+needed, and I'd recommend pin 9 for that, the highest data bit. On the other
+hand, if you are not planning to use anything else than NES / SNES on the
+port, anything between and including pin 4 and pin 9 will work.
+
+(pin 9) -----> Power
+
+  Unfortunately, there are pads that need a lot more of power, and parallel
+ports that can't give much current through the data pins. If this is your
+case, you'll need to use diodes (as a prevention of destroying your parallel
+port), and combine the currents of two or more data bits together.
+
+	   Diodes
+(pin 9) ----|>|-------+------> Power
+		      |
+(pin 8) ----|>|-------+
+		      |
+(pin 7) ----|>|-------+
+		      |
+ <and so on>          :
+		      |
+(pin 4) ----|>|-------+
+
+  Ground is quite easy. On PC's parallel port the ground is on any of the
+pins from pin 18 to pin 25. So use any pin of these you like for the ground.
+
+(pin 18) -----> Ground
+
+  NES and SNES pads have two input bits, Clock and Latch, which drive the
+serial transfer. These are connected to pins 2 and 3 of the parallel port,
+respectively.
+
+(pin 2) -----> Clock
+(pin 3) -----> Latch
+
+  And the last thing is the NES / SNES data wire. Only that isn't shared and
+each pad needs its own data pin. The parallel port pins are:
+
+(pin 10) -----> Pad 1 data
+(pin 11) -----> Pad 2 data
+(pin 12) -----> Pad 3 data
+(pin 13) -----> Pad 4 data
+(pin 15) -----> Pad 5 data
+
+  Note that pin 14 is not used, since it is not an input pin on the parallel
+port.
+
+  This is everything you need on the PC's side of the connection, now on to
+the gamepads side. The NES and SNES have different connectors. Also, there
+are quite a lot of NES clones, and because Nintendo used proprietary
+connectors for their machines, the cloners couldn't and used standard D-Cannon
+connectors. Anyway, if you've got a gamepad, and it has buttons A, B, Turbo
+A, Turbo B, Select and Start, and is connected through 5 wires, then it is
+either a NES or NES clone and will work with this connection. SNES gamepads
+also use 5 wires, but have more buttons. They will work as well, of course.
+
+Pinout for NES gamepads                 Pinout for SNES gamepads
+
+	   +----> Power                   +-----------------------\
+	   |                            7 | o  o  o  o |  x  x  o  | 1
+ 5 +---------+  7                         +-----------------------/
+   | x  x  o   \                            |  |  |  |          |
+   | o  o  o  o |                           |  |  |  |          +-> Ground
+ 4 +------------+ 1                         |  |  |  +------------> Data
+     |  |  |  |                             |  |  +---------------> Latch
+     |  |  |  +-> Ground                    |  +------------------> Clock
+     |  |  +----> Clock                     +---------------------> Power
+     |  +-------> Latch
+     +----------> Data
+
+Pinout for NES clone (db9) gamepads     Pinout for NES clone (db15) gamepads
+
+	+---------> Clock                    +-----------------> Data
+	| +-------> Latch                    |             +---> Ground
+	| | +-----> Data                     |             |
+	| | |                              ___________________
+    _____________                        8 \ o x x x x x x o / 1
+  5 \ x o o o x / 1                         \ o x x o x x o /
+     \ x o x o /                          15 `~~~~~~~~~~~~~' 9
+    9 `~~~~~~~' 6                             |     |     |
+	 |   |                                |     |     +----> Clock
+	 |   +----> Power                     |     +----------> Latch
+	 +--------> Ground                    +----------------> Power
+
+2.2 Multisystem joysticks
+~~~~~~~~~~~~~~~~~~~~~~~~~
+  In the era of 8-bit machines, there was something like de-facto standard
+for joystick ports. They were all digital, and all used D-Cannon 9 pin
+connectors (db9). Because of that, a single joystick could be used without
+hassle on Atari (130, 800XE, 800XL, 2600, 7200), Amiga, Commodore C64,
+Amstrad CPC, Sinclair ZX Spectrum and many other machines. That's why these
+joysticks are called "Multisystem".
+
+  Now their pinout:
+
+      +---------> Right
+      | +-------> Left
+      | | +-----> Down
+      | | | +---> Up
+      | | | |
+  _____________
+5 \ x o o o o / 1
+   \ x o x o /
+  9 `~~~~~~~' 6
+       |   |
+       |   +----> Button
+       +--------> Ground
+
+  However, as time passed, extensions to this standard developed, and these
+were not compatible with each other:
+
+
+	Atari 130, 800/XL/XE		   MSX
+
+					 +-----------> Power
+      +---------> Right                  | +---------> Right
+      | +-------> Left                   | | +-------> Left
+      | | +-----> Down                   | | | +-----> Down
+      | | | +---> Up                     | | | | +---> Up
+      | | | |                            | | | | |
+  _____________                        _____________
+5 \ x o o o o / 1                    5 \ o o o o o / 1
+   \ x o o o /                          \ o o o o /
+  9 `~~~~~~~' 6                        9 `~~~~~~~' 6
+       | | |                              | | | |
+       | | +----> Button                  | | | +----> Button 1
+       | +------> Power                   | | +------> Button 2
+       +--------> Ground                  | +--------> Output 3
+					  +----------> Ground
+
+	Amstrad CPC			   Commodore C64
+
+					 +-----------> Analog Y
+      +---------> Right                  | +---------> Right
+      | +-------> Left                   | | +-------> Left
+      | | +-----> Down                   | | | +-----> Down
+      | | | +---> Up                     | | | | +---> Up
+      | | | |                            | | | | |
+  _____________                        _____________
+5 \ x o o o o / 1                    5 \ o o o o o / 1
+   \ x o o o /                          \ o o o o /
+  9 `~~~~~~~' 6                        9 `~~~~~~~' 6
+       | | |                              | | | |
+       | | +----> Button 1                | | | +----> Button
+       | +------> Button 2                | | +------> Power
+       +--------> Ground                  | +--------> Ground
+					  +----------> Analog X
+
+	Sinclair Spectrum +2A/+3           Amiga 1200
+                                     
+    +-----------> Up                     +-----------> Button 3
+    | +---------> Fire                   | +---------> Right
+    | |                                  | | +-------> Left
+    | |   +-----> Ground                 | | | +-----> Down
+    | |   |                              | | | | +---> Up
+    | |   |                              | | | | |
+  _____________                        _____________
+5 \ o o x o x / 1                    5 \ o o o o o / 1
+   \ o o o o /                          \ o o o o /
+  9 `~~~~~~~' 6                        9 `~~~~~~~' 6
+     | | | |                              | | | |
+     | | | +----> Right                   | | | +----> Button 1
+     | | +------> Left                    | | +------> Power
+     | +--------> Ground                  | +--------> Ground
+     +----------> Down                    +----------> Button 2
+
+  And there were many others.
+
+2.2.1 Multisystem joysticks using db9.c
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  For the Multisystem joysticks, and their derivatives, the db9.c driver
+was written. It allows only one joystick / gamepad per parallel port, but
+the interface is easy to build and works with almost anything.
+
+  For the basic 1-button Multisystem joystick you connect its wires to the
+parallel port like this:
+
+(pin  1) -----> Power
+(pin 18) -----> Ground
+
+(pin  2) -----> Up
+(pin  3) -----> Down
+(pin  4) -----> Left
+(pin  5) -----> Right
+(pin  6) -----> Button 1
+
+  However, if the joystick is switch based (eg. clicks when you move it),
+you might or might not, depending on your parallel port, need 10 kOhm pullup
+resistors on each of the direction and button signals, like this:
+
+(pin 2) ------------+------> Up
+	  Resistor  |
+(pin 1) --[10kOhm]--+
+
+  Try without, and if it doesn't work, add them. For TTL based joysticks /
+gamepads the pullups are not needed.
+
+  For joysticks with two buttons you connect the second button to pin 7 on
+the parallel port.
+
+(pin 7) -----> Button 2
+
+  And that's it.
+
+  On a side note, if you have already built a different adapter for use with
+the digital joystick driver 0.8.0.2, this is also supported by the db9.c
+driver, as device type 8. (See section 3.2)
+
+2.2.2 Multisystem joysticks using gamecon.c
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  For some people just one joystick per parallel port is not enough, and/or
+want to use them on one parallel port together with NES/SNES/PSX pads. This is
+possible using the gamecon.c. It supports up to 5 devices of the above types,
+including 1 and 2 buttons Multisystem joysticks.
+
+  However, there is nothing for free. To allow more sticks to be used at
+once, you need the sticks to be purely switch based (that is non-TTL), and
+not to need power. Just a plain simple six switches inside. If your
+joystick can do more (eg. turbofire) you'll need to disable it totally first
+if you want to use gamecon.c.
+
+  Also, the connection is a bit more complex. You'll need a bunch of diodes,
+and one pullup resistor. First, you connect the Directions and the button
+the same as for db9, however with the diodes inbetween.
+
+	    Diodes
+(pin 2) -----|<|----> Up
+(pin 3) -----|<|----> Down
+(pin 4) -----|<|----> Left
+(pin 5) -----|<|----> Right
+(pin 6) -----|<|----> Button 1
+
+  For two button sticks you also connect the other button.
+
+(pin 7) -----|<|----> Button 2
+
+  And finally, you connect the Ground wire of the joystick, like done in
+this little schematic to Power and Data on the parallel port, as described
+for the NES / SNES pads in section 2.1 of this file - that is, one data pin
+for each joystick. The power source is shared.
+
+Data    ------------+-----> Ground
+	  Resistor  |
+Power   --[10kOhm]--+
+
+  And that's all, here we go!
+
+2.2.3 Multisystem joysticks using turbografx.c
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The TurboGraFX interface, designed by
+
+	Steffen Schwenke <schwenke@burg-halle.de>
+
+  allows up to 7 Multisystem joysticks connected to the parallel port. In
+Steffen's version, there is support for up to 5 buttons per joystick.  However,
+since this doesn't work reliably on all parallel ports, the turbografx.c driver
+supports only one button per joystick. For more information on how to build the
+interface, see
+
+	http://www2.burg-halle.de/~schwenke/parport.html
+
+2.3 Sony Playstation
+~~~~~~~~~~~~~~~~~~~~
+
+  The PSX controller is supported by the gamecon.c. Pinout of the PSX
+controller (compatible with DirectPadPro):
+
+  +---------+---------+---------+
+9 | o  o  o | o  o  o | o  o  o | 1               parallel
+   \________|_________|________/                  port pins
+    |  |      |  |  |   |
+    |  |      |  |  |   +-------->  Clock    ---  (4)
+    |  |      |  |  +------------>  Select   ---  (3)
+    |  |      |  +--------------->  Power    ---  (5-9)
+    |  |      +------------------>  Ground   ---  (18-25)
+    |  +------------------------->  Command  ---  (2)
+    +---------------------------->  Data     ---  (one of 10,11,12,13,15)
+
+  The driver supports these controllers:
+
+ * Standard PSX Pad
+ * NegCon PSX Pad
+ * Analog PSX Pad (red mode)
+ * Analog PSX Pad (green mode)
+ * PSX Rumble Pad
+
+2.4 Sega
+~~~~~~~~
+  All the Sega controllers are more or less based on the standard 2-button
+Multisystem joystick. However, since they don't use switches and use TTL
+logic, the only driver usable with them is the db9.c driver.
+
+2.4.1 Sega Master System
+~~~~~~~~~~~~~~~~~~~~~~~~
+  The SMS gamepads are almost exactly the same as normal 2-button
+Multisystem joysticks. Set the driver to Multi2 mode, use the corresponding
+parallel port pins, and the following schematic:
+
+    +-----------> Power
+    | +---------> Right
+    | | +-------> Left
+    | | | +-----> Down
+    | | | | +---> Up
+    | | | | |
+  _____________
+5 \ o o o o o / 1
+   \ o o x o /
+  9 `~~~~~~~' 6
+     | |   |
+     | |   +----> Button 1
+     | +--------> Ground
+     +----------> Button 2
+
+2.4.2 Sega Genesis aka MegaDrive
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The Sega Genesis (in Europe sold as Sega MegaDrive) pads are an extension
+to the Sega Master System pads. They use more buttons (3+1, 5+1, 6+1).  Use
+the following schematic:
+
+    +-----------> Power
+    | +---------> Right
+    | | +-------> Left
+    | | | +-----> Down
+    | | | | +---> Up
+    | | | | |
+  _____________
+5 \ o o o o o / 1
+   \ o o o o /
+  9 `~~~~~~~' 6
+     | | | |
+     | | | +----> Button 1
+     | | +------> Select
+     | +--------> Ground
+     +----------> Button 2
+
+  The Select pin goes to pin 14 on the parallel port.
+
+(pin 14) -----> Select
+
+  The rest is the same as for Multi2 joysticks using db9.c
+
+2.4.3 Sega Saturn
+~~~~~~~~~~~~~~~~~
+  Sega Saturn has eight buttons, and to transfer that, without hacks like
+Genesis 6 pads use, it needs one more select pin. Anyway, it is still
+handled by the db9.c driver. Its pinout is very different from anything
+else.  Use this schematic:
+
+    +-----------> Select 1
+    | +---------> Power
+    | | +-------> Up
+    | | | +-----> Down
+    | | | | +---> Ground
+    | | | | |
+  _____________
+5 \ o o o o o / 1
+   \ o o o o /
+  9 `~~~~~~~' 6
+     | | | |
+     | | | +----> Select 2
+     | | +------> Right
+     | +--------> Left
+     +----------> Power
+
+  Select 1 is pin 14 on the parallel port, Select 2 is pin 16 on the
+parallel port.
+
+(pin 14) -----> Select 1
+(pin 16) -----> Select 2
+
+  The other pins (Up, Down, Right, Left, Power, Ground) are the same as for
+Multi joysticks using db9.c
+
+3. The drivers
+~~~~~~~~~~~~~~
+  There are three drivers for the parallel port interfaces. Each, as
+described above, allows to connect a different group of joysticks and pads.
+Here are described their command lines:
+
+3.1 gamecon.c
+~~~~~~~~~~~~~
+  Using gamecon.c you can connect up to five devices to one parallel port. It
+uses the following kernel/module command line:
+
+	gc=port,pad1,pad2,pad3,pad4,pad5
+
+  Where 'port' the number of the parport interface (eg. 0 for parport0).
+
+  And 'pad1' to 'pad5' are pad types connected to different data input pins
+(10,11,12,13,15), as described in section 2.1 of this file.
+
+  The types are:
+
+	Type | Joystick/Pad
+	--------------------
+	  0  | None
+	  1  | SNES pad
+	  2  | NES pad
+	  4  | Multisystem 1-button joystick
+	  5  | Multisystem 2-button joystick
+	  6  | N64 pad
+	  7  | Sony PSX controller
+
+  The exact type of the PSX controller type is autoprobed, so you must have
+your controller plugged in before initializing.
+
+  Should you want to use more than one of parallel ports at once, you can use
+gc_2 and gc_3 as additional command line parameters for two more parallel
+ports.
+
+3.2 db9.c
+~~~~~~~~~
+  Apart from making an interface, there is nothing difficult on using the
+db9.c driver. It uses the following kernel/module command line:
+
+	db9=port,type
+
+  Where 'port' is the number of the parport interface (eg. 0 for parport0).
+
+  Caveat here: This driver only works on bidirectional parallel ports. If
+your parallel port is recent enough, you should have no trouble with this.
+Old parallel ports may not have this feature.
+
+  'Type' is the type of joystick or pad attached:
+
+	Type | Joystick/Pad
+	--------------------
+	  0  | None
+	  1  | Multisystem 1-button joystick
+	  2  | Multisystem 2-button joystick
+	  3  | Genesis pad (3+1 buttons)
+	  5  | Genesis pad (5+1 buttons)
+	  6  | Genesis pad (6+2 buttons)
+	  7  | Saturn pad (8 buttons)
+	  8  | Multisystem 1-button joystick (v0.8.0.2 pin-out)
+	  9  | Two Multisystem 1-button joysticks (v0.8.0.2 pin-out) 
+	 10  | Amiga CD32 pad
+
+  Should you want to use more than one of these joysticks/pads at once, you
+can use db9_2 and db9_3 as additional command line parameters for two
+more joysticks/pads.
+
+3.3 turbografx.c
+~~~~~~~~~~~~~~~~
+  The turbografx.c driver uses a very simple kernel/module command line:
+
+	tgfx=port,js1,js2,js3,js4,js5,js6,js7
+
+  Where 'port' is the number of the parport interface (eg. 0 for parport0).
+
+  'jsX' is the number of buttons the Multisystem joysticks connected to the
+interface ports 1-7 have. For a standard multisystem joystick, this is 1.
+
+  Should you want to use more than one of these interfaces at once, you can
+use tgfx_2 and tgfx_3 as additional command line parameters for two more
+interfaces.
+
+3.4 PC parallel port pinout
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		  .----------------------------------------.
+   At the PC:     \ 13 12 11 10  9  8  7  6  5  4  3  2  1 /
+                   \  25 24 23 22 21 20 19 18 17 16 15 14 /
+                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	  Pin | Name    | Description
+	~~~~~~|~~~~~~~~~|~~~~~~~~~~
+	    1 | /STROBE | Strobe
+	  2-9 | D0-D7   | Data Bit 0-7
+	   10 | /ACK    | Acknowledge
+	   11 | BUSY    | Busy
+	   12 | PE      | Paper End
+	   13 | SELIN   | Select In
+	   14 | /AUTOFD | Autofeed
+	   15 | /ERROR  | Error
+	   16 | /INIT   | Initialize
+	   17 | /SEL    | Select
+	18-25 | GND     | Signal Ground
+
+3.5 End
+~~~~~~~
+  That's all, folks! Have fun!
diff -urN linux-2.4.10-pre8/Documentation/input/joystick.txt linux/Documentation/input/joystick.txt
--- linux-2.4.10-pre8/Documentation/input/joystick.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/input/joystick.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,583 @@
+		       Linux Joystick driver v2.0.0
+	       (c) 1996-2000 Vojtech Pavlik <vojtech@suse.cz>
+			     Sponsored by SuSE
+	   $Id: joystick.txt,v 1.6 2001/06/05 09:57:01 vojtech Exp $
+----------------------------------------------------------------------------
+
+0. Disclaimer
+~~~~~~~~~~~~~
+  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 <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
+Ucitelska 1576, 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.
+
+1. Intro
+~~~~~~~~
+  The joystick driver for Linux provides support for a variety of joysticks
+and similar devices. It is based on a larger project aiming to support all
+input devices in Linux.
+
+  Should you encounter any problems while using the driver, or joysticks
+this driver can't make complete use of, I'm very interested in hearing about
+them. Bug reports and success stories are also welcome.
+
+  The input project website is at:
+
+	http://www.suse.cz/development/input/
+	http://atrey.karlin.mff.cuni.cz/~vojtech/input/
+
+  There is also a mailing list for the driver at:
+
+	listproc@atrey.karlin.mff.cuni.cz
+
+send "subscribe linux-joystick Your Name" to subscribe to it.
+
+2. Usage
+~~~~~~~~
+  For basic usage you just choose the right options in kernel config and
+you should be set.
+
+2.1 inpututils
+~~~~~~~~~~~~~~
+For testing and other purposes (for example serial devices), a set of
+utilities is available at the abovementioned website. I suggest you download
+and install it before going on.
+
+2.2 Device nodes
+~~~~~~~~~~~~~~~~
+For applications to be able to use the joysticks, in you don't use devfs,
+you'll have to manually create these nodes in /dev:
+
+cd /dev
+rm js*
+mkdir input
+mknod input/js0 c 13 0
+mknod input/js1 c 13 1
+mknod input/js2 c 13 2
+mknod input/js3 c 13 3
+ln -s input/js0 js0
+ln -s input/js1 js1
+ln -s input/js2 js2
+ln -s input/js3 js3
+
+For testing with inpututils it's also convenient to create these:
+
+mknod input/event0 c 13 64
+mknod input/event1 c 13 65
+mknod input/event2 c 13 66
+mknod input/event3 c 13 67
+
+2.4 Modules needed 
+~~~~~~~~~~~~~~~~~~
+  For all joystick drivers to function, you'll need the userland interface
+module in kernel, either loaded or compiled in:
+
+	modprobe joydev
+
+  For gameport joysticks, you'll have to load the gameport driver as well;
+
+	modprobe ns558
+
+  And for serial port joysticks, you'll need the serial input line
+discipline module loaded and the inputattach utility started:
+
+	modprobe serport
+	inputattach -xxx /dev/tts/X &
+
+  In addition to that, you'll need the joystick driver module itself, most
+usually you'll have an analog joystick:
+
+	modprobe analog
+	
+  For automatic module loading, something like this might work - tailor to
+your needs:
+
+	alias tty-ldisc-2 serport
+	alias char-major-13 input
+	above input joydev ns558 analog
+	options analog js=gameport
+
+2.5 Verifying that it works
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  For testing the joystick driver functionality, there is the jstest
+program in the utilities package. You run it by typing:
+
+	jstest /dev/js0
+
+  And it should show a line with the joystick values, which update as you
+move the stick, and press its buttons. The axes should all be zero when the
+joystick is in the center position. They should not jitter by themselves to
+other close values, and they also should be steady in any other position of
+the stick. They should have the full range from -32767 to 32767. If all this
+is met, then it's all fine, and you can play the games. :)
+
+  If it's not, then there might be a problem. Try to calibrate the joystick,
+and if it still doesn't work, read the drivers section of this file, the
+troubleshooting section, and the FAQ.
+
+2.6. Calibration
+~~~~~~~~~~~~~~~~
+  For most joysticks you won't need any manual calibration, since the
+joystick should be autocalibrated by the driver automagically. However, with
+some analog joysticks, that either do not use linear resistors, or if you
+want better precision, you can use the jscal program
+
+	jscal -c /dev/js0
+
+ included in the joystick package to set better correction coefficients than
+what the driver would choose itself.
+
+  After calibrating the joystick you can verify if you like the new
+calibration using the jstest command, and if you do, you then can save the
+correction coefficients into a file
+
+	jscal -p /dev/js0 > /etc/joystick.cal
+
+  And add a line to your rc script executing that file
+
+	source /etc/joystick.cal
+
+  This way, after the next reboot your joystick will remain calibrated. You
+can also add the jscal -p line to your shutdown script.
+
+
+3. HW specific driver information
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+In this section each of the separate hardware specific drivers is described.
+
+3.1 Analog joysticks
+~~~~~~~~~~~~~~~~~~~~
+  The analog.c uses the standard analog inputs of the gameport, and thus
+supports all standard joysticks and gamepads. It uses a very advanced
+routine for this, allowing for data precision that can't be found on any
+other system.
+
+  It also supports extensions like additional hats and buttons compatible
+with CH Flightstick Pro, ThrustMaster FCS or 6 and 8 button gamepads. Saitek
+Cyborg 'digital' joysticks are also supported by this driver, because
+they're basically souped up CHF sticks.
+
+  However the only types that can be autodetected are:
+
+* 2-axis, 4-button joystick
+* 3-axis, 4-button joystick
+* 4-axis, 4-button joystick
+* Saitek Cyborg 'digital' joysticks
+
+  For other joystick types (more/less axes, hats, and buttons) support
+you'll need to specify the types either on the kernel command line or on the
+module command line, when inserting analog.o into the kernel. The
+parameters are:
+
+	js=type,type,type,....
+
+  'type' is type of the joystick from the table below, defining joysticks
+present on gameports in the system, starting with gameport0, second 'type'
+entry defining joystick on gameport1 and so on.
+
+	Type     | Meaning
+	-----------------------------------
+	none     | No analog joystick on that port
+	auto     | Autodetect joystick
+	2btn     | 2-button n-axis joystick
+	y-joy    | Two 2-button 2-axis joysticks on an Y-cable
+	y-pad    | Two 2-button 2-axis gamepads on an Y-cable
+	fcs      | Thrustmaster FCS compatible joystick
+	chf      | Joystick with a CH Flightstick compatible hat
+	fullchf  | CH Flightstick compatible with two hats and 6 buttons
+	gamepad  | 4/6-button n-axis gamepad
+	gamepad8 | 8-button 2-axis gamepad
+
+  In case your joystick doesn't fit in any of the above categories, you can
+specify the type as a number by combining the bits in the table below. This
+is not recommended unless you really know what are you doing. It's not
+dangerous, but not simple either.
+
+	Bit | Meaning
+	--------------------------
+	 0  | Axis X1
+	 1  | Axis Y1
+	 2  | Axis X2
+	 3  | Axis Y2
+	 4  | Button A
+	 5  | Button B
+	 6  | Button C
+	 7  | Button D
+	 8  | CHF Buttons X and Y
+	 9  | CHF Hat 1
+	10  | CHF Hat 2
+	11  | FCS Hat
+	12  | Pad Button X
+	13  | Pad Button Y
+	14  | Pad Button U
+	15  | Pad Button V
+	16  | Saitek F1-F4 Buttons
+	17  | Saitek Digital Mode
+	19  | GamePad
+	20  | Joy2 Axis X1
+	21  | Joy2 Axis Y1
+	22  | Joy2 Axis X2
+	23  | Joy2 Axis Y2
+	24  | Joy2 Button A
+	25  | Joy2 Button B
+	26  | Joy2 Button C
+	27  | Joy2 Button D
+	31  | Joy2 GamePad
+
+3.2 Microsoft SideWinder joysticks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  Microsoft 'Digital Overdrive' protocol is supported by the sidewinder.c
+module. All currently supported joysticks:
+
+* Microsoft SideWinder 3D Pro
+* Microsoft SideWinder Force Feedback Pro
+* Microsoft SideWinder Force Feedback Wheel
+* Microsoft SideWinder FreeStyle Pro 
+* Microsoft SideWinder GamePad (up to four, chained)
+* Microsoft SideWinder Precision Pro 
+* Microsoft SideWinder Precision Pro USB 
+
+  are autodetected, and thus no module parameters are needed.
+
+  There is one caveat with the 3D Pro. There are 9 buttons reported,
+although the joystick has only 8. The 9th button is the mode switch on the
+rear side of the joystick. However, moving it, you'll reset the joystick,
+and make it unresponsive for about a one third of a second. Furthermore, the
+joystick will also re-center itself, taking the position it was in during
+this time as a new center position. Use it if you want, but think first.
+
+  The SideWinder Standard is not a digital joystick, and thus is supported
+by the analog driver described above. 
+
+3.3 Logitech ADI devices
+~~~~~~~~~~~~~~~~~~~~~~~~
+  Logitech ADI protocol is supported by the adi.c module. It should support
+any Logitech device using this protocol. This includes, but is not limited
+to:
+
+* Logitech CyberMan 2
+* Logitech ThunderPad Digital
+* Logitech WingMan Extreme Digital
+* Logitech WingMan Formula
+* Logitech WingMan Interceptor
+* Logitech WingMan GamePad
+* Logitech WingMan GamePad USB
+* Logitech WingMan GamePad Extreme
+* Logitech WingMan Extreme Digital 3D
+
+  ADI devices are autodetected, and the driver supports up to two (any
+combination of) devices on a single gameport, using an Y-cable or chained
+together.
+
+  Logitech WingMan Joystick, Logitech WingMan Attack, Logitech WingMan
+Extreme and Logitech WingMan ThunderPad are not digital joysticks and are
+handled by the analog driver described above. Logitech WingMan Warrior and
+Logitech Magellan are supported by serial drivers described below.  Logitech
+WingMan Force and Logitech WingMan Formula Force are supported by the
+I-Force driver described below. Logitech CyberMan is not supported yet.
+
+3.4 Gravis GrIP
+~~~~~~~~~~~~~~~
+  Gravis GrIP protocol is supported by the grip.c module. It currently
+supports:
+
+* Gravis GamePad Pro
+* Gravis BlackHawk Digital
+* Gravis Xterminator
+* Gravis Xterminator DualControl
+
+  All these devices are autodetected, and you can even use any combination
+of up to two of these pads either chained together or using an Y-cable on a
+single gameport.
+
+GrIP MultiPort isn't supported yet. Gravis Stinger is a serial device and is
+supported by the stinger driver. Other Gravis joysticks are supported by the
+analog driver.
+
+3.5 FPGaming A3D and MadCatz A3D
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The Assassin 3D protocol created by FPGaming, is used both by FPGaming
+themselves and is licensed to MadCatz. A3D devices are supported by the
+a3d.c module. It currently supports:
+
+* FPGaming Assassin 3D
+* MadCatz Panther
+* MadCatz Panther XL
+
+  All these devices are autodetected. Because the Assassin 3D and the Panther
+allow connecting analog joysticks to them, you'll need to load the analog
+driver as well to handle the attached joysticks.
+
+  The trackball should work with USB mousedev module as a normal mouse. See
+the USB documentation for how to setup an USB mouse.
+
+3.6 ThrustMaster DirectConnect (BSP)
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The TM DirectConnect (BSP) protocol is supported by the tmdc.c
+module. This includes, but is not limited to:
+
+* ThrustMaster Millenium 3D Inceptor
+* ThrustMaster 3D Rage Pad
+* ThrustMaster Fusion Digital Game Pad
+
+  Devices not directly supported, but hopefully working are:
+
+* ThrustMaster FragMaster
+* ThrustMaster Attack Throttle
+
+  If you have one of these, contact me.
+
+  TMDC devices are autodetected, and thus no parameters to the module
+are needed. Up to two TMDC devices can be connected to one gameport, using
+an Y-cable.
+
+3.7 Creative Labs Blaster
+~~~~~~~~~~~~~~~~~~~~~~~~~
+  The Blaster protocol is supported by the cobra.c module. It supports only
+the:
+
+* Creative Blaster GamePad Cobra
+
+  Up to two of these can be used on a single gameport, using an Y-cable.
+
+3.8 Genius Digital joysticks 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The Genius digitally communicating joysticks are supported by the gf2k.c
+module. This includes:
+
+* Genius Flight2000 F-23 joystick 
+* Genius Flight2000 F-31 joystick 
+* Genius G-09D gamepad
+
+  Other Genius digital joysticks are not supported yet, but support can be
+added fairly easily.
+
+3.9 InterAct Digital joysticks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The InterAct digitally communicating joysticks are supported by the
+interact.c module. This includes:
+
+* InterAct HammerHead/FX gamepad
+* InterAct ProPad8 gamepad 
+
+  Other InterAct digital joysticks are not supported yet, but support can be 
+added fairly easily.
+
+3.10 PDPI Lightning 4 gamecards
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  PDPI Lightning 4 gamecards are supported by the lightning.c module.
+Once the module is loaded, the analog driver can be used to handle the
+joysticks. Digitally communicating joystick will work only on port 0, while
+using Y-cables, you can connect up to 8 analog joysticks to a single L4
+card, 16 in case you have two in your system.
+
+3.11 Trident 4DWave / Aureal Vortex
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  Soundcards with a Trident 4DWave DX/NX or Aureal Vortex/Vortex2 chipsets
+provide an "Enhanced Game Port" mode where the soundcard handles polling the
+joystick.  This mode is supported by the pcigame.c module. Once loaded the
+analog driver can use the enhanced features of these gameports..
+
+3.13 Crystal SoundFusion
+~~~~~~~~~~~~~~~~~~~~~~~~
+  Soundcards with Crystal SoundFusion chipsets provide an "Enhanced Game
+Port", much like the 4DWave or Vortex above. This, and also the normal mode
+for the port of the SoundFusion is supported by the cs461x.c module.
+
+3.14 SoundBlaster Live!
+~~~~~~~~~~~~~~~~~~~~~~~~
+  The Live! has a special PCI gameport, which, although it doesn't provide
+any "Enhanced" stuff like 4DWave and friends, is quite a bit faster than
+it's ISA counterparts. It also requires special support, hence the
+emu10k1-gp.c module for it instead of the normal ns558.c one.
+
+3.15 SoundBlaster 64 and 128 - ES1370 and ES1371, ESS Solo1 and S3 SonicVibes
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  These PCI soundcards have specific gameports. They are handled by the
+sound drivers themselves. Make sure you select gameport support in the
+joystick menu and sound card support in the sound menu for your appropriate
+card.
+
+3.16 Amiga
+~~~~~~~~~~
+  Amiga joysticks, connected to an Amiga, are supported by the amijoy.c
+driver. Since they can't be autodetected, the driver has a command line.
+
+	amijoy=a,b
+
+  a and b define the joysticks connected to the JOY0DAT and JOY1DAT ports of
+the Amiga.
+
+	Value | Joystick type
+	---------------------
+	  0   | None
+	  1   | 1-button digital joystick
+
+  No more joystick types are supported now, but that should change in the
+future if I get an Amiga in the reach of my fingers.
+
+3.17 Game console and 8-bit pads and joysticks
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+See joystick-parport.txt for more info.
+
+3.18 SpaceTec/LabTec devices
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  SpaceTec serial devices communicate using the SpaceWare protocol. It is
+supported by the spaceorb.c and spaceball.c drivers. The devices currently
+supported by spaceorb.c are:
+
+* SpaceTec SpaceBall Avenger
+* SpaceTec SpaceOrb 360
+
+Devices currently supported by spaceball.c are:
+
+* SpaceTec SpaceBall 4000 FLX
+
+  In addition to having the spaceorb/spaceball and serport modules in the
+kernel, you also need to attach a serial port to it. to do that, run the
+inputattach program:
+
+	inputattach --spaceorb /dev/tts/x &
+or
+	inputattach --spaceball /dev/tts/x &
+
+where /dev/tts/x is the serial port which the device is connected to. After
+doing this, the device will be reported and will start working.
+
+  There is one caveat with the SpaceOrb. The button #6, the on the bottom
+side of the orb, although reported as an ordinary button, causes internal
+recentering of the spaceorb, moving the zero point to the position in which
+the ball is at the moment of pressing the button. So, think first before
+you bind it to some other function.
+
+SpaceTec SpaceBall 2003 FLX and 3003 FLX are not supported yet. 
+
+3.19 Logitech SWIFT devices
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The SWIFT serial protocol is supported by the warrior.c module. It
+currently supports only the:
+
+* Logitech WingMan Warrior
+
+but in the future, Logitech CyberMan (the original one, not CM2) could be
+supported as well. To use the module, you need to run inputattach after you
+insert/compile the module into your kernel:
+
+	inputattach --warrior /dev/tts/x &
+
+/dev/tts/x is the serial port your Warrior is attached to.
+
+3.20 Magellan / Space Mouse
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The Magellan (or Space Mouse), manufactured by LogiCad3d (formerly Space
+Systems), for many other companies (Logitech, HP, ...) is supported by the
+joy-magellan module. It currently supports only the:
+
+* Magellan 3D
+* Space Mouse
+
+models, the additional buttons on the 'Plus' versions are not supported yet.
+
+  To use it, you need to attach the serial port to the driver using the
+
+	inputattach --magellan /dev/tts/x &
+
+command. After that the Magellan will be detected, initialized, will beep,
+and the /dev/input/jsX device should become usable.
+
+3.21 I-Force devices 
+~~~~~~~~~~~~~~~~~~~~
+  All I-Force devices are supported by the iforce.c module. This includes:
+
+* AVB Mag Turbo Force
+* AVB Top Shot Pegasus
+* Logitech WingMan Force
+* Logitech WingMan Force 3D
+* Logitech WingMan Force Wheel 
+* Logitech WingMan Strike Force 3D
+* Guillemot Race Leader Force Feedback
+
+  To use it, you need to attach the serial port to the driver using the
+
+	inputattach --iforce /dev/tts/x &
+
+command. After that the I-Force device will be detected, and the
+/dev/input/jsX device should become usable.
+
+  In case you're using the device via the USB port, the inputattach command
+isn't needed.
+
+  The I-Force driver now supports force feedback via the event interface.
+
+3.22 Gravis Stinger gamepad 
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+  The Gravis Stinger serial port gamepad, designed for use with laptop
+computers, is supported by the stinger.c module. To use it, attach the
+serial port to the driver using:
+
+        inputattach --stinger /dev/tty/x &
+
+where x is the number of the serial port.
+
+4. Troubleshooting
+~~~~~~~~~~~~~~~~~~
+  There is quite a high probability that you run into some problems. For
+testing whether the driver works, if in doubt, use the jstest utility in
+some of its modes. The most useful modes are "normal" - for the 1.x
+interface, and "old" for the "0.x" interface. You run it by typing:
+
+	jstest --normal /dev/input/js0
+	jstest --old    /dev/input/js0
+
+  Additionally you can do a test with the evtest utility:
+
+	evtest /dev/input/event0
+
+  Oh, and read the FAQ! :)
+
+5. FAQ
+~~~~~~
+Q: Running 'jstest /dev/js0' results in "File not found" error. What's the
+   cause?
+A: The device files don't exist. Create them (see section 2.2).
+
+Q: Is it possible to connect my old Atari/Commodore/Amiga/console joystick
+   or pad that uses a 9-pin D-type cannon connector to the serial port of my
+   PC?
+A: Yes, it is possible, but it'll burn your serial port or the pad. It
+   won't work, of course.
+
+Q: My joystick doesn't work with Quake / Quake 2. What's the cause?
+A: Quake / Quake 2 don't support joystick. Use joy2key to simulate keypresses
+   for them.
+
+6. Programming Interface
+~~~~~~~~~~~~~~~~~~~~~~~~
+  The 1.0 driver uses a new, event based approach to the joystick driver.
+Instead of the user program polling for the joystick values, the joystick
+driver now reports only any changes of its state. See joystick-api.txt,
+joystick.h and jstest.c included in the joystick package for more
+information. The joystick device can be used in either blocking or
+nonblocking mode and supports select() calls.
+
+  For backward compatibility the old (v0.x) interface is still included.
+Any call to the joystick driver using the old interface will return values
+that are compatible to the old interface.  This interface is still limited
+to 2 axes, and applications using it usually decode only 2 buttons, although
+the driver provides up to 32.
diff -urN linux-2.4.10-pre8/Documentation/joystick-api.txt linux/Documentation/joystick-api.txt
--- linux-2.4.10-pre8/Documentation/joystick-api.txt	Fri Apr  6 10:42:48 2001
+++ linux/Documentation/joystick-api.txt	Wed Dec 31 16:00:00 1969
@@ -1,315 +0,0 @@
-		      Joystick API Documentation                -*-Text-*-
-
-		        Ragnar Hojland Espinosa
-		          <ragnar@macula.net>
-
-			      7 Aug 1998
-
-
-1. Initialization
-~~~~~~~~~~~~~~~~~
-
-Open the joystick device following the usual semantics (that is, with open).
-Since the driver now reports events instead of polling for changes,
-immediately after the open it will issue a series of synthetic events
-(JS_EVENT_INIT) that you can read to check the initial state of the
-joystick.
-
-By default, the device is opened in blocking mode.
-
-	int fd = open ("/dev/js0", O_RDONLY);
-
-
-2. Event Reading
-~~~~~~~~~~~~~~~~
-
-	struct js_event e;
-	read (fd, &e, sizeof(struct js_event));
-
-where js_event is defined as
-
-	struct js_event {
-		__u32 time;     /* event timestamp in milliseconds */
-		__s16 value;    /* value */
-		__u8 type;      /* event type */
-		__u8 number;    /* axis/button number */
-	};
-
-If the read is successful, it will return sizeof(struct js_event), unless
-you wanted to read more than one event per read as described in section 3.1.
-
-
-2.1 js_event.type
-~~~~~~~~~~~~~~~~~
-
-The possible values of ``type'' are
-
-	#define JS_EVENT_BUTTON         0x01    /* button pressed/released */
-	#define JS_EVENT_AXIS           0x02    /* joystick moved */
-	#define JS_EVENT_INIT           0x80    /* initial state of device */
-
-As mentioned above, the driver will issue synthetic JS_EVENT_INIT ORed
-events on open. That is, if it's issuing a INIT BUTTON event, the
-current type value will be
-
-	int type = JS_EVENT_BUTTON | JS_EVENT_INIT;	/* 0x81 */
-
-If you choose not to differentiate between synthetic or real events
-you can turn off the JS_EVENT_INIT bits
-
-	type &= ~JS_EVENT_INIT;				/* 0x01 */
-
-
-2.2 js_event.number
-~~~~~~~~~~~~~~~~~~~
-
-The values of ``number'' correspond to the axis or button that
-generated the event. Note that they carry separate numeration (that
-is, you have both an axis 0 and a button 0). Generally,
-
-			number
-	1st Axis X	0
-	1st Axis Y	1
-	2nd Axis X	2
-	2nd Axis Y	3
-	...and so on
-
-Hats vary from one joystick type to another. Some can be moved in 8
-directions, some only in 4, The driver, however, always reports a hat as two
-independent axis, even if the hardware doesn't allow independent movement.
-
-
-2.3 js_event.value
-~~~~~~~~~~~~~~~~~~
-
-For an axis, ``value'' is a signed integer between -32767 and +32767
-representing the position of the joystick along that axis. If you
-don't read a 0 when the joystick is `dead', or if it doesn't span the
-full range, you should recalibrate it (with, for example, jscal).
-
-For a button, ``value'' for a press button event is 1 and for a release
-button event is 0.
-
-Though this
-
-	if (js_event.type == JS_EVENT_BUTTON) {
-		buttons_state ^= (1 << js_event.number);
-	}
-
-may work well if you handle JS_EVENT_INIT events separately,
-
-	if ((js_event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) {
-		if (js_event.value)
-	        	buttons_state |= (1 << js_event.number);
-	   	else
-	      		buttons_state &= ~(1 << js_event.number);
-	}
-
-is much safer since it can't lose sync with the driver. As you would
-have to write a separate handler for JS_EVENT_INIT events in the first
-snippet, this ends up being shorter.
-
-
-2.4 js_event.time
-~~~~~~~~~~~~~~~~~
-
-The time an event was generated is stored in ``js_event.time''. It's a time
-in milliseconds since ... well, since sometime in the past.  This eases the
-task of detecting double clicks, figuring out if movement of axis and button
-presses happened at the same time, and similar.
-
-
-3. Reading
-~~~~~~~~~~
-
-If you open the device in blocking mode, a read will block (that is,
-wait) forever until an event is generated and effectively read. There
-are two alternatives if you can't afford to wait forever (which is,
-admittedly, a long time;)
-
-	a) use select to wait until there's data to be read on fd, or
-	   until it timeouts. There's a good example on the select(2)
-	   man page.
-
-	b) open the device in non-blocking mode (O_NONBLOCK)
-
-
-3.1 O_NONBLOCK
-~~~~~~~~~~~~~~
-
-If read returns -1 when reading in O_NONBLOCK mode, this isn't
-necessarily a "real" error (check errno(3)); it can just mean there
-are no events pending to be read on the driver queue. You should read
-all events on the queue (that is, until you get a -1).
-
-For example,
-
-	while (1) {
-		while (read (fd, &e, sizeof(struct js_event)) > 0) {
-	        	process_event (e);
-	   	}
-	   	/* EAGAIN is returned when the queue is empty */
-	   	if (errno != EAGAIN) {
-	      		/* error */
-	   	}
-	   	/* do something interesting with processed events */
-	}
-
-One reason for emptying the queue is that if it gets full you'll start
-missing events since the queue is finite, and older events will get
-overwritten.
-
-The other reason is that you want to know all what happened, and not
-delay the processing till later.
-
-Why can get the queue full? Because you don't empty the queue as
-mentioned, or because too much time elapses from one read to another
-and too many events to store in the queue get generated. Note that
-high system load may contribute to space those reads even more.
-
-If time between reads is enough to fill the queue and loose an event,
-the driver will switch to startup mode and next time you read it,
-synthetic events (JS_EVENT_INIT) will be generated to inform you of
-the actual state of the joystick.
-
-[As for version 1.2.8, the queue is circular and able to hold 64
- events. You can increment this size bumping up JS_BUFF_SIZE in
- joystick.h and recompiling the driver.]
-
-
-In the above code, you might as well want to read more than one event
-at a time using the typical read(2) functionality. For that, you would
-replace the read above with something like
-
-	struct js_event mybuffer[0xff];
-	int i = read (fd, mybuffer, sizeof(struct mybuffer));
-
-In this case, read would return -1 if the queue was empty, or some
-other value in which the number of events read would be i /
-sizeof(js_event)  Again, if the buffer was full, it's a good idea to
-process the events and keep reading it until you empty the driver queue.
-
-
-4. IOCTLs
-~~~~~~~~~
-
-The joystick driver defines the following ioctl(2) operations.
-
-				/* function			3rd arg  */
-	#define JSIOCGAXES	/* get number of axes		char	 */
-	#define JSIOCGBUTTONS	/* get number of buttons	char	 */
-	#define JSIOCGVERSION	/* get driver version		int	 */
-	#define JSIOCGNAME(len) /* get identifier string	char	 */
-	#define JSIOCSCORR	/* set correction values	&js_corr */
-	#define JSIOCGCORR	/* get correction values	&js_corr */
-
-For example, to read the number of axes
-
-	char number_of_axes;
-	ioctl (fd, JSIOCGAXES, &number_of_axes);
-
-
-4.1 JSIOGCVERSION
-~~~~~~~~~~~~~~~~~
-
-JSIOGCVERSION is a good way to check in run-time whether the running
-driver is 1.0+ and supports the event interface. If it is not, the
-IOCTL will fail. For a compile-time decision, you can test the
-JS_VERSION symbol
-
-	#ifdef JS_VERSION
-	#if JS_VERSION > 0xsomething
-
-
-4.2 JSIOCGNAME
-~~~~~~~~~~~~~~
-
-JSIOCGNAME(len) allows you to get the name string of the joystick - the same
-as is being printed at boot time. The 'len' argument is the length of the
-buffer provided by the application asking for the name. It is used to avoid
-possible overrun should the name be too long.
-
-	char name[128];
-	if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
-		strncpy(name, "Unknown", sizeof(name));
-	printf("Name: %s\n", name);
-
-
-4.3 JSIOC[SG]CORR
-~~~~~~~~~~~~~~~~~
-
-For usage on JSIOC[SG]CORR I suggest you to look into jscal.c  They are
-not needed in a normal program, only in joystick calibration software
-such as jscal or kcmjoy. These IOCTLs and data types aren't considered
-to be in the stable part of the API, and therefore may change without
-warning in following releases of the driver.
-
-Both JSIOCSCORR and JSIOCGCORR expect &js_corr to be able to hold
-information for all axis. That is, struct js_corr corr[MAX_AXIS];
-
-struct js_corr is defined as
-
-	struct js_corr {
-		__s32 coef[8];
-		__u16 prec;
-		__u16 type;
-	};
-
-and ``type''
-
-	#define JS_CORR_NONE            0x00    /* returns raw values */
-	#define JS_CORR_BROKEN          0x01    /* broken line */
-
-
-5. Backward compatibility
-~~~~~~~~~~~~~~~~~~~~~~~~~
-
-The 0.x joystick driver API is quite limited and its usage is deprecated.
-The driver offers backward compatibility, though. Here's a quick summary:
-
-	struct JS_DATA_TYPE js;
-	while (1) {
-		if (read (fd, &js, JS_RETURN) != JS_RETURN) {
-	      		/* error */
-	   	}
-	   	usleep (1000);
-	}
-
-As you can figure out from the example, the read returns immediately,
-with the actual state of the joystick.
-
-	struct JS_DATA_TYPE {
-		int buttons;    /* immediate button state */
-		int x;          /* immediate x axis value */
-		int y;          /* immediate y axis value */
-	};
-
-and JS_RETURN is defined as
-
-	#define JS_RETURN       sizeof(struct JS_DATA_TYPE)
-
-To test the state of the buttons,
-
-	first_button_state  = js.buttons & 1;
-	second_button_state = js.buttons & 2;
-
-The axis values do not have a defined range in the original 0.x driver,
-except for that the values are non-negative. The 1.2.8+ drivers use a
-fixed range for reporting the values, 1 being the minimum, 128 the
-center, and 255 maximum value.
-
-The v0.8.0.2 driver also had an interface for 'digital joysticks', (now
-called Multisystem joysticks in this driver), under /dev/djsX. This driver
-doesn't try to be compatible with that interface.
-
-
-6. Final Notes
-~~~~~~~~~~~~~~
-
-____/|	Comments, additions, and specially corrections are welcome.
-\ o.O|	Documentation valid for at least version 1.2.8 of the joystick
- =(_)=	driver and as usual, the ultimate source for documentation is
-   U	to "Use The Source Luke" or, at your convenience, Vojtech ;)
-
-					- Ragnar
-EOF
diff -urN linux-2.4.10-pre8/Documentation/joystick-parport.txt linux/Documentation/joystick-parport.txt
--- linux-2.4.10-pre8/Documentation/joystick-parport.txt	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/joystick-parport.txt	Wed Dec 31 16:00:00 1969
@@ -1,521 +0,0 @@
-		    Linux Joystick parport drivers v2.0
-	       (c) 1998-2000 Vojtech Pavlik <vojtech@suse.cz>
-	       (c) 1998 Andree Borrmann <a.borrmann@tu-bs.de>
-			     Sponsored by SuSE
-----------------------------------------------------------------------------
-
-0. Disclaimer
-~~~~~~~~~~~~~
-  Any information in this file is provided as-is, without any guarantee that
-it will be true. So, use it at your own risk. The possible damages that can
-happen include burning your parallel port, and/or the sticks and joystick
-and maybe even more. Like when a lightning kills you it is not our problem.
-
-1. Intro
-~~~~~~~~
-  The joystick parport drivers are used for joysticks and gamepads not
-originally designed for PCs and other computers Linux runs on. Because of
-that, PCs usually lack the right ports to connect these devices to. Parallel
-port, because of its ability to change single bits at will, and providing
-both output and input bits is the most suitable port on the PC for
-connecting such devices.
-
-2. Devices supported
-~~~~~~~~~~~~~~~~~~~~
-  Many console and 8-bit computer gamepads and joysticks are supported. The
-following subsections discuss usage of each.
-
-2.1 NES and SNES
-~~~~~~~~~~~~~~~~
-  The Nintendo Entertainment System and Super Nintendo Entertainment System
-gamepads are widely available, and easy to get. Also, they are quite easy to
-connect to a PC, and don't need much processing speed (108 us for NES and
-165 us for SNES, compared to about 1000 us for PC gamepads) to communicate
-with them.
-
-  All NES and SNES use the same synchronous serial protocol, clocked from
-the computer's side (and thus timing insensitive). To allow up to 5 NES
-and/or SNES gamepads connected to the parallel port at once, the output
-lines of the parallel port are shared, while one of 5 available input lines
-is assigned to each gamepad.
-
-  This protocol is handled by the gamecon.c driver, so that's the one
-you'll use for NES and SNES gamepads.
-
-  The main problem with PC parallel ports is that they don't have +5V power
-source on any of their pins. So, if you want a reliable source of power
-for your pads, use either keyboard or joystick port, and make a pass-through
-cable. You can also pull the power directly from the power supply (the red
-wire is +5V).
-
-  If you want to use the parallel port only, you can take the power is from
-some data pin. For most gamepad and parport implementations only one pin is
-needed, and I'd recommend pin 9 for that, the highest data bit. On the other
-hand, if you are not planning to use anything else than NES / SNES on the
-port, anything between and including pin 4 and pin 9 will work.
-
-(pin 9) -----> Power
-
-  Unfortunately, there are pads that need a lot more of power, and parallel
-ports that can't give much current through the data pins. If this is your
-case, you'll need to use diodes (as a prevention of destroying your parallel
-port), and combine the currents of two or more data bits together.
-
-	   Diodes
-(pin 9) ----|>|-------+------> Power
-		      |
-(pin 8) ----|>|-------+
-		      |
-(pin 7) ----|>|-------+
-		      |
- <and so on>          :
-		      |
-(pin 4) ----|>|-------+
-
-  Ground is quite easy. On PC's parallel port the ground is on any of the
-pins from pin 18 to pin 25. So use any pin of these you like for the ground.
-
-(pin 18) -----> Ground
-
-  NES and SNES pads have two input bits, Clock and Latch, which drive the
-serial transfer. These are connected to pins 2 and 3 of the parallel port,
-respectively.
-
-(pin 2) -----> Clock
-(pin 3) -----> Latch
-
-  And the last thing is the NES / SNES data wire. Only that isn't shared and
-each pad needs its own data pin. The parallel port pins are:
-
-(pin 10) -----> Pad 1 data
-(pin 11) -----> Pad 2 data
-(pin 12) -----> Pad 3 data
-(pin 13) -----> Pad 4 data
-(pin 15) -----> Pad 5 data
-
-  Note that pin 14 is not used, since it is not an input pin on the parallel
-port.
-
-  This is everything you need on the PC's side of the connection, now on to
-the gamepads side. The NES and SNES have different connectors. Also, there
-are quite a lot of NES clones, and because Nintendo used proprietary
-connectors for their machines, the cloners couldn't and used standard D-Cannon
-connectors. Anyway, if you've got a gamepad, and it has buttons A, B, Turbo
-A, Turbo B, Select and Start, and is connected through 5 wires, then it is
-either a NES or NES clone and will work with this connection. SNES gamepads
-also use 5 wires, but have more buttons. They will work as well, of course.
-
-Pinout for NES gamepads                 Pinout for SNES gamepads
-
-	   +----> Power                   +-----------------------\
-	   |                            7 | o  o  o  o |  x  x  o  | 1
- 5 +---------+  7                         +-----------------------/
-   | x  x  o   \                            |  |  |  |          |
-   | o  o  o  o |                           |  |  |  |          +-> Ground
- 4 +------------+ 1                         |  |  |  +------------> Data
-     |  |  |  |                             |  |  +---------------> Latch
-     |  |  |  +-> Ground                    |  +------------------> Clock
-     |  |  +----> Clock                     +---------------------> Power
-     |  +-------> Latch
-     +----------> Data
-
-Pinout for NES clone (db9) gamepads     Pinout for NES clone (db15) gamepads
-
-	+---------> Clock                    +-----------------> Data
-	| +-------> Latch                    |             +---> Ground
-	| | +-----> Data                     |             |
-	| | |                              ___________________
-    _____________                        8 \ o x x x x x x o / 1
-  5 \ x o o o x / 1                         \ o x x o x x o /
-     \ x o x o /                          15 `~~~~~~~~~~~~~' 9
-    9 `~~~~~~~' 6                             |     |     |
-	 |   |                                |     |     +----> Clock
-	 |   +----> Power                     |     +----------> Latch
-	 +--------> Ground                    +----------------> Power
-
-2.2 Multisystem joysticks
-~~~~~~~~~~~~~~~~~~~~~~~~~
-  In the era of 8-bit machines, there was something like de-facto standard
-for joystick ports. They were all digital, and all used D-Cannon 9 pin
-connectors (db9). Because of that, a single joystick could be used without
-hassle on Atari (130, 800XE, 800XL, 2600, 7200), Amiga, Commodore C64,
-Amstrad CPC, Sinclair ZX Spectrum and many other machines. That's why these
-joysticks are called "Multisystem".
-
-  Now their pinout:
-
-      +---------> Right
-      | +-------> Left
-      | | +-----> Down
-      | | | +---> Up
-      | | | |
-  _____________
-5 \ x o o o o / 1
-   \ x o x o /
-  9 `~~~~~~~' 6
-       |   |
-       |   +----> Button
-       +--------> Ground
-
-  However, as time passed, extension to this standard developed, and these
-were not compatible with each other:
-
-
-  Atari 130, 800(XL/XE)                    MSX
-
-					 +-----------> Power
-      +---------> Right                  | +---------> Right
-      | +-------> Left                   | | +-------> Left
-      | | +-----> Down                   | | | +-----> Down
-      | | | +---> Up                     | | | | +---> Up
-      | | | |                            | | | | |
-  _____________                        _____________
-5 \ x o o o o / 1                    5 \ o o o o o / 1
-   \ x o o o /                          \ o o o o /
-  9 `~~~~~~~' 6                        9 `~~~~~~~' 6
-       | | |                              | | | |
-       | | +----> Button                  | | | +----> Button 1
-       | +------> Power                   | | +------> Button 2
-       +--------> Ground                  | +--------> Output 3
-					  +----------> Ground
-
-       Amstrad CPC                         Commodore C64
-
-					 +-----------> Analog Y
-      +---------> Right                  | +---------> Right
-      | +-------> Left                   | | +-------> Left
-      | | +-----> Down                   | | | +-----> Down
-      | | | +---> Up                     | | | | +---> Up
-      | | | |                            | | | | |
-  _____________                        _____________
-5 \ x o o o o / 1                    5 \ o o o o o / 1
-   \ x o o o /                          \ o o o o /
-  9 `~~~~~~~' 6                        9 `~~~~~~~' 6
-       | | |                              | | | |
-       | | +----> Button 1                | | | +----> Button
-       | +------> Button 2                | | +------> Power
-       +--------> Ground                  | +--------> Ground
-					  +----------> Analog X
-
-  And there were many others.
-
-2.2.1 Multisystem joysticks using db9.c
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  For the Multisystem joysticks, and their derivatives, the db9.c driver
-was written. It allows only one joystick / gamepad per parallel port, but
-the interface is easy to build and works with almost anything.
-
-  For the basic 1-button Multisystem joystick you connect its wires to the
-parallel port like this:
-
-(pin  1) -----> Power
-(pin 18) -----> Ground
-
-(pin  2) -----> Up
-(pin  3) -----> Down
-(pin  4) -----> Left
-(pin  5) -----> Right
-(pin  6) -----> Button 1
-
-  However, if the joystick is switch based (eg. clicks when you move it),
-you might or might not, depending on your parallel port, need 10 kOhm pullup
-resistors on each of the direction and button signals, like this:
-
-(pin 2) ------------+------> Up
-	  Resistor  |
-(pin 1) --[10kOhm]--+
-
-  Try without, and if it doesn't work, add them. For TTL based joysticks /
-gamepads the pullups are not needed.
-
-  For joysticks with two buttons you connect the second button to pin 7 on
-the parallel port.
-
-(pin 7) -----> Button 2
-
-  And that's it.
-
-  On a side note, if you have already built a different adapter for use with
-the digital joystick driver 0.8.0.2, this is also supported by the db9.c
-driver, as device type 8. (See section 3.2)
-
-2.2.2 Multisystem joysticks using gamecon.c
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  For some people just one joystick per parallel port is not enough, and/or
-want to use them on one parallel port together with NES/SNES/PSX pads. This is
-possible using the gamecon.c. It supports up to 5 devices of the above types,
-including 1 and 2 buttons Multisystem joysticks.
-
-  However, there is nothing for free. To allow more sticks to be used at
-once, you need the sticks to be purely switch based (that is non-TTL), and
-not to need power. Just a plain simple six switches inside. If your
-joystick can do more (eg. turbofire) you'll need to disable it totally first
-if you want to use gamecon.c.
-
-  Also, the connection is a bit more complex. You'll need a bunch of diodes,
-and one pullup resistor. First, you connect the Directions and the button
-the same as for db9, however with the diodes inbetween.
-
-	    Diodes
-(pin 2) -----|<|----> Up
-(pin 3) -----|<|----> Down
-(pin 4) -----|<|----> Left
-(pin 5) -----|<|----> Right
-(pin 6) -----|<|----> Button 1
-
-  For two button sticks you also connect the other button.
-
-(pin 7) -----|<|----> Button 2
-
-  And finally, you connect the Ground wire of the joystick, like done in
-this little schematic to Power and Data on the parallel port, as described
-for the NES / SNES pads in section 2.1 of this file - that is, one data pin
-for each joystick. The power source is shared.
-
-Data    ------------+-----> Ground
-	  Resistor  |
-Power   --[10kOhm]--+
-
-  And that's all, here we go!
-
-2.2.3 Multisystem joysticks using turbografx.c
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The TurboGraFX interface, designed by
-
-	Steffen Schwenke <schwenke@burg-halle.de>
-
-  allows up to 7 Multisystem joysticks connected to the parallel port. In
-Steffen's version, there is support for up to 5 buttons per joystick.  However,
-since this doesn't work reliably on all parallel ports, the turbografx.c driver
-supports only one button per joystick. For more information on how to build the
-interface, see
-
-	http://www2.burg-halle.de/~schwenke/parport.html
-
-2.3 Sony Playstation
-~~~~~~~~~~~~~~~~~~~~
-
-  WARNING: PSX support is experimental, and at the moment doesn't seem to
-work for most people. If you like adventure, you can try yourself.
-
-  The PSX controller is supported by the gamecon.c.
-
-Pinout of the PSX controller (compatible with DirectPadPro):
-
-  +---------+---------+---------+
-9 | o  o  o | o  o  o | o  o  o | 1               parallel
-   \________|_________|________/                  port pins
-    |  |      |  |  |   |
-    |  |      |  |  |   +-------->  Clock    ---  (4)
-    |  |      |  |  +------------>  Select   ---  (3)
-    |  |      |  +--------------->  Power    ---  (5-9)
-    |  |      +------------------>  Ground   ---  (18-25)
-    |  +------------------------->  Command  ---  (2)
-    +---------------------------->  Data     ---  (10,11,12,13,15) one only...
-
-  You may have to add pull up/down resistors. Maybe your pad also won't like
-the 5V (PSX uses 3.7V).
-
-  Currently the driver supports only one psx pad per parallel port, and these
-controllers:
-
- * Standard PSX Pad
- * NegCon PSX Pad
- * Analog PSX Pad (red mode)
- * Analog PSX Pad (green mode)
-
-2.4 Sega
-~~~~~~~~
-  All the Sega controllers are more or less based on the standard 2-button
-Multisystem joystick. However, since they don't use switches and use TTL
-logic, the only driver usable with them is the db9.c driver.
-
-2.4.1 Sega Master System
-~~~~~~~~~~~~~~~~~~~~~~~~
-  The SMS gamepads are almost exactly the same as normal 2-button
-Multisystem joysticks. Set the driver to Multi2 mode, use the corresponding
-parallel port pins, and the following schematic:
-
-    +-----------> Power
-    | +---------> Right
-    | | +-------> Left
-    | | | +-----> Down
-    | | | | +---> Up
-    | | | | |
-  _____________
-5 \ o o o o o / 1
-   \ o o x o /
-  9 `~~~~~~~' 6
-     | |   |
-     | |   +----> Button 1
-     | +--------> Ground
-     +----------> Button 2
-
-2.4.2 Sega Genesis aka MegaDrive
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The Sega Genesis (in Europe sold as Sega MegaDrive) pads are an extension
-to the Sega Master System pads. They use more buttons (3+1, 5+1, 6+1).  Use
-the following schematic:
-
-    +-----------> Power
-    | +---------> Right
-    | | +-------> Left
-    | | | +-----> Down
-    | | | | +---> Up
-    | | | | |
-  _____________
-5 \ o o o o o / 1
-   \ o o o o /
-  9 `~~~~~~~' 6
-     | | | |
-     | | | +----> Button 1
-     | | +------> Select
-     | +--------> Ground
-     +----------> Button 2
-
-  The Select pin goes to pin 14 on the parallel port.
-
-(pin 14) -----> Select
-
-  The rest is the same as for Multi2 joysticks using db9.c
-
-2.4.3 Sega Saturn
-~~~~~~~~~~~~~~~~~
-  Sega Saturn has eight buttons, and to transfer that, without hacks like
-Genesis 6 pads use, it needs one more select pin. Anyway, it is still
-handled by the db9.c driver. Its pinout is very different from anything
-else.  Use this schematic:
-
-    +-----------> Select 1
-    | +---------> Power
-    | | +-------> Up
-    | | | +-----> Down
-    | | | | +---> Ground
-    | | | | |
-  _____________
-5 \ o o o o o / 1
-   \ o o o o /
-  9 `~~~~~~~' 6
-     | | | |
-     | | | +----> Select 2
-     | | +------> Right
-     | +--------> Left
-     +----------> Power
-
-  Select 1 is pin 14 on the parallel port, Select 2 is pin 16 on the
-parallel port.
-
-(pin 14) -----> Select 1
-(pin 16) -----> Select 2
-
-  The other pins (Up, Down, Right, Left, Power, Ground) are the same as for
-Multi joysticks using db9.c
-
-3. The drivers
-~~~~~~~~~~~~~~
-  There are three drivers for the parallel port interfaces. Each, as
-described above, allows to connect a different group of joysticks and pads.
-Here are described their command lines:
-
-3.1 gamecon.c
-~~~~~~~~~~~~~
-  Using gamecon.c you can connect up to five devices to one parallel port. It
-uses the following kernel/module command line:
-
-	gc=port,pad1,pad2,pad3,pad4,pad5
-
-  Where 'port' the number of the parport interface (eg. 0 for parport0).
-
-  And 'pad1' to 'pad5' are pad types connected to different data input pins
-(10,11,12,13,15), as described in section 2.1 of this file.
-
-  The types are:
-
-	Type | Joystick/Pad
-	--------------------
-	  0  | None
-	  1  | SNES pad
-	  2  | NES pad
-	  4  | Multisystem 1-button joystick
-	  5  | Multisystem 2-button joystick
-	  6  | Sony PSX controller
-	  7  | N64 pad
-
-  The exact type of the PSX controller type is autoprobed, so you must have
-your controller plugged in before initializing.
-
-  Should you want to use more than one of parallel ports at once, you can use
-gc_2 and gc_3 as additional command line parameters for two more parallel
-ports.
-
-3.2 db9.c
-~~~~~~~~~
-  Apart from making an interface, there is nothing difficult on using the
-db9.c driver. It uses the following kernel/module command line:
-
-	db9=port,type
-
-  Where 'port' is the number of the parport interface (eg. 0 for parport0).
-
-  Caveat here: This driver only works on bidirectional parallel ports. If
-your parallel port is recent enough, you should have no trouble with this.
-Old parallel ports may not have this feature.
-
-  'Type' is the type of joystick or pad attached:
-
-	Type | Joystick/Pad
-	--------------------
-	  0  | None
-	  1  | Multisystem 1-button joystick
-	  2  | Multisystem 2-button joystick
-	  3  | Genesis pad (3+1 buttons)
-	  5  | Genesis pad (5+1 buttons)
-	  6  | Genesis pad (6+2 buttons)
-	  7  | Saturn pad (8 buttons)
-	  8  | Multisystem 1-button joystick (v0.8.0.2 pin-out)
-	  9  | Two Multisystem 1-button joysticks (v0.8.0.2 pin-out) 
-	 10  | Amiga CD32 pad
-
-  Should you want to use more than one of these joysticks/pads at once, you
-can use db9_2 and db9_3 as additional command line parameters for two
-more joysticks/pads.
-
-3.3 turbografx.c
-~~~~~~~~~~~~~~~~
-  The turbografx.c driver uses a very simple kernel/module command line:
-
-	tgfx=port,js1,js2,js3,js4,js5,js6,js7
-
-  Where 'port' is the number of the parport interface (eg. 0 for parport0).
-
-  'jsX' is the number of buttons the Multisystem joysticks connected to the
-interface ports 1-7 have. For a standard multisystem joystick, this is 1.
-
-  Should you want to use more than one of these interfaces at once, you can
-use tgfx_2 and tgfx_3 as additional command line parameters for two more
-interfaces.
-
-3.4 PC parallel port pinout
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-		  .----------------------------------------.
-   At the PC:     \ 13 12 11 10  9  8  7  6  5  4  3  2  1 /
-                   \  25 24 23 22 21 20 19 18 17 16 15 14 /
-                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-
-	  Pin | Name    | Description
-	~~~~~~|~~~~~~~~~|~~~~~~~~~~
-	    1 | /STROBE | Strobe
-	  2-9 | D0-D7   | Data Bit 0-7
-	   10 | /ACK    | Acknowledge
-	   11 | BUSY    | Busy
-	   12 | PE      | Paper End
-	   13 | SELIN   | Select In
-	   14 | /AUTOFD | Autofeed
-	   15 | /ERROR  | Error
-	   16 | /INIT   | Initialize
-	   17 | /SEL    | Select
-	18-25 | GND     | Signal Ground
-
-3.5 End
-~~~~~~~
-  That's all, folks! Have fun!
diff -urN linux-2.4.10-pre8/Documentation/joystick.txt linux/Documentation/joystick.txt
--- linux-2.4.10-pre8/Documentation/joystick.txt	Fri Jul 28 12:50:51 2000
+++ linux/Documentation/joystick.txt	Wed Dec 31 16:00:00 1969
@@ -1,582 +0,0 @@
-		       Linux Joystick driver v2.0.0
-	       (c) 1996-2000 Vojtech Pavlik <vojtech@suse.cz>
-			     Sponsored by SuSE
-----------------------------------------------------------------------------
-
-0. Disclaimer
-~~~~~~~~~~~~~
-  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 <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
-Ucitelska 1576, 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.
-
-1. Intro
-~~~~~~~~
-  The joystick driver for Linux provides support for a variety of joysticks
-and similar devices. It is based on a larger project aiming to support all
-input devices in Linux.
-
-  Should you encounter any problems while using the driver, or joysticks
-this driver can't make complete use of, I'm very interested in hearing about
-them. Bug reports and success stories are also welcome.
-
-  The input project website is at:
-
-	http://www.suse.cz/development/input/
-	http://atrey.karlin.mff.cuni.cz/~vojtech/input/
-
-  There is also a mailing list for the driver at:
-
-	listproc@atrey.karlin.mff.cuni.cz
-
-send "subscribe linux-joystick Your Name" to subscribe to it.
-
-2. Usage
-~~~~~~~~
-  For basic usage you just choose the right options in kernel config and
-you should be set.
-
-2.1 inpututils
-~~~~~~~~~~~~~~
-For testing and other purposes (for example serial devices), a set of
-utilities is available at the abovementioned website. I suggest you download
-and install it before going on.
-
-2.2 Device nodes
-~~~~~~~~~~~~~~~~
-For applications to be able to use the joysticks, in you don't use devfs,
-you'll have to manually create these nodes in /dev:
-
-cd /dev
-rm js*
-mkdir input
-mknod input/js0 c 13 0
-mknod input/js1 c 13 1
-mknod input/js2 c 13 2
-mknod input/js3 c 13 3
-ln -s input/js0 js0
-ln -s input/js1 js1
-ln -s input/js2 js2
-ln -s input/js3 js3
-
-For testing with inpututils it's also convenient to create these:
-
-mknod input/event0 c 13 64
-mknod input/event1 c 13 65
-mknod input/event2 c 13 66
-mknod input/event3 c 13 67
-
-2.4 Modules needed 
-~~~~~~~~~~~~~~~~~~
-  For all joystick drivers to function, you'll need the userland interface
-module in kernel, either loaded or compiled in:
-
-	modprobe joydev
-
-  For gameport joysticks, you'll have to load the gameport driver as well;
-
-	modprove ns558
-
-  And for serial port joysticks, you'll need the serial input line
-discipline module loaded and the inputattach utility started:
-
-	modprobe serport
-	inputattach -xxx /dev/tts/X &
-
-  In addition to that, you'll need the joystick driver module itself, most
-usually you'll have an analog joystick:
-
-	modprobe analog
-	
-  For automatic module loading, something like this might work:
-
-	alias tty-ldisc-2 serport
-	alias char-major-13 joydev ns558 analog
-
-2.5 Verifying that it works
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  For testing the joystick driver functionality, there is the jstest
-program in the utilities package. You run it by typing:
-
-	jstest /dev/js0
-
-  And it should show a line with the joystick values, which update as you
-move the stick, and press its buttons. The axes should all be zero when the
-joystick is in the center position. They should not jitter by themselves to
-other close values, and they also should be steady in any other position of
-the stick. They should have the full range from -32767 to 32767. If all this
-is met, then it's all fine, and you can play the games. :)
-
-  If it's not, then there might be a problem. Try to calibrate the joystick,
-and if it still doesn't work, read the drivers section of this file, the
-troubleshooting section, and the FAQ.
-
-2.6. Calibration
-~~~~~~~~~~~~~~~~
-  For most joysticks you won't need any manual calibration, since the
-joystick should be autocalibrated by the driver automagically. However, with
-some analog joysticks, that either do not use linear resistors, or if you
-want better precision, you can use the jscal program
-
-	jscal -c /dev/js0
-
- included in the joystick package to set better correction coefficients than
-what the driver would choose itself.
-
-  After calibrating the joystick you can verify if you like the new
-calibration using the jstest command, and if you do, you then can save the
-correction coefficients into a file
-
-	jscal -p /dev/js0 > /etc/joystick.cal
-
-  And add a line to your rc script executing that file
-
-	source /etc/joystick.cal
-
-  This way, after the next reboot your joystick will remain calibrated. You
-can also add the jscal -p line to your shutdown script.
-
-
-3. HW specific driver information
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-In this section each of the separate hardware specific drivers is described.
-
-3.1 Analog joysticks
-~~~~~~~~~~~~~~~~~~~~
-  The analog.c uses the standard analog inputs of the gameport, and thus
-supports all standard joysticks and gamepads. It uses a very advanced
-routine for this, allowing for data precision that can't be found on any
-other system.
-
-  It also supports extensions like additional hats and buttons compatible
-with CH Flightstick Pro, ThrustMaster FCS or 6 and 8 button gamepads. Saitek
-Cyborg 'digital' joysticks are also supported by this driver, because
-they're basically souped up CHF sticks.
-
-  However the only types that can be autodetected are:
-
-* 2-axis, 4-button joystick
-* 3-axis, 4-button joystick
-* 4-axis, 4-button joystick
-* Saitek Cyborg 'digital' joysticks
-
-  For other joystick types (more/less axes, hats, and buttons) support
-you'll need to specify the types either on the kernel command line or on the
-module command line, when inserting analog.o into the kernel. The
-parameters are:
-
-	js=type,type,type,....
-
-  'type' is type of the joystick from the table below, defining joysticks
-present on gameports in the system, starting with gameport0, second 'type'
-entry defining joystick on gameport1 and so on.
-
-	Type     | Meaning
-	-----------------------------------
-	none     | No analog joystick on that port
-	auto     | Autodetect joystick
-	2btn     | 2-button n-axis joystick
-	y-joy    | Two 2-button 2-axis joysticks on an Y-cable
-	y-pad    | Two 2-button 2-axis gamepads on an Y-cable
-	fcs      | Thrustmaster FCS compatible joystick
-	chf      | Joystick with a CH Flightstick compatible hat
-	fullchf  | CH Flightstick compatible with two hats and 6 buttons
-	gamepad  | 4/6-button n-axis gamepad
-	gamepad8 | 8-button 2-axis gamepad
-
-  In case your joystick doesn't fit in any of the above categories, you can
-specify the type as a number by combining the bits in the table below. This
-is not recommended unless you really know what are you doing. It's not
-dangerous, but not simple either.
-
-	Bit | Meaning
-	--------------------------
-	 0  | Axis X1
-	 1  | Axis Y1
-	 2  | Axis X2
-	 3  | Axis Y2
-	 4  | Button A
-	 5  | Button B
-	 6  | Button C
-	 7  | Button D
-	 8  | CHF Buttons X and Y
-	 9  | CHF Hat 1
-	10  | CHF Hat 2
-	11  | FCS Hat
-	12  | Pad Button X
-	13  | Pad Button Y
-	14  | Pad Button U
-	15  | Pad Button V
-	16  | Saitek F1-F4 Buttons
-	17  | Saitek Digital Mode
-	19  | GamePad
-	20  | Joy2 Axis X1
-	21  | Joy2 Axis Y1
-	22  | Joy2 Axis X2
-	23  | Joy2 Axis Y2
-	24  | Joy2 Button A
-	25  | Joy2 Button B
-	26  | Joy2 Button C
-	27  | Joy2 Button D
-	31  | Joy2 GamePad
-
-3.2 Microsoft SideWinder joysticks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  Microsoft 'Digital Overdrive' protocol is supported by the sidewinder.c
-module. All currently supported joysticks:
-
-* Microsoft SideWinder 3D Pro
-* Microsoft SideWinder Force Feedback Pro
-* Microsoft SideWinder Force Feedback Wheel
-* Microsoft SideWinder FreeStyle Pro 
-* Microsoft SideWinder GamePad (up to four, chained)
-* Microsoft SideWinder Precision Pro 
-* Microsoft SideWinder Precision Pro USB 
-
-  are autodetected, and thus no module parameters are needed.
-
-  There is one caveat with the 3D Pro. There are 9 buttons reported,
-although the joystick has only 8. The 9th button is the mode switch on the
-rear side of the joystick. However, moving it, you'll reset the joystick,
-and make it unresponsive for about a one third of a second. Furthermore, the
-joystick will also re-center itself, taking the position it was in during
-this time as a new center position. Use it if you want, but think first.
-
-  The SideWinder Standard is not a digital joystick, and thus is supported
-by the analog driver described above. 
-
-3.3 Logitech ADI devices
-~~~~~~~~~~~~~~~~~~~~~~~~
-  Logitech ADI protocol is supported by the adi.c module. It should support
-any Logitech device using this protocol. This includes, but is not limited
-to:
-
-* Logitech CyberMan 2
-* Logitech ThunderPad Digital
-* Logitech WingMan Extreme Digital
-* Logitech WingMan Formula
-* Logitech WingMan Interceptor
-* Logitech WingMan GamePad
-* Logitech WingMan GamePad USB
-* Logitech WingMan GamePad Extreme
-* Logitech WingMan Extreme Digital 3D
-
-  ADI devices are autodetected, and the driver supports up to two (any
-combination of) devices on a single gameport, using an Y-cable or chained
-together.
-
-  Logitech WingMan Joystick, Logitech WingMan Attack, Logitech WingMan
-Extreme and Logitech WingMan ThunderPad are not digital joysticks and are
-handled by the analog driver described above. Logitech WingMan Warrior and
-Logitech Magellan are supported by serial drivers described below.  Logitech
-WingMan Force and Logitech WingMan Formula Force are supported by the
-I-Force driver described below. Logitech CyberMan is not supported yet.
-
-3.4 Gravis GrIP
-~~~~~~~~~~~~~~~
-  Gravis GrIP protocol is supported by the grip.c module. It currently
-supports:
-
-* Gravis GamePad Pro
-* Gravis BlackHawk Digital
-* Gravis Xterminator
-* Gravis Xterminator DualControl
-
-  All these devices are autodetected, and you can even use any combination
-of up to two of these pads either chained together or using an Y-cable on a
-single gameport.
-
-GrIP MultiPort isn't supported yet. Gravis Stinger is a serial device and
-hopefully will be supported soon. Other Gravis joysticks are supported by
-the analog driver.
-
-3.5 FPGaming A3D and MadCatz A3D
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The Assassin 3D protocol created by FPGaming, is used both by FPGaming
-themselves and is licensed to MadCatz. A3D devices are supported by the
-a3d.c module. It currently supports:
-
-* FPGaming Assassin 3D
-* MadCatz Panther
-* MadCatz Panther XL
-
-  All these devices are autodetected. Because the Assassin 3D and the Panther
-allow connecting analog joysticks to them, you'll need to load the analog
-driver as well to handle the attached joysticks.
-
-  The trackball should work with USB mousedev module as a normal mouse. See
-the USB documentation for how to setup an USB mouse.
-
-3.6 ThrustMaster DirectConnect (BSP)
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The TM DirectConnect (BSP) protocol is supported by the tmdc.c
-module. This includes, but is not limited to:
-
-* ThrustMaster Millenium 3D Inceptor
-* ThrustMaster 3D Rage Pad
-* ThrustMaster Fusion Digital Game Pad
-
-  Devices not directly supported, but hopefully working are:
-
-* ThrustMaster FragMaster
-* ThrustMaster Attack Throttle
-
-  If you have one of these, contact me.
-
-  BSP devices are autodetected, and thus no parameters to the module
-are needed. Up to two TMDC devices can be connected to one gameport, using
-an Y-cable.
-
-3.7 Creative Labs Blaster
-~~~~~~~~~~~~~~~~~~~~~~~~~
-  The Blaster protocol is supported by the cobra.c module. It supports only
-the:
-
-* Creative Blaster GamePad Cobra
-
-  Up to two of these can be used on a single gameport, using an Y-cable.
-
-3.8 Genius Digital joysticks 
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The Genius digitally communicating joysticks are supported by the gf2k.c
-module. This includes:
-
-* Genius Flight2000 F-23 joystick 
-* Genius Flight2000 F-31 joystick 
-* Genius G-09D gamepad
-
-  Other Genius digital joysticks are not supported yet, but support can be
-added fairly easily.
-
-3.9 InterAct Digital joysticks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The InterAct digitally communicating joysticks are supported by the
-interact.c module. This includes:
-
-* InterAct HammerHead/FX gamepad
-* InterAct ProPad8 gamepad 
-
-  Other InterAct digital joysticks are not supported yet, but support can be 
-added fairly easily.
-
-3.10 PDPI Lightning 4 gamecards
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  PDPI Lightning 4 gamecards are supported by the lightning.c module.
-Once the module is loaded, the analog driver can be used to handle the
-joysticks. Digitally communicating joystick will work only on port 0, while
-using Y-cables, you can connect up to 8 analog joysticks to a single L4
-card, 16 in case you have two in your system.
-
-3.11 Trident 4DWave / Aureal Vortex
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  Soundcards with a Trident 4DWave DX/NX or Aureal Vortex/Vortex2 chipsets
-provide an "Enhanced Game Port" mode where the soundcard handles polling the
-joystick.  This mode is supported by the pcigame.c module. Once loaded the
-analog driver can use the enhanced features of these gameports..
-
-3.12 Amiga
-~~~~~~~~~~
-  Amiga joysticks, connected to an Amiga, are supported by the amijoy.c
-driver. Since they can't be autodetected, the driver has a command line.
-
-	amijoy=a,b
-
-  a and b define the joysticks connected to the JOY0DAT and JOY1DAT ports of
-the Amiga.
-
-	Value | Joystick type
-	---------------------
-	  0   | None
-	  1   | 1-button digital joystick
-
-  No more joystick types are supported now, but that should change in the
-future if I get an Amiga in the reach of my fingers.
-
-3.13 Game console and 8-bit pads and joysticks
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-See joystick-parport.txt for more info.
-
-3.14 SpaceTec/LabTec devices
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  SpaceTec serial devices communicate using the SpaceWare protocol. It is
-supported by the spaceorb.c and spaceball.c drivers. The devices currently
-supported by spaceorb.c are:
-
-* SpaceTec SpaceBall Avenger
-* SpaceTec SpaceOrb 360
-
-Devices currently supported by spaceball.c are:
-
-* SpaceTec SpaceBall 4000 FLX
-
-  In addition to having the spaceorb/spaceball and serport modules in the
-kernel, you also need to attach a serial port to it. to do that, run the
-jsattach program:
-
-	inputattach --spaceorb /dev/tts/x &
-or
-	jsattach --spaceball /dev/tts/x &
-
-where /dev/tts/x is the serial port which the device is connected to. After
-doing this, the device will be reported and will start working.
-
-  There is one caveat with the SpaceOrb. The button #6, the on the bottom
-side of the orb, although reported as an ordinary button, causes internal
-recentering of the spaceorb, moving the zero point to the position in which
-the ball is at the moment of pressing the button. So, think first before
-you bind it to some other function.
-
-SpaceTec SpaceBall 2003 FLX and 3003 FLX are not supported yet. 
-
-3.15 Logitech SWIFT devices
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The SWIFT serial protocol is supported by the warrior.c module. It
-currently supports only the:
-
-* Logitech WingMan Warrior
-
-but in the future, Logitech CyberMan (the original one, not CM2) could be
-supported as well. To use the module, you need to run jsattach after you
-insert/compile the module into your kernel:
-
-	inputattach --warrior /dev/tts/x &
-
-/dev/tts/x is the serial port your Warrior is attached to.
-
-3.16 Magellan / Space Mouse
-~~~~~~~~~~~~~~~~~~~~~~~~~~~
-  The Magellan (or Space Mouse), manufactured by LogiCad3d (formerly Space
-Systems), for many other companies (Logitech, HP, ...) is supported by the
-joy-magellan module. It currently supports only the:
-
-* Magellan 3D
-* Space Mouse
-
-models, the additional buttons on the 'Plus' versions are not supported yet.
-
-  To use it, you need to attach the serial port to the driver using the
-
-	inputattach --magellan /dev/tts/x &
-
-command. After that the Magellan will be detected, initialized, will beep,
-and the /dev/input/jsX device should become usable.
-
-3.17 I-Force devices 
-~~~~~~~~~~~~~~~~~~~~
-  All I-Force devices ale supported by the iforce.c module. This includes,
-but is not limited to:
-
-* Logitech WingMan Force
-* Logitech WingMan Force Wheel 
-* Guillemot Race Leader wheel 
-
-  To use it, you need to attach the serial port to the driver using the
-
-	inputattach --iforce /dev/tts/x &
-
-command. After that the I-Force device will be detected, and the
-/dev/input/jsX device should become usable.
-
-  In case you're using the device via the USB port, the inputattach command
-isn't needed.
-
-4. Troubleshooting
-~~~~~~~~~~~~~~~~~~
-  There is quite a high probability that you run into some problems. For
-testing whether the driver works, if in doubt, use the jstest utility in
-some of its modes. The most useful modes are "normal" - for the 1.x
-interface, and "old" for the "0.x" interface. You run it by typing:
-
-	jstest --normal /dev/input/js0
-	jstest --old    /dev/input/js0
-
-  Additionally you can do a test with the evtest utility:
-
-	evtest /dev/input/event0
-
-  Oh, and read the FAQ! :)
-
-5. FAQ
-~~~~~~
-Q: Running 'jstest /dev/js0' results in "File not found" error. What's the
-   cause?
-A: The device files don't exist. Create them (see section 2.2).
-
-Q: Is it possible to connect my old Atari/Commodore/Amiga/console joystick
-   or pad that uses a 9-pin D-type cannon connector to the serial port of my
-   PC?
-A: Yes, it is possible, but it'll burn your serial port or the pad. It
-   won't work, of course.
-
-Q: My joystick doesn't work with Quake / Quake 2. What's the cause?
-A: Quake / Quake 2 don't support joystick. Use joy2key to simulate keypresses
-   for them.
-
-6. Programming Interface
-~~~~~~~~~~~~~~~~~~~~~~~~
-  The 1.0 driver uses a new, event based approach to the joystick driver.
-Instead of the user program polling for the joystick values, the joystick
-driver now reports only any changes of its state. See joystick-api.txt,
-joystick.h and jstest.c included in the joystick package for more
-information. The joystick device can be used in either blocking or
-nonblocking mode and supports select() calls.
-
-  For backward compatibility the old (v0.x) interface is still included.
-Any call to the joystick driver using the old interface will return values
-that are compatible to the old interface.  This interface is still limited
-to 2 axes, and applications using it usually decode only 2 buttons, although
-the driver provides up to 32.
-
-7. Credits
-~~~~~~~~~~
-  Thanks to the following people who contributed code, ideas or specifications
-to the joystick driver development:
-
-	Arthur C. Smith		<asmith@cbnewsd.att.com>
-	Eyal Lebedinsky		<eyal@eyal.emu.id.au>
-	Jeff Tranter		<tranter@software.mitel.com>
-	Carlos Puchol		<cpg@cs.utexas.edu>
-	Matt Rhoten		<mrhoten@oz.net>
-	Dan Fandrich		<dan@fch.wimsey.bc.ca>
-	Sverker Wilberg		<sverkerw@manila.docs.uu.se>
-	Hal Maney		<maney@norden.com>
-	Bernd Schmidt		<crux@pool.informatik.rwth-aachen.de>
-	Alan Cox		<alan@lxorguk.ukuu.org.uk>
-	John Markus Bjorndalen	<johnm@cs.uit.no>
-	Boris Muehmer		<mhs@cybernet-ag.de>
-	Robert W. Grubbs	<rwgrubbs@vt.edu>
-	Pete Chown		<pete.chown@skygate.co.uk>
-	Benji York		<benji@cookeville.com>
-	Leslie F. Donaldson	<donaldlf@cs.rose-hulman.edu>
-	Eng-Jon Ong		<ongej@dcs.qmw.ac.uk>
-	Ragnar Hojland Espinosa	<ragnar@macula.net>
-	Brian Gerst		<bgerst@quark.vpplus.com>
-	Andree Borrmann		<a.borrmann@tu-bs.de>
-	Martin Giguere		<zefrench@hotmail.com>
-	David Thompson		<dcthomp@mail.utexas.edu>
-	Justin Wake		<spectre@telefragged.com>
-	Benoit Triquet		<benoit@adsl-216-100-248-201.dsl.pacbell.net>
-	John Dahlstrom		<jodaman@bradley.edu>
-	Dan Gohman		<gohmandj@mrs.umn.edu>
-	Joe Krahn		<krahn@niehs.nih.gov>
-	David Kuder		<alphagod@penguinpowered.com>
-	Raymond Ingles		<sorceror@tir.com>
-
-  If you think you should be in this list and are not, it's possible that
-I forgot to include you - contact me and I'll correct the error. :)
diff -urN linux-2.4.10-pre8/Documentation/usb/hiddev.txt linux/Documentation/usb/hiddev.txt
--- linux-2.4.10-pre8/Documentation/usb/hiddev.txt	Wed Dec 31 16:00:00 1969
+++ linux/Documentation/usb/hiddev.txt	Mon Dec  3 23:09:47 2001
@@ -0,0 +1,162 @@
+Care and feeding of your Human Interface Devices
+
+INTRODUCTION
+
+In addition to the normal input type HID devices, USB also uses the
+human interface device protocols for things that are not really human
+interfaces, but have similar sorts of communication needs. The two big
+examples for this are power devices (especially uninterruptable power
+supplies) and monitor control on higher end monitors.
+
+To support these disparite requirements, the Linux USB system provides
+HID events to two seperate interfaces:
+* the input subsystem, which converts HID events into normal input
+device interfaces (such as keyboard, mouse and joystick) and a
+normalised event interface - see Documentation/input/input.txt
+* the hiddev interface, which provides fairly raw HID events
+
+The data flow for a HID event produced by a device is something like
+the following :
+
+ usb.c ---> hid.c  ----> input.c ----> [keyboard/mouse/joystick/event]
+                    |
+                    |
+                    --> hiddev.c ----> POWER / MONITOR CONTROL 
+
+In addition, other subsystems (apart from USB) can potentially feed
+events into the input subsystem, but these have no effect on the hid
+device interface.
+
+USING THE HID DEVICE INTERFACE
+
+The hiddev interface is a char interface using the normal USB major,
+with the minor numbers starting at 96 and finishing at 111. Therefore,
+you need the following commands:
+mknod /dev/usb/hiddev0 c 180 96
+mknod /dev/usb/hiddev1 c 180 97
+mknod /dev/usb/hiddev2 c 180 98
+mknod /dev/usb/hiddev3 c 180 99
+mknod /dev/usb/hiddev4 c 180 100
+mknod /dev/usb/hiddev5 c 180 101
+mknod /dev/usb/hiddev6 c 180 102
+mknod /dev/usb/hiddev7 c 180 103
+mknod /dev/usb/hiddev8 c 180 104
+mknod /dev/usb/hiddev9 c 180 105
+mknod /dev/usb/hiddev10 c 180 106
+mknod /dev/usb/hiddev11 c 180 107
+mknod /dev/usb/hiddev12 c 180 108
+mknod /dev/usb/hiddev13 c 180 109
+mknod /dev/usb/hiddev14 c 180 110
+mknod /dev/usb/hiddev15 c 180 111
+
+So you point your hiddev compliant user-space program at the correct
+interface for your device, and it all just works.
+
+Assuming that you have a hiddev compliant user-space program, of
+course. If you need to write one, read on.
+
+
+THE HIDDEV API
+This description should be read in conjunction with the HID
+specification, freely available from http://www.usb.org, and
+conveniently linked of http://www.linux-usb.org.
+
+The hiddev API uses a read() interface, and a set of ioctl() calls.
+
+
+read():
+This is the event interface. When the HID device performs an
+interrupt transfer, indicating a change of state, data will be made
+available at the associated hiddev device with the content of a struct
+hiddev_event: 
+
+       struct hiddev_event {
+           unsigned hid;
+           signed int value;
+       };
+
+containing the HID usage identifier for the status that changed, and
+the value that it was changed to. Note that the structure is defined
+within <linux/hiddev.h>, along with some other useful #defines and
+structures. 
+
+
+ioctl(): 
+This is the control interface. There are a number of controls: 
+
+HIDIOCGVERSION - int (read)
+Gets the version code out of the hiddev driver.
+
+HIDIOCAPPLICATION - (none)
+This ioctl call returns the HID application usage associated with the
+hid device. The third argument to ioctl() specifies which application
+index to get. This is useful when the device has more than one
+application collection. If the index is invalid (greater or equal to
+the number of application collections this device has) the ioctl
+returns -1. You can find out beforehand how many application
+collections the device has from the num_applications field from the
+hiddev_devinfo structure. 
+
+HIDIOCGDEVINFO - struct hiddev_devinfo (read)
+Gets a hiddev_devinfo structure which describes the device.
+
+HIDIOCGSTRING - struct struct hiddev_string_descriptor (read/write)
+Gets a string descriptor from the device. The caller must fill in the
+"index" field to indicate which descriptor should be returned.
+
+HIDIOCINITREPORT - (none)
+Instructs the kernel to retrieve all input and feature report values
+from the device. At this point, all the usage structures will contain
+current values for the device, and will maintain it as the device
+changes.
+
+HIDIOCGNAME - string (variable length)
+Gets the device name
+
+HIDIOCGREPORT - struct hiddev_report_info (write)
+Instructs the kernel to get a feature or input report from the device,
+in order to selectively update the usage structures (in contrast to
+INITREPORT). 
+
+HIDIOCSREPORT - struct hiddev_report_info (write)
+Instructs the kernel to send a report to the device. This report can
+be filled in by the user through HIDIOCSUSAGE calls (below) to fill in
+individual usage values in the report beforesending the report in full
+to the device. 
+
+HIDIOCGREPORTINFO - struct hiddev_report_info (read/write)
+Fills in a hiddev_report_info structure for the user. The report is
+looked up by type (input, output or feature) and id, so these fields
+must be filled in by the user. The ID can be absolute -- the actual
+report id as reported by the device -- or relative --
+HID_REPORT_ID_FIRST for the first report, and (HID_REPORT_ID_NEXT |
+report_id) for the next report after report_id. Without a-priori
+information about report ids, the right way to use this ioctl is to
+use the relative IDs above to enumerate the valid IDs. The ioctl
+returns non-zero when there is no more next ID. The real report ID is
+filled into the returned hiddev_report_info structure. 
+
+HIDIOCGFIELDINFO - struct hiddev_field_info (read/write)
+Returns the field information associated with a report in a
+hiddev_field_info structure. The user must fill in report_id and
+report_type in this structure, as above. The field_index should also
+be filled in, which should be a number from 0 and maxfield-1, as
+returned from a previous HIDIOCGREPORTINFO call. 
+
+HIDIOCGUCODE - struct hiddev_usage_ref (read/write)
+Returns the usage_code in a hiddev_usage_ref structure, given that
+given its report type, report id, field index, and index within the
+field have already been filled into the structure.
+
+HIDIOCGUSAGE - struct hiddev_usage_ref (read/write)
+Returns the value of a usage in a hiddev_usage_ref structure. The
+usage to be retrieved can be specified as above, or the user can
+choose to fill in the report_type field and specify the report_id as
+HID_REPORT_ID_UNKNOWN. In this case, the hiddev_usage_ref will be
+filled in with the report and field infomation associated with this
+usage if it is found. 
+
+HIDIOCSUSAGE - struct hiddev_usage_ref (write)
+Sets the value of a usage in an output report.
+
+
diff -urN linux-2.4.10-pre8/Documentation/usb/input.txt linux/Documentation/usb/input.txt
--- linux-2.4.10-pre8/Documentation/usb/input.txt	Fri Jul 28 12:50:52 2000
+++ linux/Documentation/usb/input.txt	Wed Dec 31 16:00:00 1969
@@ -1,306 +0,0 @@
-			  Linux Input drivers v1.0
-	       (c) 1999-2000 Vojtech Pavlik <vojtech@suse.cz>
-			     Sponsored by SuSE
-	    $Id: input.txt,v 1.4 2000/05/28 17:57:22 vojtech Exp $
-----------------------------------------------------------------------------
-
-0. Disclaimer
-~~~~~~~~~~~~~
-  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 <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
-Ucitelska 1576, 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.
-
-1. Introduction
-~~~~~~~~~~~~~~~
-  This is a collection of drivers that is designed to support all input
-devices under Linux. However, in the current kernels, although it's
-possibilities are much bigger, it's limited to USB devices only. This is
-also why it resides in the drivers/usb subdirectory.
-
-  The center of the input drivers is the input.o module, which must be
-loaded before any other of the input modules - it serves as a way of
-communication between two groups of modules:
-
-1.1 Device drivers
-~~~~~~~~~~~~~~~~~~
-  These modules talk to the hardware (for example via USB), and provide
-events (keystrokes, mouse movements) to the input.o module.
-
-1.2 Event handlers
-~~~~~~~~~~~~~~~~~~
-  These modules get events from input.o and pass them where needed via
-various interfaces - keystrokes to the kernel, mouse movements via a
-simulated PS/2 interface to GPM and X and so on.
-
-2. Simple Usage
-~~~~~~~~~~~~~~~
-  For the most usual configuration, with one USB mouse and one USB keyboard,
-you'll have to load the following modules (or have them built in to the
-kernel):
-
-	input.o
-	mousedev.o
-	keybdev.o
-	usbcore.o
-	usb-[uo]hci.o
-	hid.o
-
-  After this, the USB keyboard will work straight away, and the USB mouse
-will be available as a character device on major 13, minor 63:
-
-	crw-r--r--   1 root     root      13,  63 Mar 28 22:45 mice
-
-  This device, has to be created, unless you use devfs, in which case it's
-created automatically. The commands to do that are:
-
-	cd /dev
-	mkdir input
-	mknod input/mice c 13 63
-
-  After that you have to point GPM (the textmode mouse cut&paste tool) and
-XFree to this device to use it - GPM should be called like:
-
-	gpm -t ps2 -m /dev/input/mice
-
-  And in X:
-
-	Section "Pointer"
-	    Protocol    "ImPS/2"
-	    Device      "/dev/input/mice"
-	    ZAxisMapping 4 5
-	EndSection
-
-  When you do all of the above, you can use your USB mouse and keyboard.
-
-3. Detailed Description
-~~~~~~~~~~~~~~~~~~~~~~~
-3.1 Device drivers
-~~~~~~~~~~~~~~~~~~
-  Device drivers are the modules that generate events. The events are
-however not useful without being handled, so you also will need to use some
-of the modules from section 3.2.
-
-3.1.1 hid.c
-~~~~~~~~~~~
-  Hid.c is the largest and most complex driver of the whole suite. It
-handles all HID devices, and because there is a very wide variety of them,
-and because the USB HID specification isn't simple, it needs to be this big.
-
-  Currently, it handles USB mice, joysticks, gamepads, steering wheels
-keyboards, trackballs and digitizers.
-
- However, USB uses HID also for monitor controls, speaker controls, UPSs,
-LCDs and many other purposes.
-
- The monitor and speaker controls should be easy to add to the hid/input
-interface, but for the UPSs and LCDs it doesn't make much sense. The driver
-doesn't support these yet, and a new, non-event interface should be designed
-for them. If you have any of these devices (I don't), feel free to design
-something and if it's good, it'll get into the driver.
-
-  The usage of the hid.o module is very simple, it takes no parameters,
-detects everything automatically and when a HID device is inserted, it
-detects it appropriately.
-
-  However, because the devices vary wildly, you might happen to have a
-device that doesn't work well. In that case #define DEBUG at the beginning
-of hid.c and send me the syslog traces.
-
-3.1.2 usbmouse.c
-~~~~~~~~~~~~~~~~
-  For embedded systems, for mice with broken HID descriptors and just any
-other use when the big hid.c wouldn't be a good choice, there is the
-usbmouse.c driver. It handles USB mice only. It uses a simpler HIDBP
-protocol. This also means the mice must support this simpler protocol. Not
-all do. If you don't have any strong reason to use this module, use hid.c
-instead.
-
-3.1.3 usbkbd.c
-~~~~~~~~~~~~~~
-  Much like usbmouse.c, this module talks to keyboards with a simplified
-HIDBP protocol. It's smaller, but doesn't support any extra special keys.
-Use hid.c instead if there isn't any special reason to use this.
-
-3.1.4 wacom.c
-~~~~~~~~~~~~~
-  This is a driver for Wacom Graphire and Intuos tablets. Not for Wacom
-PenPartner, that one is handled by the HID driver. Although the Intuos and
-Graphire tablets claim that they are HID tablets as well, they are not and
-thus need this specific driver.
-
-3.1.5 wmforce.c
-~~~~~~~~~~~~~~~
-  A driver for the Logitech WingMan Force joysticks, when connected via the
-USB port. It works quite well, but there is no force feedback support yet,
-because the interface to do that is a trade secret of Immersion Corp, and
-even Logitech can't disclose it.
-
-  Support for Logitech WingMan Force Wheel isn't present in this driver, but
-if someone has the device, and is willing to cooperate, it should be a
-matter of a couple days to add it.
-
-3.2 Event handlers
-~~~~~~~~~~~~~~~~~~
-  Event handlers distribute the events from the devices to userland and
-kernel, as needed.
-
-3.2.1 keybdev.c
-~~~~~~~~~~~~~~~
-  Keybdev is currently a rather ugly hack that translates the input events
-into architecture-specific keyboard raw mode (Xlated AT Set2 on x86), and
-passes them into the handle_scancode function of the keyboard.c module. This
-works well enough on all architectures that keybdev can generate rawmode on,
-other architectures can be added to it.
-
-  The right way would be to pass the events to keyboard.c directly, best if
-keyboard.c would itself be an event handler. This is done in the input
-patch, available on the webpage mentioned below.
-
-3.2.2 mousedev.c
-~~~~~~~~~~~~~~~~
-  Mousedev is also a hack to make programs that use mouse input work. It
-takes events from either mice or digitizers/tablets and makes a PS/2-style
-(a la /dev/psaux) mouse device available to the userland. Ideally, the
-programs could use a more reasonable interface, for example evdev.c
-
-  Mousedev devices in /dev/input (as shown above) are:
-
-	crw-r--r--   1 root     root      13,  32 Mar 28 22:45 mouse0
-	crw-r--r--   1 root     root      13,  33 Mar 29 00:41 mouse1
-	crw-r--r--   1 root     root      13,  34 Mar 29 00:41 mouse2
-	crw-r--r--   1 root     root      13,  35 Apr  1 10:50 mouse3
-	...
-	...
-	crw-r--r--   1 root     root      13,  62 Apr  1 10:50 mouse30
-	crw-r--r--   1 root     root      13,  63 Apr  1 10:50 mice
-
-Each 'mouse' device is assigned to a single mouse or digitizer, except the last
-one - 'mice'. This single character device is shared by all mice and
-digitizers, and even if none are connected, the device is present.  This is
-useful for hotplugging USB mice, so that programs can open the device even when
-no mice are present.
-
-  CONFIG_INPUT_MOUSEDEV_SCREEN_[XY] in the kernel configuration are the size
-of your screen (in pixels) in XFree86. This is needed if you want to use
-your digitizer in X, because it's movement is sent to X via a virtual PS/2
-mouse and thus needs to be scaled accordingly. These values won't be used if
-you use a mouse only.
-
-  Mousedev will generate either PS/2, ImPS/2 (Microsoft IntelliMouse) or
-GenPS/2 (Genius NetMouse/NetScroll) protocols, depending on what the program
-reading the data wishes. You can set GPM and X to any of these. You'll need
-ImPS/2 if you want to make use of a wheel on a USB mouse and GenPS/2 if you
-want to use extra (up to 5) buttons. I'm not sure how much is GenPS/2 supported
-in X, though.
-
-3.2.3 joydev.c
-~~~~~~~~~~~~~~
-  Joydev implements v0.x and v1.x Linux joystick api, much like
-drivers/char/joystick/joystick.c. See joystick-api.txt in the Documentation
-subdirectory for details. Joydev does it on top of the input subsystem,
-though. As soon as any USB joystick is connected, it can be accessed in
-/dev/input on:
-
-	crw-r--r--   1 root     root      13,   0 Apr  1 10:50 js0
-	crw-r--r--   1 root     root      13,   1 Apr  1 10:50 js1
-	crw-r--r--   1 root     root      13,   2 Apr  1 10:50 js2
-	crw-r--r--   1 root     root      13,   3 Apr  1 10:50 js3
-	...
-
-And so on up to js31.
-
-3.2.4 evdev.c
-~~~~~~~~~~~~~
-  Evdev is the generic input event interface. It passes the events generated
-in the kernel straight to the program, with timestamps. The API is still
-evolving, but should be usable now. It's described in section 5.
-
-  This should be the way for GPM and X to get keyboard and mouse mouse
-events. It allows for multihead in X without any specific multihead kernel
-support. The event codes are the same on all architectures and are hardware
-independent.
-
-  The devices are in /dev/input:
-
-	crw-r--r--   1 root     root      13,  64 Apr  1 10:49 event0
-	crw-r--r--   1 root     root      13,  65 Apr  1 10:50 event1
-	crw-r--r--   1 root     root      13,  66 Apr  1 10:50 event2
-	crw-r--r--   1 root     root      13,  67 Apr  1 10:50 event3
-	...
-
-3. Contacts
-~~~~~~~~~~~
-  This effort has it's home page at:
-
-	http://www.suse.cz/development/input/
-
-You'll find both the latest HID driver and the complete Input driver there
-as well as information how to access the CVS repository for latest revisions
-of the drivers.
-
-
-  There is also a mailing list for this:
-
-	majordomo@atrey.karlin.mff.cuni.cz
-
-Send "subscribe linux-input" to subscribe to it.
-
-4. Verifying if it works
-~~~~~~~~~~~~~~~~~~~~~~~~
-  Typing a couple keys on the keyboard should be enough to check that a USB
-keyboard works and is correctly connected to the kernel keyboard driver.
-
-  Doing a cat /dev/input/mouse0 (c, 13, 32) will verify that a mouse is also
-emulated, characters should appear if you move it.
-
-  You can test the joystick emulation with the 'jstest' utility, available
-in the joystick package (see Documentation/joystick.txt).
-
-  You can test the event devics with the 'evtest' utility available on the
-input driver homepage (see the URL above).
-
-5. Event interface
-~~~~~~~~~~~~~~~~~~
-  Should you want to add event device support into any application (X, gpm,
-svgalib ...) I <vojtech@suse.cz> will be happy to provide you any help I
-can. Here goes a description of the current state of things, which is going
-to be extended, but not changed incompatibly as time goes:
-
-  You can use blocking and nonblocking reads, also select() on the
-/dev/input/eventX devices, and you'll always get a whole number of input
-events on a read. Their layout is:
-
-struct input_event {
-	struct timeval time;
-	unsigned short type;
-	unsigned short code;
-	unsigned int value;
-};
-
-  'time' is the timestamp, it returns the time at which the event happened.
-Type is for example EV_REL for relative movement, REL_KEY for a keypress or
-release. More types are defined in include/linux/input.h.
-
-  'code' is event code, for example REL_X or KEY_BACKSPACE, again a complete
-list is in include/linux/input.h.
-
-  'value' is the value the event carries. Either a relative change for
-EV_REL, absolute new value for EV_ABS (joysticks ...), or 0 for EV_KEY for
-release, 1 for keypress and 2 for autorepeat.
diff -urN linux-2.4.10-pre8/Makefile linux/Makefile
--- linux-2.4.10-pre8/Makefile	Mon Dec  3 23:09:37 2001
+++ linux/Makefile	Mon Dec  3 23:09:47 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 10
-EXTRAVERSION =-pre8
+EXTRAVERSION =-pre9
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/alpha_ksyms.c linux/arch/alpha/kernel/alpha_ksyms.c
--- linux-2.4.10-pre8/arch/alpha/kernel/alpha_ksyms.c	Mon Dec  3 23:09:37 2001
+++ linux/arch/alpha/kernel/alpha_ksyms.c	Mon Dec  3 23:09:47 2001
@@ -208,6 +208,8 @@
 EXPORT_SYMBOL(cpu_data);
 EXPORT_SYMBOL(__cpu_number_map);
 EXPORT_SYMBOL(smp_num_cpus);
+EXPORT_SYMBOL(smp_call_function);
+EXPORT_SYMBOL(smp_call_function_on_cpu);
 EXPORT_SYMBOL(global_irq_holder);
 EXPORT_SYMBOL(__global_cli);
 EXPORT_SYMBOL(__global_sti);
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/core_cia.c linux/arch/alpha/kernel/core_cia.c
--- linux-2.4.10-pre8/arch/alpha/kernel/core_cia.c	Tue May 22 16:29:57 2001
+++ linux/arch/alpha/kernel/core_cia.c	Mon Dec  3 23:09:47 2001
@@ -352,13 +352,15 @@
 	   so use them and read at window 3 base exactly 4 times. Reading
 	   more sometimes makes the chip crazy.  -ink */
 
-	bus_addr = cia_ioremap(CIA_BROKEN_TBIA_BASE);
+	bus_addr = cia_ioremap(CIA_BROKEN_TBIA_BASE, 32768 * 4);
 
 	cia_readl(bus_addr + 0x00000);
 	cia_readl(bus_addr + 0x08000);
 	cia_readl(bus_addr + 0x10000);
 	cia_readl(bus_addr + 0x18000);
 
+	cia_iounmap(bus_addr);
+
 	/* Restore normal PCI operation.  */
 	mb();
 	*(vip)CIA_IOC_CIA_CTRL = ctrl;
@@ -396,6 +398,7 @@
 	struct pci_iommu_arena *arena = pci_isa_hose->sg_isa;
 	int ctrl, addr0, tag0, pte0, data0;
 	int temp, use_tbia_try2 = 0;
+	unsigned long bus_addr;
 
 	/* pyxis -- tbia is broken */
 	if (pci_isa_hose->dense_io_base)
@@ -429,6 +432,9 @@
 	*(vip)CIA_IOC_TBn_PAGEm(0,3) = 0;
 	mb();
 
+	/* Get a usable bus address */
+	bus_addr = cia_ioremap(addr0, 8*PAGE_SIZE);
+
 	/* First, verify we can read back what we've written.  If
 	   this fails, we can't be sure of any of the other testing
 	   we're going to do, so bail.  */
@@ -464,7 +470,7 @@
 	mcheck_expected(0) = 1;
 	mcheck_taken(0) = 0;
 	mb();
-	temp = cia_readl(cia_ioremap(addr0));
+	temp = cia_readl(bus_addr);
 	mb();
 	mcheck_expected(0) = 0;
 	mb();
@@ -501,7 +507,7 @@
 	mcheck_expected(0) = 1;
 	mcheck_taken(0) = 0;
 	mb();
-	temp = cia_readl(cia_ioremap(addr0 + 4*PAGE_SIZE));
+	temp = cia_readl(bus_addr + 4*PAGE_SIZE);
 	mb();
 	mcheck_expected(0) = 0;
 	mb();
@@ -525,7 +531,7 @@
 	mcheck_expected(0) = 1;
 	mcheck_taken(0) = 0;
 	mb();
-	temp = cia_readl(cia_ioremap(addr0 + 5*PAGE_SIZE));
+	temp = cia_readl(bus_addr + 5*PAGE_SIZE);
 	mb();
 	mcheck_expected(0) = 0;
 	mb();
@@ -549,7 +555,7 @@
 	mcheck_expected(0) = 1;
 	mcheck_taken(0) = 0;
 	mb();
-	temp = cia_readl(cia_ioremap(addr0 + 6*PAGE_SIZE));
+	temp = cia_readl(bus_addr + 6*PAGE_SIZE);
 	mb();
 	mcheck_expected(0) = 0;
 	mb();
@@ -575,6 +581,9 @@
 	alpha_mv.mv_pci_tbi(arena->hose, 0, -1);
 
 exit:
+	/* unmap the bus addr */
+	cia_iounmap(bus_addr);
+
 	/* Restore normal PCI operation.  */
 	mb();
 	*(vip)CIA_IOC_CIA_CTRL = ctrl;
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/core_irongate.c linux/arch/alpha/kernel/core_irongate.c
--- linux-2.4.10-pre8/arch/alpha/kernel/core_irongate.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/core_irongate.c	Mon Dec  3 23:09:47 2001
@@ -30,6 +30,8 @@
 
 #undef DEBUG_IRONGATE 		/* define to enable verbose Irongate debug */
 
+#define IRONGATE_DEFAULT_AGP_APER_SIZE	(256*1024*1024) /* 256MB */
+
 /*
  * BIOS32-style PCI interface:
  */
@@ -374,6 +376,14 @@
 	irongate_register_dump(__FUNCTION__);
 
 	/*
+	 * HACK: set AGP aperture size to 256MB.
+	 * This should really be changed during PCI probe, when the
+	 * size of the aperture the AGP card wants is known.
+	 */
+	printk("irongate_init_arch: AGPVA was 0x%x\n", IRONGATE0->agpva);
+	IRONGATE0->agpva = (IRONGATE0->agpva & ~0x0000000f) | 0x00000007;
+
+	/*
 	 * Create our single hose.
 	 */
 
@@ -396,4 +406,202 @@
 	hose->sg_isa = hose->sg_pci = NULL;
 	__direct_map_base = 0;
 	__direct_map_size = 0xffffffff;
+}
+
+/*
+ * IO map and AGP support
+ */
+#include <linux/vmalloc.h>
+#include <asm/pgalloc.h>
+
+static inline void 
+irongate_remap_area_pte(pte_t * pte, unsigned long address, unsigned long size, 
+		     unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PMD_MASK;
+	end = address + size;
+	if (end > PMD_SIZE)
+		end = PMD_SIZE;
+	if (address >= end)
+		BUG();
+	do {
+		if (!pte_none(*pte)) {
+			printk("irongate_remap_area_pte: page already exists\n");
+			BUG();
+		}
+		set_pte(pte, 
+			mk_pte_phys(phys_addr, 
+				    __pgprot(_PAGE_VALID | _PAGE_ASM | 
+					     _PAGE_KRE | _PAGE_KWE | flags)));
+		address += PAGE_SIZE;
+		phys_addr += PAGE_SIZE;
+		pte++;
+	} while (address && (address < end));
+}
+
+static inline int 
+irongate_remap_area_pmd(pmd_t * pmd, unsigned long address, unsigned long size, 
+		     unsigned long phys_addr, unsigned long flags)
+{
+	unsigned long end;
+
+	address &= ~PGDIR_MASK;
+	end = address + size;
+	if (end > PGDIR_SIZE)
+		end = PGDIR_SIZE;
+	phys_addr -= address;
+	if (address >= end)
+		BUG();
+	do {
+		pte_t * pte = pte_alloc(&init_mm, pmd, address);
+		if (!pte)
+			return -ENOMEM;
+		irongate_remap_area_pte(pte, address, end - address, 
+				     address + phys_addr, flags);
+		address = (address + PMD_SIZE) & PMD_MASK;
+		pmd++;
+	} while (address && (address < end));
+	return 0;
+}
+
+static int
+irongate_remap_area_pages(unsigned long address, unsigned long phys_addr,
+		       unsigned long size, unsigned long flags)
+{
+	pgd_t * dir;
+	unsigned long end = address + size;
+
+	phys_addr -= address;
+	dir = pgd_offset(&init_mm, address);
+	flush_cache_all();
+	if (address >= end)
+		BUG();
+	do {
+		pmd_t *pmd;
+		pmd = pmd_alloc(&init_mm, dir, address);
+		if (!pmd)
+			return -ENOMEM;
+		if (irongate_remap_area_pmd(pmd, address, end - address,
+					 phys_addr + address, flags))
+			return -ENOMEM;
+		address = (address + PGDIR_SIZE) & PGDIR_MASK;
+		dir++;
+	} while (address && (address < end));
+	return 0;
+}
+
+#include <linux/agp_backend.h>
+#include <linux/agpgart.h>
+
+#define GET_PAGE_DIR_OFF(addr) (addr >> 22)
+#define GET_PAGE_DIR_IDX(addr) (GET_PAGE_DIR_OFF(addr))
+
+#define GET_GATT_OFF(addr) ((addr & 0x003ff000) >> 12) 
+#define GET_GATT(addr) (gatt_pages[GET_PAGE_DIR_IDX(addr)])
+
+unsigned long
+irongate_ioremap(unsigned long addr, unsigned long size)
+{
+	struct vm_struct *area;
+	unsigned long vaddr;
+	unsigned long baddr, last;
+	u32 *mmio_regs, *gatt_pages, *cur_gatt, pte;
+	unsigned long gart_bus_addr, gart_aper_size;
+
+	gart_bus_addr = (unsigned long)IRONGATE0->bar0 &
+			PCI_BASE_ADDRESS_MEM_MASK; 
+
+	if (!gart_bus_addr) /* FIXME - there must be a better way!!! */
+		return addr + IRONGATE_MEM;
+
+	gart_aper_size = IRONGATE_DEFAULT_AGP_APER_SIZE; /* FIXME */
+
+	/* 
+	 * Check for within the AGP aperture...
+	 */
+	do {
+		/*
+		 * Check the AGP area
+		 */
+		if (addr >= gart_bus_addr && addr + size - 1 < 
+		    gart_bus_addr + gart_aper_size)
+			break;
+
+		/*
+		 * Not found - assume legacy ioremap
+		 */
+		return addr + IRONGATE_MEM;
+	} while(0);
+
+	mmio_regs = (u32 *)(((unsigned long)IRONGATE0->bar1 &
+			PCI_BASE_ADDRESS_MEM_MASK) + IRONGATE_MEM);
+
+	gatt_pages = (u32 *)(phys_to_virt(mmio_regs[1])); /* FIXME */
+
+	/*
+	 * Adjust the limits (mappings must be page aligned)
+	 */
+	if (addr & ~PAGE_MASK) {
+		printk("AGP ioremap failed... addr not page aligned (0x%lx)\n",
+		       addr);
+		return addr + IRONGATE_MEM;
+	}
+	last = addr + size - 1;
+	size = PAGE_ALIGN(last) - addr;
+
+#if 0
+	printk("irongate_ioremap(0x%lx, 0x%lx)\n", addr, size);
+	printk("irongate_ioremap:  gart_bus_addr  0x%lx\n", gart_bus_addr);
+	printk("irongate_ioremap:  gart_aper_size 0x%lx\n", gart_aper_size);
+	printk("irongate_ioremap:  mmio_regs      %p\n", mmio_regs);
+	printk("irongate_ioremap:  gatt_pages     %p\n", gatt_pages);
+	
+	for(baddr = addr; baddr <= last; baddr += PAGE_SIZE)
+	{
+		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
+		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
+		printk("irongate_ioremap:  cur_gatt %p pte 0x%x\n",
+		       cur_gatt, pte);
+	}
+#endif
+
+	/*
+	 * Map it
+	 */
+	area = get_vm_area(size, VM_IOREMAP);
+	if (!area) return (unsigned long)NULL;
+
+	for(baddr = addr, vaddr = (unsigned long)area->addr; 
+	    baddr <= last; 
+	    baddr += PAGE_SIZE, vaddr += PAGE_SIZE)
+	{
+		cur_gatt = phys_to_virt(GET_GATT(baddr) & ~1);
+		pte = cur_gatt[GET_GATT_OFF(baddr)] & ~1;
+
+		if (irongate_remap_area_pages(VMALLOC_VMADDR(vaddr), 
+					   pte, PAGE_SIZE, 0)) {
+			printk("AGP ioremap: FAILED to map...\n");
+			vfree(area->addr);
+			return (unsigned long)NULL;
+		}
+	}
+
+	flush_tlb_all();
+
+	vaddr = (unsigned long)area->addr + (addr & ~PAGE_MASK);
+#if 0
+	printk("irongate_ioremap(0x%lx, 0x%lx) returning 0x%lx\n",
+	       addr, size, vaddr);
+#endif
+	return vaddr;
+}
+
+void
+irongate_iounmap(unsigned long addr)
+{
+	if (((long)addr >> 41) == -2)
+		return;	/* kseg map, nothing to do */
+	if (addr) return vfree((void *)(PAGE_MASK & addr)); 
 }
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/machvec_impl.h linux/arch/alpha/kernel/machvec_impl.h
--- linux-2.4.10-pre8/arch/alpha/kernel/machvec_impl.h	Wed Jun 21 22:30:59 2000
+++ linux/arch/alpha/kernel/machvec_impl.h	Mon Dec  3 23:09:47 2001
@@ -80,7 +80,8 @@
 	mv_writew:		CAT(low,_writew),			\
 	mv_writel:		CAT(low,_writel),			\
 	mv_writeq:		CAT(low,_writeq),			\
-	mv_ioremap:		CAT(low,_ioremap)			\
+	mv_ioremap:		CAT(low,_ioremap),			\
+	mv_iounmap:		CAT(low,_iounmap)			\
 
 #define IO(UP,low)							\
 	IO_LITE(UP,low),						\
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/pci-noop.c linux/arch/alpha/kernel/pci-noop.c
--- linux-2.4.10-pre8/arch/alpha/kernel/pci-noop.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/pci-noop.c	Mon Dec  3 23:09:47 2001
@@ -102,3 +102,38 @@
 	else
 		return -ENODEV;
 }
+/* stubs for the routines in pci_iommu.c */
+void *
+pci_alloc_consistent(struct pci_dev *pdev, long size, dma_addr_t *dma_addrp)
+{
+}
+void
+pci_free_consistent(struct pci_dev *pdev, long size, void *cpu_addr,
+		    dma_addr_t dma_addr)
+{
+}
+dma_addr_t
+pci_map_single(struct pci_dev *pdev, void *cpu_addr, long size,
+	       int direction)
+{
+}
+void
+pci_unmap_single(struct pci_dev *pdev, dma_addr_t dma_addr, long size,
+		 int direction)
+{
+}
+int
+pci_map_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
+	   int direction)
+{
+}
+void
+pci_unmap_sg(struct pci_dev *pdev, struct scatterlist *sg, int nents,
+	     int direction)
+{
+}
+int
+pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+{
+	return 0;
+}
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/pci.c linux/arch/alpha/kernel/pci.c
--- linux-2.4.10-pre8/arch/alpha/kernel/pci.c	Mon May 21 13:38:41 2001
+++ linux/arch/alpha/kernel/pci.c	Mon Dec  3 23:09:47 2001
@@ -76,6 +76,9 @@
 		dev->resource[3].end = dev->resource[3].start + 7;
 }
 
+static void __init
+quirk_cypress(struct pci_dev *dev)
+{
 /*
  * Notorious Cy82C693 chip. One of its numerous bugs: although
  * Cypress IDE controller doesn't support native mode, it has
@@ -85,31 +88,27 @@
  * and floppy controller. Ugh.
  * Fix that.
  */
-static void __init
-quirk_cypress_ide_ports(struct pci_dev *dev)
-{
-	if (dev->class >> 8 != PCI_CLASS_STORAGE_IDE)
+	if (dev->class >> 8 == PCI_CLASS_STORAGE_IDE) {
+		dev->resource[0].flags = 0;
+		dev->resource[1].flags = 0;
 		return;
-	dev->resource[0].flags = 0;
-	dev->resource[1].flags = 0;
-}
-
-static void __init
-quirk_vga_enable_rom(struct pci_dev *dev)
-{
-	/* If it's a VGA, enable its BIOS ROM at C0000.
-	   But if its a Cirrus 543x/544x DISABLE it, since
-	   enabling ROM disables the memory... */
-	if ((dev->class >> 8) == PCI_CLASS_DISPLAY_VGA &&
-	    (dev->vendor != PCI_VENDOR_ID_CIRRUS ||
-	     (dev->device < 0x00a0) || (dev->device > 0x00ac)))
-	{
-		u32 reg;
-
-		pci_read_config_dword(dev, dev->rom_base_reg, &reg);
-		reg |= PCI_ROM_ADDRESS_ENABLE;
-		pci_write_config_dword(dev, dev->rom_base_reg, reg);
-		dev->resource[PCI_ROM_RESOURCE].flags |= PCI_ROM_ADDRESS_ENABLE;
+	}
+/*
+ * Another "feature": Cypress bridge responds on the PCI bus
+ * in the address range 0xffff0000-0xffffffff (conventional
+ * x86 BIOS ROM). No way to turn this off, so if we use
+ * large SG window, we must avoid these addresses.
+ */
+	if (dev->class >> 8 == PCI_CLASS_BRIDGE_ISA) {
+		struct pci_controller *hose = dev->sysdata;
+		long overlap;
+
+		if (hose->sg_pci) {
+			overlap = hose->sg_pci->dma_base + hose->sg_pci->size;
+			overlap -= 0xffff0000;
+			if (overlap > 0)
+				hose->sg_pci->size -= overlap;
+		}
 	}
 }
 
@@ -121,8 +120,7 @@
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M5229,
 	  quirk_ali_ide_ports },
 	{ PCI_FIXUP_HEADER, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C693,
-	  quirk_cypress_ide_ports },
-	{ PCI_FIXUP_FINAL, PCI_ANY_ID, PCI_ANY_ID, quirk_vga_enable_rom },
+	  quirk_cypress },
 	{ 0 }
 };
 
@@ -148,10 +146,8 @@
 		/*
 		 * Put everything into 0x00-0xff region modulo 0x400
 		 */
-		if (start & 0x300) {
+		if (start & 0x300)
 			start = (start + 0x3ff) & ~0x3ff;
-			res->start = start;
-		}
 	}
 	else if	(res->flags & IORESOURCE_MEM) {
 		/* Make sure we start at our min on all hoses */
@@ -177,13 +173,13 @@
 		/* Align to multiple of size of minimum base.  */
 		alignto = MAX(0x1000, size);
 		start = ALIGN(start, alignto);
-		if (size <= 7 * 16*MB) {
+		if (hose->sparse_mem_base && size <= 7 * 16*MB) {
 			if (((start / (16*MB)) & 0x7) == 0) {
 				start &= ~(128*MB - 1);
 				start += 16*MB;
 				start  = ALIGN(start, alignto);
 			}
-			if (start/(128*MB) != (start + size)/(128*MB)) {
+			if (start/(128*MB) != (start + size - 1)/(128*MB)) {
 				start &= ~(128*MB - 1);
 				start += (128 + 16)*MB;
 				start  = ALIGN(start, alignto);
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/pci_impl.h linux/arch/alpha/kernel/pci_impl.h
--- linux-2.4.10-pre8/arch/alpha/kernel/pci_impl.h	Fri May 25 09:54:50 2001
+++ linux/arch/alpha/kernel/pci_impl.h	Mon Dec  3 23:09:47 2001
@@ -49,7 +49,7 @@
  * APECS and LCA have only 34 bits for physical addresses, thus limiting PCI
  * bus memory addresses for SPARSE access to be less than 128Mb.
  */
-#define APECS_AND_LCA_DEFAULT_MEM_BASE ((32+2)*1024*1024)
+#define APECS_AND_LCA_DEFAULT_MEM_BASE ((16+2)*1024*1024)
 
 /*
  * Because the MCPCIA core logic supports more bits for physical addresses,
@@ -136,6 +136,7 @@
 	spinlock_t lock;
 	struct pci_controller *hose;
 #define IOMMU_INVALID_PTE 0x2 /* 32:63 bits MBZ */
+#define IOMMU_RESERVED_PTE 0xface
 	unsigned long *ptes;
 	dma_addr_t dma_base;
 	unsigned int size;
@@ -161,3 +162,10 @@
 extern const char *const pci_io_names[];
 extern const char *const pci_mem_names[];
 extern const char pci_hae0_name[];
+
+extern int iommu_reserve(struct pci_iommu_arena *, long, long);
+extern int iommu_release(struct pci_iommu_arena *, long, long);
+extern int iommu_bind(struct pci_iommu_arena *, long, long, unsigned long *);
+extern int iommu_unbind(struct pci_iommu_arena *, long, long);
+
+
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/pci_iommu.c linux/arch/alpha/kernel/pci_iommu.c
--- linux-2.4.10-pre8/arch/alpha/kernel/pci_iommu.c	Sun Aug 12 10:51:41 2001
+++ linux/arch/alpha/kernel/pci_iommu.c	Mon Dec  3 23:09:47 2001
@@ -42,24 +42,6 @@
 	return (bytes + PAGE_SIZE - 1) >> PAGE_SHIFT;
 }
 
-static void __init
-iommu_arena_fixup(struct pci_iommu_arena * arena)
-{
-	unsigned long base, size;
-
-	/*
-	 * The Cypress chip has a quirk, it get confused by addresses
-	 * above -1M so reserve the pagetables that maps pci addresses
-	 * above -1M.
-	 */
-	base = arena->dma_base;
-	size = arena->size;
-	if (base + size > 0xfff00000) {
-		int i, fixup_start = (0xfff00000 - base) >> PAGE_SHIFT;
-		for (i= 0; i < (0x100000 >> PAGE_SHIFT); i++)
-			arena->ptes[fixup_start+i] = IOMMU_INVALID_PTE;
-	}
-}
 
 struct pci_iommu_arena *
 iommu_arena_new(struct pci_controller *hose, dma_addr_t base,
@@ -90,24 +72,19 @@
 	   unless there are chip bugs.  */
 	arena->align_entry = 1;
 
-	iommu_arena_fixup(arena);
-
 	return arena;
 }
 
-long
-iommu_arena_alloc(struct pci_iommu_arena *arena, long n)
+/* Must be called with the arena lock held */
+static long
+iommu_arena_find_pages(struct pci_iommu_arena *arena, long n, long mask)
 {
-	unsigned long flags;
 	unsigned long *ptes;
-	long i, p, nent, mask;
+	long i, p, nent;
 
-	spin_lock_irqsave(&arena->lock, flags);
-
-	/* Search forward for the first sequence of N empty ptes.  */
+	/* Search forward for the first mask-aligned sequence of N free ptes */
 	ptes = arena->ptes;
 	nent = arena->size >> PAGE_SHIFT;
-	mask = arena->align_entry - 1;
 	p = (arena->next_entry + mask) & ~mask;
 	i = 0;
 	while (i < n && p+i < nent) {
@@ -130,10 +107,31 @@
 				i = i + 1;
 		}
 
-		if (i < n) {
-			spin_unlock_irqrestore(&arena->lock, flags);
+		if (i < n)
 			return -1;
-		}
+	}
+
+	/* Success. It's the responsibility of the caller to mark them
+	   in use before releasing the lock */
+	return p;
+}
+
+long
+iommu_arena_alloc(struct pci_iommu_arena *arena, long n)
+{
+	unsigned long flags;
+	unsigned long *ptes;
+	long i, p, mask;
+
+	spin_lock_irqsave(&arena->lock, flags);
+
+	/* Search for N empty ptes */
+	ptes = arena->ptes;
+	mask = arena->align_entry - 1;
+	p = iommu_arena_find_pages(arena, n, mask);
+	if (p < 0) {
+		spin_unlock_irqrestore(&arena->lock, flags);
+		return -1;
 	}
 
 	/* Success.  Mark them all in use, ie not zero and invalid
@@ -660,6 +658,104 @@
 	arena = hose->sg_pci;
 	if (arena && arena->dma_base + arena->size - 1 <= mask)
 		return 1;
+
+	return 0;
+}
+
+
+/*
+ * AGP GART extensions to the IOMMU
+ */
+int
+iommu_reserve(struct pci_iommu_arena *arena, long pg_count, long align_mask) 
+{
+	unsigned long flags;
+	unsigned long *ptes;
+	long i, p;
+
+	if (!arena) return -EINVAL;
+
+	spin_lock_irqsave(&arena->lock, flags);
+
+	/* Search for N empty ptes.  */
+	ptes = arena->ptes;
+	p = iommu_arena_find_pages(arena, pg_count, align_mask);
+	if (p < 0) {
+		spin_unlock_irqrestore(&arena->lock, flags);
+		return -1;
+	}
+
+	/* Success.  Mark them all reserved (ie not zero and invalid)
+	   for the iommu tlb that could load them from under us.
+	   They will be filled in with valid bits by _bind() */
+	for (i = 0; i < pg_count; ++i)
+		ptes[p+i] = IOMMU_RESERVED_PTE;
+
+	arena->next_entry = p + pg_count;
+	spin_unlock_irqrestore(&arena->lock, flags);
+
+	return p;
+}
+
+int 
+iommu_release(struct pci_iommu_arena *arena, long pg_start, long pg_count)
+{
+	unsigned long *ptes;
+	long i;
+
+	if (!arena) return -EINVAL;
+
+	ptes = arena->ptes;
+
+	/* Make sure they're all reserved first... */
+	for(i = pg_start; i < pg_start + pg_count; i++)
+		if (ptes[i] != IOMMU_RESERVED_PTE)
+			return -EBUSY;
+
+	iommu_arena_free(arena, pg_start, pg_count);
+	return 0;
+}
+
+int
+iommu_bind(struct pci_iommu_arena *arena, long pg_start, long pg_count, 
+	   unsigned long *physaddrs)
+{
+	unsigned long flags;
+	unsigned long *ptes;
+	long i, j;
+
+	if (!arena) return -EINVAL;
+	
+	spin_lock_irqsave(&arena->lock, flags);
+
+	ptes = arena->ptes;
+
+	for(j = pg_start; j < pg_start + pg_count; j++) {
+		if (ptes[j] != IOMMU_RESERVED_PTE) {
+			spin_unlock_irqrestore(&arena->lock, flags);
+			return -EBUSY;
+		}
+	}
+		
+	for(i = 0, j = pg_start; i < pg_count; i++, j++)
+		ptes[j] = mk_iommu_pte(physaddrs[i]);
+
+	spin_unlock_irqrestore(&arena->lock, flags);
+
+	return 0;
+}
+
+int
+iommu_unbind(struct pci_iommu_arena *arena, long pg_start, long pg_count)
+{
+	unsigned long *p;
+	long i;
+
+	if (!arena) return -EINVAL;
+
+	p = arena->ptes + pg_start;
+	for(i = 0; i < pg_count; i++)
+		p[i] = IOMMU_RESERVED_PTE;
 
 	return 0;
 }
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/smp.c linux/arch/alpha/kernel/smp.c
--- linux-2.4.10-pre8/arch/alpha/kernel/smp.c	Sun Aug 12 10:51:41 2001
+++ linux/arch/alpha/kernel/smp.c	Mon Dec  3 23:09:47 2001
@@ -1,5 +1,13 @@
 /*
  *	linux/arch/alpha/kernel/smp.c
+ *
+ *      2001-07-09 Phil Ezolt (Phillip.Ezolt@compaq.com)
+ *            Renamed modified smp_call_function to smp_call_function_on_cpu()
+ *            Created an function that conforms to the old calling convention
+ *            of smp_call_function().
+ *
+ *            This is helpful for DCPI.
+ *
  */
 
 #include <linux/errno.h>
@@ -867,23 +875,31 @@
  */
 
 int
-smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
+smp_call_function_on_cpu (void (*func) (void *info), void *info, int retry,
+			  int wait, unsigned long to_whom)
 {
-	unsigned long to_whom = cpu_present_mask ^ (1UL << smp_processor_id());
 	struct smp_call_struct data;
 	long timeout;
+	int num_cpus_to_call;
+	long i,j;
 	
 	data.func = func;
 	data.info = info;
 	data.wait = wait;
-	atomic_set(&data.unstarted_count, smp_num_cpus - 1);
-	atomic_set(&data.unfinished_count, smp_num_cpus - 1);
+
+	to_whom &= ~(1L << smp_processor_id());
+	for (i = 0, j = 1, num_cpus_to_call = 0; i < NR_CPUS; ++i, j <<= 1)
+		if (to_whom & j)
+			num_cpus_to_call++;
+
+	atomic_set(&data.unstarted_count, num_cpus_to_call);
+	atomic_set(&data.unfinished_count, num_cpus_to_call);
 
 	/* Acquire the smp_call_function_data mutex.  */
 	if (pointer_lock(&smp_call_function_data, &data, retry))
 		return -EBUSY;
 
-	/* Send a message to all other CPUs.  */
+	/* Send a message to the requested CPUs.  */
 	send_ipi_message(to_whom, IPI_CALL_FUNC);
 
 	/* Wait for a minimal response.  */
@@ -905,6 +921,13 @@
 	}
 
 	return 0;
+}
+
+int
+smp_call_function (void (*func) (void *info), void *info, int retry, int wait)
+{
+	return smp_call_function_on_cpu (func, info, retry, wait,
+					 cpu_present_mask);
 }
 
 static void
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/sys_jensen.c linux/arch/alpha/kernel/sys_jensen.c
--- linux-2.4.10-pre8/arch/alpha/kernel/sys_jensen.c	Fri Mar  2 11:12:07 2001
+++ linux/arch/alpha/kernel/sys_jensen.c	Mon Dec  3 23:09:47 2001
@@ -35,14 +35,16 @@
 
 /*
  * Jensen is special: the vector is 0x8X0 for EISA interrupt X, and
- * 0x9X0 for the local motherboard interrupts..
+ * 0x9X0 for the local motherboard interrupts.
+ *
+ * Note especially that those local interrupts CANNOT be masked,
+ * which causes much of the pain below...
  *
  *	0x660 - NMI
  *
  *	0x800 - IRQ0  interval timer (not used, as we use the RTC timer)
  *	0x810 - IRQ1  line printer (duh..)
  *	0x860 - IRQ6  floppy disk
- *	0x8E0 - IRQ14 SCSI controller
  *
  *	0x900 - COM1
  *	0x920 - COM2
@@ -52,27 +54,77 @@
  * PCI-based systems are more sane: they don't have the local
  * interrupts at all, and have only normal PCI interrupts from
  * devices.  Happily it's easy enough to do a sane mapping from the
- * Jensen..  Note that this means that we may have to do a hardware
- * "ack" to a different interrupt than we report to the rest of the
+ * Jensen.
+ * 
+ * Note that this means that we may have to do a hardware
+ * "local_op" to a different interrupt than we report to the rest of the
  * world.
  */
 
+static unsigned int
+jensen_local_startup(unsigned int irq)
+{
+	/* the parport is really hw IRQ 1, silly Jensen.  */
+	if (irq == 7)
+		i8259a_startup_irq(1);
+	else
+		/*
+		 * For all true local interrupts, set the flag that prevents
+		 * the IPL from being dropped during handler processing.
+		 */
+		if (irq_desc[irq].action)
+			irq_desc[irq].action->flags |= SA_INTERRUPT;
+	return 0;
+}
+
+static void
+jensen_local_shutdown(unsigned int irq)
+{
+	/* the parport is really hw IRQ 1, silly Jensen.  */
+	if (irq == 7)
+		i8259a_disable_irq(1);
+}
+
+static void
+jensen_local_enable(unsigned int irq)
+{
+	/* the parport is really hw IRQ 1, silly Jensen.  */
+	if (irq == 7)
+		i8259a_enable_irq(1);
+}
+
+static void
+jensen_local_disable(unsigned int irq)
+{
+	/* the parport is really hw IRQ 1, silly Jensen.  */
+	if (irq == 7)
+		i8259a_disable_irq(1);
+}
+
 static void
 jensen_local_ack(unsigned int irq)
 {
-	/* irq1 is supposed to be the keyboard, silly Jensen.  */
+	/* the parport is really hw IRQ 1, silly Jensen.  */
 	if (irq == 7)
 		i8259a_mask_and_ack_irq(1);
 }
 
+static void
+jensen_local_end(unsigned int irq)
+{
+	/* the parport is really hw IRQ 1, silly Jensen.  */
+	if (irq == 7)
+		i8259a_end_irq(1);
+}
+
 static struct hw_interrupt_type jensen_local_irq_type = {
 	typename:	"LOCAL",
-	startup:	i8259a_startup_irq,
-	shutdown:	i8259a_disable_irq,
-	enable:		i8259a_enable_irq,
-	disable:	i8259a_disable_irq,
+	startup:	jensen_local_startup,
+	shutdown:	jensen_local_shutdown,
+	enable:		jensen_local_enable,
+	disable:	jensen_local_disable,
 	ack:		jensen_local_ack,
-	end:		i8259a_end_irq,
+	end:		jensen_local_end,
 };
 
 static void 
@@ -104,6 +156,47 @@
 		break;
 	}
 
+	/* If there is no handler yet... */
+	if (irq_desc[irq].action == NULL) {
+	    /* If it is a local interrupt that cannot be masked... */
+	    if (vector >= 0x900)
+	    {
+	        /* Clear keyboard/mouse state */
+	    	inb(0x64);
+		inb(0x60);
+		/* Reset serial ports */
+		inb(0x3fa);
+		inb(0x2fa);
+		outb(0x0c, 0x3fc);
+		outb(0x0c, 0x2fc);
+		/* Clear NMI */
+		outb(0,0x61);
+		outb(0,0x461);
+	    }
+	}
+
+#if 0
+        /* A useful bit of code to find out if an interrupt is going wild.  */
+        {
+          static unsigned int last_msg = 0, last_cc = 0;
+          static int last_irq = -1, count = 0;
+          unsigned int cc;
+
+          __asm __volatile("rpcc %0" : "=r"(cc));
+          ++count;
+#define JENSEN_CYCLES_PER_SEC	(150000000)
+          if (cc - last_msg > ((JENSEN_CYCLES_PER_SEC) * 3) ||
+	      irq != last_irq) {
+                printk(KERN_CRIT " irq %d count %d cc %u @ %lx\n",
+                       irq, count, cc-last_cc, regs->pc);
+                count = 0;
+                last_msg = cc;
+                last_irq = irq;
+          }
+          last_cc = cc;
+        }
+#endif
+
 	handle_irq(irq, regs);
 }
 
@@ -164,7 +257,7 @@
 	BUS(jensen),
 	machine_check:		jensen_machine_check,
 	max_dma_address:	ALPHA_MAX_DMA_ADDRESS,
-	rtc_port: 0x170,
+	rtc_port:		0x170,
 
 	nr_irqs:		16,
 	device_interrupt:	jensen_device_interrupt,
diff -urN linux-2.4.10-pre8/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c
--- linux-2.4.10-pre8/arch/alpha/kernel/traps.c	Sun Aug 12 10:35:37 2001
+++ linux/arch/alpha/kernel/traps.c	Mon Dec  3 23:09:47 2001
@@ -19,9 +19,37 @@
 #include <asm/uaccess.h>
 #include <asm/unaligned.h>
 #include <asm/sysinfo.h>
+#include <asm/hwrpb.h>
 
 #include "proto.h"
 
+/* data/code implementing a work-around for some SRMs which
+   mishandle opDEC faults
+*/
+static int opDEC_testing = 0;
+static int opDEC_fix = 0;
+static unsigned long opDEC_test_pc = 0;
+
+static void
+opDEC_check(void)
+{
+	unsigned long test_pc;
+
+	lock_kernel();
+	opDEC_testing = 1;
+
+	__asm__ __volatile__(
+		"       br      %0,1f\n"
+		"1:     addq    %0,8,%0\n"
+		"       stq     %0,%1\n"
+		"       cvttq/svm $f31,$f31\n"
+		: "=&r"(test_pc), "=m"(opDEC_test_pc)
+		: );
+
+	opDEC_testing = 0;
+	unlock_kernel();
+}
+
 void
 dik_show_regs(struct pt_regs *regs, unsigned long *r9_15)
 {
@@ -56,10 +84,12 @@
 #endif
 }
 
+#if 0
 static char * ireg_name[] = {"v0", "t0", "t1", "t2", "t3", "t4", "t5", "t6",
 			   "t7", "s0", "s1", "s2", "s3", "s4", "s5", "s6",
 			   "a0", "a1", "a2", "a3", "a4", "a5", "t8", "t9",
 			   "t10", "t11", "ra", "pv", "at", "gp", "sp", "zero"};
+#endif
 
 static void
 dik_show_code(unsigned int *pc)
@@ -188,8 +218,10 @@
 	 unsigned long a2, unsigned long a3, unsigned long a4,
 	 unsigned long a5, struct pt_regs regs)
 {
-	die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
+	if (!opDEC_testing || type != 4) {
+		die_if_kernel((type == 1 ? "Kernel Bug" : "Instruction fault"),
 		      &regs, type, 0);
+	}
 
 	switch (type) {
 	      case 0: /* breakpoint */
@@ -242,6 +274,21 @@
 
 	      case 4: /* opDEC */
 		if (implver() == IMPLVER_EV4) {
+			/* The some versions of SRM do not handle
+			   the opDEC properly - they return the PC of the
+			   opDEC fault, not the instruction after as the
+			   Alpha architecture requires.  Here we fix it up.
+			   We do this by intentionally causing an opDEC
+			   fault during the boot sequence and testing if
+			   we get the correct PC.  If not, we set a flag
+			   to correct it every time through.
+			*/
+			if (opDEC_testing && regs.pc == opDEC_test_pc) {
+				opDEC_fix = 4;
+				printk("opDEC fixup enabled.\n");
+			}
+			regs.pc += opDEC_fix; 
+			
 			/* EV4 does not implement anything except normal
 			   rounding.  Everything else will come here as
 			   an illegal instruction.  Emulate them.  */
@@ -257,7 +304,7 @@
 }
 
 /* There is an ifdef in the PALcode in MILO that enables a 
-   "kernel debugging entry point" as an unprivilaged call_pal.
+   "kernel debugging entry point" as an unpriviledged call_pal.
 
    We don't want to have anything to do with it, but unfortunately
    several versions of MILO included in distributions have it enabled,
@@ -933,4 +980,11 @@
 	wrent(entUna, 4);
 	wrent(entSys, 5);
 	wrent(entDbg, 6);
+
+	/* Hack for Multia (UDB) and JENSEN: some of their SRMs have
+	 * a bug in the handling of the opDEC fault.  Fix it up if so.
+	 */
+	if (implver() == IMPLVER_EV4) {
+		opDEC_check();
+	}
 }
diff -urN linux-2.4.10-pre8/arch/i386/boot/compressed/Makefile linux/arch/i386/boot/compressed/Makefile
--- linux-2.4.10-pre8/arch/i386/boot/compressed/Makefile	Tue Mar  7 11:04:12 2000
+++ linux/arch/i386/boot/compressed/Makefile	Mon Dec  3 23:09:47 2001
@@ -9,7 +9,6 @@
 
 OBJECTS = $(HEAD) misc.o
 
-CFLAGS = $(CPPFLAGS) -O2 -DSTDC_HEADERS
 ZLDFLAGS = -e startup_32
 
 #
diff -urN linux-2.4.10-pre8/arch/i386/boot/compressed/misc.c linux/arch/i386/boot/compressed/misc.c
--- linux-2.4.10-pre8/arch/i386/boot/compressed/misc.c	Tue Feb 13 13:15:04 2001
+++ linux/arch/i386/boot/compressed/misc.c	Mon Dec  3 23:09:47 2001
@@ -12,6 +12,7 @@
 #include <linux/vmalloc.h>
 #include <linux/tty.h>
 #include <asm/io.h>
+
 /*
  * gzip declarations
  */
@@ -21,6 +22,14 @@
 
 #undef memset
 #undef memcpy
+
+/*
+ * Why do we do this? Don't ask me..
+ *
+ * Incomprehensible are the ways of bootloaders.
+ */
+static void* memset(void *, int, size_t);
+static void* memcpy(void *, __const void *, size_t);
 #define memzero(s, n)     memset ((s), 0, (n))
 
 typedef unsigned char  uch;
@@ -194,7 +203,7 @@
 	outb_p(0xff & (pos >> 1), vidport+1);
 }
 
-void* memset(void* s, int c, size_t n)
+static void* memset(void* s, int c, size_t n)
 {
 	int i;
 	char *ss = (char*)s;
@@ -203,7 +212,7 @@
 	return s;
 }
 
-void* memcpy(void* __dest, __const void* __src,
+static void* memcpy(void* __dest, __const void* __src,
 			    size_t __n)
 {
 	int i;
diff -urN linux-2.4.10-pre8/arch/i386/defconfig linux/arch/i386/defconfig
--- linux-2.4.10-pre8/arch/i386/defconfig	Mon Dec  3 23:09:37 2001
+++ linux/arch/i386/defconfig	Mon Dec  3 23:09:47 2001
@@ -498,6 +498,10 @@
 # Input core support
 #
 # CONFIG_INPUT is not set
+# CONFIG_INPUT_KEYBDEV is not set
+# CONFIG_INPUT_MOUSEDEV is not set
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
 
 #
 # Character devices
@@ -528,7 +532,11 @@
 #
 # Joysticks
 #
-# CONFIG_JOYSTICK is not set
+# CONFIG_INPUT_GAMEPORT is not set
+
+#
+# Input core support is needed for gameports
+#
 
 #
 # Input core support is needed for joysticks
diff -urN linux-2.4.10-pre8/arch/m68k/amiga/config.c linux/arch/m68k/amiga/config.c
--- linux-2.4.10-pre8/arch/m68k/amiga/config.c	Mon Jun 11 19:15:27 2001
+++ linux/arch/m68k/amiga/config.c	Mon Dec  3 23:09:47 2001
@@ -44,22 +44,22 @@
 unsigned char amiga_psfreq;
 struct amiga_hw_present amiga_hw_present;
 
-static const char s_a500[] __initdata = "A500";
-static const char s_a500p[] __initdata = "A500+";
-static const char s_a600[] __initdata = "A600";
-static const char s_a1000[] __initdata = "A1000";
-static const char s_a1200[] __initdata = "A1200";
-static const char s_a2000[] __initdata = "A2000";
-static const char s_a2500[] __initdata = "A2500";
-static const char s_a3000[] __initdata = "A3000";
-static const char s_a3000t[] __initdata = "A3000T";
-static const char s_a3000p[] __initdata = "A3000+";
-static const char s_a4000[] __initdata = "A4000";
-static const char s_a4000t[] __initdata = "A4000T";
-static const char s_cdtv[] __initdata = "CDTV";
-static const char s_cd32[] __initdata = "CD32";
-static const char s_draco[] __initdata = "Draco";
-static const char *amiga_models[] __initdata = {
+static char s_a500[] __initdata = "A500";
+static char s_a500p[] __initdata = "A500+";
+static char s_a600[] __initdata = "A600";
+static char s_a1000[] __initdata = "A1000";
+static char s_a1200[] __initdata = "A1200";
+static char s_a2000[] __initdata = "A2000";
+static char s_a2500[] __initdata = "A2500";
+static char s_a3000[] __initdata = "A3000";
+static char s_a3000t[] __initdata = "A3000T";
+static char s_a3000p[] __initdata = "A3000+";
+static char s_a4000[] __initdata = "A4000";
+static char s_a4000t[] __initdata = "A4000T";
+static char s_cdtv[] __initdata = "CDTV";
+static char s_cd32[] __initdata = "CD32";
+static char s_draco[] __initdata = "Draco";
+static char *amiga_models[] __initdata = {
     s_a500, s_a500p, s_a600, s_a1000, s_a1200, s_a2000, s_a2500, s_a3000,
     s_a3000t, s_a3000p, s_a4000, s_a4000t, s_cdtv, s_cd32, s_draco,
 };
diff -urN linux-2.4.10-pre8/arch/sparc64/solaris/fs.c linux/arch/sparc64/solaris/fs.c
--- linux-2.4.10-pre8/arch/sparc64/solaris/fs.c	Sun Feb 18 19:49:54 2001
+++ linux/arch/sparc64/solaris/fs.c	Mon Dec  3 23:09:47 2001
@@ -406,21 +406,21 @@
 	u32	f_filler[16];
 };
 
-static int report_statvfs(struct inode *inode, u32 buf)
+static int report_statvfs(struct vfsmount *mnt, struct inode *inode, u32 buf)
 {
 	struct statfs s;
 	int error;
 	struct sol_statvfs *ss = (struct sol_statvfs *)A(buf);
 
-	error = vfs_statfs(inode->i_sb, &s);
+	error = vfs_statfs(mnt->mnt_sb, &s);
 	if (!error) {
-		const char *p = inode->i_sb->s_type->name;
+		const char *p = mnt->mnt_sb->s_type->name;
 		int i = 0;
 		int j = strlen (p);
 		
 		if (j > 15) j = 15;
 		if (IS_RDONLY(inode)) i = 1;
-		if (IS_NOSUID(inode)) i |= 2;
+		if (mnt->mnt_flags & MNT_NOSUID) i |= 2;
 		if (put_user (s.f_bsize, &ss->f_bsize)		||
 		    __put_user (0, &ss->f_frsize)		||
 		    __put_user (s.f_blocks, &ss->f_blocks)	||
@@ -440,21 +440,21 @@
 	return error;
 }
 
-static int report_statvfs64(struct inode *inode, u32 buf)
+static int report_statvfs64(struct vfsmount *mnt, struct inode *inode, u32 buf)
 {
 	struct statfs s;
 	int error;
 	struct sol_statvfs64 *ss = (struct sol_statvfs64 *)A(buf);
 			
-	error = vfs_statfs(inode->i_sb, &s);
+	error = vfs_statfs(mnt->mnt_sb, &s);
 	if (!error) {
-		const char *p = inode->i_sb->s_type->name;
+		const char *p = mnt->mnt_sb->s_type->name;
 		int i = 0;
 		int j = strlen (p);
 		
 		if (j > 15) j = 15;
 		if (IS_RDONLY(inode)) i = 1;
-		if (IS_NOSUID(inode)) i |= 2;
+		if (mnt->mnt_flags & MNT_NOSUID) i |= 2;
 		if (put_user (s.f_bsize, &ss->f_bsize)		||
 		    __put_user (0, &ss->f_frsize)		||
 		    __put_user (s.f_blocks, &ss->f_blocks)	||
@@ -482,7 +482,7 @@
 	error = user_path_walk((const char *)A(path),&nd);
 	if (!error) {
 		struct inode * inode = nd.dentry->d_inode;
-		error = report_statvfs(inode, buf);
+		error = report_statvfs(nd.mnt, inode, buf);
 		path_release(&nd);
 	}
 	return error;
@@ -496,7 +496,7 @@
 	error = -EBADF;
 	file = fget(fd);
 	if (file) {
-		error = report_statvfs(file->f_dentry->d_inode, buf);
+		error = report_statvfs(file->f_vfsmnt, file->f_dentry->d_inode, buf);
 		fput(file);
 	}
 
@@ -512,7 +512,7 @@
 	error = user_path_walk((const char *)A(path), &nd);
 	if (!error) {
 		struct inode * inode = nd.dentry->d_inode;
-		error = report_statvfs64(inode, buf);
+		error = report_statvfs64(nd.mnt, inode, buf);
 		path_release(&nd);
 	}
 	unlock_kernel();
@@ -528,7 +528,7 @@
 	file = fget(fd);
 	if (file) {
 		lock_kernel();
-		error = report_statvfs64(file->f_dentry->d_inode, buf);
+		error = report_statvfs64(file->f_vfsmnt, file->f_dentry->d_inode, buf);
 		unlock_kernel();
 		fput(file);
 	}
diff -urN linux-2.4.10-pre8/drivers/acorn/block/mfmhd.c linux/drivers/acorn/block/mfmhd.c
--- linux-2.4.10-pre8/drivers/acorn/block/mfmhd.c	Mon Dec  3 23:09:37 2001
+++ linux/drivers/acorn/block/mfmhd.c	Mon Dec  3 23:09:47 2001
@@ -1498,6 +1498,10 @@
 }
 
 #ifdef MODULE
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	return mfm_init();
diff -urN linux-2.4.10-pre8/drivers/acorn/char/serial-card.c linux/drivers/acorn/char/serial-card.c
--- linux-2.4.10-pre8/drivers/acorn/char/serial-card.c	Mon Sep 18 15:15:22 2000
+++ linux/drivers/acorn/char/serial-card.c	Mon Dec  3 23:09:47 2001
@@ -126,5 +126,7 @@
 
 EXPORT_NO_SYMBOLS;
 
+MODULE_LICENSE("GPL");
+
 module_init(INIT);
 module_exit(EXIT);
diff -urN linux-2.4.10-pre8/drivers/acorn/net/ether1.c linux/drivers/acorn/net/ether1.c
--- linux-2.4.10-pre8/drivers/acorn/net/ether1.c	Wed Jun 27 14:12:04 2001
+++ linux/drivers/acorn/net/ether1.c	Mon Dec  3 23:09:47 2001
@@ -1102,3 +1102,5 @@
 
 module_init(ether1_init);
 module_exit(ether1_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/acorn/net/ether3.c linux/drivers/acorn/net/ether3.c
--- linux-2.4.10-pre8/drivers/acorn/net/ether3.c	Wed Jun 27 14:12:04 2001
+++ linux/drivers/acorn/net/ether3.c	Mon Dec  3 23:09:47 2001
@@ -938,3 +938,5 @@
 
 module_init(ether3_init);
 module_exit(ether3_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/acorn/net/etherh.c linux/drivers/acorn/net/etherh.c
--- linux-2.4.10-pre8/drivers/acorn/net/etherh.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/acorn/net/etherh.c	Mon Dec  3 23:09:47 2001
@@ -67,6 +67,7 @@
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("EtherH/EtherM driver");
+MODULE_LICENSE("GPL");
 
 static char version[] __initdata =
 	"EtherH/EtherM Driver (c) 2000 Russell King v1.08\n";
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/acornscsi.c linux/drivers/acorn/scsi/acornscsi.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/acornscsi.c	Mon Dec  3 23:09:37 2001
+++ linux/drivers/acorn/scsi/acornscsi.c	Mon Dec  3 23:09:47 2001
@@ -3158,3 +3158,6 @@
 
 module_init(acornscsi_init);
 module_exit(acornscsi_exit);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/arxescsi.c linux/drivers/acorn/scsi/arxescsi.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/arxescsi.c	Thu Feb  8 16:32:44 2001
+++ linux/drivers/acorn/scsi/arxescsi.c	Mon Dec  3 23:09:47 2001
@@ -439,3 +439,4 @@
 module_init(init_arxe_scsi_driver);
 module_exit(exit_arxe_scsi_driver);
 
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/cumana_1.c linux/drivers/acorn/scsi/cumana_1.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/cumana_1.c	Thu Feb  8 16:32:44 2001
+++ linux/drivers/acorn/scsi/cumana_1.c	Mon Dec  3 23:09:47 2001
@@ -424,3 +424,6 @@
 
 module_init(cumanascsi_init);
 module_exit(cumanascsi_exit);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/cumana_2.c linux/drivers/acorn/scsi/cumana_2.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/cumana_2.c	Fri Mar  2 18:38:37 2001
+++ linux/drivers/acorn/scsi/cumana_2.c	Mon Dec  3 23:09:47 2001
@@ -86,6 +86,7 @@
 MODULE_DESCRIPTION("Cumana SCSI II driver");
 MODULE_PARM(term, "1-8i");
 MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
 
 /*
  * Use term=0,1,0,0,0 to turn terminators on/off
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/ecoscsi.c linux/drivers/acorn/scsi/ecoscsi.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/ecoscsi.c	Thu Feb  8 16:32:44 2001
+++ linux/drivers/acorn/scsi/ecoscsi.c	Mon Dec  3 23:09:47 2001
@@ -292,3 +292,6 @@
 
 module_init(ecoscsi_init);
 module_exit(ecoscsi_exit);
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/eesox.c linux/drivers/acorn/scsi/eesox.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/eesox.c	Fri Mar  2 18:38:37 2001
+++ linux/drivers/acorn/scsi/eesox.c	Mon Dec  3 23:09:47 2001
@@ -602,3 +602,5 @@
 module_init(eesox_init);
 module_exit(eesox_exit);
 
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/fas216.c linux/drivers/acorn/scsi/fas216.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/fas216.c	Thu Feb  8 16:32:44 2001
+++ linux/drivers/acorn/scsi/fas216.c	Mon Dec  3 23:09:47 2001
@@ -2777,3 +2777,5 @@
 {
 }
 #endif
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/msgqueue.c linux/drivers/acorn/scsi/msgqueue.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/msgqueue.c	Thu Feb  8 16:32:44 2001
+++ linux/drivers/acorn/scsi/msgqueue.c	Mon Dec  3 23:09:47 2001
@@ -18,6 +18,7 @@
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("SCSI message queue handling");
+MODULE_LICENSE("GPL");
 
 /*
  * Function: struct msgqueue_entry *mqe_alloc(MsgQueue_t *msgq)
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/oak.c linux/drivers/acorn/scsi/oak.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/oak.c	Thu Feb  8 16:32:44 2001
+++ linux/drivers/acorn/scsi/oak.c	Mon Dec  3 23:09:47 2001
@@ -285,3 +285,6 @@
 
 module_init(oakscsi_init);
 module_exit(oakscsi_exit);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/powertec.c linux/drivers/acorn/scsi/powertec.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/powertec.c	Fri Mar  2 18:38:37 2001
+++ linux/drivers/acorn/scsi/powertec.c	Mon Dec  3 23:09:47 2001
@@ -81,6 +81,7 @@
 MODULE_DESCRIPTION("Powertec SCSI driver");
 MODULE_PARM(term, "1-8i");
 MODULE_PARM_DESC(term, "SCSI bus termination");
+MODULE_LICENSE("GPL");
 
 static struct expansion_card *ecs[MAX_ECARDS];
 
diff -urN linux-2.4.10-pre8/drivers/acorn/scsi/queue.c linux/drivers/acorn/scsi/queue.c
--- linux-2.4.10-pre8/drivers/acorn/scsi/queue.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/acorn/scsi/queue.c	Mon Dec  3 23:09:47 2001
@@ -27,6 +27,7 @@
 
 MODULE_AUTHOR("Russell King");
 MODULE_DESCRIPTION("SCSI command queueing");
+MODULE_LICENSE("GPL");
 
 #define DEBUG
 
diff -urN linux-2.4.10-pre8/drivers/acpi/os.c linux/drivers/acpi/os.c
--- linux-2.4.10-pre8/drivers/acpi/os.c	Sun Jun 24 20:53:07 2001
+++ linux/drivers/acpi/os.c	Mon Dec  3 23:09:47 2001
@@ -156,7 +156,14 @@
 	}
 
 	if ((unsigned long) phys < virt_to_phys(high_memory)) {
+		struct page *page;
 		*virt = phys_to_virt((unsigned long) phys);
+	
+		/* Check for stamping */
+		page = virt_to_page(*virt);
+		if(page && !test_bit(PG_reserved, &page->flags))
+			printk(KERN_WARNING "ACPI attempting to access kernel owned memory at %08lX.\n", (unsigned long)phys);
+
 		return AE_OK;
 	}
 
diff -urN linux-2.4.10-pre8/drivers/acpi/ospm/ac_adapter/ac_osl.c linux/drivers/acpi/ospm/ac_adapter/ac_osl.c
--- linux-2.4.10-pre8/drivers/acpi/ospm/ac_adapter/ac_osl.c	Wed Jun 20 17:47:40 2001
+++ linux/drivers/acpi/ospm/ac_adapter/ac_osl.c	Mon Dec  3 23:09:47 2001
@@ -35,6 +35,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - AC Adapter Driver");
+MODULE_LICENSE("GPL");
 
 
 #define AC_PROC_ROOT		"ac_adapter"
diff -urN linux-2.4.10-pre8/drivers/acpi/ospm/battery/bt_osl.c linux/drivers/acpi/ospm/battery/bt_osl.c
--- linux-2.4.10-pre8/drivers/acpi/ospm/battery/bt_osl.c	Wed Jun 20 17:47:40 2001
+++ linux/drivers/acpi/ospm/battery/bt_osl.c	Mon Dec  3 23:09:47 2001
@@ -44,6 +44,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Control Method Battery Driver");
+MODULE_LICENSE("GPL");
 
 
 #define BT_PROC_ROOT		"battery"
diff -urN linux-2.4.10-pre8/drivers/acpi/ospm/busmgr/bm_osl.c linux/drivers/acpi/ospm/busmgr/bm_osl.c
--- linux-2.4.10-pre8/drivers/acpi/ospm/busmgr/bm_osl.c	Wed Jun 20 17:47:40 2001
+++ linux/drivers/acpi/ospm/busmgr/bm_osl.c	Mon Dec  3 23:09:47 2001
@@ -37,6 +37,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI Bus Manager");
+MODULE_LICENSE("GPL");
 
 
 #ifdef ACPI_DEBUG
diff -urN linux-2.4.10-pre8/drivers/acpi/ospm/button/bn_osl.c linux/drivers/acpi/ospm/button/bn_osl.c
--- linux-2.4.10-pre8/drivers/acpi/ospm/button/bn_osl.c	Wed Jun 20 17:47:40 2001
+++ linux/drivers/acpi/ospm/button/bn_osl.c	Mon Dec  3 23:09:47 2001
@@ -35,6 +35,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Button Driver");
+MODULE_LICENSE("GPL");
 
 
 #define BN_PROC_ROOT		"button"
diff -urN linux-2.4.10-pre8/drivers/acpi/ospm/ec/ec_osl.c linux/drivers/acpi/ospm/ec/ec_osl.c
--- linux-2.4.10-pre8/drivers/acpi/ospm/ec/ec_osl.c	Wed Jun 20 17:47:40 2001
+++ linux/drivers/acpi/ospm/ec/ec_osl.c	Mon Dec  3 23:09:47 2001
@@ -36,6 +36,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Embedded Controller Driver");
+MODULE_LICENSE("GPL");
 
 #ifdef ACPI_DEBUG
 
diff -urN linux-2.4.10-pre8/drivers/acpi/ospm/processor/pr_osl.c linux/drivers/acpi/ospm/processor/pr_osl.c
--- linux-2.4.10-pre8/drivers/acpi/ospm/processor/pr_osl.c	Wed Jun 20 17:47:40 2001
+++ linux/drivers/acpi/ospm/processor/pr_osl.c	Mon Dec  3 23:09:47 2001
@@ -36,6 +36,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - IA32 Processor Driver");
+MODULE_LICENSE("GPL");
 
 
 #define PR_PROC_ROOT		"processor"
diff -urN linux-2.4.10-pre8/drivers/acpi/ospm/system/sm_osl.c linux/drivers/acpi/ospm/system/sm_osl.c
--- linux-2.4.10-pre8/drivers/acpi/ospm/system/sm_osl.c	Wed Jun 20 17:47:40 2001
+++ linux/drivers/acpi/ospm/system/sm_osl.c	Mon Dec  3 23:09:47 2001
@@ -38,6 +38,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - ACPI System Driver");
+MODULE_LICENSE("GPL");
 
 
 #define SM_PROC_INFO		"info"
diff -urN linux-2.4.10-pre8/drivers/acpi/ospm/thermal/tz_osl.c linux/drivers/acpi/ospm/thermal/tz_osl.c
--- linux-2.4.10-pre8/drivers/acpi/ospm/thermal/tz_osl.c	Wed Jun 20 17:47:40 2001
+++ linux/drivers/acpi/ospm/thermal/tz_osl.c	Mon Dec  3 23:09:47 2001
@@ -35,6 +35,7 @@
 
 MODULE_AUTHOR("Andrew Grover");
 MODULE_DESCRIPTION("ACPI Component Architecture (CA) - Thermal Zone Driver");
+MODULE_LICENSE("GPL");
 
 int TZP = 0;
 MODULE_PARM(TZP, "i");
diff -urN linux-2.4.10-pre8/drivers/atm/ambassador.c linux/drivers/atm/ambassador.c
--- linux-2.4.10-pre8/drivers/atm/ambassador.c	Wed Jun 27 16:18:13 2001
+++ linux/drivers/atm/ambassador.c	Mon Dec  3 23:09:47 2001
@@ -297,16 +297,16 @@
 #define UCODE2(x) #x
 #define UCODE1(x,y) UCODE2(x ## y)
 
-static const u32 __initdata ucode_start = 
+static u32 __initdata ucode_start = 
 #include UCODE(start)
 ;
 
-static const region __initdata ucode_regions[] = {
+static region __initdata ucode_regions[] = {
 #include UCODE(regions)
   { 0, 0 }
 };
 
-static const u32 __initdata ucode_data[] = {
+static u32 __initdata ucode_data[] = {
 #include UCODE(data)
   0xdeadbeef
 };
@@ -2585,6 +2585,7 @@
 
 MODULE_AUTHOR(maintainer_string);
 MODULE_DESCRIPTION(description_string);
+MODULE_LICENSE("GPL");
 MODULE_PARM(debug,   "h");
 MODULE_PARM(cmds,    "i");
 MODULE_PARM(txs,     "i");
diff -urN linux-2.4.10-pre8/drivers/atm/ambassador.h linux/drivers/atm/ambassador.h
--- linux-2.4.10-pre8/drivers/atm/ambassador.h	Mon Dec 11 13:22:06 2000
+++ linux/drivers/atm/ambassador.h	Mon Dec  3 23:09:47 2001
@@ -664,9 +664,9 @@
   unsigned int count;
 } region;
 
-extern const region ucode_regions[];
-extern const u32 ucode_data[];
-extern const u32 ucode_start;
+static region ucode_regions[];
+static u32 ucode_data[];
+static u32 ucode_start;
 
 /* rate rounding */
 
diff -urN linux-2.4.10-pre8/drivers/atm/atmtcp.c linux/drivers/atm/atmtcp.c
--- linux-2.4.10-pre8/drivers/atm/atmtcp.c	Fri Dec 29 14:35:47 2000
+++ linux/drivers/atm/atmtcp.c	Mon Dec  3 23:09:47 2001
@@ -420,6 +420,7 @@
 	atm_tcp_ops.remove_persistent = NULL;
 }
 
+MODULE_LICENSE("GPL");
 #else
 
 struct atm_tcp_ops atm_tcp_ops = {
diff -urN linux-2.4.10-pre8/drivers/atm/eni.c linux/drivers/atm/eni.c
--- linux-2.4.10-pre8/drivers/atm/eni.c	Wed May 16 10:22:50 2001
+++ linux/drivers/atm/eni.c	Mon Dec  3 23:09:47 2001
@@ -2340,3 +2340,6 @@
 
 module_init(eni_init);
 module_exit(eni_cleanup);
+
+EXPORT_NO_SYMBOLS;
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/atm/firestream.c linux/drivers/atm/firestream.c
--- linux-2.4.10-pre8/drivers/atm/firestream.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/atm/firestream.c	Mon Dec  3 23:09:48 2001
@@ -271,11 +271,11 @@
 
    150000 packets per second is close to the limit a PC is going to have
    anyway. We therefore have to disable this for production. -- REW */
-#undef IRQ_RATE_LIMIT 100
+#undef IRQ_RATE_LIMIT // 100
 
 /* Interrupts work now. Unlike serial cards, ATM cards don't work all
    that great without interrupts. -- REW */
-#undef FS_POLL_FREQ 100
+#undef FS_POLL_FREQ // 100
 
 /* 
    This driver can spew a whole lot of debugging output at you. If you
@@ -1928,8 +1928,6 @@
 
  err_out_free_atm_dev:
 	atm_dev_deregister(atm_dev);
- err_out_free_fs_dev:
-	kfree(fs_dev);
  err_out:
 	return -ENODEV;
 }
@@ -2120,3 +2118,5 @@
 module_init(firestream_init_module);
 module_exit(firestream_cleanup_module);
 
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/atm/fore200e.c linux/drivers/atm/fore200e.c
--- linux-2.4.10-pre8/drivers/atm/fore200e.c	Wed Jun 27 16:18:13 2001
+++ linux/drivers/atm/fore200e.c	Mon Dec  3 23:09:48 2001
@@ -3000,3 +3000,5 @@
 #endif
     {}
 };
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/atm/horizon.c linux/drivers/atm/horizon.c
--- linux-2.4.10-pre8/drivers/atm/horizon.c	Fri Dec 29 14:35:47 2000
+++ linux/drivers/atm/horizon.c	Mon Dec  3 23:09:48 2001
@@ -2935,6 +2935,7 @@
 
 MODULE_AUTHOR(maintainer_string);
 MODULE_DESCRIPTION(description_string);
+MODULE_LICENSE("GPL");
 MODULE_PARM(debug, "h");
 MODULE_PARM(vpi_bits, "h");
 MODULE_PARM(max_tx_size, "h");
diff -urN linux-2.4.10-pre8/drivers/atm/idt77105.c linux/drivers/atm/idt77105.c
--- linux-2.4.10-pre8/drivers/atm/idt77105.c	Wed Jun 27 16:18:13 2001
+++ linux/drivers/atm/idt77105.c	Mon Dec  3 23:09:48 2001
@@ -374,9 +374,7 @@
             }
         }
 
-#ifdef MODULE
 	MOD_DEC_USE_COUNT;
-#endif /* MODULE */
 	return 0;
 }
 
@@ -384,6 +382,8 @@
 
 EXPORT_SYMBOL(idt77105_init);
 EXPORT_SYMBOL(idt77105_stop);
+
+MODULE_LICENSE("GPL");
 
 #ifdef MODULE
 
diff -urN linux-2.4.10-pre8/drivers/atm/nicstar.c linux/drivers/atm/nicstar.c
--- linux-2.4.10-pre8/drivers/atm/nicstar.c	Sun Jul 15 16:15:44 2001
+++ linux/drivers/atm/nicstar.c	Mon Dec  3 23:09:48 2001
@@ -271,6 +271,7 @@
 static struct timer_list ns_timer;
 static char *mac[NS_MAX_CARDS];
 MODULE_PARM(mac, "1-" __MODULE_STRING(NS_MAX_CARDS) "s");
+MODULE_LICENSE("GPL");
 
 
 /* Functions*******************************************************************/
diff -urN linux-2.4.10-pre8/drivers/atm/suni.c linux/drivers/atm/suni.c
--- linux-2.4.10-pre8/drivers/atm/suni.c	Fri May  5 12:37:52 2000
+++ linux/drivers/atm/suni.c	Mon Dec  3 23:09:48 2001
@@ -309,6 +309,8 @@
 EXPORT_SYMBOL(suni_init);
 
 
+MODULE_LICENSE("GPL");
+
 #ifdef MODULE
 
 
diff -urN linux-2.4.10-pre8/drivers/atm/uPD98402.c linux/drivers/atm/uPD98402.c
--- linux-2.4.10-pre8/drivers/atm/uPD98402.c	Wed Jun 27 16:19:07 2001
+++ linux/drivers/atm/uPD98402.c	Mon Dec  3 23:09:48 2001
@@ -255,6 +255,7 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(uPD98402_init);
 
diff -urN linux-2.4.10-pre8/drivers/atm/zatm.c linux/drivers/atm/zatm.c
--- linux-2.4.10-pre8/drivers/atm/zatm.c	Wed Jun 27 16:19:07 2001
+++ linux/drivers/atm/zatm.c	Mon Dec  3 23:09:48 2001
@@ -1846,6 +1846,8 @@
 
 #ifdef MODULE
  
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	if (!zatm_detect()) {
diff -urN linux-2.4.10-pre8/drivers/block/acsi.c linux/drivers/block/acsi.c
--- linux-2.4.10-pre8/drivers/block/acsi.c	Mon Dec  3 23:09:37 2001
+++ linux/drivers/block/acsi.c	Mon Dec  3 23:09:48 2001
@@ -1806,6 +1806,9 @@
 
 
 #ifdef MODULE
+
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	int err;
diff -urN linux-2.4.10-pre8/drivers/block/amiflop.c linux/drivers/block/amiflop.c
--- linux-2.4.10-pre8/drivers/block/amiflop.c	Mon Dec  3 23:09:37 2001
+++ linux/drivers/block/amiflop.c	Mon Dec  3 23:09:48 2001
@@ -118,6 +118,7 @@
 static long int fd_def_df0 = FD_DD_3;     /* default for df0 if it doesn't identify */
 
 MODULE_PARM(fd_def_df0,"l");
+MODULE_LICENSE("GPL");
 
 /*
  *  Macros
diff -urN linux-2.4.10-pre8/drivers/block/ataflop.c linux/drivers/block/ataflop.c
--- linux-2.4.10-pre8/drivers/block/ataflop.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/ataflop.c	Mon Dec  3 23:09:48 2001
@@ -2056,6 +2056,9 @@
 }
 
 #ifdef MODULE
+
+MODULE_LICENSE("GPL");
+
 int init_module (void)
 {
 	if (!MACH_IS_ATARI)
diff -urN linux-2.4.10-pre8/drivers/block/cciss.c linux/drivers/block/cciss.c
--- linux-2.4.10-pre8/drivers/block/cciss.c	Mon Dec  3 23:09:37 2001
+++ linux/drivers/block/cciss.c	Mon Dec  3 23:09:48 2001
@@ -50,6 +50,7 @@
 /* Embedded module documentation macros - see modules.h */
 MODULE_AUTHOR("Charles M. White III - Compaq Computer Corporation");
 MODULE_DESCRIPTION("Driver for Compaq Smart Array Controller 5300");
+MODULE_LICENSE("GPL");
 
 #include "cciss_cmd.h"
 #include "cciss.h"
diff -urN linux-2.4.10-pre8/drivers/block/cpqarray.c linux/drivers/block/cpqarray.c
--- linux-2.4.10-pre8/drivers/block/cpqarray.c	Mon Dec  3 23:09:37 2001
+++ linux/drivers/block/cpqarray.c	Mon Dec  3 23:09:48 2001
@@ -48,6 +48,7 @@
 /* Original author Chris Frantz - Compaq Computer Corporation */
 MODULE_AUTHOR("Compaq Computer Corporation");
 MODULE_DESCRIPTION("Driver for Compaq Smart2 Array Controllers");
+MODULE_LICENSE("GPL");
 
 #define MAJOR_NR COMPAQ_SMART2_MAJOR
 #include <linux/blk.h>
diff -urN linux-2.4.10-pre8/drivers/block/xd.c linux/drivers/block/xd.c
--- linux-2.4.10-pre8/drivers/block/xd.c	Mon Dec  3 23:09:37 2001
+++ linux/drivers/block/xd.c	Mon Dec  3 23:09:48 2001
@@ -376,9 +376,7 @@
 	int target = DEVICE_NR(inode->i_rdev);
 	if (target < xd_drives) {
 		xd_access[target]--;
-#ifdef MODULE
 		MOD_DEC_USE_COUNT;
-#endif /* MODULE */
 	}
 	return 0;
 }
@@ -1109,6 +1107,8 @@
 MODULE_PARM(xd, "1-4i");
 MODULE_PARM(xd_geo, "3-6i");
 MODULE_PARM(nodma, "i");
+
+MODULE_LICENSE("GPL");
 
 static void xd_done (void)
 {
diff -urN linux-2.4.10-pre8/drivers/block/z2ram.c linux/drivers/block/z2ram.c
--- linux-2.4.10-pre8/drivers/block/z2ram.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/block/z2ram.c	Mon Dec  3 23:09:48 2001
@@ -376,6 +376,9 @@
 }
 
 #if defined(MODULE)
+
+MODULE_LICENSE("GPL");
+
 int
 init_module( void )
 {
diff -urN linux-2.4.10-pre8/drivers/char/acquirewdt.c linux/drivers/char/acquirewdt.c
--- linux-2.4.10-pre8/drivers/char/acquirewdt.c	Sat May 19 17:43:05 2001
+++ linux/drivers/char/acquirewdt.c	Mon Dec  3 23:09:48 2001
@@ -226,3 +226,6 @@
 
 module_init(acq_init);
 module_exit(acq_exit);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/adbmouse.c linux/drivers/char/adbmouse.c
--- linux-2.4.10-pre8/drivers/char/adbmouse.c	Sun Dec  3 17:48:19 2000
+++ linux/drivers/char/adbmouse.c	Mon Dec  3 23:09:48 2001
@@ -205,3 +205,5 @@
 
 module_init(adb_mouse_init);
 module_exit(adb_mouse_cleanup);
+
+MODULE_LICENSE("GPL"):
diff -urN linux-2.4.10-pre8/drivers/char/advantechwdt.c linux/drivers/char/advantechwdt.c
--- linux-2.4.10-pre8/drivers/char/advantechwdt.c	Sat May 19 17:43:05 2001
+++ linux/drivers/char/advantechwdt.c	Mon Dec  3 23:09:48 2001
@@ -238,4 +238,7 @@
 module_init(advwdt_init);
 module_exit(advwdt_exit);
 
+MODULE_LICENSE("GPL");
+
 /* end of advantechwdt.c */
+
diff -urN linux-2.4.10-pre8/drivers/char/amigamouse.c linux/drivers/char/amigamouse.c
--- linux-2.4.10-pre8/drivers/char/amigamouse.c	Mon Nov 27 17:11:26 2000
+++ linux/drivers/char/amigamouse.c	Mon Dec  3 23:09:48 2001
@@ -209,3 +209,5 @@
 
 module_init(amiga_mouse_init);
 module_exit(amiga_mouse_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/amiserial.c linux/drivers/char/amiserial.c
--- linux-2.4.10-pre8/drivers/char/amiserial.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/char/amiserial.c	Mon Dec  3 23:09:48 2001
@@ -2353,3 +2353,5 @@
 	register_console(&sercons);
 }
 #endif
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/applicom.c linux/drivers/char/applicom.c
--- linux-2.4.10-pre8/drivers/char/applicom.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/applicom.c	Mon Dec  3 23:09:48 2001
@@ -1,6 +1,6 @@
 /* Derived from Applicom driver ac.c for SCO Unix                            */
 /* Ported by David Woodhouse, Axiom (Cambridge) Ltd.                         */
-/* Dave@mvhi.com  30/8/98                                                    */
+/* dwmw2@redhat.com  30/8/98                                                 */
 /* $Id: ac.c,v 1.30 2000/03/22 16:03:57 dwmw2 Exp $			     */
 /* This module is for Linux 2.1 and 2.2 series kernels.                      */
 /*****************************************************************************/
@@ -74,6 +74,7 @@
 
 MODULE_AUTHOR("David Woodhouse & Applicom International");
 MODULE_DESCRIPTION("Driver for Applicom Profibus card");
+MODULE_LICENSE("GPL");
 MODULE_PARM(irq, "i");
 MODULE_PARM_DESC(irq, "IRQ of the Applicom board");
 MODULE_PARM(mem, "i");
@@ -82,7 +83,7 @@
 MODULE_SUPPORTED_DEVICE("ac");
 
 
-struct applicom_board {
+static struct applicom_board {
 	unsigned long PhysIO;
 	unsigned long RamIO;
 	wait_queue_head_t FlagSleepSend;
@@ -100,22 +101,21 @@
 static unsigned int ReadErrorCount;	/* number of read error       */
 static unsigned int DeviceErrorCount;	/* number of device error     */
 
-static loff_t ac_llseek(struct file *, loff_t, int);
 static ssize_t ac_read (struct file *, char *, size_t, loff_t *);
 static ssize_t ac_write (struct file *, const char *, size_t, loff_t *);
 static int ac_ioctl(struct inode *, struct file *, unsigned int,
 		    unsigned long);
 static void ac_interrupt(int, void *, struct pt_regs *);
 
-struct file_operations ac_fops = {
+static struct file_operations ac_fops = {
 	owner:THIS_MODULE,
-	llseek:ac_llseek,
+	llseek:no_llseek,
 	read:ac_read,
 	write:ac_write,
 	ioctl:ac_ioctl,
 };
 
-struct miscdevice ac_miscdev = {
+static struct miscdevice ac_miscdev = {
 	AC_MINOR,
 	"ac",
 	&ac_fops
@@ -123,7 +123,7 @@
 
 static int dummy;	/* dev_id for request_irq() */
 
-int ac_register_board(unsigned long physloc, unsigned long loc, 
+static int ac_register_board(unsigned long physloc, unsigned long loc, 
 		      unsigned char boardno)
 {
 	volatile unsigned char byte_reset_it;
@@ -254,6 +254,7 @@
 
 	/* Now try the specified ISA cards */
 
+#warning "LEAK"
 	RamIO = ioremap(mem, LEN_RAM_IO * MAX_ISA_BOARD);
 
 	if (!RamIO) 
@@ -340,11 +341,6 @@
 __initcall(applicom_init);
 #endif
 
-static loff_t ac_llseek(struct file *file, loff_t offset, int origin)
-{
-	return -ESPIPE;
-}
-
 static ssize_t ac_write(struct file *file, const char *buf, size_t count, loff_t * ppos)
 {
 	unsigned int NumCard;	/* Board number 1 -> 8           */
@@ -421,7 +417,7 @@
 	}
 	
 	/* Place ourselves on the wait queue */
-	current->state = TASK_INTERRUPTIBLE;
+	set_current_state(TASK_INTERRUPTIBLE);
 	add_wait_queue(&apbs[IndexCard].FlagSleepSend, &wait);
 
 	/* Check whether the card is ready for us */
@@ -435,8 +431,9 @@
 			remove_wait_queue(&apbs[IndexCard].FlagSleepSend,
 					  &wait);
 			return -EINTR;
-	}
+		}
 		spin_lock_irqsave(&apbs[IndexCard].mutex, flags);
+		set_current_state(TASK_INTERRUPTIBLE);
 	}
 
 	/* We may not have actually slept */
@@ -521,7 +518,7 @@
 		printk("\n");
 #endif
 
-	/* Je suis stupide. DW. */
+#warning "Je suis stupide. DW. - copy*user in cli"
 
 	if (copy_to_user(buf, &st_loc, sizeof(struct st_ram_io)))
 		return -EFAULT;
@@ -550,7 +547,7 @@
 	
 	while(1) {
 		/* Stick ourself on the wait queue */
-		current->state = TASK_INTERRUPTIBLE;
+		set_current_state(TASK_INTERRUPTIBLE);
 		add_wait_queue(&FlagSleepRec, &wait);
 		
 		/* Scan each board, looking for one which has a packet for us */
@@ -565,7 +562,7 @@
 				/* Got a packet for us */
 				ret = do_ac_read(i, buf);
 				spin_unlock_irqrestore(&apbs[i].mutex, flags);
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&FlagSleepRec, &wait);
 				return tmp;
 			}
@@ -575,7 +572,7 @@
 				Dummy = readb(apbs[i].RamIO + VERS);
 				
 				spin_unlock_irqrestore(&apbs[i].mutex, flags);
-				current->state = TASK_RUNNING;
+				set_current_state(TASK_RUNNING);
 				remove_wait_queue(&FlagSleepRec, &wait);
 				
 				printk(KERN_WARNING "APPLICOM driver read error board %d, DataToPcReady = %d\n",
diff -urN linux-2.4.10-pre8/drivers/char/drm/drm_context.h linux/drivers/char/drm/drm_context.h
--- linux-2.4.10-pre8/drivers/char/drm/drm_context.h	Wed Aug 15 14:21:47 2001
+++ linux/drivers/char/drm/drm_context.h	Mon Dec  3 23:09:48 2001
@@ -181,7 +181,7 @@
 	drm_device_t	*dev	= priv->dev;
 	drm_ctx_priv_map_t request;
 	drm_map_t *map = NULL;
-	drm_map_list_t *r_list;
+	drm_map_list_t *r_list = NULL;
 	struct list_head *list;
 
 	if (copy_from_user(&request,
diff -urN linux-2.4.10-pre8/drivers/char/ds1620.c linux/drivers/char/ds1620.c
--- linux-2.4.10-pre8/drivers/char/ds1620.c	Sun Aug 13 09:54:15 2000
+++ linux/drivers/char/ds1620.c	Mon Dec  3 23:09:48 2001
@@ -410,3 +410,5 @@
 
 module_init(ds1620_init);
 module_exit(ds1620_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/dtlk.c linux/drivers/char/dtlk.c
--- linux-2.4.10-pre8/drivers/char/dtlk.c	Wed Jul  4 14:41:33 2001
+++ linux/drivers/char/dtlk.c	Mon Dec  3 23:09:48 2001
@@ -678,3 +678,5 @@
 #endif
 	return 0;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/ec3104_keyb.c linux/drivers/char/ec3104_keyb.c
--- linux-2.4.10-pre8/drivers/char/ec3104_keyb.c	Fri Apr 13 20:31:32 2001
+++ linux/drivers/char/ec3104_keyb.c	Mon Dec  3 23:09:48 2001
@@ -40,7 +40,7 @@
 #include <linux/random.h>
 #include <linux/poll.h>
 #include <linux/miscdevice.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/kbd_kern.h>
 #include <linux/smp_lock.h>
 
diff -urN linux-2.4.10-pre8/drivers/char/efirtc.c linux/drivers/char/efirtc.c
--- linux-2.4.10-pre8/drivers/char/efirtc.c	Mon Sep 18 14:57:01 2000
+++ linux/drivers/char/efirtc.c	Mon Dec  3 23:09:48 2001
@@ -403,3 +403,5 @@
 
 module_init(efi_rtc_init);
 module_exit(efi_rtc_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/esp.c linux/drivers/char/esp.c
--- linux-2.4.10-pre8/drivers/char/esp.c	Sun Jul 15 16:15:44 2001
+++ linux/drivers/char/esp.c	Mon Dec  3 23:09:48 2001
@@ -83,6 +83,8 @@
 static unsigned int rx_timeout = ESP_RX_TMOUT;
 static unsigned int pio_threshold = ESP_PIO_THRESHOLD;
 
+MODULE_LICENSE("GPL");
+
 MODULE_PARM(irq, "1-8i");
 MODULE_PARM(divisor, "1-8i");
 MODULE_PARM(dma, "i");
diff -urN linux-2.4.10-pre8/drivers/char/ftape/compressor/zftape-compress.c linux/drivers/char/ftape/compressor/zftape-compress.c
--- linux-2.4.10-pre8/drivers/char/ftape/compressor/zftape-compress.c	Tue Nov 23 10:29:15 1999
+++ linux/drivers/char/ftape/compressor/zftape-compress.c	Mon Dec  3 23:09:48 2001
@@ -1258,14 +1258,13 @@
 	TRACE_EXIT 0;
 }
 
-
 #ifdef MODULE
-#if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18)
+
 MODULE_AUTHOR(
 	"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de");
 MODULE_DESCRIPTION(
 "Compression routines for zftape. Uses the lzrw3 algorithm by Ross Williams");
-#endif
+MODULE_LICENSE("GPL");
 
 #if LINUX_VERSION_CODE >= KERNEL_VER(2,1,18)
 static int can_unload(void)
diff -urN linux-2.4.10-pre8/drivers/char/ftape/lowlevel/ftape-init.c linux/drivers/char/ftape/lowlevel/ftape-init.c
--- linux-2.4.10-pre8/drivers/char/ftape/lowlevel/ftape-init.c	Tue Nov 23 10:29:15 1999
+++ linux/drivers/char/ftape/lowlevel/ftape-init.c	Mon Dec  3 23:09:48 2001
@@ -153,6 +153,7 @@
 	"(c) 1996, 1997 Claus-Justus Heine (claus@momo.math.rwth-aachen.de)");
 MODULE_DESCRIPTION(
 	"QIC-117 driver for QIC-40/80/3010/3020 floppy tape drives.");
+MODULE_LICENSE("GPL");
 #endif
 
 /*  Called by modules package when installing the driver
diff -urN linux-2.4.10-pre8/drivers/char/ftape/zftape/zftape-init.c linux/drivers/char/ftape/zftape/zftape-init.c
--- linux-2.4.10-pre8/drivers/char/ftape/zftape/zftape-init.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/ftape/zftape/zftape-init.c	Mon Dec  3 23:09:48 2001
@@ -59,6 +59,7 @@
 		   "Support for QIC-113 compatible volume table "
 		   "and builtin compression (lzrw3 algorithm)");
 MODULE_SUPPORTED_DEVICE("char-major-27");
+MODULE_LICENSE("GPL");
 
 /*      Global vars.
  */
diff -urN linux-2.4.10-pre8/drivers/char/generic_serial.c linux/drivers/char/generic_serial.c
--- linux-2.4.10-pre8/drivers/char/generic_serial.c	Wed Jul  4 14:41:33 2001
+++ linux/drivers/char/generic_serial.c	Mon Dec  3 23:09:48 2001
@@ -1088,3 +1088,5 @@
 EXPORT_SYMBOL(gs_setserial);
 EXPORT_SYMBOL(gs_getserial);
 EXPORT_SYMBOL(gs_got_break);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/h8.c linux/drivers/char/h8.c
--- linux-2.4.10-pre8/drivers/char/h8.c	Wed Jul  4 14:41:33 2001
+++ linux/drivers/char/h8.c	Mon Dec  3 23:09:48 2001
@@ -1176,3 +1176,6 @@
 	h8_event_mask &= (~mask);
 	restore_flags(flags);
 }
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/hp600_keyb.c linux/drivers/char/hp600_keyb.c
--- linux-2.4.10-pre8/drivers/char/hp600_keyb.c	Wed Apr 11 21:24:52 2001
+++ linux/drivers/char/hp600_keyb.c	Mon Dec  3 23:09:48 2001
@@ -336,3 +336,4 @@
 #endif
 
 
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/i810-tco.c linux/drivers/char/i810-tco.c
--- linux-2.4.10-pre8/drivers/char/i810-tco.c	Wed Jul 11 14:50:47 2001
+++ linux/drivers/char/i810-tco.c	Mon Dec  3 23:09:48 2001
@@ -363,3 +363,5 @@
 
 module_init(watchdog_init);
 module_exit(watchdog_cleanup);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/ip2.c linux/drivers/char/ip2.c
--- linux-2.4.10-pre8/drivers/char/ip2.c	Thu Apr 12 12:16:35 2001
+++ linux/drivers/char/ip2.c	Mon Dec  3 23:09:48 2001
@@ -71,6 +71,8 @@
 {
 }
 
+MODULE_LICENSE("GPL");
+
 #else	// !MODULE 
 
 #ifndef NULL
diff -urN linux-2.4.10-pre8/drivers/char/ip2main.c linux/drivers/char/ip2main.c
--- linux-2.4.10-pre8/drivers/char/ip2main.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/char/ip2main.c	Mon Dec  3 23:09:48 2001
@@ -418,6 +418,7 @@
 	rirqs[iindx++] = irq;
 }
 
+#ifdef MODULE
 static int __init
 clear_requested_irq( char irq )
 {
@@ -430,6 +431,7 @@
 	}
 	return 0;
 }
+#endif
 
 static int __init
 have_requested_irq( char irq )
diff -urN linux-2.4.10-pre8/drivers/char/isicom.c linux/drivers/char/isicom.c
--- linux-2.4.10-pre8/drivers/char/isicom.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/char/isicom.c	Mon Dec  3 23:09:48 2001
@@ -1927,6 +1927,7 @@
 
 MODULE_AUTHOR("MultiTech");
 MODULE_DESCRIPTION("Driver for the ISI series of cards by MultiTech");
+MODULE_LICENSE("GPL");
 MODULE_PARM(io, "1-4i");
 MODULE_PARM_DESC(io, "I/O ports for the cards");
 MODULE_PARM(irq, "1-4i");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/Config.in linux/drivers/char/joystick/Config.in
--- linux-2.4.10-pre8/drivers/char/joystick/Config.in	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/Config.in	Mon Dec  3 23:09:48 2001
@@ -5,48 +5,45 @@
 mainmenu_option next_comment
 comment 'Joysticks'
 
-dep_mbool 'Joystick support' CONFIG_JOYSTICK $CONFIG_INPUT
-if [ "$CONFIG_JOYSTICK" != "n" ]; then
-   comment 'Game port support'
-      dep_tristate '  ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT
-      dep_tristate '  PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT
-      dep_tristate '  Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT
-      dep_tristate '  Crystal SoundFusion gameports' CONFIG_INPUT_CS461X $CONFIG_INPUT
+if [ "$CONFIG_INPUT" != "n" ]; then
+   dep_tristate 'Game port support' CONFIG_INPUT_GAMEPORT $CONFIG_INPUT
+      dep_tristate '  Classic ISA/PnP gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT_GAMEPORT
+      dep_tristate '  PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT_GAMEPORT
+      dep_tristate '  Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT_GAMEPORT
+      dep_tristate '  Crystal SoundFusion gameports' CONFIG_INPUT_CS461X  $CONFIG_INPUT_GAMEPORT
+      dep_tristate '  SoundBlaster Live! gameports' CONFIG_INPUT_EMU10K1 $CONFIG_INPUT_GAMEPORT
+   tristate 'Serial port device support' CONFIG_INPUT_SERIO
+      dep_tristate '  Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_INPUT_SERIO
+else
+   # Must explicitly set to n for drivers/sound/Config.in
+   define_tristate CONFIG_INPUT_GAMEPORT n
+   comment 'Input core support is needed for gameports'
+fi
 
-   comment 'Gameport joysticks'
-      dep_tristate '  Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT
-      dep_tristate '  Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_INPUT
-      dep_tristate '  Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_INPUT
-      dep_tristate '  Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_INPUT
-      dep_tristate '  Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_INPUT
-      dep_tristate '  Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_INPUT
-      dep_tristate '  InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_INPUT
-      dep_tristate '  ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_INPUT
-      dep_tristate '  Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_INPUT
+if [ "$CONFIG_INPUT" != "n" ]; then
+   comment 'Joysticks'
 
-   comment 'Serial port support'
-      dep_tristate '  Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_INPUT
-
-   comment 'Serial port joysticks'
-      dep_tristate '  Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_INPUT
-      dep_tristate '  LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT
-      dep_tristate '  SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT
-      dep_tristate '  SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT
-      dep_tristate '  Gravis Stinger gamepad' CONFIG_INPUT_STINGER $CONFIG_INPUT
-      dep_tristate '  I-Force/Serial controllers' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT
-      dep_tristate '  I-Force/USB controllers' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB
-
-   comment 'Parallel port joysticks'
-   if [ "$CONFIG_PARPORT" != "n" ]; then
-      dep_tristate '  Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_INPUT $CONFIG_PARPORT
-      dep_tristate '  Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_INPUT $CONFIG_PARPORT
-      dep_tristate '  Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_INPUT $CONFIG_PARPORT
-   else
-      comment '  Parport support is needed for parallel port joysticks'
-   fi
+   dep_tristate '  Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
+   dep_tristate '  Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
+   dep_tristate '  Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
+   dep_tristate '  Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
+   dep_tristate '  Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
+   dep_tristate '  Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
+   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
+   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
+   dep_tristate '  SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_SERIO
+   dep_tristate '  Gravis Stinger gamepad' CONFIG_INPUT_STINGER $CONFIG_INPUT $CONFIG_INPUT_SERIO
+   dep_tristate '  Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_INPUT $CONFIG_PARPORT
+   dep_tristate '  Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_INPUT $CONFIG_PARPORT
+   dep_tristate '  Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_INPUT $CONFIG_PARPORT
 
    if [ "$CONFIG_AMIGA" = "y" ]; then
-   comment 'System joysticks'
       dep_tristate '  Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_INPUT
    fi
 else
diff -urN linux-2.4.10-pre8/drivers/char/joystick/Makefile linux/drivers/char/joystick/Makefile
--- linux-2.4.10-pre8/drivers/char/joystick/Makefile	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/Makefile	Mon Dec  3 23:09:48 2001
@@ -30,30 +30,34 @@
 
 # Each configuration option enables a list of files.
 
-obj-$(CONFIG_INPUT_SERPORT)	+= serport.o serio.o
+obj-$(CONFIG_INPUT_GAMEPORT)	+= gameport.o
+obj-$(CONFIG_INPUT_SERIO)	+= serio.o
 
-obj-$(CONFIG_INPUT_NS558)	+= ns558.o gameport.o
-obj-$(CONFIG_INPUT_LIGHTNING)	+= lightning.o gameport.o
-obj-$(CONFIG_INPUT_PCIGAME)	+= pcigame.o gameport.o
-obj-$(CONFIG_INPUT_CS461X)	+= cs461x.o gameport.o
+obj-$(CONFIG_INPUT_SERPORT)	+= serport.o
 
-obj-$(CONFIG_INPUT_WARRIOR)	+= warrior.o serio.o
-obj-$(CONFIG_INPUT_MAGELLAN)	+= magellan.o serio.o
-obj-$(CONFIG_INPUT_SPACEORB)	+= spaceorb.o serio.o
-obj-$(CONFIG_INPUT_SPACEBALL)	+= spaceball.o serio.o
-obj-$(CONFIG_INPUT_STINGER)	+= stinger.o serio.o
-obj-$(CONFIG_INPUT_IFORCE_232)	+= iforce.o serio.o
+obj-$(CONFIG_INPUT_NS558)	+= ns558.o
+obj-$(CONFIG_INPUT_LIGHTNING)	+= lightning.o
+obj-$(CONFIG_INPUT_PCIGAME)	+= pcigame.o
+obj-$(CONFIG_INPUT_CS461X)	+= cs461x.o
+obj-$(CONFIG_INPUT_EMU10K1)	+= emu10k1-gp.o
+
+obj-$(CONFIG_INPUT_WARRIOR)	+= warrior.o
+obj-$(CONFIG_INPUT_MAGELLAN)	+= magellan.o
+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 gameport.o
-obj-$(CONFIG_INPUT_A3D)		+= a3d.o gameport.o
-obj-$(CONFIG_INPUT_ADI)		+= adi.o gameport.o
-obj-$(CONFIG_INPUT_COBRA)	+= cobra.o gameport.o
-obj-$(CONFIG_INPUT_GF2K)	+= gf2k.o gameport.o
-obj-$(CONFIG_INPUT_GRIP)	+= grip.o gameport.o
-obj-$(CONFIG_INPUT_INTERACT)	+= interact.o gameport.o
-obj-$(CONFIG_INPUT_TMDC)	+= tmdc.o gameport.o
-obj-$(CONFIG_INPUT_SIDEWINDER)	+= sidewinder.o gameport.o
+obj-$(CONFIG_INPUT_ANALOG)	+= analog.o
+obj-$(CONFIG_INPUT_A3D)		+= a3d.o
+obj-$(CONFIG_INPUT_ADI)		+= adi.o
+obj-$(CONFIG_INPUT_COBRA)	+= cobra.o
+obj-$(CONFIG_INPUT_GF2K)	+= gf2k.o
+obj-$(CONFIG_INPUT_GRIP)	+= grip.o
+obj-$(CONFIG_INPUT_INTERACT)	+= interact.o
+obj-$(CONFIG_INPUT_TMDC)	+= tmdc.o
+obj-$(CONFIG_INPUT_SIDEWINDER)	+= sidewinder.o
 
 obj-$(CONFIG_INPUT_DB9)		+= db9.o
 obj-$(CONFIG_INPUT_GAMECON)	+= gamecon.o
diff -urN linux-2.4.10-pre8/drivers/char/joystick/a3d.c linux/drivers/char/joystick/a3d.c
--- linux-2.4.10-pre8/drivers/char/joystick/a3d.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/a3d.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: a3d.c,v 1.10 2000/05/29 11:19:50 vojtech Exp $
+ * $Id: a3d.c,v 1.14 2001/04/26 10:24:46 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  *
  *  Sponsored by SuSE
  */
@@ -190,7 +190,7 @@
 
 int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct a3d *a3d = gameport->driver;
+	struct a3d *a3d = gameport->private;
 	int i;
 	for (i = 0; i < 4; i++)
 		axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
@@ -205,7 +205,7 @@
 
 int a3d_adc_open(struct gameport *gameport, int mode)
 {
-	struct a3d *a3d = gameport->driver;
+	struct a3d *a3d = gameport->private;
 	if (mode != GAMEPORT_MODE_COOKED)
 		return -1;
 	if (!a3d->used++)
@@ -219,7 +219,7 @@
 
 static void a3d_adc_close(struct gameport *gameport)
 {
-	struct a3d *a3d = gameport->driver;
+	struct a3d *a3d = gameport->private;
 	if (!--a3d->used)
 		del_timer(&a3d->timer);
 }
@@ -323,12 +323,11 @@
 		a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
 		a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
 
-		a3d->adc.driver = a3d;
+		a3d->adc.private = a3d;
 		a3d->adc.open = a3d_adc_open;
 		a3d->adc.close = a3d_adc_close;
 		a3d->adc.cooked_read = a3d_adc_cooked_read;
 		a3d->adc.fuzz = 1; 
-		a3d->adc.type = GAMEPORT_EXT; 
 
 		a3d_read(a3d, data);
 
@@ -385,3 +384,5 @@
 
 module_init(a3d_init);
 module_exit(a3d_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/adi.c linux/drivers/char/joystick/adi.c
--- linux-2.4.10-pre8/drivers/char/joystick/adi.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/adi.c	Mon Dec  3 23:09:48 2001
@@ -553,3 +553,5 @@
 
 module_init(adi_init);
 module_exit(adi_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/amijoy.c linux/drivers/char/joystick/amijoy.c
--- linux-2.4.10-pre8/drivers/char/joystick/amijoy.c	Fri Feb 16 16:02:35 2001
+++ linux/drivers/char/joystick/amijoy.c	Mon Dec  3 23:09:48 2001
@@ -42,6 +42,7 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_PARM(amijoy, "1-2i");
+MODULE_LICENSE("GPL");
 
 static int amijoy[2] = { 0, 1 };
 static int amijoy_used[2] = { 0, 0 };
diff -urN linux-2.4.10-pre8/drivers/char/joystick/analog.c linux/drivers/char/joystick/analog.c
--- linux-2.4.10-pre8/drivers/char/joystick/analog.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/analog.c	Mon Dec  3 23:09:48 2001
@@ -42,6 +42,7 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux");
+MODULE_LICENSE("GPL");
 
 /*
  * Option parsing.
diff -urN linux-2.4.10-pre8/drivers/char/joystick/cobra.c linux/drivers/char/joystick/cobra.c
--- linux-2.4.10-pre8/drivers/char/joystick/cobra.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/cobra.c	Mon Dec  3 23:09:48 2001
@@ -248,3 +248,5 @@
 
 module_init(cobra_init);
 module_exit(cobra_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/cs461x.c linux/drivers/char/joystick/cs461x.c
--- linux-2.4.10-pre8/drivers/char/joystick/cs461x.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/cs461x.c	Mon Dec  3 23:09:48 2001
@@ -10,21 +10,24 @@
 
 #include <linux/module.h>
 #include <linux/ioport.h>
+#include <linux/config.h>
 #include <linux/init.h>
 #include <linux/gameport.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
 
 MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
+MODULE_LICENSE("GPL");
 
 /*
 	These options are experimental
 
-#define COOKED_MODE
 #define CS461X_FULL_MAP
-
 */
 
+#define COOKED_MODE
+
+
 #ifndef PCI_VENDOR_ID_CIRRUS
 #define PCI_VENDOR_ID_CIRRUS            0x1013
 #endif
@@ -281,8 +284,6 @@
 	}
 	memset(port, 0, sizeof(struct gameport));
 
-	port->io = -1;
-	port->size = -1;
 	pdev->driver_data = port;
 	
 	port->open = cs461x_gameport_open;
@@ -297,9 +298,8 @@
 
 	gameport_register_port(port);
 
-	printk(KERN_INFO "gameport%d: CS461x PCI", port->number);
-	if (port->size > 1) printk(" size %d", port->size);
-	printk(" speed %d kHz\n", port->speed);
+	printk(KERN_INFO "gameport%d: CS461x Gameport speed %d kHz\n",
+		port->number, port->speed);
 
 	return 0;
 }
diff -urN linux-2.4.10-pre8/drivers/char/joystick/db9.c linux/drivers/char/joystick/db9.c
--- linux-2.4.10-pre8/drivers/char/joystick/db9.c	Mon Aug 14 13:55:01 2000
+++ linux/drivers/char/joystick/db9.c	Mon Dec  3 23:09:48 2001
@@ -41,6 +41,7 @@
 #include <linux/input.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
 MODULE_PARM(db9, "2i");
 MODULE_PARM(db9_2, "2i");
 MODULE_PARM(db9_3, "2i");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/emu10k1-gp.c linux/drivers/char/joystick/emu10k1-gp.c
--- linux-2.4.10-pre8/drivers/char/joystick/emu10k1-gp.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/char/joystick/emu10k1-gp.c	Mon Dec  3 23:09:48 2001
@@ -0,0 +1,125 @@
+/*
+ * $Id: emu10k1-gp.c,v 1.2 2001/04/24 07:48:56 vojtech Exp $
+ *
+ *  Copyright (c) 2001 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * EMU10k1 - SB Live! - gameport driver for Linux
+ */
+
+/*
+ * 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 <vojtech@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
+
+struct emu {
+	struct pci_dev *dev;
+	struct emu *next;
+	struct gameport gameport;
+	int size;
+};
+	
+static struct pci_device_id emu_tbl[] __devinitdata = {
+	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live! gameport */
+	{ 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, emu_tbl);
+
+static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+	int ioport, iolen;
+	int rc;
+	struct emu *port;
+        
+	rc = pci_enable_device(pdev);
+	if (rc) {
+		printk(KERN_ERR "emu10k1-gp: Cannot enable emu10k1 gameport (bus %d, devfn %d) error=%d\n",
+			pdev->bus->number, pdev->devfn, rc);
+		return rc;
+	}
+
+	ioport = pci_resource_start(pdev, 0);
+	iolen = pci_resource_len(pdev, 0);
+
+	if (!request_region(ioport, iolen, "emu10k1-gp"))
+		return -EBUSY;
+
+	if (!(port = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
+		printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
+		release_region(ioport, iolen);
+		return -ENOMEM;
+	}
+	memset(port, 0, sizeof(struct emu));
+
+	port->gameport.io = ioport;
+	port->size = iolen;
+	port->dev = pdev;
+	pdev->driver_data = port;
+
+	gameport_register_port(&port->gameport);
+
+	printk(KERN_INFO "gameport%d: Emu10k1 Gameport at %#x size %d speed %d kHz\n",
+		port->gameport.number, port->gameport.io, iolen, port->gameport.speed);
+
+	return 0;
+}
+
+static void __devexit emu_remove(struct pci_dev *pdev)
+{
+	struct emu *port = (struct emu *)pdev->driver_data;
+	gameport_unregister_port(&port->gameport);
+	release_region(port->gameport.io, port->size);
+	kfree(port);
+}
+
+static struct pci_driver emu_driver = {
+        name:           "Emu10k1 Gameport",
+        id_table:       emu_tbl,
+        probe:          emu_probe,
+        remove:         emu_remove,
+};
+
+int __init emu_init(void)
+{
+	return pci_module_init(&emu_driver);
+}
+
+void __exit emu_exit(void)
+{
+	pci_unregister_driver(&emu_driver);
+}
+
+module_init(emu_init);
+module_exit(emu_exit);
diff -urN linux-2.4.10-pre8/drivers/char/joystick/gamecon.c linux/drivers/char/joystick/gamecon.c
--- linux-2.4.10-pre8/drivers/char/joystick/gamecon.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/gamecon.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: gamecon.c,v 1.11 2000/11/01 12:38:53 vojtech Exp $
+ * $Id: gamecon.c,v 1.14 2001/04/29 22:42:14 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Based on the work of:
  *  	Andree Borrmann		John Dahlstrom
@@ -42,6 +42,7 @@
 #include <linux/input.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
 MODULE_PARM(gc, "2-6i");
 MODULE_PARM(gc_2,"2-6i");
 MODULE_PARM(gc_3,"2-6i");
@@ -62,7 +63,7 @@
 	struct pardevice *pd;
 	struct input_dev dev[5];
 	struct timer_list timer;
-	unsigned char pads[GC_PSX + 1];
+	unsigned char pads[GC_MAX + 1];
 	int used;
 };
 
@@ -231,7 +232,7 @@
 
 static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
 static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
-				BTN_START, BTN_SELECT, BTN_THUMB, BTN_THUMB2 };
+				BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
 
 /*
  * gc_psx_command() writes 8bit command and reads 8bit data from
@@ -345,8 +346,8 @@
 			s = gc_status_bit[i];
 
 			if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
-				input_report_abs(dev + i, ABS_X, ! - !(s & data[6]) - !(s & data[7]));
-				input_report_abs(dev + i, ABS_Y, ! - !(s & data[4]) - !(s & data[5]));
+				input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7]));
+				input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5]));
 			}
 
 			if (s & gc->pads[GC_NES])
diff -urN linux-2.4.10-pre8/drivers/char/joystick/gameport.c linux/drivers/char/joystick/gameport.c
--- linux-2.4.10-pre8/drivers/char/joystick/gameport.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/gameport.c	Mon Dec  3 23:09:48 2001
@@ -41,6 +41,7 @@
 #include <linux/delay.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(gameport_register_port);
 EXPORT_SYMBOL(gameport_unregister_port);
diff -urN linux-2.4.10-pre8/drivers/char/joystick/gf2k.c linux/drivers/char/joystick/gf2k.c
--- linux-2.4.10-pre8/drivers/char/joystick/gf2k.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/gf2k.c	Mon Dec  3 23:09:48 2001
@@ -357,3 +357,5 @@
 
 module_init(gf2k_init);
 module_exit(gf2k_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/grip.c linux/drivers/char/joystick/grip.c
--- linux-2.4.10-pre8/drivers/char/joystick/grip.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/grip.c	Mon Dec  3 23:09:48 2001
@@ -421,3 +421,5 @@
 
 module_init(grip_init);
 module_exit(grip_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/iforce.c linux/drivers/char/joystick/iforce.c
--- linux-2.4.10-pre8/drivers/char/joystick/iforce.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/iforce.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,8 @@
 /*
- * $Id: iforce.c,v 1.7 2000/06/04 14:03:36 vojtech Exp $
+ * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $
  *
- *  Copyright (c) 2000 Vojtech Pavlik
+ *  Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
+ *  Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
  *
  *  USB/RS232 I-Force joysticks and wheels.
  *
@@ -11,18 +12,18 @@
 /*
  * 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 <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
@@ -38,46 +39,216 @@
 #include <linux/serio.h>
 #include <linux/config.h>
 
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
+/* 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 <linux/ioport.h>
 
-#define USB_VENDOR_ID_LOGITECH		0x046d
-#define USB_DEVICE_ID_LOGITECH_WMFORCE	0xc281
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>, Johann Deneux <deneux@ifrance.com>");
+MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
 
-#define IFORCE_MAX_LENGTH		16
+#define IFORCE_MAX_LENGTH	16
 
 #if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE)
-#define IFORCE_232
+#define IFORCE_232	1
 #endif
 #if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE)
-#define IFORCE_USB
+#define IFORCE_USB	2
 #endif
 
+#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
+#define FF_MODCORE_MAX		3
+
+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)];
+};
+
+#define FF_CMD_EFFECT		0x010e
+#define FF_CMD_SHAPE		0x0208
+#define FF_CMD_MAGNITUDE	0x0303
+#define FF_CMD_PERIOD		0x0407
+#define FF_CMD_INTERACT		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
+
+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, BTN_DEAD, -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 abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static signed short abs_wheel[] =    { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static signed short ff_iforce[] =    { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,
+	FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 };
+
+static struct iforce_device {
+	u16 idvendor;
+	u16 idproduct;
+	char *name;
+	signed short *btn;
+	signed short *abs;
+	signed short *ff;
+} iforce_device[] = {
+	{ 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_joystick, abs_joystick, ff_iforce },
+	{ 0x05ef, 0x8884, "AVB Mag Turbo Force",			btn_wheel, abs_wheel, ff_iforce },
+	{ 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback",	btn_wheel, abs_wheel, ff_iforce },
+	{ 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]",		btn_joystick, abs_joystick, ff_iforce }
+};
+
 struct iforce {
-	signed char data[IFORCE_MAX_LENGTH];
-	struct usb_device *usbdev;
-	struct input_dev dev;
-	struct urb irq;
+	struct input_dev dev;		/* Input device interface */
+	struct iforce_device *type;
+	char name[64];
 	int open;
+	int bus;
+
+	unsigned char data[IFORCE_MAX_LENGTH];
+	unsigned char edata[IFORCE_MAX_LENGTH];
+	u16 ecmd;
+	u16 expect_packet;
+
+#ifdef IFORCE_232
+	struct serio *serio;		/* RS232 transfer */
 	int idx, pkt, len, id;
 	unsigned char csum;
+#endif
+#ifdef IFORCE_USB
+	struct usb_device *usbdev;	/* USB transfer */
+	struct urb irq, out, ctrl;
+	devrequest dr;
+#endif
+					/* Force Feedback */
+	wait_queue_head_t wait;
+	struct resource device_memory;
+	struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
 };
 
 static struct {
-        __s32 x;
-        __s32 y;
+	__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}};
 
-static char *iforce_name = "I-Force joystick/wheel";
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a)	((unsigned char)((a) >> 8))
+#define LO(a)	((unsigned char)((a) & 0xff))
+
+/* Encode a time value */
+#define TIME_SCALE(a)	((a) == 0xffff ? 0xffff : (a) * 1000 / 256)
 
-static void iforce_process_packet(struct input_dev *dev, unsigned char id, int idx, unsigned char *data)
+static void dump_packet(char *msg, u16 cmd, unsigned char *data)
 {
-	switch (id) {
+	int i;
 
-		case 1:	/* joystick position data */
-		case 3: /* wheel position data */
+	printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
+	for (i = 0; i < LO(cmd); i++)
+		printk("%02x ", data[i]);
+	printk(")\n");
+}
 
-			if (id == 1) {
+/*
+ * Send a packet of bytes to the device
+ */
+static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
+{
+	switch (iforce->bus) {
+
+#ifdef IFORCE_232
+		case IFORCE_232: {
+
+			int i;
+			unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd);
+
+			serio_write(iforce->serio, 0x2b);
+			serio_write(iforce->serio, HI(cmd));
+			serio_write(iforce->serio, LO(cmd));
+
+			for (i = 0; i < LO(cmd); i++) {
+				serio_write(iforce->serio, data[i]);
+				csum = csum ^ data[i];
+			}
+
+			serio_write(iforce->serio, csum);
+			return;
+		}
+#endif
+#ifdef IFORCE_USB
+		case IFORCE_USB: {
+
+			DECLARE_WAITQUEUE(wait, current);
+			int timeout = HZ; /* 1 second */
+
+			memcpy(iforce->out.transfer_buffer + 1, data, LO(cmd));
+			((char*)iforce->out.transfer_buffer)[0] = HI(cmd);
+			iforce->out.transfer_buffer_length = LO(cmd) + 2;
+			iforce->out.dev = iforce->usbdev;
+
+			set_current_state(TASK_INTERRUPTIBLE);
+			add_wait_queue(&iforce->wait, &wait);
+
+			if (usb_submit_urb(&iforce->out)) {
+				set_current_state(TASK_RUNNING);
+				remove_wait_queue(&iforce->wait, &wait);
+				return;
+			}
+
+			while (timeout && iforce->out.status == -EINPROGRESS)
+				timeout = schedule_timeout(timeout);
+
+			set_current_state(TASK_RUNNING);
+			remove_wait_queue(&iforce->wait, &wait);
+
+			if (!timeout)
+				usb_unlink_urb(&iforce->out);
+
+			return;
+		}
+#endif
+	}
+}
+
+static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
+{
+	struct input_dev *dev = &iforce->dev;
+	int i;
+
+#ifdef 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)
+		return;
+
+	switch (HI(cmd)) {
+
+		case 0x01:	/* joystick position data */
+		case 0x03:	/* wheel position data */
+
+			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]);
@@ -90,37 +261,95 @@
 			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);
 
-			input_report_key(dev, BTN_TRIGGER, data[5] & 0x01);
-			input_report_key(dev, BTN_TOP,     data[5] & 0x02);
-			input_report_key(dev, BTN_THUMB,   data[5] & 0x04);
-			input_report_key(dev, BTN_TOP2,    data[5] & 0x08);
-			input_report_key(dev, BTN_BASE,    data[5] & 0x10);
-			input_report_key(dev, BTN_BASE2,   data[5] & 0x20);
-			input_report_key(dev, BTN_BASE3,   data[5] & 0x40);
-			input_report_key(dev, BTN_BASE4,   data[5] & 0x80);
-			input_report_key(dev, BTN_BASE5,   data[6] & 0x01);
-			input_report_key(dev, BTN_A,       data[6] & 0x02);
-			input_report_key(dev, BTN_B,       data[6] & 0x04);
-			input_report_key(dev, BTN_C,       data[6] & 0x08);
+			for (i = 0; iforce->type->btn[i] >= 0; i++)
+				input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
+
 			break;
 
-		case 2: /* force feedback effect status */
+		case 0x02:	/* status report */
+
+			input_report_key(dev, BTN_DEAD, data[0] & 0x02);
 			break;
 	}
 }
 
+static int get_id_packet(struct iforce *iforce, char *packet)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	int timeout = HZ; /* 1 second */
+
+	switch (iforce->bus) {
+
 #ifdef IFORCE_USB
+		case IFORCE_USB:
+
+			iforce->dr.request = 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;
+			}
+
+			break;
+#endif
+#ifdef IFORCE_232
+		case IFORCE_232:
+
+			iforce->expect_packet = FF_CMD_QUERY;
+			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;
+			}
+
+			break;
+#endif
+	}
+
+	return -(iforce->edata[0] != packet[0]);
+}
 
 static int iforce_open(struct input_dev *dev)
 {
 	struct iforce *iforce = dev->private;
 
-	if (dev->idbus == BUS_USB && !iforce->open++) {
-		iforce->irq.dev = iforce->usbdev;
-		if (usb_submit_urb(&iforce->irq))
-			return -EIO;
+	switch (iforce->bus) {
+#ifdef IFORCE_USB
+		case IFORCE_USB:
+			if (iforce->open++)
+				break;
+			iforce->irq.dev = iforce->usbdev;
+			if (usb_submit_urb(&iforce->irq))
+					return -EIO;
+			break;
+#endif
 	}
-
 	return 0;
 }
 
@@ -128,48 +357,632 @@
 {
 	struct iforce *iforce = dev->private;
 
-	if (dev->idbus == BUS_USB && !--iforce->open)
-		usb_unlink_urb(&iforce->irq);
+	switch (iforce->bus) {
+#ifdef IFORCE_USB
+		case IFORCE_USB:
+			if (!--iforce->open)
+				usb_unlink_urb(&iforce->irq);
+			break;
+#endif
+	}
 }
 
-#endif
+/*
+ * Start or stop playing an effect
+ */
+
+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];
+
+	printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value);
+
+	if (type != EV_FF)
+		return -1;
+
+	switch (code) {
+
+		case FF_GAIN:
+
+			data[0] = value >> 9;
+			send_packet(iforce, FF_CMD_GAIN, data);
+
+			return 0;
+
+		case FF_AUTOCENTER:
+
+			data[0] = 0x03;
+			data[1] = value >> 9;
+			send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+			data[0] = 0x04;
+			data[1] = 0x01;
+			send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+			return 0;
+
+		default: /* Play an effect */
+
+			if (code >= iforce->dev.ff_effects_max)
+				return -1;
+
+			data[0] = LO(code);
+			data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
+			data[2] = LO(value);
+			send_packet(iforce, FF_CMD_PLAY, data);
+
+			return 0;
+	}
+
+	return -1;
+}
+
+/*
+ * 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, __s16 level)
+{
+	unsigned char data[3];
+
+	if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
+		iforce->device_memory.start, iforce->device_memory.end, 2L,
+		NULL, NULL)) {
+		return -ENOMEM;
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+	data[2] = HI(level);
+
+	send_packet(iforce, 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,
+	__s16 magnitude, __s16 offset, u16 period, u16 phase)
+{
+	unsigned char data[7];
+
+	period = TIME_SCALE(period);
+
+	if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
+		iforce->device_memory.start, iforce->device_memory.end, 2L,
+		NULL, NULL)) {
+		return -ENOMEM;
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+
+	data[2] = HI(magnitude);
+	data[3] = HI(offset);
+	data[4] = HI(phase);
+
+	data[5] = LO(period);
+	data[6] = HI(period);
+
+	send_packet(iforce, FF_CMD_PERIOD, data);
+
+	return 0;
+}
+
+/*
+ * Uploads the part of an effect setting the shape of the force
+ */
+
+static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk,
+	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 (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
+		iforce->device_memory.start, iforce->device_memory.end, 2L,
+		NULL, NULL)) {
+		return -ENOMEM;
+	}
+
+	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);
+
+	send_packet(iforce, FF_CMD_SHAPE, data);
+
+	return 0;
+}
+
+/*
+ * Component of spring, friction, inertia... effects
+ */
+
+static int make_interactive_modifier(struct iforce* iforce,
+	struct resource* mod_chunk,
+	__s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center)
+{
+	unsigned char data[10];
+
+	if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
+		iforce->device_memory.start, iforce->device_memory.end, 2L,
+		NULL, NULL)) {
+		return -ENOMEM;
+	}
+
+	data[0] = LO(mod_chunk->start);
+	data[1] = HI(mod_chunk->start);
+
+	data[2] = HI(rk);
+	data[3] = HI(lk);
+
+	data[4] = LO(center);
+	data[5] = HI(center);
+
+	data[6] = LO(db);
+	data[7] = HI(db);
 
-static void iforce_input_setup(struct iforce *iforce)
+	data[8] = HI(rsat);
+	data[9] = HI(lsat);
+
+	send_packet(iforce, FF_CMD_INTERACT, 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;
+}
+
+/*
+ * 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);
+
+	data[3]  = LO(duration);
+	data[4]  = HI(duration);
+
+	data[5]  = HI(direction);
+
+	data[6]  = LO(interval);
+	data[7]  = HI(interval);
 
-	iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-	iforce->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_TOP) | BIT(BTN_THUMB) | BIT(BTN_TOP2) |
-					BIT(BTN_BASE) | BIT(BTN_BASE2) | BIT(BTN_BASE3) | BIT(BTN_BASE4) | BIT(BTN_BASE5);
-	iforce->dev.keybit[LONG(BTN_GAMEPAD)] |= BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C);
-	iforce->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y)
-				| BIT(ABS_WHEEL) | BIT(ABS_GAS) | BIT(ABS_BRAKE);
-
-	for (i = ABS_X; i <= ABS_Y; i++) {
-		iforce->dev.absmax[i] =  1920;
-		iforce->dev.absmin[i] = -1920;
-		iforce->dev.absflat[i] = 128;
-		iforce->dev.absfuzz[i] = 16;
-	}
-
-	for (i = ABS_THROTTLE; i <= ABS_RUDDER; i++) {
-		iforce->dev.absmax[i] = 255;
-		iforce->dev.absmin[i] = 0;
-	}
-
-	for (i = ABS_HAT0X; i <= ABS_HAT0Y; i++) {
-		iforce->dev.absmax[i] =  1;
-		iforce->dev.absmin[i] = -1;
+	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);
+
+	send_packet(iforce, FF_CMD_EFFECT, data);
+
+	return 0;
+}
+
+/*
+ * Upload a periodic effect to the device
+ */
+
+static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect)
+{
+	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 err = 0;
+
+	err = make_period_modifier(iforce, mod1_chunk,
+		effect->u.periodic.magnitude, effect->u.periodic.offset,
+		effect->u.periodic.period, effect->u.periodic.phase);
+	if (err) return err;
+	set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+	err = make_shape_modifier(iforce, mod2_chunk,
+		effect->u.periodic.shape.attack_length,
+		effect->u.periodic.shape.attack_level,
+		effect->u.periodic.shape.fade_length,
+		effect->u.periodic.shape.fade_level);
+	if (err) return 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;
 	}
 
-	iforce->dev.private = iforce;
+	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->u.periodic.direction);
 
-#ifdef IFORCE_USB
+	return err;
+}
+
+/*
+ * Upload a constant force effect
+ */
+static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect)
+{
+	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 err = 0;
+
+	printk(KERN_DEBUG "iforce.c: make constant effect\n");
+
+	err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level);
+	if (err) return err;
+	set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+	err = make_shape_modifier(iforce, mod2_chunk,
+		effect->u.constant.shape.attack_length,
+		effect->u.constant.shape.attack_level,
+		effect->u.constant.shape.fade_length,
+		effect->u.constant.shape.fade_level);
+	if (err) return err;
+	set_bit(FF_MOD2_IS_USED, core_effect->flags);
+
+	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->u.constant.direction);
+
+	return err;
+}
+
+/*
+ * Upload an interactive effect. Those are for example friction, inertia, springs...
+ */
+static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect)
+{
+	int core_id = effect->id;
+	struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+	struct resource* mod_chunk = &(core_effect->mod1_chunk);
+	u8 type, axes;
+	u16 mod1, mod2, direction;
+	int err = 0;
+
+	printk(KERN_DEBUG "iforce.c: make interactive effect\n");
+
+	switch (effect->type) {
+		case FF_SPRING:		type = 0x40; break;
+		case FF_FRICTION:	type = 0x41; break;
+		default: return -1;
+	}
+
+	err = make_interactive_modifier(iforce, mod_chunk,
+		effect->u.interactive.right_saturation,
+		effect->u.interactive.left_saturation,
+		effect->u.interactive.right_coeff,
+		effect->u.interactive.left_coeff,
+		effect->u.interactive.deadband,
+		effect->u.interactive.center);
+	if (err) return err;
+	set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+	switch ((test_bit(ABS_X, &effect->u.interactive.axis) ||
+		test_bit(ABS_WHEEL, &effect->u.interactive.axis)) |
+		(!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) {
+
+		case 0: /* Only one axis, choose orientation */
+			mod1 = mod_chunk->start;
+			mod2 = 0xffff;
+			direction = effect->u.interactive.direction;
+			axes = 0x20;
+			break;
+
+		case 1:	/* Only X axis */
+			mod1 = mod_chunk->start;
+			mod2 = 0xffff;
+			direction = 0x5a00;
+			axes = 0x40;
+			break;
+
+		case 2: /* Only Y axis */
+			mod1 = 0xffff;
+			mod2 = mod_chunk->start;
+			direction = 0xb400;
+			axes = 0x80;
+			break;
+
+		case 3:	/* Both X and Y axes */
+			/* TODO: same setting for both axes is not mandatory */
+			mod1 = mod_chunk->start;
+			mod2 = mod_chunk->start;
+			direction = 0x6000;
+			axes = 0xc0;
+			break;
+
+		default:
+			return -1;
+	}
+
+	err = make_core(iforce, effect->id,
+		mod1, mod2,
+		type, axes,
+		effect->replay.length, effect->replay.delay,
+		effect->trigger.button, effect->trigger.interval,
+		direction);
+
+	return err;
+}
+
+/*
+ * 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;
+
+	printk(KERN_DEBUG "iforce.c: upload effect\n");
+
+/*
+ * Get a free id
+ */
+
+	for (id=0; id < FF_EFFECTS_MAX; ++id)
+		if (!test_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;
+	set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags);
+
+/*
+ * Upload the effect
+ */
+
+	switch (effect->type) {
+
+		case FF_PERIODIC:
+			return iforce_upload_periodic(iforce, effect);
+
+		case FF_CONSTANT:
+			return iforce_upload_constant(iforce, effect);
+
+		case FF_SPRING:
+		case FF_FRICTION:
+			return iforce_upload_interactive(iforce, effect);
+
+		default:
+			return -1;
+	}
+}
+
+/*
+ * 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;
+
+	printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id);
+
+	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_init_device(struct iforce *iforce)
+{
+	unsigned char c[] = "CEOV";
+	int i;
+
+	init_waitqueue_head(&iforce->wait);
+	iforce->dev.ff_effects_max = 10;
+
+/*
+ * Input device fields.
+ */
+
+	iforce->dev.idbus = BUS_USB;
+	iforce->dev.private = iforce;
+	iforce->dev.name = iforce->name;
 	iforce->dev.open = iforce_open;
 	iforce->dev.close = iforce_close;
-#endif
+	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 (!get_id_packet(iforce, "O"))
+			break;
+
+	if (i == 20) { /* 5 seconds */
+		printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n");
+		iforce_close(&iforce->dev);
+		return -1;
+	}
+
+/*
+ * Get device info.
+ */
+
+	if (!get_id_packet(iforce, "M"))
+		iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1];
+	if (!get_id_packet(iforce, "P"))
+		iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1];
+	if (!get_id_packet(iforce, "B"))
+		iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
+	if (!get_id_packet(iforce, "N"))
+		iforce->dev.ff_effects_max = iforce->edata[1];
+
+/*
+ * Display additional info.
+ */
+
+	for (i = 0; c[i]; i++)
+		if (!get_id_packet(iforce, c + i))
+			dump_packet("info", iforce->ecmd, iforce->edata);
+
+/*
+ * Disable spring, enable force feedback.
+ * FIXME: We should use iforce_set_autocenter() et al here.
+ */
+
+	send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000");
+	send_packet(iforce, FF_CMD_ENABLE, "\004");
+
+/*
+ * 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;
+
+	sprintf(iforce->name, iforce->type->name,
+		iforce->dev.idproduct, iforce->dev.idvendor);
+
+/*
+ * Set input device bitfields and ranges.
+ */
+
+	iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF);
+
+	for (i = 0; iforce->type->btn[i] >= 0; i++) {
+		signed short t = iforce->type->btn[i];
+		set_bit(t, iforce->dev.keybit);
+		if (t != BTN_DEAD)
+			set_bit(FF_BTN(t), iforce->dev.ffbit);
+	}
+
+	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:
+
+				iforce->dev.absmax[t] =  1920;
+				iforce->dev.absmin[t] = -1920;
+				iforce->dev.absflat[t] = 128;
+				iforce->dev.absfuzz[t] = 16;
+
+				set_bit(FF_ABS(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_HAT0X:
+			case ABS_HAT0Y:
+				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);
+
+	return 0;
 }
 
 #ifdef IFORCE_USB
@@ -178,33 +991,63 @@
 {
 	struct iforce *iforce = urb->context;
 	if (urb->status) return;
-	iforce_process_packet(&iforce->dev, iforce->data[0], 8, iforce->data + 1);
+	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) return;
+	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)
+				const struct usb_device_id *id)
 {
-	struct usb_endpoint_descriptor *endpoint;
+	struct usb_endpoint_descriptor *epirq, *epout;
 	struct iforce *iforce;
 
-	endpoint = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+	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), GFP_KERNEL))) return NULL;
+	if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
 	memset(iforce, 0, sizeof(struct iforce));
 
-	iforce->dev.name = iforce_name;
-	iforce->dev.idbus = BUS_USB;
-	iforce->dev.idvendor = dev->descriptor.idVendor;
-	iforce->dev.idproduct = dev->descriptor.idProduct;
-	iforce->dev.idversion = dev->descriptor.bcdDevice;
+	iforce->bus = IFORCE_USB;
+	iforce->usbdev = dev;
+
+	iforce->dr.requesttype = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
+	iforce->dr.index = 0;
+	iforce->dr.length = 16;
+
+	FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
+			iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
 
-	FILL_INT_URB(&iforce->irq, dev, usb_rcvintpipe(dev, endpoint->bEndpointAddress),
-			iforce->data, 8, iforce_usb_irq, iforce, endpoint->bInterval);
+	FILL_BULK_URB(&iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
+			iforce + 1, 32, iforce_usb_out, iforce);
 
-	iforce_input_setup(iforce);
+	FILL_CONTROL_URB(&iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
+			(void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
 
-	printk(KERN_INFO "input%d: %s on usb%d:%d.%d\n",
-		 iforce->dev.number, iforce_name, dev->bus->busnum, dev->devnum, ifnum);
+	if (iforce_init_device(iforce)) {
+		kfree(iforce);
+		return NULL;
+	}
+
+	printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n",
+		iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
+		iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum);
 
 	return iforce;
 }
@@ -218,8 +1061,12 @@
 }
 
 static struct usb_device_id iforce_usb_ids [] = {
-	{ USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WMFORCE) },
-	{ }						/* Terminating entry */
+	{ 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(0x06f8, 0x0001) },		/* Guillemot Race Leader Force Feedback */
+	{ }					/* Terminating entry */
 };
 
 MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
@@ -237,7 +1084,7 @@
 
 static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
 {
-        struct iforce* iforce = serio->private;
+	struct iforce* iforce = serio->private;
 
 	if (!iforce->pkt) {
 		if (data != 0x2b) {
@@ -247,14 +1094,14 @@
 		return;
 	}
 
-        if (!iforce->id) {
-		if (data > 3) {
+	if (!iforce->id) {
+		if (data > 3 && data != 0xff) {
 			iforce->pkt = 0;
 			return;
 		}
-                iforce->id = data;
+		iforce->id = data;
 		return;
-        }
+	}
 
 	if (!iforce->len) {
 		if (data > IFORCE_MAX_LENGTH) {
@@ -266,37 +1113,32 @@
 		return;
 	}
 
-        if (iforce->idx < iforce->len) {
-                iforce->csum += iforce->data[iforce->idx++] = data;
+	if (iforce->idx < iforce->len) {
+		iforce->csum += iforce->data[iforce->idx++] = data;
 		return;
 	}
 
-        if (iforce->idx == iforce->len) {
-		iforce_process_packet(&iforce->dev, iforce->id, iforce->idx, iforce->data);
+	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->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->dev.name = iforce_name;
-	iforce->dev.idbus = BUS_RS232;
-	iforce->dev.idvendor = SERIO_IFORCE;
-	iforce->dev.idproduct = 0x0001;
-	iforce->dev.idversion = 0x0100;
-
+	iforce->bus = IFORCE_232;
+	iforce->serio = serio;
 	serio->private = iforce;
 
 	if (serio_open(serio, dev)) {
@@ -304,15 +1146,21 @@
 		return;
 	}
 
-	iforce_input_setup(iforce);
+	if (iforce_init_device(iforce)) {
+		serio_close(serio);
+		kfree(iforce);
+		return;
+	}
 
-	printk(KERN_INFO "input%d: %s on serio%d\n",
-		 iforce->dev.number, iforce_name, serio->number);
+	printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n",
+		iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
+		iforce->device_memory.end, serio->number);
 }
 
 static void iforce_serio_disconnect(struct serio *serio)
 {
 	struct iforce* iforce = serio->private;
+
 	input_unregister_device(&iforce->dev);
 	serio_close(serio);
 	kfree(iforce);
diff -urN linux-2.4.10-pre8/drivers/char/joystick/interact.c linux/drivers/char/joystick/interact.c
--- linux-2.4.10-pre8/drivers/char/joystick/interact.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/interact.c	Mon Dec  3 23:09:48 2001
@@ -304,3 +304,5 @@
 
 module_init(interact_init);
 module_exit(interact_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/lightning.c linux/drivers/char/joystick/lightning.c
--- linux-2.4.10-pre8/drivers/char/joystick/lightning.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/lightning.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: lightning.c,v 1.7 2000/05/24 19:36:03 vojtech Exp $
+ * $Id: lightning.c,v 1.13 2001/04/26 10:24:46 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  *
  *  Sponsored by SuSE
  */
@@ -52,6 +52,7 @@
 #define L4_TIMEOUT		80	/* 80 us */
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
 
 struct l4 {
 	struct gameport gameport;
@@ -76,7 +77,7 @@
 
 static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->private;
 	unsigned char status;
 	int i, result = -1;
 
@@ -109,7 +110,7 @@
 
 static int l4_open(struct gameport *gameport, int mode)
 {
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->private;
         if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
 		return -1;
 	outb(L4_SELECT_ANALOG, L4_PORT);
@@ -187,7 +188,7 @@
 {
 	int i, t;
 	int cal[4];
-	struct l4 *l4 = gameport->driver;
+	struct l4 *l4 = gameport->private;
 
 	if (l4_getcal(l4->port, cal))
 		return -1;
@@ -247,16 +248,13 @@
 			l4->port = i * 4 + j;
 
 			gameport = &l4->gameport;
-			gameport->driver = l4;
+			gameport->private = l4;
 			gameport->open = l4_open;
 			gameport->cooked_read = l4_cooked_read;
 			gameport->calibrate = l4_calibrate;
-			gameport->type = GAMEPORT_EXT;
 
-			if (!i && !j) {
+			if (!i && !j)
 				gameport->io = L4_PORT;
-				gameport->size = 1;
-			}
 
 			if (rev > 0x28)		/* on 2.9+ the setcal command works correctly */
 				l4_setcal(l4->port, cal);
diff -urN linux-2.4.10-pre8/drivers/char/joystick/magellan.c linux/drivers/char/joystick/magellan.c
--- linux-2.4.10-pre8/drivers/char/joystick/magellan.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/magellan.c	Mon Dec  3 23:09:48 2001
@@ -208,3 +208,5 @@
 
 module_init(magellan_init);
 module_exit(magellan_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/ns558.c linux/drivers/char/joystick/ns558.c
--- linux-2.4.10-pre8/drivers/char/joystick/ns558.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/ns558.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: ns558.c,v 1.27 2001/03/28 09:25:05 vojtech Exp $
+ * $Id: ns558.c,v 1.29 2001/04/24 07:48:56 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *  Copyright (c) 1999 Brian Gerst
  *
  *  Sponsored by SuSE
@@ -42,23 +42,23 @@
 #include <linux/isapnp.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
 
 #define NS558_ISA	1
 #define NS558_PNP	2
-#define NS558_PCI	3
 
 static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
 				    0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
 
 struct ns558 {
 	int type;
+	int size;
 	struct pci_dev *dev;
 	struct ns558 *next;
 	struct gameport gameport;
 };
 	
 static struct ns558 *ns558;
-static int ns558_pci;
 
 /*
  * ns558_isa_probe() tries to find an isa gameport at the
@@ -132,122 +132,43 @@
 	i--;
 
 	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
-		printk(KERN_ERR "Memory allocation failed.\n");
+		printk(KERN_ERR "ns558: Memory allocation failed.\n");
 		return next;
 	}
        	memset(port, 0, sizeof(struct ns558));
 	
 	port->next = next;
 	port->type = NS558_ISA;
+	port->size = (1 << i);
 	port->gameport.io = io & (-1 << i);
-	port->gameport.size = (1 << i);
 
-	request_region(port->gameport.io, port->gameport.size, "ns558-isa");
+	request_region(port->gameport.io, (1 << i), "ns558-isa");
 
 	gameport_register_port(&port->gameport);
 
 	printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
-	if (port->gameport.size > 1) printk(" size %d", port->gameport.size);
+	if (port->size > 1) printk(" size %d", port->size);
 	printk(" speed %d kHz\n", port->gameport.speed);
 
 	return port;
 }
 
-#ifdef CONFIG_PCI
-static struct pci_device_id ns558_pci_tbl[] __devinitdata = {
-	{ 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB Live! gameport */
-	{ 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, /* ESS Solo 1 */
-	{ 0x5333, 0xca00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, /* S3 SonicVibes */
-	{ 0, }
-};
-MODULE_DEVICE_TABLE(pci, ns558_pci_tbl);
-
-static int __devinit ns558_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
-	int ioport, iolen;
-	int rc;
-	struct ns558 *port;
-        
-	rc = pci_enable_device(pdev);
-	if (rc) {
-		printk(KERN_ERR "ns558: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
-			pdev->bus->number, pdev->devfn, rc);
-		return rc;
-	}
-
-	ioport = pci_resource_start(pdev, ent->driver_data);
-	iolen = pci_resource_len(pdev, ent->driver_data);
-
-	if (!request_region(ioport, iolen, "ns558-pci"))
-		return -EBUSY;
-
-	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
-		printk(KERN_ERR "Memory allocation failed.\n");
-		release_region(ioport, iolen);
-		return -ENOMEM;
-	}
-	memset(port, 0, sizeof(struct ns558));
-
-	port->type = NS558_PCI;
-	port->gameport.io = ioport;
-	port->gameport.size = iolen;
-	port->dev = pdev;
-
-	pdev->driver_data = port;
-
-	gameport_register_port(&port->gameport);
-
-	printk(KERN_INFO "gameport%d: NS558 PCI at %#x", port->gameport.number, port->gameport.io);
-	if (port->gameport.size > 1) printk(" size %d", port->gameport.size);
-	printk(" speed %d kHz\n", port->gameport.speed);
-
-	return 0;
-}
-
-static void __devexit ns558_pci_remove(struct pci_dev *pdev)
-{
-	struct ns558 *port = (struct ns558 *)pdev->driver_data;
-	release_region(port->gameport.io, port->gameport.size);
-	kfree(port);
-}
-
-static struct pci_driver ns558_pci_driver = {
-        name:           "PCI Gameport",
-        id_table:       ns558_pci_tbl,
-        probe:          ns558_pci_probe,
-        remove:         ns558_pci_remove,
-};
-#else
-static struct pci_driver ns558_pci_driver;
-#endif /* CONFIG_PCI */
-
-
 #if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
 #define NSS558_ISAPNP
 #endif
 
 #ifdef NSS558_ISAPNP
-/*
- * PnP IDs:
- *
- * @P@0001 - ALS 100 (no comp. ID)
- * CTL00c1 - SB AWE32 PnP
- * CTL00c3 - SB AWE64 PnP
- * CTL00f0 - SB16 PnP / Vibra 16x
- * CTL7001 - SB Vibra16C PnP (no comp. ID)
- * CTL7002 - SB AWE32 (no comp. ID)
- * CSC0b35 - Crystal (no comp. ID)
- * TER1141 - Terratec AD1818
- * YMM0800 - Yamaha OPL3-SA3
- *
- * PNPb02f - Generic gameport
- */
 
 static struct isapnp_device_id pnp_devids[] = {
 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x2001), 0 },
 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 },
 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
+	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
 	{ ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 },
 	{ 0, },
 };
@@ -263,12 +184,12 @@
 		return next;
 
 	if (!(dev->resource[0].flags & IORESOURCE_IO)) {
-		printk(KERN_WARNING "No i/o ports on a gameport? Weird\n");
+		printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
 		return next;
 	}
 
 	if (dev->activate && dev->activate(dev) < 0) {
-		printk(KERN_ERR "PnP resource allocation failed\n");
+		printk(KERN_ERR "ns558: PnP resource allocation failed\n");
 		return next;
 	}
 	
@@ -279,7 +200,7 @@
 		goto deactivate;
 
 	if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
-		printk(KERN_ERR "Memory allocation failed.\n");
+		printk(KERN_ERR "ns558: Memory allocation failed.\n");
 		goto deactivate;
 	}
 	memset(port, 0, sizeof(struct ns558));
@@ -287,13 +208,13 @@
 	port->next = next;
 	port->type = NS558_PNP;
 	port->gameport.io = ioport;
-	port->gameport.size = iolen;
+	port->size = iolen;
 	port->dev = dev;
 
 	gameport_register_port(&port->gameport);
 
 	printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io);
-	if (port->gameport.size > 1) printk(" size %d", port->gameport.size);
+	if (iolen > 1) printk(" size %d", iolen);
 	printk(" speed %d kHz\n", port->gameport.speed);
 
 	return port;
@@ -309,18 +230,11 @@
 {
 	int i = 0;
 #ifdef NSS558_ISAPNP
-	struct pci_dev *dev = NULL;
 	struct isapnp_device_id *devid;
+	struct pci_dev *dev = NULL;
 #endif
 
 /*
- * Probe for PCI ports.  Always probe for PCI first,
- * it is the least-invasive probe.
- */
-
-	ns558_pci = !pci_module_init(&ns558_pci_driver);
-
-/*
  * Probe for ISA ports.
  */
 
@@ -339,7 +253,7 @@
 	}
 #endif
 
-	return (ns558 || ns558_pci) ? 0 : -ENODEV;
+	return ns558 ? 0 : -ENODEV;
 }
 
 void __exit ns558_exit(void)
@@ -358,7 +272,7 @@
 #endif
 
 			case NS558_ISA:
-				release_region(port->gameport.io, port->gameport.size);
+				release_region(port->gameport.io, port->size);
 				break;
 		
 			default:
@@ -369,9 +283,6 @@
 		kfree(port);
 		port = next;
 	}
-
-	if (ns558_pci)
-		pci_unregister_driver(&ns558_pci_driver);
 }
 
 module_init(ns558_init);
diff -urN linux-2.4.10-pre8/drivers/char/joystick/pcigame.c linux/drivers/char/joystick/pcigame.c
--- linux-2.4.10-pre8/drivers/char/joystick/pcigame.c	Fri Sep 22 14:21:17 2000
+++ linux/drivers/char/joystick/pcigame.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: pcigame.c,v 1.6 2000/05/25 12:05:24 vojtech Exp $
+ * $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $
  *
- *  Copyright (c) 2000 Vojtech Pavlik
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
  *  Based on the work of:
  *	Raymond Ingles
@@ -76,19 +76,19 @@
 
 static unsigned char pcigame_read(struct gameport *gameport)
 {
-	struct pcigame *pcigame = gameport->driver;
+	struct pcigame *pcigame = gameport->private;
 	return readb(pcigame->base + pcigame->data->legacy);
 }
 
 static void pcigame_trigger(struct gameport *gameport)
 {
-	struct pcigame *pcigame = gameport->driver;
+	struct pcigame *pcigame = gameport->private;
 	writeb(0xff, pcigame->base + pcigame->data->legacy);
 }
 
 static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
 {
-        struct pcigame *pcigame = gameport->driver;
+        struct pcigame *pcigame = gameport->private;
 	int i;
 
 	*buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf;
@@ -103,7 +103,7 @@
 
 static int pcigame_open(struct gameport *gameport, int mode)
 {
-	struct pcigame *pcigame = gameport->driver;
+	struct pcigame *pcigame = gameport->private;
 
 	switch (mode) {
 		case GAMEPORT_MODE_COOKED:
@@ -135,8 +135,7 @@
 	pcigame->dev = dev;
 	dev->driver_data = pcigame;
 
-	pcigame->gameport.driver = pcigame;
-	pcigame->gameport.type = GAMEPORT_EXT;
+	pcigame->gameport.private = pcigame;
 	pcigame->gameport.fuzz = 64;
 	
 	pcigame->gameport.read = pcigame_read;
@@ -196,3 +195,5 @@
 
 module_init(pcigame_init);
 module_exit(pcigame_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/serio.c linux/drivers/char/joystick/serio.c
--- linux-2.4.10-pre8/drivers/char/joystick/serio.c	Mon Oct 16 12:58:51 2000
+++ linux/drivers/char/joystick/serio.c	Mon Dec  3 23:09:48 2001
@@ -35,6 +35,7 @@
 #include <linux/serio.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(serio_register_port);
 EXPORT_SYMBOL(serio_unregister_port);
diff -urN linux-2.4.10-pre8/drivers/char/joystick/serport.c linux/drivers/char/joystick/serport.c
--- linux-2.4.10-pre8/drivers/char/joystick/serport.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/serport.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: serport.c,v 1.4 2000/05/29 10:54:53 vojtech Exp $
+ * $Id: serport.c,v 1.7 2001/05/25 19:00:27 jdeneux Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Sponsored by SuSE
  */
@@ -148,7 +148,11 @@
 	DECLARE_WAITQUEUE(wait, current);
 	char name[32];
 
+#ifdef CONFIG_DEVFS_FS
 	sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+#else
+	sprintf(name, "%s%d", tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+#endif
 
 	serio_register_port(&serport->serio);
 
@@ -218,3 +222,5 @@
 
 module_init(serport_init);
 module_exit(serport_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/sidewinder.c linux/drivers/char/joystick/sidewinder.c
--- linux-2.4.10-pre8/drivers/char/joystick/sidewinder.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/sidewinder.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: sidewinder.c,v 1.18 2001/02/28 07:09:30 vojtech Exp $
+ * $Id: sidewinder.c,v 1.20 2001/05/19 08:14:54 vojtech Exp $
  *
- *  Copyright (c) 1998-2000 Vojtech Pavlik
+ *  Copyright (c) 1998-2001 Vojtech Pavlik
  *
  *  Sponsored by SuSE
  */
@@ -582,6 +582,9 @@
 	if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
 		goto fail1;
 
+	dbg("Init 0: Opened gameport %d, io %#x, speed %d",
+		gameport->number, gameport->io, gameport->speed);
+
 	i = sw_read_packet(gameport, buf, SW_LENGTH, 0);		/* Read normal packet */
 	m |= sw_guess_mode(buf, i);					/* Data packet (1-bit) can carry mode info [FSP] */
 	udelay(SW_TIMEOUT);
@@ -754,3 +757,5 @@
 
 module_init(sw_init);
 module_exit(sw_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/spaceball.c linux/drivers/char/joystick/spaceball.c
--- linux-2.4.10-pre8/drivers/char/joystick/spaceball.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/spaceball.c	Mon Dec  3 23:09:48 2001
@@ -234,3 +234,5 @@
 
 module_init(spaceball_init);
 module_exit(spaceball_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/spaceorb.c linux/drivers/char/joystick/spaceorb.c
--- linux-2.4.10-pre8/drivers/char/joystick/spaceorb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/spaceorb.c	Mon Dec  3 23:09:48 2001
@@ -223,3 +223,5 @@
 
 module_init(spaceorb_init);
 module_exit(spaceorb_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/stinger.c linux/drivers/char/joystick/stinger.c
--- linux-2.4.10-pre8/drivers/char/joystick/stinger.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/stinger.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: stinger.c,v 1.1 2000/07/17 10:42:14 vojtech Exp $
+ * $Id: stinger.c,v 1.4 2001/05/23 09:25:02 vojtech Exp $
  *
- *  Copyright (c) 2000 Vojtech Pavlik
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
  *  Copyright (c) 2000 Mark Fletcher
  *
  *  Sponsored by SuSE
@@ -79,8 +79,8 @@
 	input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1));
 	input_report_key(dev, BTN_START,   (data[3] & 0x01));
 
-	input_report_abs(dev, ABS_X, ((data[1] & 0x3F) - ((data[0] & 0x01) << 6)));
-	input_report_abs(dev, ABS_Y, ((data[2] & 0x3F) - ((data[0] & 0x02) << 5)));
+	input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6));
+	input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F));
 
 	return;
 }
@@ -198,3 +198,5 @@
 
 module_init(stinger_init);
 module_exit(stinger_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/tmdc.c linux/drivers/char/joystick/tmdc.c
--- linux-2.4.10-pre8/drivers/char/joystick/tmdc.c	Wed Apr 11 19:02:30 2001
+++ linux/drivers/char/joystick/tmdc.c	Mon Dec  3 23:09:48 2001
@@ -374,3 +374,5 @@
 
 module_init(tmdc_init);
 module_exit(tmdc_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/turbografx.c linux/drivers/char/joystick/turbografx.c
--- linux-2.4.10-pre8/drivers/char/joystick/turbografx.c	Wed Jun 21 08:22:21 2000
+++ linux/drivers/char/joystick/turbografx.c	Mon Dec  3 23:09:48 2001
@@ -40,6 +40,7 @@
 #include <linux/init.h>
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
 MODULE_PARM(tgfx, "2-8i");
 MODULE_PARM(tgfx_2, "2-8i");
 MODULE_PARM(tgfx_3, "2-8i");
diff -urN linux-2.4.10-pre8/drivers/char/joystick/warrior.c linux/drivers/char/joystick/warrior.c
--- linux-2.4.10-pre8/drivers/char/joystick/warrior.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/char/joystick/warrior.c	Mon Dec  3 23:09:48 2001
@@ -210,3 +210,5 @@
 
 module_init(warrior_init);
 module_exit(warrior_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/logibusmouse.c linux/drivers/char/logibusmouse.c
--- linux-2.4.10-pre8/drivers/char/logibusmouse.c	Mon Jun 19 13:25:06 2000
+++ linux/drivers/char/logibusmouse.c	Mon Dec  3 23:09:48 2001
@@ -158,3 +158,6 @@
 
 module_init(logi_busmouse_init);
 module_exit(logi_busmouse_cleanup);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/lp.c linux/drivers/char/lp.c
--- linux-2.4.10-pre8/drivers/char/lp.c	Sun Aug 12 12:31:28 2001
+++ linux/drivers/char/lp.c	Mon Dec  3 23:09:48 2001
@@ -838,3 +838,6 @@
 __setup("lp=", lp_setup);
 module_init(lp_init_module);
 module_exit(lp_cleanup_module);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/machzwd.c linux/drivers/char/machzwd.c
--- linux-2.4.10-pre8/drivers/char/machzwd.c	Wed Jul  4 14:41:33 2001
+++ linux/drivers/char/machzwd.c	Mon Dec  3 23:09:48 2001
@@ -36,7 +36,7 @@
 #include <linux/sched.h>
 #include <linux/miscdevice.h>
 #include <linux/watchdog.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/fcntl.h>
 #include <linux/smp_lock.h>
@@ -99,6 +99,7 @@
 
 MODULE_AUTHOR("Fernando Fuganti <fuganti@conectiva.com.br>");
 MODULE_DESCRIPTION("MachZ ZF-Logic Watchdog driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(action, "i");
 MODULE_PARM_DESC(action, "after watchdog resets, generate: 0 = RESET(*)  1 = SMI  2 = NMI  3 = SCI");
 
diff -urN linux-2.4.10-pre8/drivers/char/mixcomwd.c linux/drivers/char/mixcomwd.c
--- linux-2.4.10-pre8/drivers/char/mixcomwd.c	Tue May 22 10:23:16 2001
+++ linux/drivers/char/mixcomwd.c	Mon Dec  3 23:09:48 2001
@@ -269,3 +269,6 @@
 
 module_init(mixcomwd_init);
 module_exit(mixcomwd_exit);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/msbusmouse.c linux/drivers/char/msbusmouse.c
--- linux-2.4.10-pre8/drivers/char/msbusmouse.c	Mon Jun 19 13:25:06 2000
+++ linux/drivers/char/msbusmouse.c	Mon Dec  3 23:09:48 2001
@@ -167,3 +167,6 @@
 
 module_init(ms_bus_mouse_init)
 module_exit(ms_bus_mouse_exit)
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/mxser.c linux/drivers/char/mxser.c
--- linux-2.4.10-pre8/drivers/char/mxser.c	Mon Aug  6 10:33:27 2001
+++ linux/drivers/char/mxser.c	Mon Dec  3 23:09:48 2001
@@ -180,10 +180,13 @@
 
 MODULE_AUTHOR("William Chen");
 MODULE_DESCRIPTION("MOXA Smartio Family Multiport Board Device Driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(ioaddr, "1-4i");
 MODULE_PARM(ttymajor, "i");
 MODULE_PARM(calloutmajor, "i");
 MODULE_PARM(verbose, "i");
+
+EXPORT_NO_SYMBOLS;
 
 struct mxser_hwconf {
 	int board_type;
diff -urN linux-2.4.10-pre8/drivers/char/n_hdlc.c linux/drivers/char/n_hdlc.c
--- linux-2.4.10-pre8/drivers/char/n_hdlc.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/n_hdlc.c	Mon Dec  3 23:09:48 2001
@@ -1031,3 +1031,6 @@
 
 module_init(n_hdlc_init);
 module_exit(n_hdlc_exit);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/n_r3964.c linux/drivers/char/n_r3964.c
--- linux-2.4.10-pre8/drivers/char/n_r3964.c	Thu Aug 16 09:49:49 2001
+++ linux/drivers/char/n_r3964.c	Mon Dec  3 23:09:48 2001
@@ -1473,3 +1473,7 @@
    return -1;
 }
 
+
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/nvram.c linux/drivers/char/nvram.c
--- linux-2.4.10-pre8/drivers/char/nvram.c	Sun Aug  5 13:12:40 2001
+++ linux/drivers/char/nvram.c	Mon Dec  3 23:09:48 2001
@@ -695,9 +695,14 @@
 
 #endif /* MACH == ATARI */
 
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
+
 /*
  * Local variables:
  *  c-indent-level: 4
  *  tab-width: 4
  * End:
  */
+
diff -urN linux-2.4.10-pre8/drivers/char/nwflash.c linux/drivers/char/nwflash.c
--- linux-2.4.10-pre8/drivers/char/nwflash.c	Wed Jun 27 14:12:04 2001
+++ linux/drivers/char/nwflash.c	Mon Dec  3 23:09:48 2001
@@ -688,6 +688,8 @@
 
 EXPORT_NO_SYMBOLS;
 
+MODULE_LICENSE("GPL");
+
 MODULE_PARM(flashdebug, "i");
 
 module_init(nwflash_init);
diff -urN linux-2.4.10-pre8/drivers/char/pcmcia/serial_cs.c linux/drivers/char/pcmcia/serial_cs.c
--- linux-2.4.10-pre8/drivers/char/pcmcia/serial_cs.c	Sun Aug 12 11:14:00 2001
+++ linux/drivers/char/pcmcia/serial_cs.c	Mon Dec  3 23:09:48 2001
@@ -663,3 +663,5 @@
 
 module_init(init_serial_cs);
 module_exit(exit_serial_cs);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/pcwd.c linux/drivers/char/pcwd.c
--- linux-2.4.10-pre8/drivers/char/pcwd.c	Thu May 24 15:14:08 2001
+++ linux/drivers/char/pcwd.c	Mon Dec  3 23:09:48 2001
@@ -656,3 +656,7 @@
 
 module_init(pcwatchdog_init);
 module_exit(pcwatchdog_exit);
+
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/pcxx.c linux/drivers/char/pcxx.c
--- linux-2.4.10-pre8/drivers/char/pcxx.c	Tue May 22 10:23:16 2001
+++ linux/drivers/char/pcxx.c	Mon Dec  3 23:09:48 2001
@@ -113,6 +113,7 @@
 # if (LINUX_VERSION_CODE > 0x020111)
 MODULE_AUTHOR("Bernhard Kaindl");
 MODULE_DESCRIPTION("Digiboard PC/X{i,e,eve} driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(verbose,     "i");
 MODULE_PARM(debug,       "i");
 MODULE_PARM(io,          "1-4i");
diff -urN linux-2.4.10-pre8/drivers/char/ppdev.c linux/drivers/char/ppdev.c
--- linux-2.4.10-pre8/drivers/char/ppdev.c	Mon Dec  3 23:09:37 2001
+++ linux/drivers/char/ppdev.c	Mon Dec  3 23:09:48 2001
@@ -754,3 +754,7 @@
 
 module_init(ppdev_init);
 module_exit(ppdev_cleanup);
+
+MODULE_LICENSE("GPL");
+
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/riscom8.c linux/drivers/char/riscom8.c
--- linux-2.4.10-pre8/drivers/char/riscom8.c	Mon Aug  6 16:24:33 2001
+++ linux/drivers/char/riscom8.c	Mon Dec  3 23:09:48 2001
@@ -1906,6 +1906,8 @@
 MODULE_PARM(iobase1, "i");
 MODULE_PARM(iobase2, "i");
 MODULE_PARM(iobase3, "i");
+
+MODULE_LICENSE("GPL");
 #endif /* MODULE */
 
 /*
diff -urN linux-2.4.10-pre8/drivers/char/rocket.c linux/drivers/char/rocket.c
--- linux-2.4.10-pre8/drivers/char/rocket.c	Mon Jul  2 13:56:41 2001
+++ linux/drivers/char/rocket.c	Mon Dec  3 23:09:48 2001
@@ -157,6 +157,7 @@
 #if ((LINUX_VERSION_CODE > 0x020111) && defined(MODULE))
 MODULE_AUTHOR("Theodore Ts'o");
 MODULE_DESCRIPTION("Comtrol Rocketport driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(board1,     "i");
 MODULE_PARM_DESC(board1, "I/O port for (ISA) board #1");
 MODULE_PARM(board2,     "i");
diff -urN linux-2.4.10-pre8/drivers/char/sbc60xxwdt.c linux/drivers/char/sbc60xxwdt.c
--- linux-2.4.10-pre8/drivers/char/sbc60xxwdt.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/char/sbc60xxwdt.c	Mon Dec  3 23:09:48 2001
@@ -340,3 +340,6 @@
 
 module_init(sbc60xxwdt_init);
 module_exit(sbc60xxwdt_unload);
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/ser_a2232.c linux/drivers/char/ser_a2232.c
--- linux-2.4.10-pre8/drivers/char/ser_a2232.c	Wed Jul  4 14:41:33 2001
+++ linux/drivers/char/ser_a2232.c	Mon Dec  3 23:09:48 2001
@@ -878,3 +878,7 @@
 }
 #endif
 /***************************** End of Functions *********************/
+
+MODULE_AUTHOR("Enver Haase");
+MODULE_DESCRIPTION("Amiga A2232 multi-serial board driver");
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/serial.c linux/drivers/char/serial.c
--- linux-2.4.10-pre8/drivers/char/serial.c	Mon Aug 13 16:37:33 2001
+++ linux/drivers/char/serial.c	Mon Dec  3 23:09:48 2001
@@ -5719,6 +5719,7 @@
 module_exit(rs_fini);
 MODULE_DESCRIPTION("Standard/generic (dumb) serial driver");
 MODULE_AUTHOR("Theodore Ts'o <tytso@mit.edu>");
+MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.4.10-pre8/drivers/char/serial167.c linux/drivers/char/serial167.c
--- linux-2.4.10-pre8/drivers/char/serial167.c	Wed May 16 10:31:27 2001
+++ linux/drivers/char/serial167.c	Mon Dec  3 23:09:48 2001
@@ -3084,3 +3084,5 @@
 } /* debug_setup */
 
 #endif
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/serial_21285.c linux/drivers/char/serial_21285.c
--- linux-2.4.10-pre8/drivers/char/serial_21285.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/serial_21285.c	Mon Dec  3 23:09:48 2001
@@ -505,3 +505,6 @@
 }
 
 #endif	/* CONFIG_SERIAL_21285_CONSOLE */
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/serial_amba.c linux/drivers/char/serial_amba.c
--- linux-2.4.10-pre8/drivers/char/serial_amba.c	Fri Feb  9 11:30:22 2001
+++ linux/drivers/char/serial_amba.c	Mon Dec  3 23:09:48 2001
@@ -2027,3 +2027,6 @@
 }
 
 #endif /* CONFIG_SERIAL_AMBA_CONSOLE */
+
+MODULE_LICENSE("GPL");
+EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/char/specialix.c linux/drivers/char/specialix.c
--- linux-2.4.10-pre8/drivers/char/specialix.c	Wed May 16 10:31:27 2001
+++ linux/drivers/char/specialix.c	Mon Dec  3 23:09:48 2001
@@ -2440,3 +2440,5 @@
 	
 }
 #endif /* MODULE */
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/char/stallion.c linux/drivers/char/stallion.c
--- linux-2.4.10-pre8/drivers/char/stallion.c	Fri Mar  2 11:12:07 2001
+++ linux/drivers/char/stallion.c	Mon Dec  3 23:09:48 2001
@@ -314,6 +314,7 @@
  */
 MODULE_AUTHOR("Greg Ungerer");
 MODULE_DESCRIPTION("Stallion Multiport Serial Driver");
+MODULE_LICENSE("GPL");
 
 MODULE_PARM(board0, "1-4s");
 MODULE_PARM_DESC(board0, "Board 0 config -> name[,ioaddr[,ioaddr2][,irq]]");
diff -urN linux-2.4.10-pre8/drivers/char/synclink.c linux/drivers/char/synclink.c
--- linux-2.4.10-pre8/drivers/char/synclink.c	Wed Jul 25 14:12:02 2001
+++ linux/drivers/char/synclink.c	Mon Dec  3 23:09:48 2001
@@ -934,6 +934,8 @@
 };
 MODULE_DEVICE_TABLE(pci, synclink_pci_tbl);
 
+MODULE_LICENSE("GPL");
+
 static struct pci_driver synclink_pci_driver = {
 	name:		"synclink",
 	id_table:	synclink_pci_tbl,
diff -urN linux-2.4.10-pre8/drivers/char/toshiba.c linux/drivers/char/toshiba.c
--- linux-2.4.10-pre8/drivers/char/toshiba.c	Fri Apr  6 10:42:55 2001
+++ linux/drivers/char/toshiba.c	Mon Dec  3 23:09:48 2001
@@ -82,6 +82,8 @@
 
 MODULE_PARM(tosh_fn, "i");
 
+MODULE_LICENSE("GPL");
+
 
 static int tosh_get_info(char *, char **, off_t, int);
 static int tosh_ioctl(struct inode *, struct file *, unsigned int,
diff -urN linux-2.4.10-pre8/drivers/char/w83877f_wdt.c linux/drivers/char/w83877f_wdt.c
--- linux-2.4.10-pre8/drivers/char/w83877f_wdt.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/char/w83877f_wdt.c	Mon Dec  3 23:09:48 2001
@@ -340,3 +340,5 @@
 
 module_init(w83877f_wdt_init);
 module_exit(w83877f_wdt_unload);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/ide/buddha.c linux/drivers/ide/buddha.c
--- linux-2.4.10-pre8/drivers/ide/buddha.c	Sun Jul 15 16:22:23 2001
+++ linux/drivers/ide/buddha.c	Mon Dec  3 23:09:48 2001
@@ -43,7 +43,7 @@
 #define BUDDHA_BASE2	0xa00
 #define BUDDHA_BASE3	0xc00
 
-static const u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
+static u_int buddha_bases[CATWEASEL_NUM_HWIFS] __initdata = {
     BUDDHA_BASE1, BUDDHA_BASE2, BUDDHA_BASE3
 };
 
@@ -76,7 +76,7 @@
 #define BUDDHA_IRQ2	0xf40		/* interrupt */
 #define BUDDHA_IRQ3	0xf80
 
-static const int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
+static int buddha_irqports[CATWEASEL_NUM_HWIFS] __initdata = {
     BUDDHA_IRQ1, BUDDHA_IRQ2, BUDDHA_IRQ3
 };
 
diff -urN linux-2.4.10-pre8/drivers/ide/via82cxxx.c linux/drivers/ide/via82cxxx.c
--- linux-2.4.10-pre8/drivers/ide/via82cxxx.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/ide/via82cxxx.c	Mon Dec  3 23:09:48 2001
@@ -1,5 +1,5 @@
 /*
- * $Id: via82cxxx.c,v 3.28 2001/09/01 21:10:00 vojtech Exp $
+ * $Id: via82cxxx.c,v 3.29 2001/09/10 10:06:00 vojtech Exp $
  *
  *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
@@ -90,7 +90,7 @@
 #define VIA_BAD_PREQ		0x010	/* Crashes if PREQ# till DDACK# set */
 #define VIA_BAD_CLK66		0x020	/* 66 MHz clock doesn't work correctly */
 #define VIA_SET_FIFO		0x040	/* Needs to have FIFO split set */
-#define VIA_SET_THRESH		0x080	/* Needs to have FIFO thresholds set */
+#define VIA_NO_UNMASK		0x080	/* Doesn't work with IRQ unmasking on */
 
 /*
  * VIA SouthBridge chips.
@@ -106,7 +106,7 @@
 #ifdef FUTURE_BRIDGES
 	{ "vt8237",	PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt8235",	PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_100 },
-	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C,    0x30, 0x4f, VIA_UDMA_100 },
+	{ "vt8233c",	PCI_DEVICE_ID_VIA_8233C,    0x00, 0x2f, VIA_UDMA_100 },
 #endif
 	{ "vt8233",	PCI_DEVICE_ID_VIA_8233_0,   0x00, 0x2f, VIA_UDMA_100 },
 	{ "vt8231",	PCI_DEVICE_ID_VIA_8231,     0x00, 0x2f, VIA_UDMA_100 },
@@ -120,7 +120,7 @@
 	{ "vt82c586b",	PCI_DEVICE_ID_VIA_82C586_0, 0x30, 0x3f, VIA_UDMA_33 | VIA_SET_FIFO },
 	{ "vt82c586a",	PCI_DEVICE_ID_VIA_82C586_0, 0x20, 0x2f, VIA_UDMA_33 | VIA_SET_FIFO },
 	{ "vt82c586",	PCI_DEVICE_ID_VIA_82C586_0, 0x00, 0x0f, VIA_UDMA_NONE | VIA_SET_FIFO },
-	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO },
+	{ "vt82c576",	PCI_DEVICE_ID_VIA_82C576,   0x00, 0x2f, VIA_UDMA_NONE | VIA_SET_FIFO | VIA_NO_UNMASK },
 	{ NULL }
 };
 
@@ -161,7 +161,7 @@
 
 	via_print("----------VIA BusMastering IDE Configuration----------------");
 
-	via_print("Driver Version:                     3.27");
+	via_print("Driver Version:                     3.29");
 	via_print("South Bridge:                       VIA %s", via_config->name);
 
 	pci_read_config_byte(isa_dev, PCI_REVISION_ID, &t);
@@ -431,7 +431,7 @@
 	}
 
 	if (via_config->flags & VIA_BAD_CLK66) {			/* Disable Clk66 */
-		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Would cause trouble on 596a */
+		pci_read_config_dword(dev, VIA_UDMA_TIMING, &u);	/* Would cause trouble on 596a and 686 */
 		pci_write_config_dword(dev, VIA_UDMA_TIMING, u & ~0x80008);
 	}
 
@@ -460,9 +460,6 @@
 		}
 	}
 
-	if (via_config->flags & VIA_SET_THRESH)				/* 1/2 FIFO full to trigger xmit */
-		t = (t & 0xf0) | 0x0a;
-
 	pci_write_config_byte(dev, VIA_FIFO_CONFIG, t);
 
 /*
@@ -516,7 +513,7 @@
 
 	for (i = 0; i < 2; i++) {
 		hwif->drives[i].io_32bit = 1;
-		hwif->drives[i].unmask = 1;
+		hwif->drives[i].unmask = (via_config->flags & VIA_NO_UNMASK) ? 0 : 1;
 		hwif->drives[i].autotune = 1;
 		hwif->drives[i].dn = hwif->channel * 2 + i;
 	}
diff -urN linux-2.4.10-pre8/drivers/ieee1394/video1394.c linux/drivers/ieee1394/video1394.c
--- linux-2.4.10-pre8/drivers/ieee1394/video1394.c	Thu Aug 16 09:49:49 2001
+++ linux/drivers/ieee1394/video1394.c	Mon Dec  3 23:09:48 2001
@@ -103,7 +103,7 @@
 	int ctxMatch;
 	wait_queue_head_t waitq;
         spinlock_t lock;
-    unsigned int syt_offset;
+	unsigned int syt_offset;
 	int flags;
 };
 
diff -urN linux-2.4.10-pre8/drivers/input/Config.in linux/drivers/input/Config.in
--- linux-2.4.10-pre8/drivers/input/Config.in	Tue Aug 22 11:41:14 2000
+++ linux/drivers/input/Config.in	Mon Dec  3 23:09:48 2001
@@ -6,15 +6,13 @@
 comment 'Input core support'
 
 tristate 'Input core support' CONFIG_INPUT
-if [ "$CONFIG_INPUT" != "n" ]; then
-   dep_tristate '  Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
-   dep_tristate '  Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
-   if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
-      int '   Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
-      int '   Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
-   fi
-   dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
-   dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+dep_tristate '  Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
+dep_tristate '  Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
+if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
+   int '   Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
+   int '   Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
 fi
+dep_tristate '  Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
+dep_tristate '  Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
 
 endmenu
diff -urN linux-2.4.10-pre8/drivers/input/evdev.c linux/drivers/input/evdev.c
--- linux-2.4.10-pre8/drivers/input/evdev.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/input/evdev.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: evdev.c,v 1.10 2000/06/23 09:23:00 vojtech Exp $
+ * $Id: evdev.c,v 1.27 2001/05/28 09:06:44 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  Event char devices, giving access to raw input device events.
  *
@@ -11,18 +11,18 @@
 /*
  * 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 <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
@@ -72,7 +72,7 @@
 		list->buffer[list->head].code = code;
 		list->buffer[list->head].value = value;
 		list->head = (list->head + 1) & (EVDEV_BUFFER_SIZE - 1);
-		
+
 		kill_fasync(&list->fasync, SIGIO, POLL_IN);
 
 		list = list->next;
@@ -104,7 +104,7 @@
 
 	if (!--list->evdev->open) {
 		if (list->evdev->exist) {
-			input_close_device(&list->evdev->handle);	
+			input_close_device(&list->evdev->handle);
 		} else {
 			input_unregister_minor(list->evdev->devfs);
 			evdev_table[list->evdev->minor] = NULL;
@@ -138,14 +138,26 @@
 
 	if (!list->evdev->open++)
 		if (list->evdev->exist)
-			input_open_device(&list->evdev->handle);	
+			input_open_device(&list->evdev->handle);
 
 	return 0;
 }
 
 static ssize_t evdev_write(struct file * file, const char * buffer, size_t count, loff_t *ppos)
 {
-	return -EINVAL;
+	struct evdev_list *list = file->private_data;
+	struct input_event event;
+	int retval = 0;
+
+	while (retval < count) {
+
+		if (copy_from_user(&event, buffer + retval, sizeof(struct input_event)))
+			return -EFAULT;
+		input_event(list->evdev->handle.dev, event.type, event.code, event.value);
+		retval += sizeof(struct input_event);
+	}
+
+	return retval;
 }
 
 static ssize_t evdev_read(struct file * file, char * buffer, size_t count, loff_t *ppos)
@@ -161,6 +173,10 @@
 
 		while (list->head == list->tail) {
 
+			if (!list->evdev->exist) {
+				retval = -ENODEV;
+				break;
+			}
 			if (file->f_flags & O_NONBLOCK) {
 				retval = -EAGAIN;
 				break;
@@ -187,7 +203,7 @@
 		retval += sizeof(struct input_event);
 	}
 
-	return retval;	
+	return retval;
 }
 
 /* No kernel lock - fine */
@@ -219,6 +235,32 @@
 			if ((retval = put_user(dev->idversion, ((short *) arg) + 3))) return retval;
 			return 0;
 
+		case EVIOCSFF:
+			if (dev->upload_effect) {
+				struct ff_effect effect;
+				int err;
+
+				if (copy_from_user((void*)(&effect), (void*)arg, sizeof(effect))) {
+					return -EINVAL;
+				}
+				err = dev->upload_effect(dev, &effect);
+				if (put_user(effect.id, &(((struct ff_effect*)arg)->id))) {
+					return -EINVAL;
+				}
+				return err;
+			}
+			else return -ENOSYS;
+
+		case EVIOCRMFF:
+			if (dev->erase_effect) {
+				return dev->erase_effect(dev, (int)arg);
+			}
+			else return -ENOSYS;
+
+		case EVIOCGEFFECTS:
+			put_user(dev->ff_effects_max, (int*) arg);
+			return 0;
+
 		default:
 
 			if (_IOC_TYPE(cmd) != 'E' || _IOC_DIR(cmd) != _IOC_READ)
@@ -236,6 +278,7 @@
 					case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
 					case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
 					case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
+					case EV_FF:  bits = dev->ffbit;  len = FF_MAX;  break;
 					default: return -EINVAL;
 				}
 				len = NBITS(len) * sizeof(long);
@@ -310,7 +353,7 @@
 
 	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);
+//	printk(KERN_INFO "event%d: Event device for input%d\n", minor, dev->number);
 
 	return &evdev->handle;
 }
@@ -323,13 +366,14 @@
 
 	if (evdev->open) {
 		input_close_device(handle);
+		wake_up_interruptible(&evdev->wait);
 	} else {
 		input_unregister_minor(evdev->devfs);
 		evdev_table[evdev->minor] = NULL;
 		kfree(evdev);
 	}
 }
-	
+
 static struct input_handler evdev_handler = {
 	event:		evdev_event,
 	connect:	evdev_connect,
diff -urN linux-2.4.10-pre8/drivers/input/input.c linux/drivers/input/input.c
--- linux-2.4.10-pre8/drivers/input/input.c	Fri Nov 17 16:52:23 2000
+++ linux/drivers/input/input.c	Mon Dec  3 23:09:48 2001
@@ -1,7 +1,7 @@
 /*
- * $Id: input.c,v 1.7 2000/05/28 17:31:36 vojtech Exp $
+ * $Id: input.c,v 1.20 2001/05/17 15:50:27 vojtech Exp $
  *
- *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *  Copyright (c) 1999-2001 Vojtech Pavlik
  *
  *  The input layer module itself
  *
@@ -124,6 +124,13 @@
 
 			break;
 
+		case EV_MSC:
+
+			if (code > MSC_MAX || !test_bit(code, dev->mscbit))
+				return;
+	
+			break;
+
 		case EV_LED:
 	
 			if (code > LED_MAX || !test_bit(code, dev->ledbit) || !!test_bit(code, dev->led) == value)
@@ -152,14 +159,11 @@
 			if (dev->event) dev->event(dev, type, code, value);
 
 			break;
-	}
-/*
- * Add randomness.
- */
 
-#if 0 /* BUG */
-	add_input_randomness(((unsigned long) dev) ^ (type << 24) ^ (code << 16) ^ value);
-#endif
+		case EV_FF:
+			if (dev->event) dev->event(dev, type, code, value);
+			break;
+	}
 
 /*
  * Distribute the event to handler modules.
diff -urN linux-2.4.10-pre8/drivers/input/keybdev.c linux/drivers/input/keybdev.c
--- linux-2.4.10-pre8/drivers/input/keybdev.c	Wed Apr 25 14:35:25 2001
+++ linux/drivers/input/keybdev.c	Mon Dec  3 23:09:48 2001
@@ -39,7 +39,8 @@
 
 #if defined(CONFIG_X86) || defined(CONFIG_IA64) || defined(__alpha__) || \
     defined(__mips__) || defined(CONFIG_SPARC64) || defined(CONFIG_SUPERH) || \
-    defined(CONFIG_PPC) || defined(__mc68000__)
+    defined(CONFIG_PPC) || defined(__mc68000__) || defined(__hppa__) || \
+    defined(__arm__)
 
 static int x86_sysrq_alt = 0;
 #ifdef CONFIG_SPARC64
@@ -197,14 +198,14 @@
 
 	input_open_device(handle);
 
-	printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
+//	printk(KERN_INFO "keybdev.c: Adding keyboard: input%d\n", dev->number);
 
 	return handle;
 }
 
 static void keybdev_disconnect(struct input_handle *handle)
 {
-	printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
+//	printk(KERN_INFO "keybdev.c: Removing keyboard: input%d\n", handle->dev->number);
 	input_close_device(handle);
 	kfree(handle);
 }
diff -urN linux-2.4.10-pre8/drivers/input/mousedev.c linux/drivers/input/mousedev.c
--- linux-2.4.10-pre8/drivers/input/mousedev.c	Sun Mar 25 18:14:20 2001
+++ linux/drivers/input/mousedev.c	Mon Dec  3 23:09:48 2001
@@ -1,9 +1,9 @@
 /*
- * $Id: mousedev.c,v 1.15 2000/08/14 21:05:26 vojtech Exp $
+ * $Id: mousedev.c,v 1.24 2000/11/15 10:57:45 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
- *  Input driver to PS/2 or ImPS/2 device driver module.
+ *  Input driver to ImExPS/2 device driver module.
  *
  *  Sponsored by SuSE
  */
@@ -66,20 +66,22 @@
 	signed char ps2[6];
 	unsigned long buttons;
 	unsigned char ready, buffer, bufsiz;
-	unsigned char mode, genseq, impseq;
+	unsigned char mode, imexseq, impsseq;
 };
 
-#define MOUSEDEV_GENIUS_LEN	5
-#define MOUSEDEV_IMPS_LEN	6
+#define MOUSEDEV_SEQ_LEN	6
 
-static unsigned char mousedev_genius_seq[] = { 0xe8, 3, 0xe6, 0xe6, 0xe6 };
 static unsigned char mousedev_imps_seq[] = { 0xf3, 200, 0xf3, 100, 0xf3, 80 };
+static unsigned char mousedev_imex_seq[] = { 0xf3, 200, 0xf3, 200, 0xf3, 80 };
 
 static struct input_handler mousedev_handler;
 
 static struct mousedev *mousedev_table[MOUSEDEV_MINORS];
 static struct mousedev mousedev_mix;
 
+static int xres = CONFIG_INPUT_MOUSEDEV_SCREEN_X;
+static int yres = CONFIG_INPUT_MOUSEDEV_SCREEN_Y;
+
 static void mousedev_event(struct input_handle *handle, unsigned int type, unsigned int code, int value)
 {
 	struct mousedev *mousedevs[3] = { handle->private, &mousedev_mix, NULL };
@@ -99,12 +101,12 @@
 					switch (code) {
 						case ABS_X:	
 							size = handle->dev->absmax[ABS_X] - handle->dev->absmin[ABS_X];
-							list->dx += (value * CONFIG_INPUT_MOUSEDEV_SCREEN_X - list->oldx) / size;
+							list->dx += (value * xres - list->oldx) / size;
 							list->oldx += list->dx * size;
 							break;
 						case ABS_Y:
 							size = handle->dev->absmax[ABS_Y] - handle->dev->absmin[ABS_Y];
-							list->dy -= (value * CONFIG_INPUT_MOUSEDEV_SCREEN_Y - list->oldy) / size;
+							list->dy -= (value * yres - list->oldy) / size;
 							list->oldy -= list->dy * size;
 							break;
 					}
@@ -124,12 +126,12 @@
 						case BTN_TOUCH:
 						case BTN_LEFT:   index = 0; break;
 						case BTN_4:
-						case BTN_EXTRA:  if (list->mode > 1) { index = 4; break; }
+						case BTN_EXTRA:  if (list->mode == 2) { index = 4; break; }
 						case BTN_STYLUS:
 						case BTN_1:
 						case BTN_RIGHT:  index = 1; break;
 						case BTN_3:
-						case BTN_SIDE:   if (list->mode > 1) { index = 3; break; }
+						case BTN_SIDE:   if (list->mode == 2) { index = 3; break; }
 						case BTN_2:
 						case BTN_STYLUS2:
 						case BTN_MIDDLE: index = 2; break;	
@@ -257,14 +259,19 @@
 	list->dy -= list->ps2[off + 2];
 	list->bufsiz = off + 3;
 
-	if (list->mode > 1)
-		list->ps2[off] |= ((list->buttons & 0x18) << 3);
+	if (list->mode == 2) {
+		list->ps2[off + 3] = (list->dz > 7 ? 7 : (list->dz < -7 ? -7 : list->dz));
+		list->dz -= list->ps2[off + 3];
+		list->ps2[off + 3] = (list->ps2[off + 3] & 0x0f) | ((list->buttons & 0x18) << 1);
+		list->bufsiz++;
+	}
 	
-	if (list->mode) {
+	if (list->mode == 1) {
 		list->ps2[off + 3] = (list->dz > 127 ? 127 : (list->dz < -127 ? -127 : list->dz));
-		list->bufsiz++;
 		list->dz -= list->ps2[off + 3];
+		list->bufsiz++;
 	}
+
 	if (!list->dx && !list->dy && (!list->mode || !list->dz)) list->ready = 0;
 	list->buffer = list->bufsiz;
 }
@@ -278,27 +285,26 @@
 
 	for (i = 0; i < count; i++) {
 
-		if (get_user(c, &buffer[i]))
+		if (get_user(c, buffer + i))
 			return -EFAULT;
 
-		if (c == mousedev_genius_seq[list->genseq]) {
-			if (++list->genseq == MOUSEDEV_GENIUS_LEN) {
-				list->genseq = 0;
-				list->ready = 1;
+		if (c == mousedev_imex_seq[list->imexseq]) {
+			if (++list->imexseq == MOUSEDEV_SEQ_LEN) {
+				list->imexseq = 0;
 				list->mode = 2;
 			}
-		} else list->genseq = 0;
+		} else list->imexseq = 0;
 
-		if (c == mousedev_imps_seq[list->impseq]) {
-			if (++list->impseq == MOUSEDEV_IMPS_LEN) {
-				list->impseq = 0;
-				list->ready = 1;
+		if (c == mousedev_imps_seq[list->impsseq]) {
+			if (++list->impsseq == MOUSEDEV_SEQ_LEN) {
+				list->impsseq = 0;
 				list->mode = 1;
 			}
-		} else list->impseq = 0;
+		} else list->impsseq = 0;
 
 		list->ps2[0] = 0xfa;
 		list->bufsiz = 1;
+		list->ready = 1;
 
 		switch (c) {
 
@@ -307,16 +313,16 @@
 				break;
 
 			case 0xf2: /* Get ID */
-				list->ps2[1] = (list->mode == 1) ? 3 : 0;
+				switch (list->mode) {
+					case 0: list->ps2[1] = 0;
+					case 1: list->ps2[1] = 3;
+					case 2: list->ps2[1] = 4;
+				}
 				list->bufsiz = 2;
 				break;
 
 			case 0xe9: /* Get info */
-				if (list->mode == 2) {
-					list->ps2[1] = 0x00; list->ps2[2] = 0x33; list->ps2[3] = 0x55;
-				} else {
-					list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
-				}
+				list->ps2[1] = 0x60; list->ps2[2] = 3; list->ps2[3] = 200;
 				list->bufsiz = 4;
 				break;
 		}
@@ -434,7 +440,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);
+//	printk(KERN_INFO "mouse%d: PS/2 mouse device for input%d\n", minor, dev->number);
 
 	return &mousedev->handle;
 }
@@ -491,3 +497,7 @@
 
 MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
 MODULE_DESCRIPTION("Input driver to PS/2 or ImPS/2 device driver");
+MODULE_PARM(xres, "i");
+MODULE_PARM_DESC(xres, "Horizontal screen resolution");
+MODULE_PARM(yres, "i");
+MODULE_PARM_DESC(yres, "Vertical screen resolution");
diff -urN linux-2.4.10-pre8/drivers/isdn/eicon/Divas_mod.c linux/drivers/isdn/eicon/Divas_mod.c
--- linux-2.4.10-pre8/drivers/isdn/eicon/Divas_mod.c	Fri Mar  2 11:12:08 2001
+++ linux/drivers/isdn/eicon/Divas_mod.c	Mon Dec  3 23:09:48 2001
@@ -29,7 +29,7 @@
 #include <linux/pci.h>
 #include <linux/ioport.h>
 #include <linux/slab.h>
-#include <errno.h>
+#include <linux/errno.h>
 
 #include "adapter.h"
 #include "uxio.h"
diff -urN linux-2.4.10-pre8/drivers/media/video/saa7111.c linux/drivers/media/video/saa7111.c
--- linux-2.4.10-pre8/drivers/media/video/saa7111.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/saa7111.c	Mon Dec  3 23:09:48 2001
@@ -28,7 +28,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/sched.h>
 
diff -urN linux-2.4.10-pre8/drivers/media/video/saa7185.c linux/drivers/media/video/saa7185.c
--- linux-2.4.10-pre8/drivers/media/video/saa7185.c	Sat May 19 17:43:06 2001
+++ linux/drivers/media/video/saa7185.c	Mon Dec  3 23:09:48 2001
@@ -28,7 +28,7 @@
 #include <linux/fs.h>
 #include <linux/kernel.h>
 #include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/pci.h>
 #include <linux/signal.h>
diff -urN linux-2.4.10-pre8/drivers/mtd/chips/amd_flash.c linux/drivers/mtd/chips/amd_flash.c
--- linux-2.4.10-pre8/drivers/mtd/chips/amd_flash.c	Tue Jun 12 10:30:27 2001
+++ linux/drivers/mtd/chips/amd_flash.c	Mon Dec  3 23:09:48 2001
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/flashchip.h>
diff -urN linux-2.4.10-pre8/drivers/net/Space.c linux/drivers/net/Space.c
--- linux-2.4.10-pre8/drivers/net/Space.c	Tue Jul 17 18:53:55 2001
+++ linux/drivers/net/Space.c	Mon Dec  3 23:09:48 2001
@@ -102,15 +102,11 @@
 extern int mac89x0_probe(struct net_device *dev);
 extern int mc32_probe(struct net_device *dev);
   
-/* Gigabit Ethernet adapters */
-extern int yellowfin_probe(struct net_device *dev);
-
 /* Detachable devices ("pocket adaptors") */
 extern int de600_probe(struct net_device *);
 extern int de620_probe(struct net_device *);
 
 /* FDDI adapters */
-extern int apfddi_init(struct net_device *dev);
 extern int skfp_probe(struct net_device *dev);
 
 /* Fibre Channel adapters */
diff -urN linux-2.4.10-pre8/drivers/net/eql.c linux/drivers/net/eql.c
--- linux-2.4.10-pre8/drivers/net/eql.c	Wed Jul  4 14:41:33 2001
+++ linux/drivers/net/eql.c	Mon Dec  3 23:09:48 2001
@@ -121,7 +121,7 @@
 
 #include <asm/uaccess.h>
 
-static const char version[] __initdata = 
+static char version[] __initdata = 
 	"Equalizer1996: $Revision: 1.2.1 $ $Date: 1996/09/22 13:52:00 $ Simon Janes (simon@ncm.com)\n";
 
 #ifndef EQL_DEBUG
diff -urN linux-2.4.10-pre8/drivers/net/ewrk3.c linux/drivers/net/ewrk3.c
--- linux-2.4.10-pre8/drivers/net/ewrk3.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/net/ewrk3.c	Mon Dec  3 23:09:48 2001
@@ -164,7 +164,7 @@
 
 #include "ewrk3.h"
 
-static const char version[] __initdata =
+static char version[] __initdata =
 "ewrk3.c:v0.43a 2001/02/04 davies@maniac.ultranet.com\n";
 
 #ifdef EWRK3_DEBUG
diff -urN linux-2.4.10-pre8/drivers/net/fc/iph5526.c linux/drivers/net/fc/iph5526.c
--- linux-2.4.10-pre8/drivers/net/fc/iph5526.c	Wed Jun 20 11:19:02 2001
+++ linux/drivers/net/fc/iph5526.c	Mon Dec  3 23:09:48 2001
@@ -118,6 +118,8 @@
 };
 MODULE_DEVICE_TABLE(pci, iph5526_pci_tbl);
 
+MODULE_LICENSE("GPL");
+
 #define MAX_FC_CARDS 2
 static struct fc_info *fc[MAX_FC_CARDS+1];
 static unsigned int pci_irq_line;
diff -urN linux-2.4.10-pre8/drivers/net/hamradio/6pack.c linux/drivers/net/hamradio/6pack.c
--- linux-2.4.10-pre8/drivers/net/hamradio/6pack.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/hamradio/6pack.c	Mon Dec  3 23:09:48 2001
@@ -699,10 +699,10 @@
 
 /* Initialize 6pack control device -- register 6pack line discipline */
 
-static const char msg_banner[]  __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n";
-static const char msg_invparm[] __initdata = KERN_ERR  "6pack: sixpack_maxdev parameter too large.\n";
-static const char msg_nomem[]   __initdata = KERN_ERR  "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n";
-static const char msg_regfail[] __initdata = KERN_ERR  "6pack: can't register line discipline (err = %d)\n";
+static char msg_banner[]  __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n";
+static char msg_invparm[] __initdata = KERN_ERR  "6pack: sixpack_maxdev parameter too large.\n";
+static char msg_nomem[]   __initdata = KERN_ERR  "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n";
+static char msg_regfail[] __initdata = KERN_ERR  "6pack: can't register line discipline (err = %d)\n";
 
 static int __init sixpack_init_driver(void)
 {
diff -urN linux-2.4.10-pre8/drivers/net/hamradio/bpqether.c linux/drivers/net/hamradio/bpqether.c
--- linux-2.4.10-pre8/drivers/net/hamradio/bpqether.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/net/hamradio/bpqether.c	Mon Dec  3 23:09:48 2001
@@ -87,7 +87,7 @@
 
 #include <linux/bpqether.h>
 
-static const char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n";
+static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n";
 
 static unsigned char ax25_bcast[AX25_ADDR_LEN] =
 	{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
diff -urN linux-2.4.10-pre8/drivers/net/hamradio/mkiss.c linux/drivers/net/hamradio/mkiss.c
--- linux-2.4.10-pre8/drivers/net/hamradio/mkiss.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/hamradio/mkiss.c	Mon Dec  3 23:09:48 2001
@@ -54,7 +54,7 @@
 #include <linux/tcp.h>
 #endif
 
-static const char banner[] __initdata = KERN_INFO "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
+static char banner[] __initdata = KERN_INFO "mkiss: AX.25 Multikiss, Hans Albas PE1AYX\n";
 
 #define NR_MKISS 4
 #define MKISS_SERIAL_TYPE_NORMAL 1
diff -urN linux-2.4.10-pre8/drivers/net/hamradio/scc.c linux/drivers/net/hamradio/scc.c
--- linux-2.4.10-pre8/drivers/net/hamradio/scc.c	Sun Aug  5 13:12:40 2001
+++ linux/drivers/net/hamradio/scc.c	Mon Dec  3 23:09:48 2001
@@ -184,7 +184,7 @@
 #include <linux/kernel.h>
 #include <linux/proc_fs.h>
 
-static const char banner[] __initdata = KERN_INFO "AX.25: Z8530 SCC driver version "VERSION".dl1bke\n";
+static char banner[] __initdata = KERN_INFO "AX.25: Z8530 SCC driver version "VERSION".dl1bke\n";
 
 static void t_dwait(unsigned long);
 static void t_txdelay(unsigned long);
diff -urN linux-2.4.10-pre8/drivers/net/hamradio/yam.c linux/drivers/net/hamradio/yam.c
--- linux-2.4.10-pre8/drivers/net/hamradio/yam.c	Wed Apr 18 14:40:06 2001
+++ linux/drivers/net/hamradio/yam.c	Mon Dec  3 23:09:48 2001
@@ -81,7 +81,7 @@
 /* --------------------------------------------------------------------- */
 
 static const char yam_drvname[] = "yam";
-static const char yam_drvinfo[] __initdata = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n";
+static char yam_drvinfo[] __initdata = KERN_INFO "YAM driver version 0.8 by F1OAT/F6FBB\n";
 
 /* --------------------------------------------------------------------- */
 
diff -urN linux-2.4.10-pre8/drivers/net/ioc3-eth.c linux/drivers/net/ioc3-eth.c
--- linux-2.4.10-pre8/drivers/net/ioc3-eth.c	Tue Jul 17 18:53:55 2001
+++ linux/drivers/net/ioc3-eth.c	Mon Dec  3 23:09:48 2001
@@ -45,7 +45,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/skbuff.h>
-#include <linux/mii.h>
+#include <linux/dp83840.h>
 
 #include <asm/byteorder.h>
 #include <asm/io.h>
diff -urN linux-2.4.10-pre8/drivers/net/irda/ali-ircc.c linux/drivers/net/irda/ali-ircc.c
--- linux-2.4.10-pre8/drivers/net/irda/ali-ircc.c	Sun Aug  5 13:12:40 2001
+++ linux/drivers/net/irda/ali-ircc.c	Mon Dec  3 23:09:48 2001
@@ -1344,6 +1344,7 @@
 {
 	struct ali_ircc_cb *self;
 	int iobase;
+	char hwname[32];
 		
 	IRDA_DEBUG(2, __FUNCTION__ "(), ---------------- Start ----------------\n");
 	
@@ -1380,11 +1381,14 @@
 	/* Ready to play! */
 	netif_start_queue(dev); //benjamin by irport
 	
+	/* Give self a hardware name */
+	sprintf(hwname, "ALI-FIR @ 0x%03x", self->io.fir_base);
+
 	/* 
 	 * Open new IrLAP layer instance, now that everything should be
 	 * initialized properly 
 	 */
-	self->irlap = irlap_open(dev, &self->qos);
+	self->irlap = irlap_open(dev, &self->qos, hwname);
 		
 	MOD_INC_USE_COUNT;
 
diff -urN linux-2.4.10-pre8/drivers/net/irda/irda-usb.c linux/drivers/net/irda/irda-usb.c
--- linux-2.4.10-pre8/drivers/net/irda/irda-usb.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/irda/irda-usb.c	Mon Dec  3 23:09:48 2001
@@ -1,14 +1,14 @@
 /*****************************************************************************
  *
  * Filename:      irda-usb.c
- * Version:       0.9
+ * Version:       0.9a
  * Description:   IrDA-USB Driver
  * Status:        Experimental 
  * Author:        Dag Brattli <dag@brattli.net>
  *
+ *	Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
  *      Copyright (C) 2001, Dag Brattli <dag@brattli.net>
  *      Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
- *	Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
  *          
  *	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
@@ -46,23 +46,6 @@
 
 static int qos_mtt_bits = 0;
 
-static void irda_usb_dump_class_desc(struct irda_class_desc *desc);
-static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum);
-static void irda_usb_disconnect(struct usb_device *dev, void *ptr);
-static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
-static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
-static int irda_usb_open(struct irda_usb_cb *self);
-static int irda_usb_close(struct irda_usb_cb *self);
-static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb);
-static void write_bulk_callback(purb_t purb);
-static void irda_usb_receive(purb_t purb);
-static int irda_usb_net_init(struct net_device *dev);
-static int irda_usb_net_open(struct net_device *dev);
-static int irda_usb_net_close(struct net_device *dev);
-static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
-static void irda_usb_net_timeout(struct net_device *dev);
-static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev);
-
 /* Master instance for each hardware found */
 #define NIRUSB 4		/* Max number of USB-IrDA dongles */
 static struct irda_usb_cb irda_instance[NIRUSB];
@@ -85,697 +68,649 @@
 
 MODULE_DEVICE_TABLE(usb, dongles);
 
+/*------------------------------------------------------------------*/
+
+static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum);
+static void irda_usb_disconnect(struct usb_device *dev, void *ptr);
+static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self);
+static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *dev);
+static int irda_usb_open(struct irda_usb_cb *self);
+static int irda_usb_close(struct irda_usb_cb *self);
+static void speed_bulk_callback(purb_t purb);
+static void write_bulk_callback(purb_t purb);
+static void irda_usb_receive(purb_t purb);
+static int irda_usb_net_init(struct net_device *dev);
+static int irda_usb_net_open(struct net_device *dev);
+static int irda_usb_net_close(struct net_device *dev);
+static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static void irda_usb_net_timeout(struct net_device *dev);
+static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev);
+
+/************************ TRANSMIT ROUTINES ************************/
 /*
- * This routine is called by the USB subsystem for each new device
- * in the system. We need to check if the device is ours, and in
- * this case start handling it.
- * Note : it might be worth protecting this function by a global
- * spinlock...
+ * Receive packets from the IrDA stack and send them on the USB pipe.
+ * Handle speed change, timeout and lot's of uglyness...
  */
-static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
-			   const struct usb_device_id *id)
-{
-	struct irda_usb_cb *self = NULL;
-	struct usb_interface_descriptor *interface;
-	struct usb_endpoint_descriptor *endpoint;
-	struct irda_class_desc *irda_desc;
-	int capability = id->driver_info;
-	int ret;
-	int ep;
-	int i;
-
-	IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
-	
-	MESSAGE("IRDA-USB found at address %d\n", dev->devnum);
 
-	/* Try to cleanup all instance that have a pending disconnect
-	 * Instance will be in this state is the disconnect() occurs
-	 * before the net_close().
-	 * Jean II */
-	for (i = 0; i < NIRUSB; i++) {
-		struct irda_usb_cb *irda = &irda_instance[i];
-		if ((irda->usbdev != NULL) &&
-		    (irda->present == 0) &&
-		    (irda->netopen == 0)) {
-			IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n");
-			irda_usb_disconnect(irda->usbdev, (void *) irda);
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_usb_build_header(self, skb, header)
+ *
+ *   Builds USB-IrDA outbound header
+ *
+ * When we send an IrDA frame over an USB pipe, we add to it a 1 byte
+ * header. This function create this header with the proper values.
+ *
+ * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2
+ * that the setting of the link speed and xbof number in this outbound header
+ * should be applied *AFTER* the frame has been sent.
+ * Unfortunately, some devices are not compliant with that... It seems that
+ * reading the spec is far too difficult...
+ * Jean II
+ */
+static void irda_usb_build_header(struct irda_usb_cb *self,
+				  __u8 *header,
+				  int	force)
+{
+	/* Set the negotiated link speed */
+	if (self->new_speed != -1) {
+		/* Hum... Ugly hack :-(
+		 * Some device are not compliant with the spec and change
+		 * parameters *before* sending the frame. - Jean II
+		 */
+		if ((self->capability & IUC_SPEED_BUG) &&
+		    (!force) && (self->speed != -1)) {
+			/* No speed and xbofs change here
+			 * (we'll do it later in the write callback) */
+			IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n");
+			*header = 0;
+			return;
 		}
-	}
 
-	/* Find an free instance to handle this new device... */
-	self = NULL;
-	for (i = 0; i < NIRUSB; i++) {
-		if(irda_instance[i].usbdev == NULL) {
-			self = &irda_instance[i];
+		IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed);
+		self->speed = self->new_speed;
+		self->new_speed = -1;
+
+		switch (self->speed) {
+		case 2400:
+		        *header = SPEED_2400;
+			break;
+		default:
+		case 9600:
+			*header = SPEED_9600;
+			break;
+		case 19200:
+			*header = SPEED_19200;
+			break;
+		case 38400:
+			*header = SPEED_38400;
+			break;
+		case 57600:
+		        *header = SPEED_57600;
+			break;
+		case 115200:
+		        *header = SPEED_115200;
+			break;
+		case 576000:
+		        *header = SPEED_576000;
+			break;
+		case 1152000:
+		        *header = SPEED_1152000;
+			break;
+		case 4000000:
+		        *header = SPEED_4000000;
+			self->new_xbofs = 0;
 			break;
 		}
-	}
-	if (self == NULL) {
-		IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n",
-			   NIRUSB);
-		return NULL;
-	}
-
-	/* Reset the instance */
-	self->present = 0;
-	self->netopen = 0;
-
-       /* Is this really necessary? */
-	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
-		err("set_configuration failed");
-		return NULL;
-	}
+	} else
+		/* No change */
+		*header = 0;
 	
-        /* Is this really necessary? */
-	ret = usb_set_interface(dev, ifnum, 0);
-	IRDA_DEBUG(0, "usb-irda: set interface result %d\n", ret);
-	switch (ret) {
-		case USB_ST_NOERROR:		/* 0 */
+	/* Set the negotiated additional XBOFS */
+	if (self->new_xbofs != -1) {
+		IRDA_DEBUG(2, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs);
+		self->xbofs = self->new_xbofs;
+		self->new_xbofs = -1;
+
+		switch (self->xbofs) {
+		case 48:
+			*header |= 0x10;
 			break;
-		case USB_ST_STALL:		/* -EPIPE = -32 */
-			usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
-			IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" );
+		case 28:
+		case 24:	/* USB spec 1.0 says 24 */
+			*header |= 0x20;
 			break;
 		default:
-			IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret);
-			return NULL;
+		case 12:
+			*header |= 0x30;
 			break;
+		case 5: /* Bug in IrLAP spec? (should be 6) */
+		case 6:
+			*header |= 0x40;
+			break;
+		case 3:
+			*header |= 0x50;
+			break;
+		case 2:
+			*header |= 0x60;
+			break;
+		case 1:
+			*header |= 0x70;
+			break;
+		case 0:
+			*header |= 0x80;
+			break;
+		}
 	}
-	
-	/* Find our endpoints */
-	interface = &dev->actconfig->interface[ifnum].altsetting[0];
-	endpoint = interface->endpoint;
-	ep = endpoint[0].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-	if ((endpoint[0].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-		self->bulk_in_ep = ep;
-	else {
-		self->bulk_out_ep = ep;
-		self->bulk_out_mtu = endpoint[0].wMaxPacketSize;
-	}
-
-	ep = endpoint[1].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
-	if ((endpoint[1].bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN)
-		self->bulk_in_ep = ep;
-	else {
-		self->bulk_out_ep = ep;
-		self->bulk_out_mtu = endpoint[1].wMaxPacketSize;
-	}
-
-	if (self->bulk_out_ep == 0 || self->bulk_in_ep == 0 ||
-	    endpoint [0].bmAttributes != USB_ENDPOINT_XFER_BULK ||
-	    endpoint [1].bmAttributes != USB_ENDPOINT_XFER_BULK) 
-	{
-		ERROR(__FUNCTION__ "(), Bogus endpoints");
-		return NULL;
-	}
-
-	/* Find IrDA class descriptor */
-	irda_desc = irda_usb_find_class_desc(dev, ifnum);
-	if (irda_desc == NULL)
-		return NULL;
-	
-	self->irda_desc =  irda_desc;	
-	self->present = 1;
-	self->netopen = 0;
-	self->capability = capability;
-	self->usbdev = dev;
-	ret = irda_usb_open(self);
-	if (ret)
-		return NULL;
-
-	return self;
 }
 
+/*------------------------------------------------------------------*/
 /*
- * Function irda_usb_find_class_desc(dev, ifnum)
- *
- *    Returns instance of IrDA class descriptor, or NULL if not found
- *
+ * Send a command to change the speed of the dongle
  */
-static struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
+static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
 {
-	struct usb_interface_descriptor *interface;
-	struct irda_class_desc *desc, *ptr;
+	unsigned long flags;
+	__u8 *frame;
+	purb_t purb;
 	int ret;
-		
-	desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
-	if (desc == NULL) 
-		return NULL;
-	memset(desc, 0, sizeof(struct irda_class_desc));
-	
-	ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc));
-	IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret);
-	if (ret) {
-		WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret);  
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
+		   self->new_speed, self->new_xbofs);
+
+	/* Grab the speed URB */
+	purb = &self->speed_urb;
+	if (purb->status != USB_ST_NOERROR) {
+		WARNING(__FUNCTION__ "(), URB still in use!\n");
+		return;
 	}
 
-	/* Check if we found it? */
-	if (desc->bDescriptorType == USB_DT_IRDA)
-		return desc;
+	spin_lock_irqsave(&self->lock, flags);
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n");
-	
-	/* Check if the class descriptor is interleaved with standard descriptors */
-	interface = &dev->actconfig->interface[ifnum].altsetting[0];
-	ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr);
-	if (ret) {
-		kfree(desc);
-		return NULL;
+	/* Allocate the fake frame */
+	frame = self->speed_buff;
+
+	/* Set the new speed and xbofs in this fake frame */
+	irda_usb_build_header(self, frame, 1);
+
+	/* Submit the 0 length IrDA frame to trigger new speed settings */
+        FILL_BULK_URB(purb, self->usbdev,
+		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+                      frame, IRDA_USB_SPEED_MTU,
+                      speed_bulk_callback, self);
+	purb->transfer_buffer_length = USB_IRDA_HEADER;
+	purb->transfer_flags = USB_QUEUE_BULK;
+	purb->timeout = MSECS_TO_JIFFIES(100);
+
+	if ((ret = usb_submit_urb(purb))) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n");
 	}
-	*desc = *ptr;
-#if 0
-	irda_usb_dump_class_desc(desc);
-#endif	
-	return desc;
+	spin_unlock_irqrestore(&self->lock, flags);
 }
 
+#ifdef IU_BUG_KICK_TX
+/*------------------------------------------------------------------*/
 /*
- * Function usb_irda_dump_class_desc(desc)
- *
- *    Prints out the contents of the IrDA class descriptor
- *
+ * Send an empty URB to the dongle
+ * The goal there is to try to resynchronise with the dongle. An empty
+ * frame signify the end of a Tx frame. Jean II
  */
-static void irda_usb_dump_class_desc(struct irda_class_desc *desc)
+static inline void irda_usb_send_empty(struct irda_usb_cb *self)
 {
-	printk("bLength=%x\n", desc->bLength);
-	printk("bDescriptorType=%x\n", desc->bDescriptorType);
-	printk("bcdSpecRevision=%x\n", desc->bcdSpecRevision); 
-	printk("bmDataSize=%x\n", desc->bmDataSize);
-	printk("bmWindowSize=%x\n", desc->bmWindowSize);
-	printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
-	printk("wBaudRate=%x\n", desc->wBaudRate);
-	printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);
-	printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
-	printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList);
-}												
-	
-static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct irda_usb_cb *self = (struct irda_usb_cb *) ptr;
-	int i;
+	purb_t purb;
+	int ret;
 
 	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
-	/* Oups ! We are not there any more */
-	self->present = 0;
-
-	/* Hum... Check if networking is still active */
-	if (self->netopen) {
-		/* Accept no more transmissions */
-		/*netif_device_detach(self->netdev);*/
-		netif_stop_queue(self->netdev);
-		/* Stop all the receive URBs */
-		for (i = 0; i < IU_MAX_RX_URBS; i++)
-			usb_unlink_urb(&(self->rx_urb[i]));
-		/* Cancel Tx and speed URB */
-		usb_unlink_urb(&(self->tx_urb));
-		usb_unlink_urb(&(self->speed_urb));
-
-		IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n");
-		/* better not do anything just yet, usb_irda_cleanup()
-		 * will do whats needed */
+	/* Grab the empty URB */
+	purb = &self->empty_urb;
+	if (purb->status != USB_ST_NOERROR) {
+		WARNING(__FUNCTION__ "(), Empty URB still in use!\n");
 		return;
 	}
 
-	/* Cleanup the device stuff */
-	irda_usb_close(self);
-	/* No longer attached to USB bus */
-	self->usbdev = NULL;
-	IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n");
-}
+	/* Submit the Empty URB */
+        FILL_BULK_URB(purb, self->usbdev,
+		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+                      self->speed_buff, IRDA_USB_SPEED_MTU,
+                      speed_bulk_callback, self);
+	purb->transfer_buffer_length = 0;
+	purb->transfer_flags = USB_QUEUE_BULK;
+	purb->timeout = MSECS_TO_JIFFIES(100);
 
-static struct usb_driver irda_driver = {
-	name:		"irda-usb",
-	probe:		irda_usb_probe,
-	disconnect:	irda_usb_disconnect,
-	id_table:	dongles,
-};
+	if ((ret = usb_submit_urb(purb))) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), failed Empty URB\n");
+	}
+}
+#endif IU_BUG_KICK_TX
 
-static void irda_usb_init_qos(struct irda_usb_cb *self)
+/*------------------------------------------------------------------*/
+/*
+ * Note : this function will be called with both speed_urb and empty_urb...
+ */
+static void speed_bulk_callback(purb_t purb)
 {
-	struct irda_class_desc *desc;
-
-	desc = self->irda_desc;
+	struct irda_usb_cb *self = purb->context;
 	
-	/* Initialize QoS for this device */
-	irda_init_max_qos_capabilies(&self->qos);
-
-	self->qos.baud_rate.bits       = desc->wBaudRate;
-	self->qos.min_turn_time.bits   = desc->bmMinTurnaroundTime;
-	self->qos.additional_bofs.bits = desc->bmAdditionalBOFs;
-	self->qos.window_size.bits     = desc->bmWindowSize;
-	self->qos.data_size.bits       = desc->bmDataSize;
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);
+	/* We should always have a context */
+	if (self == NULL) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n");
+		return;
+	}
 
-	/* Don't always trust what the dongle tell us */
-	if (self->capability & IUC_SIR_ONLY)
-		self->qos.baud_rate.bits	&= 0xff;
-	if (self->capability & IUC_SMALL_PKT)
-		self->qos.data_size.bits	 = 0x07;
-	if (self->capability & IUC_NO_WINDOW)
-		self->qos.window_size.bits	 = 0x01;
-	if (self->capability & IUC_MAX_WINDOW)
-		self->qos.window_size.bits	 = 0x7f;
-	if (self->capability & IUC_MAX_XBOFS)
-		self->qos.additional_bofs.bits	 = 0x01;
+	/* Check for timeout and other USB nasties */
+	if(purb->status != USB_ST_NOERROR) {
+		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
+		WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+
+		/* Don't do anything here, that might confuse the USB layer.
+		 * Instead, we will wait for irda_usb_net_timeout(), the
+		 * network layer watchdog, to fix the situation.
+		 * Jean II */
+		/* A reset of the dongle might be welcomed here - Jean II */
+		return;
+	}
 
-#if 1
-	/* Module parameter can override the rx window size */
-	if (qos_mtt_bits)
-		self->qos.min_turn_time.bits = qos_mtt_bits;
-#endif	    
-	/* 
-	 * Note : most of those values apply only for the receive path,
-	 * the transmit path will be set differently - Jean II 
-	 */
-	irda_qos_bits_to_value(&self->qos);
+	/* urb is now available */
+	purb->status = USB_ST_NOERROR;
 
-	self->flags |= IFF_SIR;
-	if (self->qos.baud_rate.value > 115200)
-		self->flags |= IFF_MIR;
-	if (self->qos.baud_rate.value > 1152000)
-		self->flags |= IFF_FIR;
-	if (self->qos.baud_rate.value > 4000000)
-		self->flags |= IFF_VFIR;
+	/* If it was the speed URB, allow the stack to send more packets */
+	if(purb == &self->speed_urb) {
+		netif_wake_queue(self->netdev);
+	}
 }
 
-static int irda_usb_open(struct irda_usb_cb *self)
+/*------------------------------------------------------------------*/
+/*
+ * Send an IrDA frame to the USB dongle (for transmission)
+ */
+static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-	struct net_device *netdev;
-	int err;
+	struct irda_usb_cb *self = netdev->priv;
+	purb_t purb = &self->tx_urb;
+	unsigned long flags;
+	s32 speed;
+	s16 xbofs;
+	int res, mtt;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	/* Check if the device is still there */
+	if ((!self) || (!self->present)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");
+		return 1;	/* Failed */
+	}
 
-	spin_lock_init(&self->lock);
+	netif_stop_queue(netdev);
 
-	irda_usb_init_qos(self);
-	
-	self->tx_list = hashbin_new(HB_GLOBAL);
+	/* Check if we need to change the number of xbofs */
+        xbofs = irda_get_next_xbofs(skb);
+        if ((xbofs != self->xbofs) && (xbofs != -1)) {
+		self->new_xbofs = xbofs;
+	}
 
-	/* Create a network device for us */
-	if (!(netdev = dev_alloc("irda%d", &err))) {
-		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
-		return -1;
+        /* Check if we need to change the speed */
+	speed = irda_get_next_speed(skb);
+	if ((speed != self->speed) && (speed != -1)) {
+		/* Set the desired speed */
+		self->new_speed = speed;
+
+		/* Check for empty frame */
+		if (!skb->len) {
+			/* IrLAP send us an empty frame to make us change the
+			 * speed. Changing speed with the USB adapter is in
+			 * fact sending an empty frame to the adapter, so we
+			 * could just let the present function do its job.
+			 * However, we would wait for min turn time,
+			 * do an extra memcpy and increment packet counters...
+			 * Jean II */
+			irda_usb_change_speed_xbofs(self);
+			netdev->trans_start = jiffies;
+			dev_kfree_skb(skb);
+			/* Will netif_wake_queue() in callback */
+			return 0;
+		}
 	}
-	self->netdev = netdev;
- 	netdev->priv = (void *) self;
 
-	/* Override the network functions we need to use */
-	netdev->init            = irda_usb_net_init;
-	netdev->hard_start_xmit = irda_usb_hard_xmit;
-	netdev->tx_timeout	= irda_usb_net_timeout;
-	netdev->watchdog_timeo  = 110*HZ/1000;  /* 110 ms > USB timeout */
-	netdev->open            = irda_usb_net_open;
-	netdev->stop            = irda_usb_net_close;
-	netdev->get_stats	= irda_usb_net_get_stats;
-	netdev->do_ioctl        = irda_usb_net_ioctl;
+	if (purb->status != USB_ST_NOERROR) {
+		WARNING(__FUNCTION__ "(), URB still in use!\n");
+		dev_kfree_skb(skb);
+		return 0;
+	}
 
-	rtnl_lock();
-	err = register_netdevice(netdev);
-	rtnl_unlock();
-	if (err) {
-		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
-		return -1;
+	/* Make room for IrDA-USB header (note skb->len += USB_IRDA_HEADER) */
+	if (skb_cow(skb, USB_IRDA_HEADER)) {
+		dev_kfree_skb(skb);
+		return 0;
 	}
-	MESSAGE("IrDA: Registered device %s\n", netdev->name);
 
-	return 0;
-}
+	spin_lock_irqsave(&self->lock, flags);
 
-static int irda_usb_close(struct irda_usb_cb *self)
-{
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	/* Change setting for next frame */
+	irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);
 
-	ASSERT(self != NULL, return -1;);
+	/* FIXME: Make macro out of this one */
+	((struct irda_skb_cb *)skb->cb)->context = self;
 
-	/* Remove netdevice */
-	if (self->netdev) {
-		rtnl_lock();
-		unregister_netdevice(self->netdev);
-		self->netdev = NULL;
-		rtnl_unlock();
+        FILL_BULK_URB(purb, self->usbdev, 
+		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
+                      skb->data, IRDA_USB_MAX_MTU,
+                      write_bulk_callback, skb);
+	purb->transfer_buffer_length = skb->len;
+	purb->transfer_flags = USB_QUEUE_BULK;
+#ifdef IU_USE_USB_ZERO_FLAG
+	/* This flag indicates that what we send is not a continuous stream
+	 * of data but separate frames. In this case, the USB layer will
+	 * insert empty packet to separate our frames.
+	 * This flag was previously called USB_DISABLE_SPD - Jean II */
+	purb->transfer_flags |= USB_ZERO_PACKET;
+#endif IU_USE_USB_ZERO_FLAG
+	purb->timeout = MSECS_TO_JIFFIES(100);
+	
+	/* Generate min turn time. FIXME: can we do better than this? */
+	/* Trying to a turnaround time at this level is trying to measure
+	 * processor clock cycle with a watch, approximate at best...
+	 *
+	 * What we know is the last time we received a frame over USB.
+	 * Due to latency over USB that depend on the USB load, we don't
+	 * know when this frame was received over IrDA (a few ms before ?)
+	 * Then, same story for our outgoing frame...
+	 *
+	 * In theory, the USB dongle is supposed to handle the turnaround
+	 * by itself (spec 1.0, chater 4, page 6). Who knows ??? That's
+	 * why this code is enabled only for dongles that doesn't meet
+	 * the spec.
+	 * Jean II */
+	if (self->capability & IUC_NO_TURN) {
+		mtt = irda_get_mtt(skb);
+		if (mtt) {
+			int diff;
+			get_fast_time(&self->now);
+			diff = self->now.tv_usec - self->stamp.tv_usec;
+			if (diff < 0)
+				diff += 1000000;
+
+		        /* Check if the mtt is larger than the time we have
+			 * already used by all the protocol processing
+			 */
+			if (mtt > diff) {
+				mtt -= diff;
+				if (mtt > 1000)
+					mdelay(mtt/1000);
+				else
+					udelay(mtt);
+			}
+		}
 	}
-	hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any);
+	
+	if ((res = usb_submit_urb(purb))) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n");
+		self->stats.tx_errors++;
+		/* Let USB recover : We will catch that in the watchdog */
+		/*netif_start_queue(netdev);*/
+	} else {
+		/* Increment packet stats */
+		self->stats.tx_packets++;
+                self->stats.tx_bytes += skb->len;
+		
+		netdev->trans_start = jiffies;
+
+#ifdef IU_BUG_KICK_TX
+		/* Kick Tx?
+		 * If the packet is a multiple of 64, the USB layer
+		 * should send an empty frame (a short packet) to signal
+		 * the end of frame (that's part of the USB spec).
+		 * If we enable USB_ZERO_PACKET, the USB layer will just do
+		 * that (more efficiently) and this code is useless.
+		 * Better keep this code until USB code clear up this mess...
+		 *
+		 * Note : we can't use the speed URB, because the frame
+		 * might contain a speed change that may be deferred
+		 * (so we have hard_xmit => tx_urb+empty_urb+speed_urb).
+		 * Jean II */
+		if ((skb->len % self->bulk_out_mtu) == 0) {
+			IRDA_DEBUG(2, __FUNCTION__ "(), Kick Tx...\n");
+			irda_usb_send_empty(self);
+		}
+#endif IU_BUG_KICK_TX
+	}
+	spin_unlock_irqrestore(&self->lock, flags);
 	
 	return 0;
 }
 
+/*------------------------------------------------------------------*/
 /*
- * Function irda_usb_build_header(self, skb, header)
- *
- *   Builds USB-IrDA outbound header
- *
- * Important note : the USB-IrDA spec 1.0 say very clearly in chapter 5.4.2.2
- * that the setting of the link speed and xbof number in this outbound header
- * should be applied *AFTER* the frame has been sent.
- * Unfortunately, some devices are not compliant with that... It seems that
- * reading the spec is far too difficult...
- * Jean II
+ * Note : this function will be called only for tx_urb...
  */
-static void irda_usb_build_header(struct irda_usb_cb *self, u8 *header,
-				  int force)
+static void write_bulk_callback(purb_t purb)
 {
-	/* Set the negotiated link speed */
-	if (self->new_speed != -1) {
-		/* Hum... Ugly hack :-(
-		 * Some device are not compliant with the spec and change
-		 * parameters *before* sending the frame. - Jean II
-		 */
-		if ((self->capability & IUC_SPEED_BUG) &&
-		    (!force) && (self->speed != -1)) 
-		{
-			/* No speed and xbofs change here
-			 * (we'll do it later in the write callback) */
-			IRDA_DEBUG(2, __FUNCTION__ "(), not changing speed yet\n");
-			*header = 0;
-			return;
-		}
+	struct sk_buff *skb = purb->context;
+	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
+	
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-		IRDA_DEBUG(2, __FUNCTION__ "(), changing speed to %d\n", self->new_speed);
-		self->speed = self->new_speed;
-		self->new_speed = -1;
+	/* We should always have a context */
+	if (self == NULL) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n");
+		return;
+	}
 
-		switch (self->speed) {
-		case 2400:
-		        *header = SPEED_2400;
-			break;
-		default:
-		case 9600:
-			*header = SPEED_9600;
-			break;
-		case 19200:
-			*header = SPEED_19200;
-			break;
-		case 38400:
-			*header = SPEED_38400;
-			break;
-		case 57600:
-		        *header = SPEED_57600;
-			break;
-		case 115200:
-		        *header = SPEED_115200;
-			break;
-		case 576000:
-		        *header = SPEED_576000;
-			break;
-		case 1152000:
-		        *header = SPEED_1152000;
-			break;
-		case 4000000:
-		        *header = SPEED_4000000;
-			self->new_xbofs = 0;
-			break;
-		}
-	} else
-		/* No change */
-		*header = 0;
-	
-	/* Set the negotiated additional XBOFS */
-	if (self->new_xbofs != -1) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), changing xbofs to %d\n", self->new_xbofs);
-		self->xbofs = self->new_xbofs;
-		self->new_xbofs = -1;
+	/* Free up the skb */
+	dev_kfree_skb_any(skb);
+	purb->context = NULL;
 
-		switch (self->xbofs) {
-		case 48:
-			*header |= 0x10;
-			break;
-		case 28:
-		case 24: /* USB spec 1.0 says 24 */
-			*header |= 0x20;
-			break;
-		default:
-		case 12:
-			*header |= 0x30;
-			break;
-		case 5: /* Bug in IrLAP spec? (should be 6) */
-		case 6:
-			*header |= 0x40;
-			break;
-		case 3:
-			*header |= 0x50;
-			break;
-		case 2:
-			*header |= 0x60;
-			break;
-		case 1:
-			*header |= 0x70;
-			break;
-		case 0:
-			*header |= 0x80;
-			break;
-		}
+	/* Check for timeout and other USB nasties */
+	if(purb->status != USB_ST_NOERROR) {
+		/* I get a lot of -ECONNABORTED = -103 here - Jean II */
+		WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", purb->status, purb->transfer_flags);
+
+		/* Don't do anything here, that might confuse the USB layer,
+		 * and we could go in recursion and blow the kernel stack...
+		 * Instead, we will wait for irda_usb_net_timeout(), the
+		 * network layer watchdog, to fix the situation.
+		 * Jean II */
+		/* A reset of the dongle might be welcomed here - Jean II */
+		return;
 	}
-}
-
-static void irda_usb_change_speed_xbofs(struct irda_usb_cb *self)
-{
-	struct sk_buff *skb;
-	unsigned long flags;
-	purb_t purb;
-	int ret;
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), speed=%d, xbofs=%d\n",
-		   self->new_speed, self->new_xbofs);
+	/* urb is now available */
+	purb->status = USB_ST_NOERROR;
 
-	purb = &self->speed_urb;
-	if (purb->status != USB_ST_NOERROR) {
-		WARNING(__FUNCTION__ "(), URB still in use!\n");
+	/* If the network is closed, stop everything */
+	if ((!self->netopen) || (!self->present)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");
 		return;
 	}
-	spin_lock_irqsave(&self->lock, flags);
-
-	/* Allocate the fake frame */
-	skb = dev_alloc_skb(IRDA_USB_SPEED_MTU);
-	if (!skb)
-		return;
-	((struct irda_skb_cb *)skb->cb)->context = self;
-
-	/* Set the new speed and xbofs in this fake frame */
-	irda_usb_build_header(self, skb_put(skb, USB_IRDA_HEADER), 1);
-
-	/* Submit the 0 length IrDA frame to trigger new speed settings */
-        FILL_BULK_URB(purb, self->usbdev,
-		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
-                      skb->data, IRDA_USB_MAX_MTU,
-                      write_bulk_callback, skb);
-	purb->transfer_buffer_length = skb->len;
-	purb->transfer_flags |= USB_QUEUE_BULK;
-	purb->timeout = MSECS_TO_JIFFIES(100);
 
-	if ((ret = usb_submit_urb(purb))) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), failed Speed URB\n");
+	/* If we need to change the speed or xbofs, do it now */
+	if ((self->new_speed != -1) || (self->new_xbofs != -1)) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n");
+		irda_usb_change_speed_xbofs(self);
+	} else {
+		/* Otherwise, allow the stack to send more packets */
+		netif_wake_queue(self->netdev);
 	}
-	spin_unlock_irqrestore(&self->lock, flags);
 }
 
-static int irda_usb_hard_xmit(struct sk_buff *skb, struct net_device *netdev)
+/*------------------------------------------------------------------*/
+/*
+ * Watchdog timer from the network layer.
+ * After a predetermined timeout, if we don't give confirmation that
+ * the packet has been sent (i.e. no call to netif_wake_queue()),
+ * the network layer will call this function.
+ * Note that URB that we submit have also a timeout. When the URB timeout
+ * expire, the normal URB callback is called (write_bulk_callback()).
+ */
+static void irda_usb_net_timeout(struct net_device *netdev)
 {
 	struct irda_usb_cb *self = netdev->priv;
-	purb_t purb = &self->tx_urb;
-	unsigned long flags;
-	s32 speed;
-	s16 xbofs;
-	int mtt;
+	purb_t purb;
+	int	done = 0;	/* If we have made any progress */
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
 
-	/* Check if the device is still there */
 	if ((!self) || (!self->present)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Device is gone...\n");
-		return 1;	/* Failed */
+		WARNING(__FUNCTION__ "(), device not present!\n");
+		netif_stop_queue(netdev);
+		return;
 	}
 
-	netif_stop_queue(netdev);
+#ifdef IU_BUG_KICK_TX
+	/* Check empty URB */
+	purb = &(self->empty_urb);
+	if (purb->status != USB_ST_NOERROR) {
+		WARNING("%s: Empty change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
 
-	/* Check if we need to change the number of xbofs */
-        xbofs = irda_get_next_xbofs(skb);
-        if ((xbofs != self->xbofs) && (xbofs != -1)) {
-		self->new_xbofs = xbofs;
+		switch (purb->status) {
+		case -ECONNABORTED:		/* -103 */
+		case -ECONNRESET:		/* -104 */
+		case -ENOENT:			/* -2 */
+			purb->status = USB_ST_NOERROR;
+			done = 1;
+			break;
+		case USB_ST_URB_PENDING:	/* -EINPROGRESS == -115 */
+			usb_unlink_urb(purb);
+			/* Note : above will *NOT* call netif_wake_queue()
+			 * in completion handler - Jean II */
+			done = 1;
+			break;
+		default:
+			/* ??? */
+			break;
+		}
 	}
+#endif IU_BUG_KICK_TX
 
-        /* Check if we need to change the speed */
-	speed = irda_get_next_speed(skb);
-	if ((speed != self->speed) && (speed != -1)) {
-		/* Set the desired speed */
-		self->new_speed = speed;
+	/* Check speed URB */
+	purb = &(self->speed_urb);
+	if (purb->status != USB_ST_NOERROR) {
+		WARNING("%s: Speed change timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
 
-		/* Check for empty frame */
-		if (!skb->len) {
-			/* IrLAP send us an empty frame to make us change the
-			 * speed. Changing speed with the USB adapter is in
-			 * fact sending an empty frame to the adapter, so we
-			 * could just let the present function do its job.
-			 * However, we would wait for min turn time,
-			 * do an extra memcpy and increment packet counters...
-			 * Jean II */
-			irda_usb_change_speed_xbofs(self);
-			netdev->trans_start = jiffies;
-			dev_kfree_skb(skb);
-			/* Will netif_wake_queue() in callback */
-			return 0;
+		switch (purb->status) {
+		case -ECONNABORTED:		/* -103 */
+		case -ECONNRESET:		/* -104 */
+		case -ENOENT:			/* -2 */
+			purb->status = USB_ST_NOERROR;
+			netif_wake_queue(self->netdev);
+			done = 1;
+			break;
+		case USB_ST_URB_PENDING:	/* -EINPROGRESS == -115 */
+			usb_unlink_urb(purb);
+			/* Note : above will call netif_wake_queue()
+			 * in completion handler - Jean II */
+			done = 1;
+			break;
+		default:
+			/* ??? */
+			break;
 		}
 	}
 
+	/* Check Tx URB */
+	purb = &(self->tx_urb);
 	if (purb->status != USB_ST_NOERROR) {
-		WARNING(__FUNCTION__ "(), URB still in use!\n");
-		dev_kfree_skb(skb);
-		return 0;
-	}
-
-	/* Make room for IrDA-USB header */
-	if (skb_cow(skb, USB_IRDA_HEADER)) {
-		dev_kfree_skb(skb);
-		return 0;
-	}
+		struct sk_buff *skb = purb->context;
 
-	spin_lock_irqsave(&self->lock, flags);
-	
-	/* Change setting for next frame */
-	irda_usb_build_header(self, skb_push(skb, USB_IRDA_HEADER), 0);
+		WARNING("%s: Tx timed out, urb->status=%d, urb->transfer_flags=0x%04X\n", netdev->name, purb->status, purb->transfer_flags);
 
-	/* FIXME: Make macro out of this one */
-	((struct irda_skb_cb *)skb->cb)->context = self;
+		/* Increase error count */
+		self->stats.tx_errors++;
 
-        FILL_BULK_URB(purb, self->usbdev, 
-		      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
-                      skb->data, IRDA_USB_MAX_MTU,
-                      write_bulk_callback, skb);
-	purb->transfer_buffer_length = skb->len;
-	purb->transfer_flags |= USB_QUEUE_BULK;
-	purb->timeout = MSECS_TO_JIFFIES(100);
-	
-	/* Generate min turn time */
-	mtt = irda_get_mtt(skb);
-	if (mtt) {
-		int diff;
-		get_fast_time(&self->now);
-		diff = self->now.tv_usec - self->stamp.tv_usec;
-		if (diff < 0)
-			diff += 1000000;
+#ifdef IU_BUG_KICK_TIMEOUT
+		/* Can't be a bad idea to reset the speed ;-) - Jean II */
+		if(self->new_speed == -1)
+			self->new_speed = self->speed;
+		if(self->new_xbofs == -1)
+			self->new_xbofs = self->xbofs;
+		irda_usb_change_speed_xbofs(self);
+#endif IU_BUG_KICK_TIMEOUT
 
-                /* Check if the mtt is larger than the time we have
-		 * already used by all the protocol processing
-		 */
-		if (mtt > diff) {
-			mtt -= diff;
-			if (mtt > 1000) {
-				/* 
-				* FIXME: can we do better than this? Maybe call
-				* a function which sends a frame to a non 
-				* existing device, or change the speed to the 
-				* current one a number of times just to burn 
-				* time a better way.
-				*/															
-				mdelay(mtt/1000);
-				irda_usb_write_bulk(self, purb);
-				goto out;	
-			} else
-				udelay(mtt);
+		switch (purb->status) {
+		case -ECONNABORTED:		/* -103 */
+		case -ECONNRESET:		/* -104 */
+		case -ENOENT:			/* -2 */
+			if(skb != NULL) {
+				dev_kfree_skb_any(skb);
+				purb->context = NULL;
+			}
+			purb->status = USB_ST_NOERROR;
+			netif_wake_queue(self->netdev);
+			done = 1;
+			break;
+		case USB_ST_URB_PENDING:	/* -EINPROGRESS == -115 */
+			usb_unlink_urb(purb);
+			/* Note : above will call netif_wake_queue()
+			 * in completion handler - Jean II */
+			done = 1;
+			break;
+		default:
+			/* ??? */
+			break;
 		}
-	}	
-	irda_usb_write_bulk(self, purb);
-out:
-	spin_unlock_irqrestore(&self->lock, flags);
-	
-	return 0;
-}
+	}
 
-static void irda_usb_write_bulk(struct irda_usb_cb *self, purb_t purb)
-{
-	int len = purb->transfer_buffer_length; 
-	int res;
-	
-	if ((res = usb_submit_urb(purb))) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), failed Tx URB\n");
-		self->stats.tx_errors++;
-		netif_start_queue(self->netdev);
+	/* Maybe we need a reset */
+	/* Note : Some drivers seem to use a usb_set_interface() when they
+	 * need to reset the hardware. Hum...
+	 */
 
-		return;
-	}
-	self->stats.tx_packets++;
-        self->stats.tx_bytes += len;
-	self->netdev->trans_start = jiffies;
-	
-	/* Send empty frame if size if a multiple of the USB max packet size */
-	ASSERT(self->bulk_out_mtu == 64, return;);
-	if ((len % self->bulk_out_mtu) == 0) {
-		/* Borrow speed urb */
-		purb = &self->speed_urb;
-		FILL_BULK_URB(purb, self->usbdev,
-			      usb_sndbulkpipe(self->usbdev, self->bulk_out_ep),
-			      self, /* Anything not on the stack will do */
-			      IRDA_USB_MAX_MTU, NULL, NULL);
-		purb->transfer_buffer_length = 0;
-		purb->transfer_flags |= USB_QUEUE_BULK;
-		res = usb_submit_urb(purb);
-	}
+	/* if(done == 0) */
 }
 
+/************************* RECEIVE ROUTINES *************************/
 /*
- * Note : this function will be called with both tx_urb and speed_urb...
+ * Receive packets from the USB layer stack and pass them to the IrDA stack.
+ * Try to work around USB failures...
  */
-static void write_bulk_callback(purb_t purb)
-{
-	struct sk_buff *skb = purb->context;
-	struct irda_usb_cb *self = ((struct irda_skb_cb *) skb->cb)->context;
-	
-	/* We should always have a context */
-	if (self == NULL) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Bug : self == NULL\n");
-		return;
-	}
 
-	/* urb is now available */
-	purb->status = USB_ST_NOERROR;
+/*------------------------------------------------------------------*/
+/*
+ * Submit a Rx URB to the USB layer to handle reception of a frame
+ *
+ * Important note :
+ * The function process_urb() in usb-uhci.c contains the following code :
+ * >	urb->complete ((struct urb *) urb);
+ * >	// Re-submit the URB if ring-linked
+ * >	if (is_ring && (urb->status != -ENOENT) && !contains_killed) {
+ * >		urb->dev=usb_dev;
+ * >		uhci_submit_urb (urb);
+ * >	}
+ * The way I see it is that if we submit more than one Rx URB at a
+ * time, the Rx URB can be automatically re-submitted after the
+ * completion handler is called.
+ * We make sure to disable this feature by setting urb->next to NULL
+ *
+ * My take is that it's a questionable feature, and quite difficult
+ * to control and to make work effectively.
+ * The outcome (re-submited or not) depend on various complex
+ * test ('is_ring' and 'contains_killed'), and the completion handler
+ * don't have this information, so basically the driver has no way
+ * to know if URB are resubmitted or not. Yuck !
+ * If everything is perfect, it's cool, but the problem is when
+ * an URB is killed (timeout, call to unlink_urb(), ...), things get
+ * messy...
+ * The other problem is that this scheme deal only with the URB
+ * and ignore everything about the associated buffer. So, it would
+ * resubmit URB even if the buffer is still in use or non-existent.
+ * On the other hand, submitting ourself in the completion callback
+ * is quite trivial and work well (this function).
+ * Moreover, this scheme doesn't allow to have an idle URB, which is
+ * necessary to overcome some URB failures.
+ *
+ * Jean II
+ */
+static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
+{
+	struct irda_skb_cb *cb;
+	int ret;
 
-	dev_kfree_skb_any(skb);
-	purb->context = NULL;
+	IRDA_DEBUG(2, __FUNCTION__ "()\n");
 
-        /* Check for timeout and other USB nasties */
-        if (purb->status != USB_ST_NOERROR) {
-	        /* I get a lot of -ECONNABORTED = -103 here - Jean II */
-	        WARNING(__FUNCTION__ "(), URB complete status %d, transfer_flags 0x%04X\n", 
-			purb->status, purb->transfer_flags);
-	        /* Don't do anything here, that might confuse the USB layer,
-	         * and we could go in recursion and blow the kernel stack...
-	         * Instead, we will wait for irda_usb_net_timeout(), the
-	         * network layer watchdog, to fix the situation.
-	         * Jean II */
-	        /* A reset of the dongle might be welcomed here - Jean II */
-	        return;
-	}
-													
-
-	/* URB is now available */
-	purb->status = USB_ST_NOERROR;
-
-	/* If the network is closed, stop everything */
-	if ((!self->netopen) || (!self->present)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Network is gone...\n");
-		return;
-	}
-
-	/* If we need to change the speed or xbofs, do it now */
-	if ((self->new_speed != -1) || (self->new_xbofs != -1)) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Changing speed now...\n");
-		irda_usb_change_speed_xbofs(self);
-	} else {
-		/* Otherwise, allow the stack to send more packets */
-		netif_wake_queue(self->netdev);
-	}
-}
-
-static void irda_usb_submit(struct irda_usb_cb *self, struct sk_buff *skb, purb_t purb)
-{
-	struct irda_skb_cb *cb;
-	int ret;
-
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
-	/* Check that we have an urb */
-	if (!purb) {
-		IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n");
-		return;
+	/* Check that we have an urb */
+	if (!purb) {
+		IRDA_DEBUG(0, __FUNCTION__ "(), Bug : purb == NULL\n");
+		return;
 	}
 
 	/* Allocate new skb if it has not been recycled */
@@ -804,9 +739,9 @@
 		      usb_rcvbulkpipe(self->usbdev, self->bulk_in_ep), 
 		      skb->data, skb->truesize,
                       irda_usb_receive, skb);
-	purb->transfer_flags |= USB_QUEUE_BULK;
+	purb->transfer_flags = USB_QUEUE_BULK;
 	purb->status = USB_ST_NOERROR;
-	purb->next = NULL; /* Make sure we don't auto resubmit */ 
+	purb->next = NULL;	/* Don't auto resubmit URBs */
 	
 	ret = usb_submit_urb(purb);
 	if (ret) {
@@ -816,6 +751,7 @@
 	}
 }
 
+/*------------------------------------------------------------------*/
 /*
  * Function irda_usb_receive(purb)
  *
@@ -829,6 +765,8 @@
 	struct irda_skb_cb *cb;
 	struct sk_buff *new;
 	
+	IRDA_DEBUG(2, __FUNCTION__ "(), len=%d\n", purb->actual_length);
+	
 	/* Find ourselves */
 	cb = (struct irda_skb_cb *) skb->cb;
 	ASSERT(cb != NULL, return;);
@@ -843,25 +781,25 @@
 	}
 	
 	/* Check the status */
-	if (purb->status != USB_ST_NOERROR) {
+	if(purb->status != USB_ST_NOERROR) {
 		switch (purb->status) {
 		case USB_ST_CRC:		/* -EILSEQ */
 			self->stats.rx_errors++;
 			self->stats.rx_crc_errors++;	
 			break;
-		case -ECONNRESET:
-		        WARNING(__FUNCTION__ "(), Connection Reset !!!\n");
+		case -ECONNRESET:		/* -104 */
+			WARNING(__FUNCTION__ "(), Connection Reset (-104), transfer_flags 0x%04X \n", purb->transfer_flags);
 			/* uhci_cleanup_unlink() is going to kill the Rx
 			 * URB just after we return. No problem, at this
 			 * point the URB will be idle ;-) - Jean II */
 			break;
 		default:
-			WARNING(__FUNCTION__ "(), RX status %d\n", purb->status);
+			WARNING(__FUNCTION__ "(), RX status %d,transfer_flags 0x%04X \n", purb->status, purb->transfer_flags);
 			break;
 		}
 		goto done;
 	}
-
+	
 	/* Check for empty frames */
 	if (purb->actual_length <= USB_IRDA_HEADER) {
 		WARNING(__FUNCTION__ "(), empty frame!\n");
@@ -892,7 +830,7 @@
 		
 		/* Copy packet, so we can recycle the original */
 		memcpy(skb_put(new, skb->len), skb->data, skb->len);
-		/* We will cleanup the skb in irda_usb_submit */
+		/* We will cleanup the skb in irda_usb_submit() */
 	} else {
 		/* Deliver the original skb */
 		new = skb;
@@ -907,17 +845,65 @@
         new->mac.raw  = new->data;
         new->protocol = htons(ETH_P_IRDA);
         netif_rx(new);
+
 done:
-	/* Recycle Rx URB (and possible the skb as well) */
-	irda_usb_submit(self, skb, self->rx_idle_urb);
+	/* Note : at this point, the URB we've just received (purb)
+	 * is still referenced by the USB layer. For example, if we
+	 * have received a -ECONNRESET, uhci_cleanup_unlink() will
+	 * continue to process it (in fact, cleaning it up).
+	 * If we were to submit this URB, disaster would ensue.
+	 * Therefore, we submit our idle URB, and put this URB in our
+	 * idle slot....
+	 * Jean II */
+	/* Note : with this scheme, we could submit the idle URB before
+	 * processing the Rx URB. Another time... Jean II */
 
-        /* Recycle Rx URB : Now, the idle URB is the present one */
-	self->rx_idle_urb = purb;
+	/* Submit the idle URB to replace the URB we've just received */
+	irda_usb_submit(self, skb, self->idle_rx_urb);
+	/* Recycle Rx URB : Now, the idle URB is the present one */
+	self->idle_rx_urb = purb;
 	purb->context = NULL;
-	/* Prevent the USB layer playing games with our URBs */
-	purb->status = -ENOENT;
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * Callbak from IrDA layer. IrDA wants to know if we have
+ * started receiving anything.
+ */
+static int irda_usb_is_receiving(struct irda_usb_cb *self)
+{
+	/* Note : because of the way UHCI works, it's almost impossible
+	 * to get this info. The Controller DMA directly to memory and
+	 * signal only when the whole frame is finished. To know if the
+	 * first TD of the URB has been filled or not seems hard work...
+	 *
+	 * The other solution would be to use the "receiving" command
+	 * on the default decriptor with a usb_control_msg(), but that
+	 * would add USB traffic and would return result only in the
+	 * next USB frame (~1ms).
+	 *
+	 * I've been told that current dongles send status info on their
+	 * interrupt endpoint, and that's what the Windows driver uses
+	 * to know this info. Unfortunately, this is not yet in the spec...
+	 *
+	 * Jean II
+	 */
+
+	return 0; /* For now */
+}
+
+/********************** IRDA DEVICE CALLBACKS **********************/
+/*
+ * Main calls from the IrDA/Network subsystem.
+ * Mostly registering a new irda-usb device and removing it....
+ * We only deal with the IrDA side of the business, the USB side will
+ * be dealt with below...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Callback when a new IrDA device is created.
+ */
 static int irda_usb_net_init(struct net_device *dev)
 {
 	IRDA_DEBUG(0, __FUNCTION__ "()\n");
@@ -930,6 +916,7 @@
 	return 0;
 }
 
+/*------------------------------------------------------------------*/
 /*
  * Function irda_usb_net_open (dev)
  *
@@ -940,6 +927,7 @@
 static int irda_usb_net_open(struct net_device *netdev)
 {
 	struct irda_usb_cb *self;
+	char	hwname[16];
 	int i;
 	
 	IRDA_DEBUG(0, __FUNCTION__ "()\n");
@@ -970,174 +958,597 @@
 	 * Open new IrLAP layer instance to take care of us...
 	 * Note : will send immediately a speed change...
 	 */
-	self->irlap = irlap_open(netdev, &self->qos);
+	sprintf(hwname, "usb#%d", self->usbdev->devnum);
+	self->irlap = irlap_open(netdev, &self->qos, hwname);
 	ASSERT(self->irlap != NULL, return -1;);
 
 	/* Allow IrLAP to send data to us */
 	netif_start_queue(netdev);
 
-	/* Now that we can pass data to IrLAP, allow the USB layer
-	 * to send us some data... */
-	for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++)
-		irda_usb_submit(self, NULL, &(self->rx_urb[i]));
-	/* Note : we submit all the Rx URB except for one - Jean II */
-	self->rx_idle_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
-	self->rx_idle_urb->context = NULL;
+	/* Now that we can pass data to IrLAP, allow the USB layer
+	 * to send us some data... */
+	for (i = 0; i < IU_MAX_ACTIVE_RX_URBS; i++)
+		irda_usb_submit(self, NULL, &(self->rx_urb[i]));
+	/* Note : we submit all the Rx URB except for one - Jean II */
+	self->idle_rx_urb = &(self->rx_urb[IU_MAX_ACTIVE_RX_URBS]);
+	self->idle_rx_urb->context = NULL;
+
+	/* Ready to play !!! */
+	MOD_INC_USE_COUNT;
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_usb_net_close (self)
+ *
+ *    Network device is taken down. Usually this is done by 
+ *    "ifconfig irda0 down" 
+ */
+static int irda_usb_net_close(struct net_device *netdev)
+{
+	struct irda_usb_cb *self;
+	int	i;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(netdev != NULL, return -1;);
+	self = (struct irda_usb_cb *) netdev->priv;
+	ASSERT(self != NULL, return -1;);
+
+	/* Clear this flag *before* unlinking the urbs and *before*
+	 * stopping the network Tx queue - Jean II */
+	self->netopen = 0;
+
+	/* Stop network Tx queue */
+	netif_stop_queue(netdev);
+
+	/* Deallocate all the Rx path buffers (URBs and skb) */
+	for (i = 0; i < IU_MAX_RX_URBS; i++) {
+		purb_t purb = &(self->rx_urb[i]);
+		struct sk_buff *skb = (struct sk_buff *) purb->context;
+		/* Cancel the receive command */
+		usb_unlink_urb(purb);
+		/* The skb is ours, free it */
+		if(skb) {
+			dev_kfree_skb(skb);
+			purb->context = NULL;
+		}
+	}
+	/* Cancel Tx and speed URB */
+	usb_unlink_urb(&(self->tx_urb));
+	usb_unlink_urb(&(self->speed_urb));
+
+	/* Stop and remove instance of IrLAP */
+	if (self->irlap)
+		irlap_close(self->irlap);
+	self->irlap = NULL;
+
+	MOD_DEC_USE_COUNT;
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * IOCTLs : Extra out-of-band network commands...
+ */
+static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+	struct if_irda_req *irq = (struct if_irda_req *) rq;
+	struct irda_usb_cb *self;
+	int ret = 0;
+
+	ASSERT(dev != NULL, return -1;);
+	self = dev->priv;
+	ASSERT(self != NULL, return -1;);
+
+	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+
+	/* Check if the device is still there */
+	if(!self->present)
+		return -EFAULT;
+
+	switch (cmd) {
+	case SIOCSBANDWIDTH: /* Set bandwidth */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		/* Set the desired speed */
+		self->new_speed = irq->ifr_baudrate;
+		irda_usb_change_speed_xbofs(self);
+		/* Note : will spinlock in above function */
+		break;
+	case SIOCSMEDIABUSY: /* Set media busy */
+		if (!capable(CAP_NET_ADMIN))
+			return -EPERM;
+		irda_device_set_media_busy(self->netdev, TRUE);
+		break;
+	case SIOCGRECEIVING: /* Check if we are receiving right now */
+		irq->ifr_receiving = irda_usb_is_receiving(self);
+		break;
+	default:
+		ret = -EOPNOTSUPP;
+	}
+	
+	return ret;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Get device stats (for /proc/net/dev and ifconfig)
+ */
+static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev)
+{
+	struct irda_usb_cb *self = dev->priv;
+	return &self->stats;
+}
+
+/********************* IRDA CONFIG SUBROUTINES *********************/
+/*
+ * Various subroutines dealing with IrDA and network stuff we use to
+ * configure and initialise each irda-usb instance.
+ * These functions are used below in the main calls of the driver...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Set proper values in the IrDA QOS structure
+ */
+static inline void irda_usb_init_qos(struct irda_usb_cb *self)
+{
+	struct irda_class_desc *desc;
+
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+	
+	desc = self->irda_desc;
+	
+	/* Initialize QoS for this device */
+	irda_init_max_qos_capabilies(&self->qos);
+
+	self->qos.baud_rate.bits       = desc->wBaudRate;
+	self->qos.min_turn_time.bits   = desc->bmMinTurnaroundTime;
+	self->qos.additional_bofs.bits = desc->bmAdditionalBOFs;
+	self->qos.window_size.bits     = desc->bmWindowSize;
+	self->qos.data_size.bits       = desc->bmDataSize;
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), dongle says speed=0x%X, size=0x%X, window=0x%X, bofs=0x%X, turn=0x%X\n", self->qos.baud_rate.bits, self->qos.data_size.bits, self->qos.window_size.bits, self->qos.additional_bofs.bits, self->qos.min_turn_time.bits);
+
+	/* Don't always trust what the dongle tell us */
+	if(self->capability & IUC_SIR_ONLY)
+		self->qos.baud_rate.bits	&= 0xff;
+	if(self->capability & IUC_SMALL_PKT)
+		self->qos.data_size.bits	 = 0x07;
+	if(self->capability & IUC_NO_WINDOW)
+		self->qos.window_size.bits	 = 0x01;
+	if(self->capability & IUC_MAX_WINDOW)
+		self->qos.window_size.bits	 = 0x7f;
+	if(self->capability & IUC_MAX_XBOFS)
+		self->qos.additional_bofs.bits	 = 0x01;
+
+#if 1
+	/* Module parameter can override the rx window size */
+	if (qos_mtt_bits)
+		self->qos.min_turn_time.bits = qos_mtt_bits;
+#endif	    
+	/* 
+	 * Note : most of those values apply only for the receive path,
+	 * the transmit path will be set differently - Jean II 
+	 */
+	irda_qos_bits_to_value(&self->qos);
+
+	self->flags |= IFF_SIR;
+	if (self->qos.baud_rate.value > 115200)
+		self->flags |= IFF_MIR;
+	if (self->qos.baud_rate.value > 1152000)
+		self->flags |= IFF_FIR;
+	if (self->qos.baud_rate.value > 4000000)
+		self->flags |= IFF_VFIR;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Initialise the network side of the irda-usb instance
+ * Called when a new USB instance is registered in irda_usb_probe()
+ */
+static inline int irda_usb_open(struct irda_usb_cb *self)
+{
+	struct net_device *netdev;
+	int err;
+
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	spin_lock_init(&self->lock);
+
+	irda_usb_init_qos(self);
+	
+	/* Initialise list of skb beeing curently transmitted */
+	self->tx_list = hashbin_new(HB_GLOBAL);
+
+	/* Allocate the buffer for speed changes */
+	/* Don't change this buffer size and allocation without doing
+	 * some heavy and complete testing. Don't ask why :-(
+	 * Jean II */
+	self->speed_buff = (char *) kmalloc(IRDA_USB_SPEED_MTU, GFP_KERNEL);
+	if (self->speed_buff == NULL) 
+		return -1;
+	memset(self->speed_buff, 0, IRDA_USB_SPEED_MTU);
+
+	/* Create a network device for us */
+	if (!(netdev = dev_alloc("irda%d", &err))) {
+		ERROR(__FUNCTION__ "(), dev_alloc() failed!\n");
+		return -1;
+	}
+	self->netdev = netdev;
+ 	netdev->priv = (void *) self;
+
+	/* Override the network functions we need to use */
+	netdev->init            = irda_usb_net_init;
+	netdev->hard_start_xmit = irda_usb_hard_xmit;
+	netdev->tx_timeout	= irda_usb_net_timeout;
+	netdev->watchdog_timeo  = 110*HZ/1000;	/* 110 ms > USB timeout */
+	netdev->open            = irda_usb_net_open;
+	netdev->stop            = irda_usb_net_close;
+	netdev->get_stats	= irda_usb_net_get_stats;
+	netdev->do_ioctl        = irda_usb_net_ioctl;
+
+	rtnl_lock();
+	err = register_netdevice(netdev);
+	rtnl_unlock();
+	if (err) {
+		ERROR(__FUNCTION__ "(), register_netdev() failed!\n");
+		return -1;
+	}
+	MESSAGE("IrDA: Registered device %s\n", netdev->name);
+
+	return 0;
+}
+
+/*------------------------------------------------------------------*/
+/*
+ * Cleanup the network side of the irda-usb instance
+ * Called when a USB instance is removed in irda_usb_disconnect()
+ */
+static inline int irda_usb_close(struct irda_usb_cb *self)
+{
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(self != NULL, return -1;);
+
+	/* Remove netdevice */
+	if (self->netdev) {
+		rtnl_lock();
+		unregister_netdevice(self->netdev);
+		self->netdev = NULL;
+		rtnl_unlock();
+	}
+	/* Delete all pending skbs */
+	hashbin_delete(self->tx_list, (FREE_FUNC) &dev_kfree_skb_any);
+	/* Remove the speed buffer */
+	if (self->speed_buff != NULL) {
+		kfree(self->speed_buff);
+		self->speed_buff = NULL;
+	}
+
+	return 0;
+}
+
+/********************** USB CONFIG SUBROUTINES **********************/
+/*
+ * Various subroutines dealing with USB stuff we use to configure and
+ * initialise each irda-usb instance.
+ * These functions are used below in the main calls of the driver...
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_usb_parse_endpoints(dev, ifnum)
+ *
+ *    Parse the various endpoints and find the one we need.
+ *
+ * The endpoint are the pipes used to communicate with the USB device.
+ * The spec defines 2 endpoints of type bulk transfer, one in, and one out.
+ * These are used to pass frames back and forth with the dongle.
+ * Most dongle have also an interrupt endpoint, that will be probably
+ * documented in the next spec...
+ */
+static inline int irda_usb_parse_endpoints(struct irda_usb_cb *self, struct usb_endpoint_descriptor *endpoint, int ennum)
+{
+	int i;		/* Endpoint index in table */
+		
+	/* Init : no endpoints */
+	self->bulk_in_ep = 0;
+	self->bulk_out_ep = 0;
+	self->bulk_int_ep = 0;
+
+	/* Let's look at all those endpoints */
+	for(i = 0; i < ennum; i++) {
+		/* All those variables will get optimised by the compiler,
+		 * so let's aim for clarity... - Jean II */
+		__u8 ep;	/* Endpoint address */
+		__u8 dir;	/* Endpoint direction */
+		__u8 attr;	/* Endpoint attribute */
+		__u16 psize;	/* Endpoint max packet size in bytes */
+
+		/* Get endpoint address, direction and attribute */
+		ep = endpoint[i].bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+		dir = endpoint[i].bEndpointAddress & USB_ENDPOINT_DIR_MASK;
+		attr = endpoint[i].bmAttributes;
+		psize = endpoint[i].wMaxPacketSize;
+
+		/* Is it a bulk endpoint ??? */
+		if(attr == USB_ENDPOINT_XFER_BULK) {
+			/* We need to find an IN and an OUT */
+			if(dir == USB_DIR_IN) {
+				/* This is our Rx endpoint */
+				self->bulk_in_ep = ep;
+			} else {
+				/* This is our Tx endpoint */
+				self->bulk_out_ep = ep;
+				self->bulk_out_mtu = psize;
+			}
+		} else {
+			if((attr == USB_ENDPOINT_XFER_INT) &&
+			   (dir == USB_DIR_IN)) {
+				/* This is our interrupt endpoint */
+				self->bulk_int_ep = ep;
+			} else {
+				ERROR(__FUNCTION__ "(), Unrecognised endpoint %02X.\n", ep);
+			}
+		}
+	}
+
+	IRDA_DEBUG(0, __FUNCTION__ "(), And our endpoints are : in=%02X, out=%02X (%d), int=%02X\n", self->bulk_in_ep, self->bulk_out_ep, self->bulk_out_mtu, self->bulk_int_ep);
+	/* Should be 8, 16, 32 or 64 bytes */
+	ASSERT(self->bulk_out_mtu == 64, ;);
+
+	return((self->bulk_in_ep != 0) && (self->bulk_out_ep != 0));
+}
+
+#ifdef IU_DUMP_CLASS_DESC
+/*------------------------------------------------------------------*/
+/*
+ * Function usb_irda_dump_class_desc(desc)
+ *
+ *    Prints out the contents of the IrDA class descriptor
+ *
+ */
+static inline void irda_usb_dump_class_desc(struct irda_class_desc *desc)
+{
+	printk("bLength=%x\n", desc->bLength);
+	printk("bDescriptorType=%x\n", desc->bDescriptorType);
+	printk("bcdSpecRevision=%x\n", desc->bcdSpecRevision); 
+	printk("bmDataSize=%x\n", desc->bmDataSize);
+	printk("bmWindowSize=%x\n", desc->bmWindowSize);
+	printk("bmMinTurnaroundTime=%d\n", desc->bmMinTurnaroundTime);
+	printk("wBaudRate=%x\n", desc->wBaudRate);
+	printk("bmAdditionalBOFs=%x\n", desc->bmAdditionalBOFs);
+	printk("bIrdaRateSniff=%x\n", desc->bIrdaRateSniff);
+	printk("bMaxUnicastList=%x\n", desc->bMaxUnicastList);
+}
+#endif IU_DUMP_CLASS_DESC
+
+/*------------------------------------------------------------------*/
+/*
+ * Function irda_usb_find_class_desc(dev, ifnum)
+ *
+ *    Returns instance of IrDA class descriptor, or NULL if not found
+ *
+ * The class descriptor is some extra info that IrDA USB devices will
+ * offer to us, describing their IrDA characteristics. We will use that in
+ * irda_usb_init_qos()
+ */
+static inline struct irda_class_desc *irda_usb_find_class_desc(struct usb_device *dev, unsigned int ifnum)
+{
+	struct usb_interface_descriptor *interface;
+	struct irda_class_desc *desc, *ptr;
+	int ret;
+		
+	desc = kmalloc(sizeof (struct irda_class_desc), GFP_KERNEL);
+	if (desc == NULL) 
+		return NULL;
+	memset(desc, 0, sizeof(struct irda_class_desc));
+	
+	ret = usb_get_class_descriptor(dev, ifnum, USB_DT_IRDA, 0, (void *) desc, sizeof(struct irda_class_desc));
+	IRDA_DEBUG(0, __FUNCTION__ "(), ret=%d\n", ret);
+	if (ret) {
+		WARNING("usb-irda: usb_get_class_descriptor failed (0x%x)\n", ret);  
+	}
+
+	/* Check if we found it? */
+	if (desc->bDescriptorType == USB_DT_IRDA)
+		return desc;
 
-	/* Ready to play !!! */
-	MOD_INC_USE_COUNT;
-	return 0;
+	IRDA_DEBUG(0, __FUNCTION__ "(), parsing extra descriptors ...\n");
+	
+	/* Check if the class descriptor is interleaved with standard descriptors */
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	ret = usb_get_extra_descriptor(interface, USB_DT_IRDA, &ptr);
+	if (ret) {
+		kfree(desc);
+		return NULL;
+	}
+	*desc = *ptr;
+#ifdef IU_DUMP_CLASS_DESC
+	irda_usb_dump_class_desc(desc);
+#endif	IU_DUMP_CLASS_DESC
+	return desc;
 }
 
+/*********************** USB DEVICE CALLBACKS ***********************/
 /*
- * Function irda_usb_net_close (self)
- *
- *    Network device is taken down. Usually this is done by 
- *    "ifconfig irda0 down" 
+ * Main calls from the USB subsystem.
+ * Mostly registering a new irda-usb device and removing it....
  */
-static int irda_usb_net_close(struct net_device *netdev)
+
+/*------------------------------------------------------------------*/
+/*
+ * This routine is called by the USB subsystem for each new device
+ * in the system. We need to check if the device is ours, and in
+ * this case start handling it.
+ * Note : it might be worth protecting this function by a global
+ * spinlock... Or not, because maybe USB already deal with that...
+ */
+static void *irda_usb_probe(struct usb_device *dev, unsigned int ifnum,
+			    const struct usb_device_id *id)
 {
-	struct irda_usb_cb *self;
+	struct irda_usb_cb *self = NULL;
+	struct usb_interface_descriptor *interface;
+	struct irda_class_desc *irda_desc;
+	int ret;
 	int i;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
-	ASSERT(netdev != NULL, return -1;);
-	self = (struct irda_usb_cb *) netdev->priv;
-	ASSERT(self != NULL, return -1;);
-
-	/* Clear this flag *before* unlinking the urbs and *before*
-	 * stopping the network Tx queue - Jean II */
-	self->netopen = 0;
+	/* Note : the probe make sure to call us only for devices that
+	 * matches the list of dongle (top of the file). So, we
+	 * don't need to check if the dongle is really ours.
+	 * Jean II */
 
-	/* Stop network Tx queue */
-	netif_stop_queue(netdev);
+	IRDA_DEBUG(0, "Vendor: %x, Product: %x\n", dev->descriptor.idVendor, dev->descriptor.idProduct);
+	
+	MESSAGE("IRDA-USB found at address %d\n", dev->devnum);
 
-	/* Deallocate all the Rx path buffers (URBs and skb) */
-	for (i = 0; i < IU_MAX_RX_URBS; i++) {
-		purb_t purb = &(self->rx_urb[i]);
-		struct sk_buff *skb = (struct sk_buff *) purb->context;
-		/* Cancel the receive command */
-		usb_unlink_urb(purb);
-		/* The skb is ours, free it */
-		if (skb) {
-			dev_kfree_skb(skb);
-			purb->context = NULL;
+	/* Try to cleanup all instance that have a pending disconnect
+	 * Instance will be in this state is the disconnect() occurs
+	 * before the net_close().
+	 * Jean II */
+	for (i = 0; i < NIRUSB; i++) {
+		struct irda_usb_cb *irda = &irda_instance[i];
+		if((irda->usbdev != NULL) &&
+		   (irda->present == 0) &&
+		   (irda->netopen == 0)) {
+			IRDA_DEBUG(0, __FUNCTION__ "(), found a zombie instance !!!\n");
+			irda_usb_disconnect(irda->usbdev, (void *) irda);
 		}
 	}
-	/* Cancel Tx and speed URB */
-	usb_unlink_urb(&self->tx_urb);
-	usb_unlink_urb(&self->speed_urb);
-	
-	/* Stop and remove instance of IrLAP */
-	if (self->irlap)
-		irlap_close(self->irlap);
-	self->irlap = NULL;
-
-	MOD_DEC_USE_COUNT;
-
-	return 0;
-}
 
-static void irda_usb_net_timeout(struct net_device *netdev)
-{
-	struct irda_usb_cb *self = netdev->priv;
-	int done = 0;	/* If we have made any progress */
-	purb_t purb;
+	/* Find an free instance to handle this new device... */
+	self = NULL;
+	for (i = 0; i < NIRUSB; i++) {
+		if(irda_instance[i].usbdev == NULL) {
+			self = &irda_instance[i];
+			break;
+		}
+	}
+	if(self == NULL) {
+		IRDA_DEBUG(0, "Too many USB IrDA devices !!! (max = %d)\n",
+			   NIRUSB);
+		return NULL;
+	}
 
-	IRDA_DEBUG(0, __FUNCTION__ "(), Network layer thinks we timed out!\n");
+	/* Reset the instance */
+	self->present = 0;
+	self->netopen = 0;
 
-	if (!self || !self->present) {
-		WARNING(__FUNCTION__ "(), device not present!\n");
-		netif_stop_queue(netdev);
-		return;
+       /* Is this really necessary? */
+	if (usb_set_configuration (dev, dev->config[0].bConfigurationValue) < 0) {
+		err("set_configuration failed");
+		return NULL;
 	}
-	WARNING("%s: Tx timed out\n", netdev->name);
 
-	/* Check Tx URB */
-	purb = &self->tx_urb;
-	switch (purb->status) {
-		case -ECONNABORTED:	/* Can't find proper USB_ST_* code */
-			purb->status = USB_ST_NOERROR;
-			netif_wake_queue(self->netdev);
-			done = 1;
+	/* Is this really necessary? */
+	/* Note : some driver do hardcode the interface number, some others
+	 * specify an alternate, but very few driver do like this.
+	 * Jean II */
+	ret = usb_set_interface(dev, ifnum, 0);
+	IRDA_DEBUG(0, "usb-irda: set interface %d result %d\n", ifnum, ret);
+	switch (ret) {
+		case USB_ST_NOERROR:		/* 0 */
 			break;
-		case USB_ST_URB_PENDING:	/* -EINPROGRESS == -115 */
-			usb_unlink_urb(purb);
-			done = 1;
+		case USB_ST_STALL:		/* -EPIPE = -32 */
+			usb_clear_halt(dev, usb_sndctrlpipe(dev, 0));
+			IRDA_DEBUG(0, __FUNCTION__ "(), Clearing stall on control interface\n" );
 			break;
 		default:
+			IRDA_DEBUG(0, __FUNCTION__ "(), Unknown error %d\n", ret);
+			return NULL;
 			break;
 	}
-	/* Check speed URB */
-	purb = &self->speed_urb;
-	switch (purb->status) {
-		case -ECONNABORTED:	/* Can't find proper USB_ST_* code */
-			purb->status = USB_ST_NOERROR;
-			netif_wake_queue(self->netdev);
-			done = 1;
-			break;
-		case USB_ST_URB_PENDING:	/* -EINPROGRESS */
-			usb_unlink_urb(purb);
-			done = 1;
-			break;
-		default:
-			break;
+
+	/* Find our endpoints */
+	interface = &dev->actconfig->interface[ifnum].altsetting[0];
+	if(!irda_usb_parse_endpoints(self, interface->endpoint,
+				     interface->bNumEndpoints)) {
+		ERROR(__FUNCTION__ "(), Bogus endpoints...\n");
+		return NULL;
 	}
-	/* Maybe we need a reset */
-	/* if(done == 0) */
-}
 
-static int irda_usb_is_receiving(struct irda_usb_cb *self)
-{
-	return 0; /* For now */
+	/* Find IrDA class descriptor */
+	irda_desc = irda_usb_find_class_desc(dev, ifnum);
+	if (irda_desc == NULL)
+		return NULL;
+	
+	self->irda_desc =  irda_desc;	
+	self->present = 1;
+	self->netopen = 0;
+	self->capability = id->driver_info;
+	self->usbdev = dev;
+	ret = irda_usb_open(self);
+	if (ret)
+		return NULL;
+
+	return self;
 }
 
-static int irda_usb_net_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+/*------------------------------------------------------------------*/
+/*
+ * The current irda-usb device is removed, the USB layer tell us
+ * to shut it down...
+ */
+static void irda_usb_disconnect(struct usb_device *dev, void *ptr)
 {
-	struct if_irda_req *irq = (struct if_irda_req *) rq;
-	struct irda_usb_cb *self;
-	int ret = 0;
+	struct irda_usb_cb *self = (struct irda_usb_cb *) ptr;
+	int i;
 
-	ASSERT(dev != NULL, return -1;);
-	self = dev->priv;
-	ASSERT(self != NULL, return -1;);
+	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 
-	IRDA_DEBUG(2, __FUNCTION__ "(), %s, (cmd=0x%X)\n", dev->name, cmd);
+	/* Oups ! We are not there any more */
+	self->present = 0;
 
-	/* Check if the device is still there */
-	if (!self->present)
-		return -EFAULT;
+	/* Hum... Check if networking is still active */
+	if (self->netopen) {
+		/* Accept no more transmissions */
+		/*netif_device_detach(self->netdev);*/
+		netif_stop_queue(self->netdev);
+		/* Stop all the receive URBs */
+		for (i = 0; i < IU_MAX_RX_URBS; i++)
+			usb_unlink_urb(&(self->rx_urb[i]));
+		/* Cancel Tx and speed URB */
+		usb_unlink_urb(&(self->tx_urb));
+		usb_unlink_urb(&(self->speed_urb));
 
-	switch (cmd) {
-	case SIOCSBANDWIDTH: /* Set bandwidth */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		/* Set the desired speed */
-		self->new_speed = irq->ifr_baudrate;
-		irda_usb_change_speed_xbofs(self);
-		/* Note : will spinlock in above function */
-		break;
-	case SIOCSMEDIABUSY: /* Set media busy */
-		if (!capable(CAP_NET_ADMIN))
-			return -EPERM;
-		irda_device_set_media_busy(self->netdev, TRUE);
-		break;
-	case SIOCGRECEIVING: /* Check if we are receiving right now */
-		irq->ifr_receiving = irda_usb_is_receiving(self);
-		break;
-	default:
-		ret = -EOPNOTSUPP;
+		IRDA_DEBUG(0, __FUNCTION__ "(), postponing disconnect, network is still active...\n");
+		/* better not do anything just yet, usb_irda_cleanup()
+		 * will do whats needed */
+		return;
 	}
-	return ret;
-}
 
-static struct net_device_stats *irda_usb_net_get_stats(struct net_device *dev)
-{
-	struct irda_usb_cb *self = dev->priv;
-	return &self->stats;
+	/* Cleanup the device stuff */
+	irda_usb_close(self);
+	/* No longer attached to USB bus */
+	self->usbdev = NULL;
+	IRDA_DEBUG(0, __FUNCTION__ "(), USB IrDA Disconnected\n");
 }
 
+/*------------------------------------------------------------------*/
+/*
+ * USB device callbacks
+ */
+static struct usb_driver irda_driver = {
+	name:		"irda-usb",
+	probe:		irda_usb_probe,
+	disconnect:	irda_usb_disconnect,
+	id_table:	dongles,
+};
+
+/************************* MODULE CALLBACKS *************************/
+/*
+ * Deal with module insertion/removal
+ * Mostly tell USB about our existence
+ */
+
+/*------------------------------------------------------------------*/
+/*
+ * Module insertion
+ */
 int __init usb_irda_init(void)
 {
 	if (usb_register(&irda_driver) < 0)
@@ -1148,10 +1559,14 @@
 }
 module_init(usb_irda_init);
 
+/*------------------------------------------------------------------*/
+/*
+ * Module removal
+ */
 void __exit usb_irda_cleanup(void)
 {
 	struct irda_usb_cb *irda = NULL;
-	int i;
+	int	i;
 
 	/* Find zombie instances and kill them... */
 	for (i = 0; i < NIRUSB; i++) {
@@ -1162,15 +1577,17 @@
 			irda_usb_disconnect(irda->usbdev, (void *) irda);
 		}
 	}
+
 	/* Deregister the driver and remove all pending instances */
 	usb_deregister(&irda_driver);
 }
 module_exit(usb_irda_cleanup);
 
+/*------------------------------------------------------------------*/
+/*
+ * Module parameters
+ */
 MODULE_PARM(qos_mtt_bits, "i");
 MODULE_PARM_DESC(qos_mtt_bits, "Minimum Turn Time");
 MODULE_AUTHOR("Roman Weissgaerber <weissg@vienna.at>, Dag Brattli <dag@brattli.net> and Jean Tourrilhes <jt@hpl.hp.com>");
 MODULE_DESCRIPTION("IrDA-USB Dongle Driver"); 
-
-
-
diff -urN linux-2.4.10-pre8/drivers/net/irda/irport.c linux/drivers/net/irda/irport.c
--- linux-2.4.10-pre8/drivers/net/irda/irport.c	Sun Aug 12 10:51:42 2001
+++ linux/drivers/net/irda/irport.c	Mon Dec  3 23:09:48 2001
@@ -774,6 +774,7 @@
 {
 	struct irport_cb *self;
 	int iobase;
+	char hwname[16];
 
 	IRDA_DEBUG(0, __FUNCTION__ "()\n");
 	
@@ -792,11 +793,14 @@
 	irport_start(self);
 
 
+	/* Give self a hardware name */
+	sprintf(hwname, "SIR @ 0x%03x", self->io.sir_base);
+
 	/* 
 	 * Open new IrLAP layer instance, now that everything should be
 	 * initialized properly 
 	 */
-	self->irlap = irlap_open(dev, &self->qos);
+	self->irlap = irlap_open(dev, &self->qos, hwname);
 
 	/* FIXME: change speed of dongle */
 	/* Ready to play! */
diff -urN linux-2.4.10-pre8/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- linux-2.4.10-pre8/drivers/net/irda/irtty.c	Wed Jul  4 11:50:38 2001
+++ linux/drivers/net/irda/irtty.c	Mon Dec  3 23:09:48 2001
@@ -895,6 +895,8 @@
 static int irtty_net_open(struct net_device *dev)
 {
 	struct irtty_cb *self = (struct irtty_cb *) dev->priv;
+	struct tty_struct *tty = self->tty;
+	char hwname[16];
 
 	ASSERT(self != NULL, return -1;);
 	ASSERT(self->magic == IRTTY_MAGIC, return -1;);
@@ -907,11 +909,16 @@
 	/* Make sure we can receive more data */
 	irtty_stop_receiver(self, FALSE);
 
+	/* Give self a hardware name */
+	sprintf(hwname, "%s%d", tty->driver.name,
+		MINOR(tty->device) - tty->driver.minor_start +
+		tty->driver.name_base);
+
 	/* 
 	 * Open new IrLAP layer instance, now that everything should be
 	 * initialized properly 
 	 */
-	self->irlap = irlap_open(dev, &self->qos);
+	self->irlap = irlap_open(dev, &self->qos, hwname);
 
 	MOD_INC_USE_COUNT;
 
diff -urN linux-2.4.10-pre8/drivers/net/irda/nsc-ircc.c linux/drivers/net/irda/nsc-ircc.c
--- linux-2.4.10-pre8/drivers/net/irda/nsc-ircc.c	Wed Jul  4 11:50:38 2001
+++ linux/drivers/net/irda/nsc-ircc.c	Mon Dec  3 23:09:48 2001
@@ -1836,6 +1836,7 @@
 {
 	struct nsc_ircc_cb *self;
 	int iobase;
+	char hwname[32];
 	__u8 bank;
 	
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
@@ -1874,14 +1875,16 @@
 	outb(bank, iobase+BSR);
 
 	/* Ready to play! */
-
 	netif_start_queue(dev);
 	
+	/* Give self a hardware name */
+	sprintf(hwname, "NSC-FIR @ 0x%03x", self->io.fir_base);
+
 	/* 
 	 * Open new IrLAP layer instance, now that everything should be
 	 * initialized properly 
 	 */
-	self->irlap = irlap_open(dev, &self->qos);
+	self->irlap = irlap_open(dev, &self->qos, hwname);
 
 	MOD_INC_USE_COUNT;
 
diff -urN linux-2.4.10-pre8/drivers/net/irda/toshoboe.c linux/drivers/net/irda/toshoboe.c
--- linux-2.4.10-pre8/drivers/net/irda/toshoboe.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/irda/toshoboe.c	Mon Dec  3 23:09:48 2001
@@ -510,6 +510,7 @@
 toshoboe_net_open (struct net_device *dev)
 {
   struct toshoboe_cb *self;
+  char hwname[32];
 
   IRDA_DEBUG (4, __FUNCTION__ "()\n");
 
@@ -537,11 +538,13 @@
 
   /* Ready to play! */
   netif_start_queue(dev);  
+  /* Give self a hardware name */
+  sprintf(hwname, "Toshiba-FIR @ 0x%03x", self->base);
   /* 
    * Open new IrLAP layer instance, now that everything should be
    * initialized properly 
    */
-  self->irlap = irlap_open(dev, &self->qos);	
+  self->irlap = irlap_open(dev, &self->qos, hwname);	
 
   self->open = 1;
 	
diff -urN linux-2.4.10-pre8/drivers/net/irda/vlsi_ir.c linux/drivers/net/irda/vlsi_ir.c
--- linux-2.4.10-pre8/drivers/net/irda/vlsi_ir.c	Sun Aug 12 10:51:42 2001
+++ linux/drivers/net/irda/vlsi_ir.c	Mon Dec  3 23:09:48 2001
@@ -776,6 +776,7 @@
 {
 	vlsi_irda_dev_t *idev = ndev->priv;
 	struct pci_dev *pdev = idev->pdev;
+	char	hwname[32];
 	int	err;
 
 	MOD_INC_USE_COUNT;		/* still needed? - we have SET_MODULE_OWNER! */
@@ -824,7 +825,8 @@
 		(idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR"),
 		(sirpulse)?"3/16 bittime":"short");
 
-	idev->irlap = irlap_open(ndev,&idev->qos);
+	sprintf(hwname, "VLSI-FIR");
+	idev->irlap = irlap_open(ndev,&idev->qos,hwname);
 
 	netif_start_queue(ndev);
 
diff -urN linux-2.4.10-pre8/drivers/net/irda/w83977af_ir.c linux/drivers/net/irda/w83977af_ir.c
--- linux-2.4.10-pre8/drivers/net/irda/w83977af_ir.c	Tue Mar 20 12:04:59 2001
+++ linux/drivers/net/irda/w83977af_ir.c	Mon Dec  3 23:09:48 2001
@@ -1210,6 +1210,7 @@
 {
 	struct w83977af_ir *self;
 	int iobase;
+	char hwname[32];
 	__u8 set;
 	
 	IRDA_DEBUG(0, __FUNCTION__ "()\n");
@@ -1251,11 +1252,14 @@
 	/* Ready to play! */
 	netif_start_queue(dev);
 	
+	/* Give self a hardware name */
+	sprintf(hwname, "w83977af @ 0x%03x", self->io.fir_base);
+
 	/* 
 	 * Open new IrLAP layer instance, now that everything should be
 	 * initialized properly 
 	 */
-	self->irlap = irlap_open(dev, &self->qos);
+	self->irlap = irlap_open(dev, &self->qos, hwname);
 
 	MOD_INC_USE_COUNT;
 
diff -urN linux-2.4.10-pre8/drivers/net/ncr885e.c linux/drivers/net/ncr885e.c
--- linux-2.4.10-pre8/drivers/net/ncr885e.c	Mon Jul  2 14:03:04 2001
+++ linux/drivers/net/ncr885e.c	Mon Dec  3 23:09:48 2001
@@ -19,7 +19,7 @@
 #include <linux/sched.h>
 #include <linux/timer.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/netdevice.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
diff -urN linux-2.4.10-pre8/drivers/net/pcmcia/xirc2ps_cs.c linux/drivers/net/pcmcia/xirc2ps_cs.c
--- linux-2.4.10-pre8/drivers/net/pcmcia/xirc2ps_cs.c	Wed Apr 18 14:40:05 2001
+++ linux/drivers/net/pcmcia/xirc2ps_cs.c	Mon Dec  3 23:09:48 2001
@@ -2084,6 +2084,8 @@
 	MAYBE_SET(irq_list[2], 8);
 	MAYBE_SET(irq_list[3], 9);
 #undef  MAYBE_SET(X,Y)
+
+	return 0;
 }
 
 __setup("xirc2ps_cs=", setup_xirc2ps_cs);
diff -urN linux-2.4.10-pre8/drivers/net/strip.c linux/drivers/net/strip.c
--- linux-2.4.10-pre8/drivers/net/strip.c	Sun Feb  4 10:05:30 2001
+++ linux/drivers/net/strip.c	Mon Dec  3 23:09:48 2001
@@ -2828,7 +2828,7 @@
  * STRIP driver
  */
 
-static const char signon[] __initdata = KERN_INFO "STRIP: Version %s (unlimited channels)\n";
+static char signon[] __initdata = KERN_INFO "STRIP: Version %s (unlimited channels)\n";
 
 static int __init strip_init_driver(void)
 {
diff -urN linux-2.4.10-pre8/drivers/net/sungem.c linux/drivers/net/sungem.c
--- linux-2.4.10-pre8/drivers/net/sungem.c	Tue Aug 14 19:57:28 2001
+++ linux/drivers/net/sungem.c	Mon Dec  3 23:09:48 2001
@@ -14,7 +14,7 @@
 #include <linux/ptrace.h>
 #include <linux/ioport.h>
 #include <linux/in.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
diff -urN linux-2.4.10-pre8/drivers/net/tokenring/abyss.c linux/drivers/net/tokenring/abyss.c
--- linux-2.4.10-pre8/drivers/net/tokenring/abyss.c	Fri May 25 09:58:07 2001
+++ linux/drivers/net/tokenring/abyss.c	Mon Dec  3 23:09:48 2001
@@ -53,6 +53,8 @@
 };
 MODULE_DEVICE_TABLE(pci, abyss_pci_tbl);
 
+MODULE_LICENSE("GPL");
+
 static int abyss_open(struct net_device *dev);
 static int abyss_close(struct net_device *dev);
 static void abyss_enable(struct net_device *dev);
diff -urN linux-2.4.10-pre8/drivers/net/tokenring/ibmtr.c linux/drivers/net/tokenring/ibmtr.c
--- linux-2.4.10-pre8/drivers/net/tokenring/ibmtr.c	Sun Aug  5 13:12:41 2001
+++ linux/drivers/net/tokenring/ibmtr.c	Mon Dec  3 23:09:48 2001
@@ -1924,6 +1924,8 @@
 static int irq[IBMTR_MAX_ADAPTERS];
 static int mem[IBMTR_MAX_ADAPTERS];
 
+MODULE_LICENSE("GPL");
+
 MODULE_PARM(io, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(IBMTR_MAX_ADAPTERS) "i");
diff -urN linux-2.4.10-pre8/drivers/net/tokenring/madgemc.c linux/drivers/net/tokenring/madgemc.c
--- linux-2.4.10-pre8/drivers/net/tokenring/madgemc.c	Fri May 25 09:58:07 2001
+++ linux/drivers/net/tokenring/madgemc.c	Mon Dec  3 23:09:48 2001
@@ -793,6 +793,8 @@
 }
 #endif /* MODULE */
 
+MODULE_LICENSE("GPL");
+
 
 /*
  * Local variables:
@@ -804,3 +806,4 @@
  *  tab-width: 8
  * End:
  */
+
diff -urN linux-2.4.10-pre8/drivers/net/tokenring/olympic.c linux/drivers/net/tokenring/olympic.c
--- linux-2.4.10-pre8/drivers/net/tokenring/olympic.c	Wed Jun 20 11:13:18 2001
+++ linux/drivers/net/tokenring/olympic.c	Mon Dec  3 23:09:48 2001
@@ -1722,4 +1722,4 @@
 module_init(olympic_pci_init) ; 
 module_exit(olympic_pci_cleanup) ; 
 
-
+MODULE_LICENSE("GPL");
\ No newline at end of file
diff -urN linux-2.4.10-pre8/drivers/net/tokenring/smctr.c linux/drivers/net/tokenring/smctr.c
--- linux-2.4.10-pre8/drivers/net/tokenring/smctr.c	Thu Jun 21 14:28:39 2001
+++ linux/drivers/net/tokenring/smctr.c	Mon Dec  3 23:09:48 2001
@@ -5733,6 +5733,8 @@
 static int irq[SMCTR_MAX_ADAPTERS];
 static int mem[SMCTR_MAX_ADAPTERS];
 
+MODULE_LICENSE("GPL");
+
 MODULE_PARM(io,  "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i");
 MODULE_PARM(mem, "1-" __MODULE_STRING(SMCTR_MAX_ADAPTERS) "i");
diff -urN linux-2.4.10-pre8/drivers/net/tokenring/tms380tr.c linux/drivers/net/tokenring/tms380tr.c
--- linux-2.4.10-pre8/drivers/net/tokenring/tms380tr.c	Wed May 16 10:31:27 2001
+++ linux/drivers/net/tokenring/tms380tr.c	Mon Dec  3 23:09:48 2001
@@ -71,10 +71,8 @@
 static const char version[] = "tms380tr.c: v1.08 14/01/2001 by Christoph Goos, Adam Fritzler\n";
 #endif
 
-#ifdef MODULE
 #include <linux/module.h>
 #include <linux/version.h>
-#endif
 
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -2416,6 +2414,8 @@
 	TMS380_module = NULL;
 }
 #endif
+
+MODULE_LICENSE("GPL");
 
 
 /*
diff -urN linux-2.4.10-pre8/drivers/net/tokenring/tmsisa.c linux/drivers/net/tokenring/tmsisa.c
--- linux-2.4.10-pre8/drivers/net/tokenring/tmsisa.c	Fri Apr 20 11:54:22 2001
+++ linux/drivers/net/tokenring/tmsisa.c	Mon Dec  3 23:09:48 2001
@@ -372,6 +372,8 @@
 static int irq[ISATR_MAX_ADAPTERS];
 static int dma[ISATR_MAX_ADAPTERS];
 
+MODULE_LICENSE("GPL");
+
 MODULE_PARM(io, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i");
 MODULE_PARM(irq, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i");
 MODULE_PARM(dma, "1-" __MODULE_STRING(ISATR_MAX_ADAPTERS) "i");
diff -urN linux-2.4.10-pre8/drivers/net/tokenring/tmspci.c linux/drivers/net/tokenring/tmspci.c
--- linux-2.4.10-pre8/drivers/net/tokenring/tmspci.c	Fri May 25 09:58:07 2001
+++ linux/drivers/net/tokenring/tmspci.c	Mon Dec  3 23:09:48 2001
@@ -67,6 +67,8 @@
 };
 MODULE_DEVICE_TABLE(pci, tmspci_pci_tbl);
 
+MODULE_LICENSE("GPL");
+
 static void tms_pci_read_eeprom(struct net_device *dev);
 static unsigned short tms_pci_setnselout_pins(struct net_device *dev);
 
diff -urN linux-2.4.10-pre8/drivers/net/wan/c101.c linux/drivers/net/wan/c101.c
--- linux-2.4.10-pre8/drivers/net/wan/c101.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/c101.c	Mon Dec  3 23:09:48 2001
@@ -371,5 +371,6 @@
 
 MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
 MODULE_DESCRIPTION("Moxa C101 serial port driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(hw, "s");		/* hw=irq,ram:irq,... */
 EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/net/wan/comx-hw-comx.c linux/drivers/net/wan/comx-hw-comx.c
--- linux-2.4.10-pre8/drivers/net/wan/comx-hw-comx.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/comx-hw-comx.c	Mon Dec  3 23:09:48 2001
@@ -63,6 +63,7 @@
 
 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>, Tivadar Szemethy <tiv@itc.hu>, Arpad Bakay");
 MODULE_DESCRIPTION("Hardware-level driver for the COMX and HICOMX adapters\n");
+MODULE_LICENSE("GPL");
 
 #define	COMX_readw(dev, offset)	(readw(dev->mem_start + offset + \
 	(unsigned int)(((struct comx_privdata *)\
diff -urN linux-2.4.10-pre8/drivers/net/wan/comx-hw-locomx.c linux/drivers/net/wan/comx-hw-locomx.c
--- linux-2.4.10-pre8/drivers/net/wan/comx-hw-locomx.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/comx-hw-locomx.c	Mon Dec  3 23:09:48 2001
@@ -54,6 +54,7 @@
 
 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
 MODULE_DESCRIPTION("Hardware driver for the LoCOMX board");
+MODULE_LICENSE("GPL");
 
 #define RX_DMA 3
 #define TX_DMA 1
diff -urN linux-2.4.10-pre8/drivers/net/wan/comx-hw-mixcom.c linux/drivers/net/wan/comx-hw-mixcom.c
--- linux-2.4.10-pre8/drivers/net/wan/comx-hw-mixcom.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/comx-hw-mixcom.c	Mon Dec  3 23:09:48 2001
@@ -58,6 +58,7 @@
 
 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
 MODULE_DESCRIPTION("Hardware-level driver for the serial port of the MixCom board");
+MODULE_LICENSE("GPL");
 
 #define MIXCOM_DATA(d) ((struct mixcom_privdata *)(COMX_CHANNEL(d)-> \
 	HW_privdata))
diff -urN linux-2.4.10-pre8/drivers/net/wan/comx-proto-fr.c linux/drivers/net/wan/comx-proto-fr.c
--- linux-2.4.10-pre8/drivers/net/wan/comx-proto-fr.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/comx-proto-fr.c	Mon Dec  3 23:09:48 2001
@@ -53,7 +53,8 @@
 
 MODULE_AUTHOR("Author: Tivadar Szemethy <tiv@itc.hu>");
 MODULE_DESCRIPTION("Frame Relay protocol implementation for the COMX drivers"
-	"for Linux kernel 2.2.X");
+	"for Linux kernel 2.4.X");
+MODULE_LICENSE("GPL");
 
 #define	FRAD_UI		0x03
 #define	NLPID_IP	0xcc
diff -urN linux-2.4.10-pre8/drivers/net/wan/comx-proto-lapb.c linux/drivers/net/wan/comx-proto-lapb.c
--- linux-2.4.10-pre8/drivers/net/wan/comx-proto-lapb.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/comx-proto-lapb.c	Mon Dec  3 23:09:48 2001
@@ -543,3 +543,5 @@
 module_init(comx_proto_lapb_init);
 #endif
 module_exit(comx_proto_lapb_exit);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/net/wan/comx-proto-ppp.c linux/drivers/net/wan/comx-proto-ppp.c
--- linux-2.4.10-pre8/drivers/net/wan/comx-proto-ppp.c	Tue Mar  6 19:44:36 2001
+++ linux/drivers/net/wan/comx-proto-ppp.c	Mon Dec  3 23:09:48 2001
@@ -49,6 +49,7 @@
 
 MODULE_AUTHOR("Author: Gergely Madarasz <gorgo@itc.hu>");
 MODULE_DESCRIPTION("Cisco-HDLC / Synchronous PPP driver for the COMX sync serial boards");
+MODULE_LICENSE("GPL");
 
 static struct comx_protocol syncppp_protocol;
 static struct comx_protocol hdlc_protocol;
diff -urN linux-2.4.10-pre8/drivers/net/wan/comx.c linux/drivers/net/wan/comx.c
--- linux-2.4.10-pre8/drivers/net/wan/comx.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/comx.c	Mon Dec  3 23:09:48 2001
@@ -78,6 +78,7 @@
 
 MODULE_AUTHOR("Gergely Madarasz <gorgo@itc.hu>");
 MODULE_DESCRIPTION("Common code for the COMX synchronous serial adapters");
+MODULE_LICENSE("GPL");
 
 extern int comx_hw_comx_init(void);
 extern int comx_hw_locomx_init(void);
diff -urN linux-2.4.10-pre8/drivers/net/wan/cosa.c linux/drivers/net/wan/cosa.c
--- linux-2.4.10-pre8/drivers/net/wan/cosa.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/net/wan/cosa.c	Mon Dec  3 23:09:48 2001
@@ -251,6 +251,7 @@
 
 MODULE_AUTHOR("Jan \"Yenya\" Kasprzak, <kas@fi.muni.cz>");
 MODULE_DESCRIPTION("Modular driver for the COSA or SRP synchronous card");
+MODULE_LICENSE("GPL");
 #endif
 
 /* I use this mainly for testing purposes */
diff -urN linux-2.4.10-pre8/drivers/net/wan/cycx_main.c linux/drivers/net/wan/cycx_main.c
--- linux-2.4.10-pre8/drivers/net/wan/cycx_main.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/cycx_main.c	Mon Dec  3 23:09:48 2001
@@ -56,6 +56,7 @@
 
 MODULE_AUTHOR("Arnaldo Carvalho de Melo");
 MODULE_DESCRIPTION("Cyclom 2X Sync Card Driver.");
+MODULE_LICENSE("GPL");
 MODULE_PARM(cycx_debug, "i");
 MODULE_PARM_DESC(cycx_debug, "cyclomx debug level");
 
diff -urN linux-2.4.10-pre8/drivers/net/wan/dlci.c linux/drivers/net/wan/dlci.c
--- linux-2.4.10-pre8/drivers/net/wan/dlci.c	Fri Apr 20 11:54:22 2001
+++ linux/drivers/net/wan/dlci.c	Mon Dec  3 23:09:48 2001
@@ -609,3 +609,7 @@
 	dlci_ioctl_hook = NULL;
 }
 #endif /* MODULE */
+
+MODULE_AUTHOR("Mike McLagan");
+MODULE_DESCRIPTION("Frame Relay DLCI layer");
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/net/wan/dscc4.c linux/drivers/net/wan/dscc4.c
--- linux-2.4.10-pre8/drivers/net/wan/dscc4.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/dscc4.c	Mon Dec  3 23:09:48 2001
@@ -114,6 +114,7 @@
 /* Module parameters */
 MODULE_AUTHOR("Maintainer: Francois Romieu <romieu@cogenit.fr>");
 MODULE_DESCRIPTION("Siemens PEB20534 PCI Controller");
+MODULE_LICENSE("GPL");
 MODULE_PARM(debug,"i");
 
 /* Structures */
diff -urN linux-2.4.10-pre8/drivers/net/wan/hdlc.c linux/drivers/net/wan/hdlc.c
--- linux-2.4.10-pre8/drivers/net/wan/hdlc.c	Tue Jun 12 11:06:54 2001
+++ linux/drivers/net/wan/hdlc.c	Mon Dec  3 23:09:48 2001
@@ -1437,6 +1437,7 @@
 
 MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
 MODULE_DESCRIPTION("HDLC support module");
+MODULE_LICENSE("GPL");
 
 EXPORT_SYMBOL(hdlc_netif_rx);
 EXPORT_SYMBOL(register_hdlc_device);
diff -urN linux-2.4.10-pre8/drivers/net/wan/lapbether.c linux/drivers/net/wan/lapbether.c
--- linux-2.4.10-pre8/drivers/net/wan/lapbether.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/net/wan/lapbether.c	Mon Dec  3 23:09:48 2001
@@ -467,7 +467,7 @@
 	notifier_call: lapbeth_device_event,
 };
 
-static const char banner[] __initdata = KERN_INFO "LAPB Ethernet driver version 0.01\n";
+static char banner[] __initdata = KERN_INFO "LAPB Ethernet driver version 0.01\n";
 
 static int __init lapbeth_init_driver(void)
 {
@@ -510,4 +510,6 @@
 
 MODULE_AUTHOR("Jonathan Naylor <g4klx@g4klx.demon.co.uk>");
 MODULE_DESCRIPTION("The unofficial LAPB over Ethernet driver");
+MODULE_LICENSE("GPL");
+
 
diff -urN linux-2.4.10-pre8/drivers/net/wan/lmc/lmc_main.c linux/drivers/net/wan/lmc/lmc_main.c
--- linux-2.4.10-pre8/drivers/net/wan/lmc/lmc_main.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/net/wan/lmc/lmc_main.c	Mon Dec  3 23:09:48 2001
@@ -108,6 +108,8 @@
 };
 
 MODULE_DEVICE_TABLE(pci, lmc_pci_tbl);
+
+MODULE_LICENSE("GPL");
 #endif
 
 
diff -urN linux-2.4.10-pre8/drivers/net/wan/n2.c linux/drivers/net/wan/n2.c
--- linux-2.4.10-pre8/drivers/net/wan/n2.c	Tue Mar  6 19:44:37 2001
+++ linux/drivers/net/wan/n2.c	Mon Dec  3 23:09:48 2001
@@ -586,5 +586,6 @@
 
 MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
 MODULE_DESCRIPTION("RISCom/N2 serial port driver");
+MODULE_LICENSE("GPL");
 MODULE_PARM(hw, "s");		/* hw=io,irq,ram,ports:io,irq,... */
 EXPORT_NO_SYMBOLS;
diff -urN linux-2.4.10-pre8/drivers/net/wan/sdla.c linux/drivers/net/wan/sdla.c
--- linux-2.4.10-pre8/drivers/net/wan/sdla.c	Wed Apr 18 14:40:07 2001
+++ linux/drivers/net/wan/sdla.c	Mon Dec  3 23:09:48 2001
@@ -1665,6 +1665,8 @@
 #ifdef MODULE
 static struct net_device sdla0 = {"sdla0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, sdla_init};
 
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	int result;
diff -urN linux-2.4.10-pre8/drivers/net/wan/sdla_chdlc.c linux/drivers/net/wan/sdla_chdlc.c
--- linux-2.4.10-pre8/drivers/net/wan/sdla_chdlc.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/sdla_chdlc.c	Mon Dec  3 23:09:48 2001
@@ -4742,4 +4742,6 @@
 #endif
 
 
+MODULE_LICENSE("GPL");
+
 /****** End ****************************************************************/
diff -urN linux-2.4.10-pre8/drivers/net/wan/sdla_fr.c linux/drivers/net/wan/sdla_fr.c
--- linux-2.4.10-pre8/drivers/net/wan/sdla_fr.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/sdla_fr.c	Mon Dec  3 23:09:48 2001
@@ -5476,5 +5476,6 @@
 
 	
 
+MODULE_LICENSE("GPL");
 
 /****** End *****************************************************************/
diff -urN linux-2.4.10-pre8/drivers/net/wan/sdla_ft1.c linux/drivers/net/wan/sdla_ft1.c
--- linux-2.4.10-pre8/drivers/net/wan/sdla_ft1.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/sdla_ft1.c	Mon Dec  3 23:09:48 2001
@@ -23,27 +23,17 @@
 #include <linux/module.h>
 #include <linux/version.h>
 #include <linux/kernel.h>	/* printk(), and other useful stuff */
+#include <linux/module.h>
 #include <linux/stddef.h>	/* offsetof(), etc. */
 #include <linux/errno.h>	/* return codes */
 #include <linux/string.h>	/* inline memset(), etc. */
-#include <linux/slab.h>	/* kmalloc(), kfree() */
+#include <linux/slab.h>		/* kmalloc(), kfree() */
 #include <linux/wanrouter.h>	/* WAN router definitions */
 #include <linux/wanpipe.h>	/* WANPIPE common user API definitions */
 #include <linux/if_arp.h>	/* ARPHRD_* defines */
 
-#if defined(LINUX_2_4)
-  #include <linux/inetdevice.h>
-  #include <asm/uaccess.h>
-
-#elif defined(LINUX_2_1)
-  #include <linux/inetdevice.h>
-  #include <asm/uaccess.h>
-
-#else
-  #include <net/route.h>          /* Adding new route entries */
-  #include <asm/segment.h>
-  #define test_and_set_bit set_bit
-#endif
+#include <linux/inetdevice.h>
+#include <asm/uaccess.h>
 
 #include <linux/in.h>		/* sockaddr_in */
 #include <linux/inet.h>	
@@ -385,3 +375,4 @@
 	return 0;
 }
 
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/net/wan/sdla_ppp.c linux/drivers/net/wan/sdla_ppp.c
--- linux-2.4.10-pre8/drivers/net/wan/sdla_ppp.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/sdla_ppp.c	Mon Dec  3 23:09:48 2001
@@ -3721,5 +3721,6 @@
 	return 0;
 }
 
+MODULE_LICENSE("GPL");
 
 /****** End *****************************************************************/
diff -urN linux-2.4.10-pre8/drivers/net/wan/sdla_x25.c linux/drivers/net/wan/sdla_x25.c
--- linux-2.4.10-pre8/drivers/net/wan/sdla_x25.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/sdla_x25.c	Mon Dec  3 23:09:48 2001
@@ -5570,4 +5570,6 @@
 
 }
 
+MODULE_LICENSE("GPL");
+
 /****** End *****************************************************************/
diff -urN linux-2.4.10-pre8/drivers/net/wan/sdladrv.c linux/drivers/net/wan/sdladrv.c
--- linux-2.4.10-pre8/drivers/net/wan/sdladrv.c	Sun May 20 12:11:39 2001
+++ linux/drivers/net/wan/sdladrv.c	Mon Dec  3 23:09:48 2001
@@ -213,13 +213,13 @@
  * Note: All data must be explicitly initialized!!!
  */
 
-#ifdef LINUX_2_4
 static struct pci_device_id sdladrv_pci_tbl[] __initdata = {
 	{ V3_VENDOR_ID, V3_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID, },
 	{ }			/* Terminating entry */
 };
 MODULE_DEVICE_TABLE(pci, sdladrv_pci_tbl);
-#endif
+
+MODULE_LICENSE("GPL");
 
 /* private data */
 static char modname[]	= "sdladrv";
diff -urN linux-2.4.10-pre8/drivers/net/wan/sdlamain.c linux/drivers/net/wan/sdlamain.c
--- linux-2.4.10-pre8/drivers/net/wan/sdlamain.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/net/wan/sdlamain.c	Mon Dec  3 23:09:48 2001
@@ -1440,4 +1440,6 @@
 	return;
 }
 
+MODULE_LICENSE("GPL");
+
 /****** End *********************************************************/
diff -urN linux-2.4.10-pre8/drivers/net/wan/syncppp.c linux/drivers/net/wan/syncppp.c
--- linux-2.4.10-pre8/drivers/net/wan/syncppp.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/net/wan/syncppp.c	Mon Dec  3 23:09:48 2001
@@ -1397,7 +1397,7 @@
 	func:	sppp_rcv,
 };
 
-static const char banner[] __initdata = 
+static char banner[] __initdata = 
 	KERN_INFO "Cronyx Ltd, Synchronous PPP and CISCO HDLC (c) 1994\n"
 	KERN_INFO "Linux port (c) 1998 Building Number Three Ltd & "
 		  "Jan \"Yenya\" Kasprzak.\n";
@@ -1420,3 +1420,5 @@
 module_init(sync_ppp_init);
 module_exit(sync_ppp_cleanup);
 MODULE_PARM(debug,"1i");
+MODULE_LICENSE("GPL");
+
diff -urN linux-2.4.10-pre8/drivers/net/wan/wanpipe_multppp.c linux/drivers/net/wan/wanpipe_multppp.c
--- linux-2.4.10-pre8/drivers/net/wan/wanpipe_multppp.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wan/wanpipe_multppp.c	Mon Dec  3 23:09:48 2001
@@ -2474,4 +2474,6 @@
 }
 
 
+MODULE_LICENSE("GPL");
+
 /****** End ****************************************************************/
diff -urN linux-2.4.10-pre8/drivers/net/wan/x25_asy.c linux/drivers/net/wan/x25_asy.c
--- linux-2.4.10-pre8/drivers/net/wan/x25_asy.c	Wed Apr 18 14:40:07 2001
+++ linux/drivers/net/wan/x25_asy.c	Mon Dec  3 23:09:48 2001
@@ -42,7 +42,9 @@
 static x25_asy_ctrl_t	**x25_asy_ctrls = NULL;
 
 int x25_asy_maxdev = SL_NRUNIT;		/* Can be overridden with insmod! */
+
 MODULE_PARM(x25_asy_maxdev, "i");
+MODULE_LICENSE("GPL");
 
 static struct tty_ldisc	x25_ldisc;
 
diff -urN linux-2.4.10-pre8/drivers/net/wireless/airo_cs.c linux/drivers/net/wireless/airo_cs.c
--- linux-2.4.10-pre8/drivers/net/wireless/airo_cs.c	Wed Jun 20 11:10:53 2001
+++ linux/drivers/net/wireless/airo_cs.c	Mon Dec  3 23:09:48 2001
@@ -31,7 +31,7 @@
 
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/netdevice.h>
@@ -55,7 +55,7 @@
 #ifdef PCMCIA_DEBUG
 static int pc_debug = PCMCIA_DEBUG;
 MODULE_PARM(pc_debug, "i");
-static char *version = "$Revision: 1.1.18.1 $";
+static char *version = "$Revision: 1.2 $";
 #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
 #else
 #define DEBUG(n, args...)
@@ -75,6 +75,7 @@
 MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
                    cards.  This is the module that links the PCMCIA card \
 		   with the airo module.");
+MODULE_LICENSE("Dual BSD/GPL");
 MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards");
 MODULE_PARM(irq_mask, "i");
 MODULE_PARM(irq_list, "1-4i");
diff -urN linux-2.4.10-pre8/drivers/net/wireless/airport.c linux/drivers/net/wireless/airport.c
--- linux-2.4.10-pre8/drivers/net/wireless/airport.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/net/wireless/airport.c	Mon Dec  3 23:09:48 2001
@@ -16,7 +16,7 @@
 #include <linux/init.h>
 #include <linux/sched.h>
 #include <linux/ptrace.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/ioport.h>
@@ -39,9 +39,10 @@
 #include "hermes.h"
 #include "orinoco.h"
 
-static const char version[] __initdata = "airport.c 0.06f (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
+static char version[] __initdata = "airport.c 0.06f (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
 MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
 MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
+MODULE_LICENSE("Dual MPL/GPL");
 
 typedef struct dldwd_card {
 	struct device_node* node;
diff -urN linux-2.4.10-pre8/drivers/parport/Config.in linux/drivers/parport/Config.in
--- linux-2.4.10-pre8/drivers/parport/Config.in	Tue Jul 10 16:07:46 2001
+++ linux/drivers/parport/Config.in	Mon Dec  3 23:09:48 2001
@@ -25,12 +25,8 @@
          bool '    SuperIO chipset support (EXPERIMENTAL)' CONFIG_PARPORT_PC_SUPERIO
       fi
    fi
-   if [ "$CONFIG_PARPORT_PC" = "y" ]; then
-      # Don't bother with this if parport_pc is a module; it only affects
-      # the presence or not of some __init's, which are no-ops for modules.
-      if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
-	 bool '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA
-      fi
+   if [ "$CONFIG_HOTPLUG" = "y" -a "$CONFIG_PCMCIA" != "n" ]; then
+	 dep_tristate '    Support for PCMCIA management for PC-style ports' CONFIG_PARPORT_PC_PCMCIA $CONFIG_PCMCIA
    fi
    if [ "$CONFIG_ARM" = "y" ]; then
       dep_tristate '  Archimedes hardware' CONFIG_PARPORT_ARC $CONFIG_PARPORT
diff -urN linux-2.4.10-pre8/drivers/parport/Makefile linux/drivers/parport/Makefile
--- linux-2.4.10-pre8/drivers/parport/Makefile	Tue Jul 10 16:07:46 2001
+++ linux/drivers/parport/Makefile	Mon Dec  3 23:09:48 2001
@@ -23,6 +23,7 @@
 obj-$(CONFIG_PARPORT)		+= parport.o
 obj-$(CONFIG_PARPORT_PC)	+= parport_pc.o
 obj-$(CONFIG_PARPORT_SERIAL)	+= parport_serial.o
+obj-$(CONFIG_PARPORT_PC_PCMCIA)+= parport_cs.o
 obj-$(CONFIG_PARPORT_AMIGA)	+= parport_amiga.o
 obj-$(CONFIG_PARPORT_MFC3)	+= parport_mfc3.o
 obj-$(CONFIG_PARPORT_ATARI)	+= parport_atari.o
diff -urN linux-2.4.10-pre8/drivers/parport/parport_cs.c linux/drivers/parport/parport_cs.c
--- linux-2.4.10-pre8/drivers/parport/parport_cs.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/parport/parport_cs.c	Mon Dec  3 23:09:48 2001
@@ -0,0 +1,482 @@
+/*======================================================================
+
+    A driver for PCMCIA parallel port adapters
+
+    (specifically, for the Quatech SPP-100 EPP card: other cards will
+    probably require driver tweaks)
+    
+    parport_cs.c 1.20 2000/11/02 23:15:05
+
+    The contents of this file are subject to the Mozilla Public
+    License Version 1.1 (the "License"); you may not use this file
+    except in compliance with the License. You may obtain a copy of
+    the License at http://www.mozilla.org/MPL/
+
+    Software distributed under the License is distributed on an "AS
+    IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+    implied. See the License for the specific language governing
+    rights and limitations under the License.
+
+    The initial developer of the original code is David A. Hinds
+    <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
+    Alternatively, the contents of this file may be used under the
+    terms of the GNU General Public License version 2 (the "GPL"), in
+    which case the provisions of the GPL are applicable instead of the
+    above.  If you wish to allow the use of your version of this file
+    only under the terms of the GPL and not to allow others to use
+    your version of this file under the MPL, indicate your decision
+    by deleting the provisions above and replace them with the notice
+    and other provisions required by the GPL.  If you do not delete
+    the provisions above, a recipient may use your version of this
+    file under either the MPL or the GPL.
+    
+======================================================================*/
+
+
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/ioport.h>
+
+#include <linux/parport.h>
+#include <linux/parport_pc.h>
+
+#include <pcmcia/version.h>
+#include <pcmcia/cs_types.h>
+#include <pcmcia/cs.h>
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+#include <pcmcia/cisreg.h>
+#include <pcmcia/ciscode.h>
+
+#ifdef PCMCIA_DEBUG
+static int pc_debug = PCMCIA_DEBUG;
+MODULE_PARM(pc_debug, "i");
+#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
+static char *version =
+"parport_cs.c 1.20 2000/11/02 23:15:05 (David Hinds)";
+#else
+#define DEBUG(n, args...)
+#endif
+
+#ifndef VERSION
+#define VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))
+#endif
+
+/*====================================================================*/
+
+/* Parameters that can be set with 'insmod' */
+
+/* Bit map of interrupts to choose from */
+static u_int irq_mask = 0xdeb8;
+static int irq_list[4] = { -1 };
+static int epp_mode = 1;
+
+MODULE_PARM(irq_mask, "i");
+MODULE_PARM(irq_list, "1-4i");
+MODULE_PARM(epp_mode, "i");
+
+/*====================================================================*/
+
+#define FORCE_EPP_MODE	0x08
+
+typedef struct parport_info_t {
+    dev_link_t		link;
+    int			ndev;
+    dev_node_t		node;
+    struct parport	*port;
+} parport_info_t;
+
+static dev_link_t *parport_attach(void);
+static void parport_detach(dev_link_t *);
+static void parport_config(dev_link_t *link);
+static void parport_cs_release(u_long arg);
+static int parport_event(event_t event, int priority,
+			 event_callback_args_t *args);
+
+static dev_info_t dev_info = "parport_cs";
+static dev_link_t *dev_list = NULL;
+
+extern struct parport_operations parport_pc_ops;
+static struct parport_operations parport_cs_ops;
+
+/*====================================================================*/
+
+static void cs_error(client_handle_t handle, int func, int ret)
+{
+    error_info_t err = { func, ret };
+    CardServices(ReportError, handle, &err);
+}
+
+/*======================================================================
+
+    parport_attach() creates an "instance" of the driver, allocating
+    local data structures for one device.  The device is registered
+    with Card Services.
+
+======================================================================*/
+
+static dev_link_t *parport_attach(void)
+{
+    parport_info_t *info;
+    dev_link_t *link;
+    client_reg_t client_reg;
+    int i, ret;
+    
+    DEBUG(0, "parport_attach()\n");
+
+    /* Create new parport device */
+    info = kmalloc(sizeof(*info), GFP_KERNEL);
+    if (!info) return NULL;
+    memset(info, 0, sizeof(*info));
+    link = &info->link; link->priv = info;
+
+    link->release.function = &parport_cs_release;
+    link->release.data = (u_long)link;
+    link->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+    link->io.Attributes2 = IO_DATA_PATH_WIDTH_8;
+    link->irq.Attributes = IRQ_TYPE_EXCLUSIVE;
+    link->irq.IRQInfo1 = IRQ_INFO2_VALID|IRQ_LEVEL_ID;
+    if (irq_list[0] == -1)
+	link->irq.IRQInfo2 = irq_mask;
+    else
+	for (i = 0; i < 4; i++)
+	    link->irq.IRQInfo2 |= 1 << irq_list[i];
+    link->conf.Attributes = CONF_ENABLE_IRQ;
+    link->conf.Vcc = 50;
+    link->conf.IntType = INT_MEMORY_AND_IO;
+    
+    /* Register with Card Services */
+    link->next = dev_list;
+    dev_list = link;
+    client_reg.dev_info = &dev_info;
+    client_reg.Attributes = INFO_IO_CLIENT | INFO_CARD_SHARE;
+    client_reg.EventMask =
+	CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
+	CS_EVENT_RESET_PHYSICAL | CS_EVENT_CARD_RESET |
+	CS_EVENT_PM_SUSPEND | CS_EVENT_PM_RESUME;
+    client_reg.event_handler = &parport_event;
+    client_reg.Version = 0x0210;
+    client_reg.event_callback_args.client_data = link;
+    ret = CardServices(RegisterClient, &link->handle, &client_reg);
+    if (ret != CS_SUCCESS) {
+	cs_error(link->handle, RegisterClient, ret);
+	parport_detach(link);
+	return NULL;
+    }
+    
+    return link;
+} /* parport_attach */
+
+/*======================================================================
+
+    This deletes a driver "instance".  The device is de-registered
+    with Card Services.  If it has been released, all local data
+    structures are freed.  Otherwise, the structures will be freed
+    when the device is released.
+
+======================================================================*/
+
+static void parport_detach(dev_link_t *link)
+{
+    dev_link_t **linkp;
+    int ret;
+
+    DEBUG(0, "parport_detach(0x%p)\n", link);
+    
+    /* Locate device structure */
+    for (linkp = &dev_list; *linkp; linkp = &(*linkp)->next)
+	if (*linkp == link) break;
+    if (*linkp == NULL)
+	return;
+
+    del_timer(&link->release);
+    if (link->state & DEV_CONFIG)
+	parport_cs_release((u_long)link);
+    
+    if (link->handle) {
+	ret = CardServices(DeregisterClient, link->handle);
+	if (ret != CS_SUCCESS)
+	    cs_error(link->handle, DeregisterClient, ret);
+    }
+    
+    /* Unlink, free device structure */
+    *linkp = link->next;
+    kfree(link->priv);
+    
+} /* parport_detach */
+
+/*======================================================================
+
+    parport_config() is scheduled to run after a CARD_INSERTION event
+    is received, to configure the PCMCIA socket, and to make the
+    parport device available to the system.
+
+======================================================================*/
+
+#define CS_CHECK(fn, args...) \
+while ((last_ret=CardServices(last_fn=(fn), args))!=0) goto cs_failed
+
+#define CFG_CHECK(fn, args...) \
+if (CardServices(fn, args) != 0) goto next_entry
+
+static struct { u_int flag; char *name; } mode[] = {
+    { PARPORT_MODE_TRISTATE, "PS2" },
+    { PARPORT_MODE_EPP, "EPP" },
+    { PARPORT_MODE_ECP, "ECP" },
+};
+
+void parport_config(dev_link_t *link)
+{
+    client_handle_t handle = link->handle;
+    parport_info_t *info = link->priv;
+    tuple_t tuple;
+    u_short buf[128];
+    cisparse_t parse;
+    config_info_t conf;
+    cistpl_cftable_entry_t *cfg = &parse.cftable_entry;
+    cistpl_cftable_entry_t dflt = { 0 };
+    struct parport *p;
+    int i, last_ret, last_fn;
+    
+    DEBUG(0, "parport_config(0x%p)\n", link);
+    
+    tuple.TupleData = (cisdata_t *)buf;
+    tuple.TupleOffset = 0; tuple.TupleDataMax = 255;
+    tuple.Attributes = 0;
+    tuple.DesiredTuple = CISTPL_CONFIG;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    CS_CHECK(GetTupleData, handle, &tuple);
+    CS_CHECK(ParseTuple, handle, &tuple, &parse);
+    link->conf.ConfigBase = parse.config.base;
+    link->conf.Present = parse.config.rmask[0];
+    
+    /* Configure card */
+    link->state |= DEV_CONFIG;
+
+    /* Not sure if this is right... look up the current Vcc */
+    CS_CHECK(GetConfigurationInfo, handle, &conf);
+    
+    tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
+    tuple.Attributes = 0;
+    CS_CHECK(GetFirstTuple, handle, &tuple);
+    while (1) {
+	CFG_CHECK(GetTupleData, handle, &tuple);
+	CFG_CHECK(ParseTuple, handle, &tuple, &parse);
+
+	if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) {
+	    cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io;
+	    link->conf.ConfigIndex = cfg->index;
+	    if (epp_mode)
+		link->conf.ConfigIndex |= FORCE_EPP_MODE;
+	    link->io.BasePort1 = io->win[0].base;
+	    link->io.NumPorts1 = io->win[0].len;
+	    link->io.IOAddrLines = io->flags & CISTPL_IO_LINES_MASK;
+	    if (io->nwin == 2) {
+		link->io.BasePort2 = io->win[1].base;
+		link->io.NumPorts2 = io->win[1].len;
+	    }
+	    CFG_CHECK(RequestIO, link->handle, &link->io);
+	    /* If we've got this far, we're done */
+	    break;
+	}
+	
+    next_entry:
+	if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg;
+	CS_CHECK(GetNextTuple, handle, &tuple);
+    }
+    
+    CS_CHECK(RequestIRQ, handle, &link->irq);
+    CS_CHECK(RequestConfiguration, handle, &link->conf);
+
+    p = parport_pc_probe_port(link->io.BasePort1, link->io.BasePort2,
+			      link->irq.AssignedIRQ, PARPORT_DMA_NONE,
+			      NULL);
+    if (p == NULL) {
+	printk(KERN_NOTICE "parport_cs: parport_pc_probe_port() at "
+	       "0x%3x, irq %u failed\n", link->io.BasePort1,
+	       link->irq.AssignedIRQ);
+	goto failed;
+    }
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,6))
+#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
+    p->private_data = kmalloc(sizeof(struct parport_pc_private),
+			      GFP_KERNEL);
+    ((struct parport_pc_private *)(p->private_data))->ctr = 0x0c;
+#endif
+    parport_proc_register(p);
+    p->flags |= PARPORT_FLAG_COMA;
+    parport_pc_write_econtrol(p, 0x00);
+    parport_pc_write_control(p, 0x0c);
+    parport_pc_write_data(p, 0x00);
+#endif
+
+    p->modes |= PARPORT_MODE_PCSPP;
+    if (epp_mode)
+	p->modes |= PARPORT_MODE_TRISTATE | PARPORT_MODE_EPP;
+    info->ndev = 1;
+    info->node.major = LP_MAJOR;
+    info->node.minor = p->number;
+    info->port = p;
+    strcpy(info->node.dev_name, p->name);
+    link->dev = &info->node;
+    printk(KERN_INFO "%s: PC-style PCMCIA at %#x", p->name,
+	   link->io.BasePort1);
+    if (link->io.NumPorts2)
+	printk(" & %#x", link->io.BasePort2);
+    printk(", irq %u [SPP", link->irq.AssignedIRQ);
+    for (i = 0; i < 5; i++)
+	if (p->modes & mode[i].flag) printk(",%s", mode[i].name);
+    printk("]\n");
+    
+    link->state &= ~DEV_CONFIG_PENDING;
+    return;
+    
+cs_failed:
+    cs_error(link->handle, last_fn, last_ret);
+failed:
+    parport_cs_release((u_long)link);
+
+} /* parport_config */
+
+/*======================================================================
+
+    After a card is removed, parport_cs_release() will unregister the
+    device, and release the PCMCIA configuration.  If the device is
+    still open, this will be postponed until it is closed.
+    
+======================================================================*/
+
+void parport_cs_release(u_long arg)
+{
+    dev_link_t *link = (dev_link_t *)arg;
+    parport_info_t *info = link->priv;
+    
+    DEBUG(0, "parport_release(0x%p)\n", link);
+
+    if (info->ndev) {
+	struct parport *p = info->port;
+#if (LINUX_VERSION_CODE < VERSION(2,3,6))
+	if (!(p->flags & PARPORT_FLAG_COMA))
+	    parport_quiesce(p);
+#endif
+	parport_proc_unregister(p);
+#if (LINUX_VERSION_CODE >= VERSION(2,2,8))
+	kfree(p->private_data);
+#endif
+	parport_unregister_port(p);
+    }
+    info->ndev = 0;
+    link->dev = NULL;
+    
+    CardServices(ReleaseConfiguration, link->handle);
+    CardServices(ReleaseIO, link->handle, &link->io);
+    CardServices(ReleaseIRQ, link->handle, &link->irq);
+    
+    link->state &= ~DEV_CONFIG;
+
+} /* parport_cs_release */
+
+/*======================================================================
+
+    The card status event handler.  Mostly, this schedules other
+    stuff to run after an event is received.
+    
+======================================================================*/
+
+int parport_event(event_t event, int priority,
+		  event_callback_args_t *args)
+{
+    dev_link_t *link = args->client_data;
+
+    DEBUG(1, "parport_event(0x%06x)\n", event);
+    
+    switch (event) {
+    case CS_EVENT_CARD_REMOVAL:
+	link->state &= ~DEV_PRESENT;
+	if (link->state & DEV_CONFIG)
+	    mod_timer(&link->release, jiffies + HZ/20);
+	break;
+    case CS_EVENT_CARD_INSERTION:
+	link->state |= DEV_PRESENT | DEV_CONFIG_PENDING;
+	parport_config(link);
+	break;
+    case CS_EVENT_PM_SUSPEND:
+	link->state |= DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_RESET_PHYSICAL:
+	if (link->state & DEV_CONFIG)
+	    CardServices(ReleaseConfiguration, link->handle);
+	break;
+    case CS_EVENT_PM_RESUME:
+	link->state &= ~DEV_SUSPEND;
+	/* Fall through... */
+    case CS_EVENT_CARD_RESET:
+	if (DEV_OK(link))
+	    CardServices(RequestConfiguration, link->handle, &link->conf);
+	break;
+    }
+    return 0;
+} /* parport_event */
+
+/*====================================================================*/
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,6))
+
+static void inc_use_count(void)
+{
+    MOD_INC_USE_COUNT;
+    parport_pc_ops.inc_use_count();
+}
+
+static void dec_use_count(void)
+{
+    MOD_DEC_USE_COUNT;
+    parport_pc_ops.dec_use_count();
+}
+
+#endif
+
+/*====================================================================*/
+
+static int __init init_parport_cs(void)
+{
+    servinfo_t serv;
+    DEBUG(0, "%s\n", version);
+    CardServices(GetCardServicesInfo, &serv);
+    if (serv.Revision != CS_RELEASE_CODE) {
+	printk(KERN_NOTICE "parport_cs: Card Services release "
+	       "does not match!\n");
+	return -1;
+    }
+
+#if (LINUX_VERSION_CODE < VERSION(2,3,6))
+    /* This is to protect against unloading modules out of order */
+    parport_cs_ops = parport_pc_ops;
+    parport_cs_ops.inc_use_count = &inc_use_count;
+    parport_cs_ops.dec_use_count = &dec_use_count;
+#endif
+
+    register_pccard_driver(&dev_info, &parport_attach, &parport_detach);
+    return 0;
+}
+
+static void __exit exit_parport_cs(void)
+{
+    DEBUG(0, "parport_cs: unloading\n");
+    unregister_pccard_driver(&dev_info);
+    while (dev_list != NULL)
+	parport_detach(dev_list);
+}
+
+module_init(init_parport_cs);
+module_exit(exit_parport_cs);
diff -urN linux-2.4.10-pre8/drivers/scsi/Makefile linux/drivers/scsi/Makefile
--- linux-2.4.10-pre8/drivers/scsi/Makefile	Mon Dec  3 23:09:38 2001
+++ linux/drivers/scsi/Makefile	Mon Dec  3 23:09:48 2001
@@ -139,7 +139,7 @@
 obj-$(CONFIG_BLK_DEV_SR)	+= sr_mod.o
 obj-$(CONFIG_CHR_DEV_SG)	+= sg.o
 
-list-multi	:= scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o
+list-multi	:= scsi_mod.o sd_mod.o sr_mod.o initio.o a100u2w.o cpqfc.o
 scsi_mod-objs	:= scsi.o hosts.o scsi_ioctl.o constants.o \
 			scsicam.o scsi_proc.o scsi_error.o \
 			scsi_obsolete.o scsi_queue.o scsi_lib.o \
@@ -149,6 +149,7 @@
 sr_mod-objs	:= sr.o sr_ioctl.o sr_vendor.o
 initio-objs	:= ini9100u.o i91uscsi.o
 a100u2w-objs	:= inia100.o i60uscsi.o
+cpqfc-objs	:= cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o cpqfcTSworker.o cpqfcTStrigger.o
 
 include $(TOPDIR)/Rules.make
 
@@ -168,6 +169,9 @@
 a100u2w.o: $(a100u2w-objs)
 	$(LD) -r -o $@ $(a100u2w-objs)
 
+cpqfc.o: $(cpqfc-objs)
+	$(LD) -r -o $@ $(cpqfc-objs)
+
 53c8xx_d.h: 53c7,8xx.scr script_asm.pl
 	ln -sf 53c7,8xx.scr fake8.c
 	$(CPP) $(CPPFLAGS) -traditional -DCHIP=810 fake8.c | grep -v '^#' | $(PERL) script_asm.pl 
@@ -212,8 +216,3 @@
 	echo "/* WARNING: GENERATED FILE (from $<), DO NOT MODIFY */" > $@
 	echo "#define MEM_MAPPED" >> $@
 	cat $< >> $@
-
-cpqfc.o: cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o cpqfcTSworker.o \
-	cpqfcTStrigger.o
-	$(LD) -r -o cpqfc.o cpqfcTSinit.o cpqfcTScontrol.o \
-	cpqfcTSi2c.o cpqfcTSworker.o cpqfcTStrigger.o
diff -urN linux-2.4.10-pre8/drivers/sound/wavfront.c linux/drivers/sound/wavfront.c
--- linux-2.4.10-pre8/drivers/sound/wavfront.c	Sun Aug 12 10:38:48 2001
+++ linux/drivers/sound/wavfront.c	Mon Dec  3 23:09:49 2001
@@ -86,22 +86,6 @@
 
 #include <linux/wavefront.h>
 
-/*
- *	This sucks, hopefully it'll get standardised
- */
- 
-#if defined(__alpha__)
-#ifdef CONFIG_SMP
-#define LOOPS_PER_TICK cpu_data[smp_processor_id()].loops_per_jiffy
-#else
-#define LOOPS_PER_TICK	loops_per_jiffy
-#endif
-#endif
-
-#if defined(__i386__)
-#define LOOPS_PER_TICK current_cpu_data.loops_per_jiffy
-#endif
- 
 #define _MIDI_SYNTH_C_
 #define MIDI_SYNTH_NAME	"WaveFront MIDI"
 #define MIDI_SYNTH_CAPS	SYNTH_CAP_INPUT
@@ -191,21 +175,17 @@
 					     version of the WaveFront OS
 					  */
 
-int wait_usecs = 150; /* This magic number seems to give pretty optimal
-			 throughput based on my limited experimentation.
-			 If you want to play around with it and find a better
-			 value, be my guest. Remember, the idea is to
-			 get a number that causes us to just busy wait
-			 for as many WaveFront commands as possible, without
-			 coming up with a number so large that we hog the
-			 whole CPU.
-
-			 Specifically, with this number, out of about 134,000
-			 status waits, only about 250 result in a sleep.
-		      */
+int wait_polls = 2000;	/* This is a number of tries we poll the status register
+			   before resorting to sleeping. WaveFront being an ISA
+			   card each poll takes about 1.2us. So before going to
+			   sleep we wait up to 2.4ms in a loop.
+			*/
+
+int sleep_length = HZ/100; /* This says how long we're going to sleep between polls.
+			      10ms sounds reasonable for fast response.
+			   */
 
-int sleep_interval = 100;     /* HZ/sleep_interval seconds per sleep */
-int sleep_tries = 50;       /* number of times we'll try to sleep */
+int sleep_tries = 50;       /* Wait for status 0.5 seconds total. */
 
 int reset_time = 2;        /* hundreths of a second we wait after a HW reset for
 			      the expected interrupt.
@@ -222,8 +202,8 @@
 MODULE_PARM(wf_raw,"i");
 MODULE_PARM(fx_raw,"i");
 MODULE_PARM(debug_default,"i");
-MODULE_PARM(wait_usecs,"i");
-MODULE_PARM(sleep_interval,"i");
+MODULE_PARM(wait_polls,"i");
+MODULE_PARM(sleep_length,"i");
 MODULE_PARM(sleep_tries,"i");
 MODULE_PARM(ospath,"s");
 MODULE_PARM(reset_time,"i");
@@ -437,54 +417,30 @@
 }
 
 static int
-wavefront_sleep (int limit)
-
-{
-	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(limit);
-
-	return signal_pending(current);
-}
-
-static int
 wavefront_wait (int mask)
 
 {
-	int             i;
-	static int      short_loop_cnt = 0;
-
-	/* Compute the loop count that lets us sleep for about the
-	   right amount of time, cache issues, bus speeds and all
-	   other issues being unequal but largely irrelevant.
-	*/
-
-	if (short_loop_cnt == 0) {
-		short_loop_cnt = wait_usecs *
-			(LOOPS_PER_TICK / (1000000 / HZ));
-	}
-
-	/* Spin for a short period of time, because >99% of all
-	   requests to the WaveFront can be serviced inline like this.
-	*/
+	int i;
 
-	for (i = 0; i < short_loop_cnt; i++) {
-		if (wavefront_status() & mask) {
+	for (i = 0; i < wait_polls; i++)
+		if (wavefront_status() & mask)
 			return 1;
-		}
-	}
 
 	for (i = 0; i < sleep_tries; i++) {
 
 		if (wavefront_status() & mask) {
+			set_current_state(TASK_RUNNING);
 			return 1;
 		}
 
-		if (wavefront_sleep (HZ/sleep_interval)) {
-			return (0);
-		}
+		set_current_state(TASK_INTERRUPTIBLE);
+		schedule_timeout(sleep_length);
+		if (signal_pending(current))
+			break;
 	}
 
-	return (0);
+	set_current_state(TASK_RUNNING);
+	return 0;
 }
 
 static int
diff -urN linux-2.4.10-pre8/drivers/usb/Makefile linux/drivers/usb/Makefile
--- linux-2.4.10-pre8/drivers/usb/Makefile	Mon Dec  3 23:09:38 2001
+++ linux/drivers/usb/Makefile	Mon Dec  3 23:09:49 2001
@@ -14,8 +14,9 @@
 
 # Multipart objects.
 
-list-multi		:= usbcore.o
+list-multi		:= usbcore.o hid.o
 usbcore-objs		:= usb.o usb-debug.o hub.o
+hid-objs		:= hid-core.o hid-input.o
 
 ifneq ($(CONFIG_USB_PWC),n)
 	export-objs		+= pwc-uncompress.o
@@ -31,6 +32,10 @@
 	usbcore-objs	+= devio.o inode.o drivers.o devices.o
 endif
 
+ifeq ($(CONFIG_USB_HIDDEV),y)
+	hid-objs	+= hiddev.o
+endif
+
 # Object file lists.
 
 obj-y	:=
@@ -91,6 +96,8 @@
 usbcore.o: $(usbcore-objs)
 	$(LD) -r -o $@ $(usbcore-objs)
 
-pwc.o:		$(pwc-objs)
-	$(LD) -r -o $@ $(pwc-objs)
+hid.o: $(hid-objs)
+	$(LD) -r -o $@ $(hid-objs)
 
+pwc.o: $(pwc-objs)
+	$(LD) -r -o $@ $(pwc-objs)
diff -urN linux-2.4.10-pre8/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c
--- linux-2.4.10-pre8/drivers/usb/bluetooth.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/usb/bluetooth.c	Mon Dec  3 23:09:49 2001
@@ -517,7 +517,7 @@
 				}
 				
 
-				buffer_size = min_t (int, count, bluetooth->bulk_out_buffer_size);
+				buffer_size = min (count, bluetooth->bulk_out_buffer_size);
 				memcpy (urb->transfer_buffer, current_position, buffer_size);
 
 				/* build up our urb */
diff -urN linux-2.4.10-pre8/drivers/usb/hid-core.c linux/drivers/usb/hid-core.c
--- linux-2.4.10-pre8/drivers/usb/hid-core.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hid-core.c	Mon Dec  3 23:09:49 2001
@@ -0,0 +1,1307 @@
+/*
+ * $Id: hid-core.c,v 1.8 2001/05/23 12:02:18 vojtech Exp $
+ *
+ *  Copyright (c) 1999 Andreas Gal
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  USB HID support for Linux
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/mm.h>
+#include <linux/smp_lock.h>
+#include <linux/spinlock.h>
+#include <asm/unaligned.h>
+#include <linux/input.h>
+
+#undef DEBUG
+#undef DEBUG_DATA
+
+#include <linux/usb.h>
+
+#include "hid.h"
+#ifdef CONFIG_USB_HIDDEV
+#include <linux/hiddev.h>
+#endif
+
+/*
+ * Version Information
+ */
+
+#define DRIVER_VERSION "v1.8"
+#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>"
+#define DRIVER_DESC "USB HID support drivers"
+
+static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
+				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
+
+/*
+ * Register a new report for a device.
+ */
+
+static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
+{
+	struct hid_report_enum *report_enum = device->report_enum + type;
+	struct hid_report *report;
+
+	if (report_enum->report_id_hash[id])
+		return report_enum->report_id_hash[id];
+
+	if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
+		return NULL;
+	memset(report, 0, sizeof(struct hid_report));
+
+	if (id != 0) report_enum->numbered = 1;
+
+	report->id = id;
+	report->type = type;
+	report->size = 0;
+	report->device = device;
+	report_enum->report_id_hash[id] = report;
+
+	list_add_tail(&report->list, &report_enum->report_list);
+
+	return report;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
+{
+	struct hid_field *field;
+
+	if (report->maxfield == HID_MAX_FIELDS) {
+		dbg("too many fields in report");
+		return NULL;
+	}
+
+	if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+		+ values * sizeof(unsigned), GFP_KERNEL))) return NULL;
+
+	memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
+		+ values * sizeof(unsigned));
+
+	report->field[report->maxfield++] = field;
+	field->usage = (struct hid_usage *)(field + 1);
+	field->value = (unsigned *)(field->usage + usages);
+	field->report = report;
+
+	return field;
+}
+
+/*
+ * Open a collection. The type/usage is pushed on the stack.
+ */
+
+static int open_collection(struct hid_parser *parser, unsigned type)
+{
+	struct hid_collection *collection;
+	unsigned usage;
+
+	usage = parser->local.usage[0];
+
+	if (type == HID_COLLECTION_APPLICATION
+		&& parser->device->maxapplication < HID_MAX_APPLICATIONS)
+			parser->device->application[parser->device->maxapplication++] = usage;
+
+	if (parser->collection_stack_ptr == HID_COLLECTION_STACK_SIZE) {
+		dbg("collection stack overflow");
+		return -1;
+	}
+
+	collection = parser->collection_stack + parser->collection_stack_ptr++;
+	collection->type = type;
+	collection->usage = usage;
+
+	return 0;
+}
+
+/*
+ * Close a collection.
+ */
+
+static int close_collection(struct hid_parser *parser)
+{
+	if (!parser->collection_stack_ptr) {
+		dbg("collection stack underflow");
+		return -1;
+	}
+	parser->collection_stack_ptr--;
+	return 0;
+}
+
+/*
+ * Climb up the stack, search for the specified collection type
+ * and return the usage.
+ */
+
+static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
+{
+	int n;
+	for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
+		if (parser->collection_stack[n].type == type)
+			return parser->collection_stack[n].usage;
+	return 0; /* we know nothing about this usage type */
+}
+
+/*
+ * Add a usage to the temporary parser table.
+ */
+
+static int hid_add_usage(struct hid_parser *parser, unsigned usage)
+{
+	if (parser->local.usage_index >= HID_MAX_USAGES) {
+		dbg("usage index exceeded");
+		return -1;
+	}
+	parser->local.usage[parser->local.usage_index++] = usage;
+	return 0;
+}
+
+/*
+ * Register a new field for this report.
+ */
+
+static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
+{
+	struct hid_report *report;
+	struct hid_field *field;
+	int usages;
+	unsigned offset;
+	int i;
+
+	if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
+		dbg("hid_register_report failed");
+		return -1;
+	}
+
+	if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */
+		if (parser->global.logical_maximum <= parser->global.logical_minimum) {
+			dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
+			return -1;
+		}
+		usages = parser->local.usage_index;
+		/* Hint: we can assume usages < MAX_USAGE here */
+	} else { /* VARIABLE */
+		usages = parser->global.report_count;
+	}
+
+	offset = report->size;
+	report->size += parser->global.report_size * parser->global.report_count;
+
+	if (usages == 0)
+		return 0; /* ignore padding fields */
+
+	if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
+		return 0;
+
+	field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
+	field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
+	field->application = hid_lookup_collection(parser, HID_COLLECTION_APPLICATION);
+
+	for (i = 0; i < usages; i++)
+		field->usage[i].hid = parser->local.usage[i];
+
+	field->maxusage = usages;
+	field->flags = flags;
+	field->report_offset = offset;
+	field->report_type = report_type;
+	field->report_size = parser->global.report_size;
+	field->report_count = parser->global.report_count;
+	field->logical_minimum = parser->global.logical_minimum;
+	field->logical_maximum = parser->global.logical_maximum;
+	field->physical_minimum = parser->global.physical_minimum;
+	field->physical_maximum = parser->global.physical_maximum;
+	field->unit_exponent = parser->global.unit_exponent;
+	field->unit = parser->global.unit;
+
+	return 0;
+}
+
+/*
+ * Read data value from item.
+ */
+
+static __inline__ __u32 item_udata(struct hid_item *item)
+{
+	switch (item->size) {
+		case 1: return item->data.u8;
+		case 2: return item->data.u16;
+		case 4: return item->data.u32;
+	}
+	return 0;
+}
+
+static __inline__ __s32 item_sdata(struct hid_item *item)
+{
+	switch (item->size) {
+		case 1: return item->data.s8;
+		case 2: return item->data.s16;
+		case 4: return item->data.s32;
+	}
+	return 0;
+}
+
+/*
+ * Process a global item.
+ */
+
+static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
+{
+	switch (item->tag) {
+
+		case HID_GLOBAL_ITEM_TAG_PUSH:
+
+			if (parser->global_stack_ptr == HID_GLOBAL_STACK_SIZE) {
+				dbg("global enviroment stack overflow");
+				return -1;
+			}
+
+			memcpy(parser->global_stack + parser->global_stack_ptr++,
+				&parser->global, sizeof(struct hid_global));
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_POP:
+
+			if (!parser->global_stack_ptr) {
+				dbg("global enviroment stack underflow");
+				return -1;
+			}
+
+			memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
+				sizeof(struct hid_global));
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
+			parser->global.usage_page = item_udata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
+			parser->global.logical_minimum = item_sdata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
+			parser->global.logical_maximum = item_sdata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
+			parser->global.physical_minimum = item_sdata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
+			parser->global.physical_maximum = item_sdata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
+			parser->global.unit_exponent = item_udata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_UNIT:
+			parser->global.unit = item_udata(item);
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
+			if ((parser->global.report_size = item_udata(item)) > 32) {
+				dbg("invalid report_size %d", parser->global.report_size);
+				return -1;
+			}
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
+			if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
+				dbg("invalid report_count %d", parser->global.report_count);
+				return -1;
+			}
+			return 0;
+
+		case HID_GLOBAL_ITEM_TAG_REPORT_ID:
+			if ((parser->global.report_id = item_udata(item)) == 0) {
+				dbg("report_id 0 is invalid");
+				return -1;
+			}
+			return 0;
+
+		default:
+			dbg("unknown global tag 0x%x", item->tag);
+			return -1;
+	}
+}
+
+/*
+ * Process a local item.
+ */
+
+static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
+{
+	__u32 data;
+	unsigned n;
+
+	if (item->size == 0) {
+		dbg("item data expected for local item");
+		return -1;
+	}
+
+	data = item_udata(item);
+
+	switch (item->tag) {
+
+		case HID_LOCAL_ITEM_TAG_DELIMITER:
+
+			if (data) {
+				/*
+				 * We treat items before the first delimiter
+				 * as global to all usage sets (branch 0).
+				 * In the moment we process only these global
+				 * items and the first delimiter set.
+				 */
+				if (parser->local.delimiter_depth != 0) {
+					dbg("nested delimiters");
+					return -1;
+				}
+				parser->local.delimiter_depth++;
+				parser->local.delimiter_branch++;
+			} else {
+				if (parser->local.delimiter_depth < 1) {
+					dbg("bogus close delimiter");
+					return -1;
+				}
+				parser->local.delimiter_depth--;
+			}
+			return 1;
+
+		case HID_LOCAL_ITEM_TAG_USAGE:
+
+			if (parser->local.delimiter_branch > 1) {
+				dbg("alternative usage ignored");
+				return 0;
+			}
+
+			if (item->size <= 2)
+				data = (parser->global.usage_page << 16) + data;
+
+			return hid_add_usage(parser, data);
+
+		case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
+
+			if (parser->local.delimiter_branch > 1) {
+				dbg("alternative usage ignored");
+				return 0;
+			}
+
+			if (item->size <= 2)
+				data = (parser->global.usage_page << 16) + data;
+
+			parser->local.usage_minimum = data;
+			return 0;
+
+		case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
+
+			if (parser->local.delimiter_branch > 1) {
+				dbg("alternative usage ignored");
+				return 0;
+			}
+
+			if (item->size <= 2)
+				data = (parser->global.usage_page << 16) + data;
+
+			for (n = parser->local.usage_minimum; n <= data; n++)
+				if (hid_add_usage(parser, n)) {
+					dbg("hid_add_usage failed\n");
+					return -1;
+				}
+			return 0;
+
+		default:
+
+			dbg("unknown local item tag 0x%x", item->tag);
+			return 0;
+	}
+	return 0;
+}
+
+/*
+ * Process a main item.
+ */
+
+static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
+{
+	__u32 data;
+	int ret;
+
+	data = item_udata(item);
+
+	switch (item->tag) {
+		case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
+			ret = open_collection(parser, data & 3);
+			break;
+		case HID_MAIN_ITEM_TAG_END_COLLECTION:
+			ret = close_collection(parser);
+			break;
+		case HID_MAIN_ITEM_TAG_INPUT:
+			ret = hid_add_field(parser, HID_INPUT_REPORT, data);
+			break;
+		case HID_MAIN_ITEM_TAG_OUTPUT:
+			ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
+			break;
+		case HID_MAIN_ITEM_TAG_FEATURE:
+			ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
+			break;
+		default:
+			dbg("unknown main item tag 0x%x", item->tag);
+			ret = 0;
+	}
+
+	memset(&parser->local, 0, sizeof(parser->local));	/* Reset the local parser environment */
+
+	return ret;
+}
+
+/*
+ * Process a reserved item.
+ */
+
+static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
+{
+	dbg("reserved item type, tag 0x%x", item->tag);
+	return 0;
+}
+
+/*
+ * Free a report and all registered fields. The field->usage and
+ * field->value table's are allocated behind the field, so we need
+ * only to free(field) itself.
+ */
+
+static void hid_free_report(struct hid_report *report)
+{
+	unsigned n;
+
+	for (n = 0; n < report->maxfield; n++)
+		kfree(report->field[n]);
+	if (report->data)
+		kfree(report->data);
+	kfree(report);
+}
+
+/*
+ * Free a device structure, all reports, and all fields.
+ */
+
+static void hid_free_device(struct hid_device *device)
+{
+	unsigned i,j;
+
+	for (i = 0; i < HID_REPORT_TYPES; i++) {
+		struct hid_report_enum *report_enum = device->report_enum + i;
+
+		for (j = 0; j < 256; j++) {
+			struct hid_report *report = report_enum->report_id_hash[j];
+			if (report) hid_free_report(report);
+		}
+	}
+
+	if (device->rdesc) kfree(device->rdesc);
+}
+
+/*
+ * Fetch a report description item from the data stream. We support long
+ * items, though they are not used yet.
+ */
+
+static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
+{
+	if ((end - start) > 0) {
+
+		__u8 b = *start++;
+		item->type = (b >> 2) & 3;
+		item->tag  = (b >> 4) & 15;
+
+		if (item->tag == HID_ITEM_TAG_LONG) {
+
+			item->format = HID_ITEM_FORMAT_LONG;
+
+			if ((end - start) >= 2) {
+
+				item->size = *start++;
+				item->tag  = *start++;
+
+				if ((end - start) >= item->size) {
+					item->data.longdata = start;
+					start += item->size;
+					return start;
+				}
+			}
+		} else {
+
+			item->format = HID_ITEM_FORMAT_SHORT;
+			item->size = b & 3;
+			switch (item->size) {
+
+				case 0:
+					return start;
+
+				case 1:
+					if ((end - start) >= 1) {
+						item->data.u8 = *start++;
+						return start;
+					}
+					break;
+
+				case 2:
+					if ((end - start) >= 2) {
+						item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++));
+						return start;
+					}
+
+				case 3:
+					item->size++;
+					if ((end - start) >= 4) {
+						item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++));
+						return start;
+					}
+			}
+		}
+	}
+	return NULL;
+}
+
+/*
+ * Parse a report description into a hid_device structure. Reports are
+ * enumerated, fields are attached to these reports.
+ */
+
+static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
+{
+	struct hid_device *device;
+	struct hid_parser *parser;
+	struct hid_item item;
+	__u8 *end;
+	unsigned i;
+	static int (*dispatch_type[])(struct hid_parser *parser,
+				      struct hid_item *item) = {
+		hid_parser_main,
+		hid_parser_global,
+		hid_parser_local,
+		hid_parser_reserved
+	};
+
+	if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
+		return NULL;
+	memset(device, 0, sizeof(struct hid_device));
+
+	for (i = 0; i < HID_REPORT_TYPES; i++)
+		INIT_LIST_HEAD(&device->report_enum[i].report_list);
+
+	if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) {
+		kfree(device);
+		return NULL;
+	}
+	memcpy(device->rdesc, start, size);
+
+	if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
+		kfree(device->rdesc);
+		kfree(device);
+		return NULL;
+	}
+	memset(parser, 0, sizeof(struct hid_parser));
+	parser->device = device;
+
+	end = start + size;
+	while ((start = fetch_item(start, end, &item)) != 0) {
+		if (item.format != HID_ITEM_FORMAT_SHORT) {
+			dbg("unexpected long global item");
+			hid_free_device(device);
+			kfree(parser);
+			return NULL;
+		}
+		if (dispatch_type[item.type](parser, &item)) {
+			dbg("item %u %u %u %u parsing failed\n",
+				item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+			hid_free_device(device);
+			kfree(parser);
+			return NULL;
+		}
+
+		if (start == end) {
+			if (parser->collection_stack_ptr) {
+				dbg("unbalanced collection at end of report description");
+				hid_free_device(device);
+				kfree(parser);
+				return NULL;
+			}
+			if (parser->local.delimiter_depth) {
+				dbg("unbalanced delimiter at end of report description");
+				hid_free_device(device);
+				kfree(parser);
+				return NULL;
+			}
+			kfree(parser);
+			return device;
+		}
+	}
+
+	dbg("item fetching failed at offset %d\n", (int)(end - start));
+	hid_free_device(device);
+	kfree(parser);
+	return NULL;
+}
+
+/*
+ * Convert a signed n-bit integer to signed 32-bit integer. Common
+ * cases are done through the compiler, the screwed things has to be
+ * done by hand.
+ */
+
+static __inline__ __s32 snto32(__u32 value, unsigned n)
+{
+	switch (n) {
+		case 8:  return ((__s8)value);
+		case 16: return ((__s16)value);
+		case 32: return ((__s32)value);
+	}
+	return value & (1 << (n - 1)) ? value | (-1 << n) : value;
+}
+
+/*
+ * Convert a signed 32-bit integer to a signed n-bit integer.
+ */
+
+static __inline__ __u32 s32ton(__s32 value, unsigned n)
+{
+	__s32 a = value >> (n - 1);
+	if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
+	return value & ((1 << n) - 1);
+}
+
+/*
+ * Extract/implement a data field from/to a report.
+ */
+
+static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+{
+	report += (offset >> 5) << 2; offset &= 31;
+	return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1);
+}
+
+static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+{
+	report += (offset >> 5) << 2; offset &= 31;
+	put_unaligned((get_unaligned((__u64*)report)
+		& cpu_to_le64(~((((__u64) 1 << n) - 1) << offset)))
+		| cpu_to_le64((__u64)value << offset), (__u64*)report);
+}
+
+/*
+ * Search an array for a value.
+ */
+
+static __inline__ int search(__s32 *array, __s32 value, unsigned n)
+{
+	while (n--) if (*array++ == value) return 0;
+	return -1;
+}
+
+static void hid_process_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
+{
+	hid_dump_input(usage, value);
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		hidinput_hid_event(hid, field, usage, value);
+#ifdef CONFIG_USB_HIDDEV
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		hiddev_hid_event(hid, usage->hid, value);
+#endif
+}
+
+
+/*
+ * Analyse a received field, and fetch the data from it. The field
+ * content is stored for next report processing (we do differential
+ * reporting to the layer).
+ */
+
+static void hid_input_field(struct hid_device *hid, struct hid_field *field, __u8 *data)
+{
+	unsigned n;
+	unsigned count = field->report_count;
+	unsigned offset = field->report_offset;
+	unsigned size = field->report_size;
+	__s32 min = field->logical_minimum;
+	__s32 max = field->logical_maximum;
+	__s32 value[count]; /* WARNING: gcc specific */
+
+	for (n = 0; n < count; n++) {
+
+			value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
+						    extract(data, offset + n * size, size);
+
+			if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
+			    && value[n] >= min && value[n] <= max
+			    && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+				return;
+	}
+
+	for (n = 0; n < count; n++) {
+
+		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
+
+			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+				if (!value[n]) continue;
+			} else {
+				if (value[n] == field->value[n]) continue;
+			}	
+			hid_process_event(hid, field, &field->usage[n], value[n]);
+			continue;
+		}
+
+		if (field->value[n] >= min && field->value[n] <= max
+			&& field->usage[field->value[n] - min].hid
+			&& search(value, field->value[n], count))
+				hid_process_event(hid, field, &field->usage[field->value[n] - min], 0);
+
+		if (value[n] >= min && value[n] <= max
+			&& field->usage[value[n] - min].hid
+			&& search(field->value, value[n], count))
+				hid_process_event(hid, field, &field->usage[value[n] - min], 1);
+	}
+
+	memcpy(field->value, value, count * sizeof(__s32));
+}
+
+static int hid_input_report(int type, u8 *data, int len, struct hid_device *hid)
+{
+	struct hid_report_enum *report_enum = hid->report_enum + type;
+	struct hid_report *report;
+	int n, size;
+
+	if (!len) {
+		dbg("empty report");
+		return -1;
+	}
+
+#ifdef DEBUG_DATA
+	printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered)\n", len, report_enum->numbered ? "" : "un");
+#endif
+
+	n = 0;				/* Normally report number is 0 */
+	if (report_enum->numbered) {	/* Device uses numbered reports, data[0] is report number */
+		n = *data++;
+		len--;
+	}
+
+	if (!(report = report_enum->report_id_hash[n])) {
+		dbg("undefined report_id %d received", n);
+#ifdef DEBUG
+			printk(KERN_DEBUG __FILE__ ": report (size %u) = ", len);
+			for (n = 0; n < len; n++)
+				printk(" %02x", data[n]);
+			printk("\n");
+#endif
+
+		return -1;
+	}
+
+	size = ((report->size - 1) >> 3) + 1;
+
+	if (len < size) {
+
+		if (size <= 8) {
+			dbg("report %d is too short, (%d < %d)", report->id, len, size);
+			return -1;
+		}
+
+		/*
+		 * Some low-speed devices have large reports and maxpacketsize 8.
+		 * We buffer the data in that case and parse it when we got it all.
+		 * Works only for unnumbered reports. Doesn't make sense for numbered
+		 * reports anyway - then they don't need to be large.
+		 */
+
+		if (!report->data)
+			if (!(report->data = kmalloc(size, GFP_ATOMIC))) {
+				dbg("couldn't allocate report buffer");
+				return -1;
+			}
+
+		if (report->idx + len > size) {
+			dbg("report data buffer overflow");
+			report->idx = 0;
+			return -1;
+		}
+
+		memcpy(report->data + report->idx, data, len);
+		report->idx += len;
+
+		if (report->idx < size)
+			return 0;
+
+		data = report->data;
+	}
+
+	for (n = 0; n < report->maxfield; n++)
+		hid_input_field(hid, report->field[n], data);
+
+	report->idx = 0;
+	return 0;
+}
+
+/*
+ * Interrupt input handler.
+ */
+
+static void hid_irq(struct urb *urb)
+{
+	if (urb->status) {
+		dbg("nonzero status in irq %d", urb->status);
+		return;
+	}
+
+	hid_input_report(HID_INPUT_REPORT, urb->transfer_buffer, urb->actual_length, urb->context);
+}
+
+/*
+ * hid_read_report() reads in report values without waiting for an irq urb.
+ */
+
+void hid_read_report(struct hid_device *hid, struct hid_report *report)
+{
+	int len = ((report->size - 1) >> 3) + 1 + hid->report_enum[report->type].numbered;
+	u8 data[len];
+	int read;
+
+	if ((read = usb_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, data, len)) != len) {
+		dbg("reading report type %d id %d failed len %d read %d", report->type + 1, report->id, len, read);
+		return;
+	}
+
+	hid_input_report(report->type, data, len, hid);
+}
+
+/*
+ * Output the field into the report.
+ */
+
+static void hid_output_field(struct hid_field *field, __u8 *data)
+{
+	unsigned count = field->report_count;
+	unsigned offset = field->report_offset;
+	unsigned size = field->report_size;
+	unsigned n;
+
+	for (n = 0; n < count; n++) {
+		if (field->logical_minimum < 0)	/* signed values */
+			implement(data, offset + n * size, size, s32ton(field->value[n], size));
+		 else				/* unsigned values */
+			implement(data, offset + n * size, size, field->value[n]);
+	}
+}
+
+/*
+ * Create a report.
+ */
+
+void hid_output_report(struct hid_report *report, __u8 *data)
+{
+	unsigned n;
+	for (n = 0; n < report->maxfield; n++)
+		hid_output_field(report->field[n], data);
+}
+
+/*
+ * Set a field value. The report this field belongs to has to be
+ * created and transfered to the device, to set this value in the
+ * device.
+ */
+
+int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
+{
+	unsigned size = field->report_size;
+
+	hid_dump_input(field->usage + offset, value);
+
+	if (offset >= field->report_count) {
+		dbg("offset exceeds report_count");
+		return -1;
+	}
+	if (field->logical_minimum < 0) {
+		if (value != snto32(s32ton(value, size), size)) {
+			dbg("value %d is out of range", value);
+			return -1;
+		}
+	}
+	if (   (value > field->logical_maximum)
+	    || (value < field->logical_minimum)) {
+		dbg("value %d is invalid", value);
+		return -1;
+	}
+	field->value[offset] = value;
+	return 0;
+}
+
+int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
+{
+	struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT;
+	struct list_head *list = report_enum->report_list.next;
+	int i, j;
+
+	while (list != &report_enum->report_list) {
+		struct hid_report *report = (struct hid_report *) list;
+		list = list->next;
+		for (i = 0; i < report->maxfield; i++) {
+			*field = report->field[i];
+			for (j = 0; j < (*field)->maxusage; j++)
+				if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
+					return j;
+		}
+	}
+	return -1;
+}
+
+static int hid_submit_out(struct hid_device *hid)
+{
+	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length);
+	hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
+	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
+	hid->urbout.dev = hid->dev;
+
+	if (usb_submit_urb(&hid->urbout)) {
+		err("usb_submit_urb(out) failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void hid_ctrl(struct urb *urb)
+{
+	struct hid_device *hid = urb->context;
+
+	if (urb->status)
+		warn("ctrl urb status %d received", urb->status);
+
+	hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+
+	if (hid->outhead != hid->outtail)
+		hid_submit_out(hid);
+}
+
+void hid_write_report(struct hid_device *hid, struct hid_report *report)
+{
+	hid_output_report(report, hid->out[hid->outhead].buffer);
+
+	hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | report->id);
+	hid->out[hid->outhead].dr.length = cpu_to_le16((report->size + 7) >> 3);
+
+	hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+
+	if (hid->outhead == hid->outtail)
+		hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
+
+	if (hid->urbout.status != -EINPROGRESS)
+		hid_submit_out(hid);
+}
+
+int hid_open(struct hid_device *hid)
+{
+	if (hid->open++)
+		return 0;
+
+	hid->urb.dev = hid->dev;
+
+	if (usb_submit_urb(&hid->urb))
+		return -EIO;
+
+	return 0;
+}
+
+void hid_close(struct hid_device *hid)
+{
+	if (!--hid->open)
+		usb_unlink_urb(&hid->urb);
+}
+
+/*
+ * Initialize all readable reports
+ */
+void hid_init_reports(struct hid_device *hid)
+{
+	int i;
+	struct hid_report *report;
+	struct hid_report_enum *report_enum;
+	struct list_head *list;
+
+	for (i = 0; i < HID_REPORT_TYPES; i++) {
+		if (i == HID_FEATURE_REPORT || i == HID_INPUT_REPORT) {
+			report_enum = hid->report_enum + i;
+			list = report_enum->report_list.next;
+			while (list != &report_enum->report_list) {
+				report = (struct hid_report *) list;
+				usb_set_idle(hid->dev, hid->ifnum, 0, report->id);
+				hid_read_report(hid, report);
+				list = list->next;
+			}
+		}
+	}
+}
+
+#define USB_VENDOR_ID_WACOM		0x056a
+#define USB_DEVICE_ID_WACOM_GRAPHIRE	0x0010
+#define USB_DEVICE_ID_WACOM_INTUOS	0x0020
+
+struct hid_blacklist {
+	__u16 idVendor;
+	__u16 idProduct;
+} hid_blacklist[] = {
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1},
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},
+	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},
+	{ 0, 0 }
+};
+
+static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum)
+{
+	struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;
+	struct hid_descriptor *hdesc;
+	struct hid_device *hid;
+	unsigned rsize = 0;
+	char *buf;
+	int n;
+
+	for (n = 0; hid_blacklist[n].idVendor; n++)
+		if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) &&
+			(hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL;
+
+	if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc) && ((!interface->bNumEndpoints) ||
+		usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc))) {
+			dbg("class descriptor not present\n");
+			return NULL;
+	}
+
+	for (n = 0; n < hdesc->bNumDescriptors; n++)
+		if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT)
+			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
+
+	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
+		dbg("weird size of report descriptor (%u)", rsize);
+		return NULL;
+	}
+
+	{
+		__u8 rdesc[rsize];
+
+		if ((n = usb_get_class_descriptor(dev, interface->bInterfaceNumber, USB_DT_REPORT, 0, rdesc, rsize)) < 0) {
+			dbg("reading report descriptor failed");
+			return NULL;
+		}
+
+#ifdef DEBUG_DATA
+		printk(KERN_DEBUG __FILE__ ": report descriptor (size %u, read %d) = ", rsize, n);
+		for (n = 0; n < rsize; n++)
+			printk(" %02x", (unsigned) rdesc[n]);
+		printk("\n");
+#endif
+
+		if (!(hid = hid_parse_report(rdesc, rsize))) {
+			dbg("parsing report descriptor failed");
+			return NULL;
+		}
+	}
+
+	for (n = 0; n < interface->bNumEndpoints; n++) {
+
+		struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n];
+		int pipe, maxp;
+
+		if ((endpoint->bmAttributes & 3) != 3)		/* Not an interrupt endpoint */
+			continue;
+
+		if (!(endpoint->bEndpointAddress & 0x80))	/* Not an input endpoint */
+			continue;
+
+		pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
+		maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+		FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval);
+
+		break;
+	}
+
+	if (n == interface->bNumEndpoints) {
+		dbg("couldn't find an input interrupt endpoint");
+		hid_free_device(hid);
+		return NULL;
+	}
+
+	hid->version = hdesc->bcdHID;
+	hid->country = hdesc->bCountryCode;
+	hid->dev = dev;
+	hid->ifnum = interface->bInterfaceNumber;
+
+	for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
+		hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
+		hid->out[n].dr.request = USB_REQ_SET_REPORT;
+		hid->out[n].dr.index = cpu_to_le16(hid->ifnum);
+	}
+
+	hid->name[0] = 0;
+
+	if (!(buf = kmalloc(63, GFP_KERNEL)))
+		return NULL;
+
+	if (usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0) {
+		strcat(hid->name, buf);
+		if (usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
+			sprintf(hid->name, "%s %s", hid->name, buf);
+	} else
+		sprintf(hid->name, "%04x:%04x", dev->descriptor.idVendor, dev->descriptor.idProduct);
+
+	kfree(buf);
+
+	FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0),
+		(void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid);
+
+/*
+ * Some devices don't like this and crash. I don't know of any devices
+ * needing this, so it is disabled for now.
+ */
+
+#if 0
+	if (interface->bInterfaceSubClass == 1)
+		usb_set_protocol(dev, hid->ifnum, 1);
+#endif
+
+	return hid;
+}
+
+static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
+		       const struct usb_device_id *id)
+{
+	struct hid_device *hid;
+	int i;
+	char *c;
+
+	dbg("HID probe called for ifnum %d", ifnum);
+
+	if (!(hid = usb_hid_configure(dev, ifnum)))
+		return NULL;
+
+	hid_init_reports(hid);
+	hid_dump_device(hid);
+
+	if (!hidinput_connect(hid))
+		hid->claimed |= HID_CLAIMED_INPUT;
+#ifdef CONFIG_USB_HIDDEV
+	if (!hiddev_connect(hid))
+		hid->claimed |= HID_CLAIMED_HIDDEV;
+#endif
+	printk(KERN_INFO);
+
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		printk("input%d", hid->input.number);
+	if (hid->claimed == (HID_CLAIMED_INPUT | HID_CLAIMED_HIDDEV))
+		printk(",");
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		printk("hiddev%d", hid->minor);
+
+	c = "Device";
+	for (i = 0; i < hid->maxapplication; i++)
+		if (IS_INPUT_APPLICATION(hid->application[i])) {
+			c = hid_types[hid->application[i] & 0xffff];
+			break;
+		}
+
+	printk(": USB HID v%x.%02x %s [%s] on usb%d:%d.%d\n",
+		hid->version >> 8, hid->version & 0xff, c, hid->name,
+		dev->bus->busnum, dev->devnum, ifnum);
+
+	return hid;
+}
+
+static void hid_disconnect(struct usb_device *dev, void *ptr)
+{
+	struct hid_device *hid = ptr;
+
+	dbg("cleanup called");
+	usb_unlink_urb(&hid->urb);
+
+	if (hid->claimed & HID_CLAIMED_INPUT)
+		hidinput_disconnect(hid);
+#ifdef CONFIG_USB_HIDDEV
+	if (hid->claimed & HID_CLAIMED_HIDDEV)
+		hiddev_disconnect(hid);
+#endif
+	hid_free_device(hid);
+}
+
+static struct usb_device_id hid_usb_ids [] = {
+	{ match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
+	    bInterfaceClass: USB_INTERFACE_CLASS_HID },
+	{ }						/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, hid_usb_ids);
+
+static struct usb_driver hid_driver = {
+	name:		"hid",
+	probe:		hid_probe,
+	disconnect:	hid_disconnect,
+	id_table:	hid_usb_ids,
+};
+
+static int __init hid_init(void)
+{
+	usb_register(&hid_driver);
+#ifdef CONFIG_USB_HIDDEV
+	hiddev_init();
+#endif
+	info(DRIVER_VERSION " " DRIVER_AUTHOR);
+	info(DRIVER_DESC);
+
+	return 0;
+}
+
+static void __exit hid_exit(void)
+{
+#ifdef CONFIG_USB_HIDDEV
+	hiddev_exit();
+#endif
+	usb_deregister(&hid_driver);
+}
+
+module_init(hid_init);
+module_exit(hid_exit);
+
+MODULE_AUTHOR( DRIVER_AUTHOR );
+MODULE_DESCRIPTION( DRIVER_DESC );
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/usb/hid-debug.h linux/drivers/usb/hid-debug.h
--- linux-2.4.10-pre8/drivers/usb/hid-debug.h	Mon Jun 19 13:42:41 2000
+++ linux/drivers/usb/hid-debug.h	Mon Dec  3 23:09:49 2001
@@ -1,8 +1,8 @@
 /*
- * $Id: hid-debug.h,v 1.2 2000/05/29 10:54:53 vojtech Exp $
+ * $Id: hid-debug.h,v 1.3 2001/05/10 15:56:07 vojtech Exp $
  *
- *  (c) 1999 Andreas Gal	<gal@cs.uni-magdeburg.de>
- *  (c) 2000 Vojtech Pavlik	<vojtech@suse.cz>
+ *  (c) 1999 Andreas Gal		<gal@cs.uni-magdeburg.de>
+ *  (c) 2000-2001 Vojtech Pavlik	<vojtech@suse.cz>
  *
  *  Some debug stuff for the HID parser.
  *
@@ -196,16 +196,18 @@
 	printk(")\n");
 }
 
-void hid_dump_device(struct hid_device *device) {
+static void hid_dump_device(struct hid_device *device) {
 	struct hid_report_enum *report_enum;
 	struct hid_report *report;
 	struct list_head *list;
 	unsigned i,k;
 	static char *table[] = {"INPUT", "OUTPUT", "FEATURE"};
 	
-	printk("Application(");
-	resolv_usage(device->application);
-	printk(")\n");
+	for (i = 0; i < device->maxapplication; i++) {
+		printk("Application(");
+		resolv_usage(device->application[i]);
+		printk(")\n");
+	}
 
 	for (i = 0; i < HID_REPORT_TYPES; i++) {
 		report_enum = device->report_enum + i;
@@ -228,8 +230,8 @@
 	}
 }
 
-void hid_dump_input(struct hid_usage *usage, __s32 value) {
-	printk("hidd: input ");
+static void hid_dump_input(struct hid_usage *usage, __s32 value) {
+	printk("hid-debug: input ");
 	resolv_usage(usage->hid);
 	printk(" = %d\n", value);
 }
diff -urN linux-2.4.10-pre8/drivers/usb/hid-input.c linux/drivers/usb/hid-input.c
--- linux-2.4.10-pre8/drivers/usb/hid-input.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hid-input.c	Mon Dec  3 23:09:49 2001
@@ -0,0 +1,424 @@
+/*
+ * $Id: hid-input.c,v 1.5 2001/05/23 09:25:02 vojtech Exp $
+ *
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ *  USB HID to Linux Input mapping module
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "hid.h"
+
+#define unk	KEY_UNKNOWN
+
+static unsigned char hid_keyboard[256] = {
+	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
+	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
+	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
+	 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
+	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
+	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
+	 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,
+	120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
+	115,114,unk,unk,unk,124,unk,181,182,183,184,185,186,187,188,189,
+	190,191,192,193,194,195,196,197,198,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
+	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
+	150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
+};
+
+static struct {
+	__s32 x;
+	__s32 y;
+}  hid_hat_to_axis[] = {{0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+static void hidinput_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage)
+{
+	struct input_dev *input = &device->input;
+	int max;
+	unsigned long *bit;
+
+	switch (usage->hid & HID_USAGE_PAGE) {
+
+		case HID_UP_KEYBOARD:
+
+			set_bit(EV_REP, input->evbit);
+			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+
+			if ((usage->hid & HID_USAGE) < 256) {
+				if (!(usage->code = hid_keyboard[usage->hid & HID_USAGE]))
+					return;
+				clear_bit(usage->code, bit);
+			} else
+				usage->code = KEY_UNKNOWN;
+
+			break;
+
+		case HID_UP_BUTTON:
+
+			usage->code = ((usage->hid - 1) & 0xf) + 0x100;
+			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+
+			switch (field->application) {
+				case HID_GD_GAMEPAD:  usage->code += 0x10;
+				case HID_GD_JOYSTICK: usage->code += 0x10;
+				case HID_GD_MOUSE:    usage->code += 0x10; break;
+				default:
+					if (field->physical == HID_GD_POINTER)
+						usage->code += 0x10;
+					break;
+			}
+			break;
+
+		case HID_UP_GENDESK:
+
+			if ((usage->hid & 0xf0) == 0x80) {	/* SystemControl */
+				switch (usage->hid & 0xf) {
+					case 0x1: usage->code = KEY_POWER;  break;
+					case 0x2: usage->code = KEY_SLEEP;  break;
+					case 0x3: usage->code = KEY_WAKEUP; break;
+					default: usage->code = KEY_UNKNOWN; break;
+				}
+				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+				break;
+			}
+
+			usage->code = usage->hid & 0xf;
+
+			if (field->report_size == 1) {
+				usage->code = BTN_MISC;
+				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+				break;
+			}
+
+			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+				usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
+				break;
+			}
+
+			usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
+
+			if (usage->hid == HID_GD_HATSWITCH) {
+				usage->code = ABS_HAT0X;
+				usage->hat = 1 + (field->logical_maximum == 4);
+			}
+			break;
+
+		case HID_UP_LED:
+
+			usage->code = (usage->hid - 1) & 0xf;
+			usage->type = EV_LED; bit = input->ledbit; max = LED_MAX;
+			break;
+
+		case HID_UP_DIGITIZER:
+
+			switch (usage->hid & 0xff) {
+
+				case 0x30: /* TipPressure */
+
+					if (!test_bit(BTN_TOUCH, input->keybit)) {
+						device->quirks |= HID_QUIRK_NOTOUCH;
+						set_bit(EV_KEY, input->evbit);
+						set_bit(BTN_TOUCH, input->keybit);
+					}
+					usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
+					usage->code = ABS_PRESSURE;
+					clear_bit(usage->code, bit);
+					break;
+
+				case 0x32: /* InRange */
+
+					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+					switch (field->physical & 0xff) {
+						case 0x21: usage->code = BTN_TOOL_MOUSE; break;
+						case 0x22: usage->code = BTN_TOOL_FINGER; break;
+						default: usage->code = BTN_TOOL_PEN; break;
+					}
+					break;
+
+				case 0x3c: /* Invert */
+
+					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+					usage->code = BTN_TOOL_RUBBER;
+					clear_bit(usage->code, bit);
+					break;
+
+				case 0x33: /* Touch */
+				case 0x42: /* TipSwitch */
+				case 0x43: /* TipSwitch2 */
+
+					device->quirks &= ~HID_QUIRK_NOTOUCH;
+					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+					usage->code = BTN_TOUCH;
+					clear_bit(usage->code, bit);
+					break;
+
+				case 0x44: /* BarrelSwitch */
+
+					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+					usage->code = BTN_STYLUS;
+					clear_bit(usage->code, bit);
+					break;
+
+				default:  goto unknown;
+			}
+			break;
+
+		case HID_UP_CONSUMER:	/* USB HUT v1.1, pages 56-62 */
+
+			switch (usage->hid & HID_USAGE) {
+				case 0x000: usage->code = 0; break;
+				case 0x034: usage->code = KEY_SLEEP;		break;
+				case 0x036: usage->code = BTN_MISC;		break;
+				case 0x08a: usage->code = KEY_WWW;		break;
+				case 0x095: usage->code = KEY_HELP;		break;
+
+				case 0x0b4: usage->code = KEY_REWIND;		break;
+				case 0x0b5: usage->code = KEY_NEXTSONG;		break;
+				case 0x0b6: usage->code = KEY_PREVIOUSSONG;	break;
+				case 0x0b7: usage->code = KEY_STOPCD;		break;
+				case 0x0b8: usage->code = KEY_EJECTCD;		break;
+				case 0x0cd: usage->code = KEY_PLAYPAUSE;	break;
+
+				case 0x0e2: usage->code = KEY_MUTE;		break;
+				case 0x0e9: usage->code = KEY_VOLUMEUP;		break;
+				case 0x0ea: usage->code = KEY_VOLUMEDOWN;	break;
+
+				case 0x183: usage->code = KEY_CONFIG;		break;
+				case 0x18a: usage->code = KEY_MAIL;		break;
+				case 0x192: usage->code = KEY_CALC;		break;
+				case 0x194: usage->code = KEY_FILE;		break;
+
+				case 0x21a: usage->code = KEY_UNDO;		break;
+				case 0x21b: usage->code = KEY_COPY;		break;
+				case 0x21c: usage->code = KEY_CUT;		break;
+				case 0x21d: usage->code = KEY_PASTE;		break;
+
+				case 0x221: usage->code = KEY_FIND;		break;
+				case 0x223: usage->code = KEY_HOMEPAGE;		break;
+				case 0x224: usage->code = KEY_BACK;		break;
+				case 0x225: usage->code = KEY_FORWARD;		break;
+				case 0x226: usage->code = KEY_STOP;		break;
+				case 0x227: usage->code = KEY_REFRESH;		break;
+				case 0x22a: usage->code = KEY_BOOKMARKS;	break;
+
+				default:    usage->code = KEY_UNKNOWN;		break;
+
+			}
+
+			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+			break;
+
+		default:
+		unknown:
+
+			if (field->report_size == 1) {
+
+				if (field->report->type == HID_OUTPUT_REPORT) {
+					usage->code = LED_MISC;
+					usage->type = EV_LED; bit = input->ledbit; max = LED_MAX;
+					break;
+				}
+
+				usage->code = BTN_MISC;
+				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
+				break;
+			}
+
+			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
+				usage->code = REL_MISC;
+				usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
+				break;
+			}
+
+			usage->code = ABS_MISC;
+			usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
+			break;
+	}
+
+	set_bit(usage->type, input->evbit);
+
+	while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
+		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
+	}
+
+	if (usage->code > max) return;
+
+	if (usage->type == EV_ABS) {
+		int a = field->logical_minimum;
+		int b = field->logical_maximum;
+
+		input->absmin[usage->code] = a;
+		input->absmax[usage->code] = b;
+		input->absfuzz[usage->code] = (b - a) >> 8;
+		input->absflat[usage->code] = (b - a) >> 4;
+	}
+
+	if (usage->hat) {
+		int i;
+		for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
+			input->absmax[i] = 1;
+			input->absmin[i] = -1;
+			input->absfuzz[i] = 0;
+			input->absflat[i] = 0;
+		}
+		set_bit(usage->code + 1, input->absbit);
+	}
+}
+
+void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
+{
+	struct input_dev *input = &hid->input;
+	int *quirks = &hid->quirks;
+
+	if (usage->hat) {
+		if (usage->hat == 2) value = value * 2;
+		if (value > 8) value = 8;
+		input_event(input, usage->type, usage->code    , hid_hat_to_axis[value].x);
+		input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y);
+		return;
+	}
+
+	if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
+		*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
+		return;
+	}
+
+	if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
+		if (value) {
+			input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
+			return;
+		}
+		input_event(input, usage->type, usage->code, 0);
+		input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
+		return;
+	}
+
+	if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
+		int a = field->logical_minimum;
+		int b = field->logical_maximum;
+		input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
+	}
+
+	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */
+		return;
+
+	input_event(input, usage->type, usage->code, value);
+
+	if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
+		input_event(input, usage->type, usage->code, 0);
+}
+
+static int hidinput_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+	struct hid_device *hid = dev->private;
+	struct hid_field *field = NULL;
+	int offset;
+
+	if ((offset = hid_find_field(hid, type, code, &field)) == -1) {
+		warn("event field not found");
+		return -1;
+	}
+
+	hid_set_field(field, offset, value);
+	hid_write_report(hid, field->report);
+
+	return 0;
+}
+
+static int hidinput_open(struct input_dev *dev)
+{
+	struct hid_device *hid = dev->private;
+	return hid_open(hid);
+}
+
+static void hidinput_close(struct input_dev *dev)
+{
+	struct hid_device *hid = dev->private;
+	hid_close(hid);
+}
+
+/*
+ * Register the input device; print a message.
+ * Configure the input layer interface
+ * Read all reports and initalize the absoulte field values.
+ */
+
+int hidinput_connect(struct hid_device *hid)
+{
+	struct usb_device *dev = hid->dev;
+	struct hid_report_enum *report_enum;
+	struct hid_report *report;
+	struct list_head *list;
+	int i, j, k;
+
+	for (i = 0; i < hid->maxapplication; i++)
+		if (IS_INPUT_APPLICATION(hid->application[i]))
+			break;
+
+	if (i == hid->maxapplication)
+		return -1;
+
+	hid->input.private = hid;
+	hid->input.event = hidinput_input_event;
+	hid->input.open = hidinput_open;
+	hid->input.close = hidinput_close;
+
+	hid->input.name = hid->name;
+	hid->input.idbus = BUS_USB;
+	hid->input.idvendor = dev->descriptor.idVendor;
+	hid->input.idproduct = dev->descriptor.idProduct;
+	hid->input.idversion = dev->descriptor.bcdDevice;
+
+	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+		report_enum = hid->report_enum + k;
+		list = report_enum->report_list.next;
+		while (list != &report_enum->report_list) {
+			report = (struct hid_report *) list;
+			for (i = 0; i < report->maxfield; i++)
+				for (j = 0; j < report->field[i]->maxusage; j++)
+					hidinput_configure_usage(hid, report->field[i], report->field[i]->usage + j);
+			list = list->next;
+		}
+	}
+
+	input_register_device(&hid->input);
+
+	return 0;
+}
+
+void hidinput_disconnect(struct hid_device *hid)
+{
+	input_unregister_device(&hid->input);
+}
diff -urN linux-2.4.10-pre8/drivers/usb/hid.c linux/drivers/usb/hid.c
--- linux-2.4.10-pre8/drivers/usb/hid.c	Tue Jun 12 15:53:37 2001
+++ linux/drivers/usb/hid.c	Wed Dec 31 16:00:00 1969
@@ -1,1576 +0,0 @@
-/*
- * $Id: hid.c,v 1.16 2000/09/18 21:38:55 vojtech Exp $
- *
- *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000 Vojtech Pavlik
- *
- *  USB HID support for the Linux input drivers
- *
- *  Sponsored by SuSE
- */
-
-/*
- * 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 <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/mm.h>
-#include <linux/smp_lock.h>
-#include <linux/spinlock.h>
-#undef DEBUG
-#undef DEBUG_DATA
-#include <linux/usb.h>
-
-#include <asm/unaligned.h>
-
-#include "hid.h"
-
-#ifdef DEBUG
-#include "hid-debug.h"
-#else
-#define hid_dump_input(a,b)	do { } while (0)
-#define hid_dump_device(c)	do { } while (0)
-#endif
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.16"
-#define DRIVER_AUTHOR "Andreas Gal, Vojtech Pavlik <vojtech@suse.cz>"
-#define DRIVER_DESC "USB HID support drivers"
-
-#define unk	KEY_UNKNOWN
-
-static unsigned char hid_keyboard[256] = {
-	  0,  0,  0,  0, 30, 48, 46, 32, 18, 33, 34, 35, 23, 36, 37, 38,
-	 50, 49, 24, 25, 16, 19, 31, 20, 22, 47, 17, 45, 21, 44,  2,  3,
-	  4,  5,  6,  7,  8,  9, 10, 11, 28,  1, 14, 15, 57, 12, 13, 26,
-	 27, 43, 84, 39, 40, 41, 51, 52, 53, 58, 59, 60, 61, 62, 63, 64,
-	 65, 66, 67, 68, 87, 88, 99, 70,119,110,102,104,111,107,109,106,
-	105,108,103, 69, 98, 55, 74, 78, 96, 79, 80, 81, 75, 76, 77, 71,
-	 72, 73, 82, 83, 86,127,116,117, 85, 89, 90, 91, 92, 93, 94, 95,
-	120,121,122,123,134,138,130,132,128,129,131,137,133,135,136,113,
-	115,114,unk,unk,unk,124,unk,181,182,183,184,185,186,187,188,189,
-	190,191,192,193,194,195,196,197,198,unk,unk,unk,unk,unk,unk,unk,
-	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-	unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,unk,
-	 29, 42, 56,125, 97, 54,100,126,164,166,165,163,161,115,114,113,
-	150,158,159,128,136,177,178,176,142,152,173,140,unk,unk,unk,unk
-};
-
-static struct {
-	__s32 x;
-	__s32 y;
-}  hid_hat_to_axis[] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}, { 0, 0}};
-
-static char *hid_types[] = {"Device", "Pointer", "Mouse", "Device", "Joystick",
-				"Gamepad", "Keyboard", "Keypad", "Multi-Axis Controller"};
-
-/*
- * Register a new report for a device.
- */
-
-static struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id)
-{
-	struct hid_report_enum *report_enum = device->report_enum + type;
-	struct hid_report *report;
-	 
-	if (report_enum->report_id_hash[id])
-		return report_enum->report_id_hash[id];
-
-	if (!(report = kmalloc(sizeof(struct hid_report), GFP_KERNEL)))
-		return NULL;
-	memset(report, 0, sizeof(struct hid_report));
-
-	if (id != 0) report_enum->numbered = 1;
-
-	report->id = id;
-	report->type = type;
-	report->size = 0;
-	report->device = device;
-	report_enum->report_id_hash[id] = report;
-
-	list_add_tail(&report->list, &report_enum->report_list);
-
-	return report;
-}
-
-/*
- * Register a new field for this report.
- */
-
-static struct hid_field *hid_register_field(struct hid_report *report, unsigned usages, unsigned values)
-{
-	if (report->maxfield < HID_MAX_FIELDS) {
-		struct hid_field *field;
-
-		if (!(field = kmalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-				+ values * sizeof(unsigned), GFP_KERNEL)))
-			return NULL;
-		memset(field, 0, sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
-				+ values * sizeof(unsigned));
-
-		report->field[report->maxfield++] = field;
-		field->usage = (struct hid_usage *)(field + 1);
-		field->value = (unsigned *)(field->usage + usages);
-		field->report = report;
-
-		return field;
-	}
-
-	dbg("too many fields in report");
-	return NULL;
-}
-
-/*
- * Open a collection. The type/usage is pushed on the stack.
- */
-
-static int open_collection(struct hid_parser *parser, unsigned type)
-{
-	unsigned usage;
-
-	usage = parser->local.usage[0];
-
-	if (type == HID_COLLECTION_APPLICATION && !parser->device->application)
-		parser->device->application = usage;
-
-	if (parser->collection_stack_ptr < HID_COLLECTION_STACK_SIZE) { /* PUSH on stack */
-		struct hid_collection *collection = parser->collection_stack + parser->collection_stack_ptr++;
-		collection->type = type;
-		collection->usage = usage;
-		return 0;
-	}
-
-	dbg("collection stack overflow");
-	return -1;
-}
-
-/*
- * Close a collection.
- */
-
-static int close_collection(struct hid_parser *parser)
-{
-	if (parser->collection_stack_ptr > 0) {	/* POP from stack */
-		parser->collection_stack_ptr--;
-		return 0;
-	}
-	dbg("collection stack underflow");
-	return -1;
-}
-
-/*
- * Climb up the stack, search for the specified collection type
- * and return the usage.
- */
-
-static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
-{
-	int n;
-	for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
-		if (parser->collection_stack[n].type == type)
-			return parser->collection_stack[n].usage;
-	return 0; /* we know nothing about this usage type */
-}
-
-/*
- * Add a usage to the temporary parser table.
- */
-
-static int hid_add_usage(struct hid_parser *parser, unsigned usage)
-{
-	if (parser->local.usage_index >= HID_MAX_USAGES) {
-		dbg("usage index exceeded");
-		return -1;
-	}
-	parser->local.usage[parser->local.usage_index++] = usage;
-	return 0;
-}
-
-/*
- * Register a new field for this report.
- */
-
-static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsigned flags)
-{
-	struct hid_report *report;
-	struct hid_field *field;
-	int usages;
-	unsigned offset;
-	int i;
-
-	if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
-    		dbg("hid_register_report failed");
-		return -1;
-	}
-
-	if (HID_MAIN_ITEM_VARIABLE & ~flags) { /* ARRAY */
-		if (parser->global.logical_maximum <= parser->global.logical_minimum) {
-			dbg("logical range invalid %d %d", parser->global.logical_minimum, parser->global.logical_maximum);
-			return -1;
-		}
-		usages = parser->local.usage_index;
-		/* Hint: we can assume usages < MAX_USAGE here */
-	} else { /* VARIABLE */
-		usages = parser->global.report_count;
-	}
-	offset = report->size;
-	report->size += parser->global.report_size *
-			parser->global.report_count;
-	if (usages == 0)
-		return 0; /* ignore padding fields */
-	if ((field = hid_register_field(report, usages,
-			     parser->global.report_count)) == NULL)
-		return 0;
-	field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
-	field->logical = hid_lookup_collection(parser, HID_COLLECTION_LOGICAL);
-	for (i = 0; i < usages; i++) field->usage[i].hid = parser->local.usage[i];
-	field->maxusage = usages;
-	field->flags = flags;
-	field->report_offset = offset;
-	field->report_type = report_type;
-	field->report_size = parser->global.report_size;
-	field->report_count = parser->global.report_count;
-	field->logical_minimum = parser->global.logical_minimum;
-	field->logical_maximum = parser->global.logical_maximum;
-	field->physical_minimum = parser->global.physical_minimum;
-	field->physical_maximum = parser->global.physical_maximum;
-	field->unit_exponent = parser->global.unit_exponent;
-	field->unit = parser->global.unit;
-	return 0;
-}
-
-/*
- * Read data value from item.
- */
-
-static __inline__ __u32 item_udata(struct hid_item *item)
-{
-	switch (item->size) {
-		case 1: return item->data.u8;
-		case 2: return item->data.u16;
-		case 4: return item->data.u32;
-	}
-	return 0;
-}
-
-static __inline__ __s32 item_sdata(struct hid_item *item)
-{
-	switch (item->size) {
-		case 1: return item->data.s8;
-		case 2: return item->data.s16;
-		case 4: return item->data.s32;
-	}
-	return 0;
-}
-
-/*
- * Process a global item.
- */
-
-static int hid_parser_global(struct hid_parser *parser, struct hid_item *item)
-{
-	switch (item->tag) {
-
-		case HID_GLOBAL_ITEM_TAG_PUSH:
-
-			if (parser->global_stack_ptr < HID_GLOBAL_STACK_SIZE) {
-				memcpy(parser->global_stack + parser->global_stack_ptr++,
-					&parser->global, sizeof(struct hid_global));
-				return 0;
-			}
-			dbg("global enviroment stack overflow");
-			return -1;
-
-		case HID_GLOBAL_ITEM_TAG_POP:
-
-			if (parser->global_stack_ptr > 0) {
-				memcpy(&parser->global, parser->global_stack + --parser->global_stack_ptr,
-					sizeof(struct hid_global));
-				return 0;
-			}
-			dbg("global enviroment stack underflow");
-			return -1;
-
-		case HID_GLOBAL_ITEM_TAG_USAGE_PAGE:
-			parser->global.usage_page = item_udata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_LOGICAL_MINIMUM:
-			parser->global.logical_minimum = item_sdata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_LOGICAL_MAXIMUM:
-			parser->global.logical_maximum = item_sdata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MINIMUM:
-			parser->global.physical_minimum = item_sdata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_PHYSICAL_MAXIMUM:
-			parser->global.physical_maximum = item_sdata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_UNIT_EXPONENT:
-			parser->global.unit_exponent = item_udata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_UNIT:
-			parser->global.unit = item_udata(item);
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_REPORT_SIZE:
-			if ((parser->global.report_size = item_udata(item)) > 32) {
-				dbg("invalid report_size %d", parser->global.report_size);
-				return -1;
-			}
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_REPORT_COUNT:
-			if ((parser->global.report_count = item_udata(item)) > HID_MAX_USAGES) {
-				dbg("invalid report_count %d", parser->global.report_count);
-				return -1;
-			}
-			return 0;
-
-		case HID_GLOBAL_ITEM_TAG_REPORT_ID:
-			if ((parser->global.report_id = item_udata(item)) == 0) {
-				dbg("report_id 0 is invalid");
-				return -1;
-			}
-			return 0;
-
-		default:
-			dbg("unknown global tag 0x%x", item->tag);
-			return -1;
-	}
-}
-
-/*
- * Process a local item.
- */
-
-static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
-{
-	__u32 data;
-
-	if (item->size == 0) {
-		dbg("item data expected for local item");
-		return -1;
-	}
-
-	data = item_udata(item);
-
-	switch (item->tag) {
-
-		case HID_LOCAL_ITEM_TAG_DELIMITER:
-
-			if (data) {
-				/*
-				 * We treat items before the first delimiter
-				 * as global to all usage sets (branch 0).
-				 * In the moment we process only these global
-				 * items and the first delimiter set.
-				 */
-				if (parser->local.delimiter_depth != 0) {
-					dbg("nested delimiters");
-					return -1;
-				}
-				parser->local.delimiter_depth++;
-				parser->local.delimiter_branch++;
-			} else {
-				if (parser->local.delimiter_depth < 1) {
-					dbg("bogus close delimiter");
-					return -1;
-				}
-				parser->local.delimiter_depth--;
-			}
-			return 1;
-
-		case HID_LOCAL_ITEM_TAG_USAGE:
-
-			if (parser->local.delimiter_branch < 2) {
-				if (item->size <= 2)
-					data = (parser->global.usage_page << 16) + data;
-				return hid_add_usage(parser, data);
-			}
-			dbg("alternative usage ignored");
-			return 0;
-
-		case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
-
-			if (parser->local.delimiter_branch < 2) {
-				if (item->size <= 2)
-					data = (parser->global.usage_page << 16) + data;
-				parser->local.usage_minimum = data;
-				return 0;
-			}
-			dbg("alternative usage ignored");
-			return 0;
-
-		case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM:
-
-			if (parser->local.delimiter_branch < 2) {
-				unsigned n;
-				if (item->size <= 2)
-					data = (parser->global.usage_page << 16) + data;
-				for (n = parser->local.usage_minimum; n <= data; n++)
-					if (hid_add_usage(parser, n)) {
-						dbg("hid_add_usage failed\n");
-						return -1;
-					}
-				return 0;
-			}
-			dbg("alternative usage ignored");
-			return 0;
-
-		default:
-
-			dbg("unknown local item tag 0x%x", item->tag);
-			return 0;
-	}
-}
-
-/*
- * Process a main item.
- */
-
-static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
-{
-	__u32 data;
-	int ret;
-
-	data = item_udata(item);
-	
-	switch (item->tag) {
-		case HID_MAIN_ITEM_TAG_BEGIN_COLLECTION:
-			ret = open_collection(parser, data & 3);
-			break;
-		case HID_MAIN_ITEM_TAG_END_COLLECTION:
-			ret = close_collection(parser);
-			break;
-		case HID_MAIN_ITEM_TAG_INPUT:
-			ret = hid_add_field(parser, HID_INPUT_REPORT, data);
-			break;
-		case HID_MAIN_ITEM_TAG_OUTPUT:
-			ret = hid_add_field(parser, HID_OUTPUT_REPORT, data);
-			break;
-		case HID_MAIN_ITEM_TAG_FEATURE:
-			ret = hid_add_field(parser, HID_FEATURE_REPORT, data);
-			break;
-		default:
-			dbg("unknown main item tag 0x%x", item->tag);
-			ret = 0;
-	}
-
-	memset(&parser->local, 0, sizeof(parser->local));	/* Reset the local parser environment */
-
-	return ret;
-}
-
-/*
- * Process a reserved item.
- */
-
-static int hid_parser_reserved(struct hid_parser *parser, struct hid_item *item)
-{
-	dbg("reserved item type, tag 0x%x", item->tag);
-	return 0;
-}
-
-/*
- * Free a report and all registered fields. The field->usage and
- * field->value table's are allocated behind the field, so we need
- * only to free(field) itself.
- */
-
-static void hid_free_report(struct hid_report *report)
-{
-	unsigned n;
-
-	for (n = 0; n < report->maxfield; n++)
-		kfree(report->field[n]);
-	kfree(report);
-}
-
-/*
- * Free a device structure, all reports, and all fields.
- */
-
-static void hid_free_device(struct hid_device *device)
-{
-	unsigned i,j;
-
-	for (i = 0; i < HID_REPORT_TYPES; i++) {
-		struct hid_report_enum *report_enum = device->report_enum + i;
-
-		for (j = 0; j < 256; j++) {
-			struct hid_report *report = report_enum->report_id_hash[j];
-			if (report) hid_free_report(report);
-		}
-	}
-
-	if (device->rdesc) kfree(device->rdesc);
-}
-
-/*
- * Fetch a report description item from the data stream. We support long
- * items, though they are not used yet.
- */
-
-static __u8 *fetch_item(__u8 *start, __u8 *end, struct hid_item *item)
-{
-	if ((end - start) > 0) {
-
-		__u8 b = *start++;
-		item->type = (b >> 2) & 3;
-		item->tag  = (b >> 4) & 15;
-
-		if (item->tag == HID_ITEM_TAG_LONG) {
-
-			item->format = HID_ITEM_FORMAT_LONG;
-
-			if ((end - start) >= 2) {
-
-				item->size = *start++;
-				item->tag  = *start++;
-
-				if ((end - start) >= item->size) {
-					item->data.longdata = start;
-					start += item->size;
-					return start;
-				}
-			}
-		} else {
-
-			item->format = HID_ITEM_FORMAT_SHORT;
-			item->size = b & 3;
-			switch (item->size) {
-
-				case 0:
-					return start;
-
-				case 1: 
-					if ((end - start) >= 1) {
-						item->data.u8 = *start++;
-						return start;
-					}
-					break;
-
-				case 2: 
-					if ((end - start) >= 2) {
-						item->data.u16 = le16_to_cpu( get_unaligned(((__u16*)start)++));
-						return start;
-					}
-
-				case 3: 
-					item->size++;
-					if ((end - start) >= 4) {
-						item->data.u32 = le32_to_cpu( get_unaligned(((__u32*)start)++));
-						return start;
-					}
-			}
-		}
-	}
-	return NULL;
-}
-
-/*
- * Parse a report description into a hid_device structure. Reports are
- * enumerated, fields are attached to these reports.
- */
-
-static struct hid_device *hid_parse_report(__u8 *start, unsigned size)
-{
-	struct hid_device *device;
-	struct hid_parser *parser;
-	struct hid_item    item;
-	__u8 *end;
-	unsigned i;
-	static int (*dispatch_type[])(struct hid_parser *parser,
-				      struct hid_item *item) = {
-		hid_parser_main,
-		hid_parser_global,
-		hid_parser_local,
-		hid_parser_reserved
-	};
-
-	if (!(device = kmalloc(sizeof(struct hid_device), GFP_KERNEL)))
-		return NULL;
-	memset(device, 0, sizeof(struct hid_device));
-
-	for (i = 0; i < HID_REPORT_TYPES; i++)
-		INIT_LIST_HEAD(&device->report_enum[i].report_list);
-
-	if (!(device->rdesc = (__u8 *)kmalloc(size, GFP_KERNEL))) {
-		kfree(device);
-		return NULL;
-	}
-	memcpy(device->rdesc, start, size);
-
-	if (!(parser = kmalloc(sizeof(struct hid_parser), GFP_KERNEL))) {
-		kfree(device->rdesc);
-		kfree(device);
-		return NULL;
-	}
-	memset(parser, 0, sizeof(struct hid_parser));
-	parser->device = device;
-	
-	end = start + size;
-	while ((start = fetch_item(start, end, &item)) != 0) {
-		if (item.format != HID_ITEM_FORMAT_SHORT) {
-			dbg("unexpected long global item");
-			hid_free_device(device);
-			kfree(parser);
-			return NULL;
-		}
-		if (dispatch_type[item.type](parser, &item)) {
-			dbg("item %u %u %u %u parsing failed\n",
-				item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
-			hid_free_device(device);
-			kfree(parser);
-			return NULL;
-		}
-
-		if (start == end) {
-			if (parser->collection_stack_ptr) {
-				dbg("unbalanced collection at end of report description");
-				hid_free_device(device);
-				kfree(parser);
-				return NULL;
-			}
-			if (parser->local.delimiter_depth) {
-				dbg("unbalanced delimiter at end of report description");
-				hid_free_device(device);
-				kfree(parser);
-				return NULL;
-			}
-			kfree(parser);
-			return device;
-		}
-	}
-
-	dbg("item fetching failed at offset %d\n", (int)(end - start));
-	hid_free_device(device);
-	kfree(parser);
-	return NULL;
-}
-
-/*
- * Convert a signed n-bit integer to signed 32-bit integer. Common
- * cases are done through the compiler, the screwed things has to be
- * done by hand.
- */
-
-static __inline__ __s32 snto32(__u32 value, unsigned n)
-{
-	switch (n) {
-		case 8:  return ((__s8)value);
-		case 16: return ((__s16)value);
-		case 32: return ((__s32)value);
-	}
-	return value & (1 << (n - 1)) ? value | (-1 << n) : value;
-}
-
-/*
- * Convert a signed 32-bit integer to a signed n-bit integer. 
- */
-
-static __inline__ __u32 s32ton(__s32 value, unsigned n)
-{
-	__s32 a = value >> (n - 1);
-	if (a && a != -1) return value < 0 ? 1 << (n - 1) : (1 << (n - 1)) - 1;
-	return value & ((1 << n) - 1);
-}
-
-/*
- * Extract/implement a data field from/to a report. We use 64-bit unsigned,
- * 32-bit aligned, so that we can possibly have alignment problems on some
- * odd architectures.
- */
-
-static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
-{
-	report += (offset >> 5) << 2; offset &= 31;
-	return (le64_to_cpu(get_unaligned((__u64*)report)) >> offset) & ((1 << n) - 1);
-}
-
-static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
-{
-	report += (offset >> 5) << 2; offset &= 31;
-	*(__u64*)report &= cpu_to_le64(~((((__u64) 1 << n) - 1) << offset));
-	*(__u64*)report |= cpu_to_le64((__u64)value << offset);
-}
-
-static void hid_configure_usage(struct hid_device *device, struct hid_field *field, struct hid_usage *usage)
-{
-	struct input_dev *input = &device->input;
-	int max;
-	unsigned long *bit;
-
-	switch (usage->hid & HID_USAGE_PAGE) {
-
-		case HID_UP_KEYBOARD:
-
-			set_bit(EV_REP, input->evbit);
-			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-
-			if ((usage->hid & HID_USAGE) < 256) {
-				if (!(usage->code = hid_keyboard[usage->hid & HID_USAGE]))
-					return;
-				clear_bit(usage->code, bit);
-			} else
-				usage->code = KEY_UNKNOWN;
-
-			break; 
-
-		case HID_UP_BUTTON:
-
-			usage->code = ((usage->hid - 1) & 0xf) + 0x100;
-			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-			
-			switch (device->application) {
-				case HID_GD_GAMEPAD:  usage->code += 0x10;
-				case HID_GD_JOYSTICK: usage->code += 0x10;
-				case HID_GD_MOUSE:    usage->code += 0x10; break;
-				default:
-					if (field->physical == HID_GD_POINTER)
-						usage->code += 0x10;
-					break;
-			}
-			break;
-
-		case HID_UP_GENDESK:
-
-			if ((usage->hid & 0xf0) == 0x80) {	/* SystemControl */
-				switch (usage->hid & 0xf) {
-					case 0x1: usage->code = KEY_POWER;  break;
-					case 0x2: usage->code = KEY_SLEEP;  break;
-					case 0x3: usage->code = KEY_WAKEUP; break;
-					default: usage->code = KEY_UNKNOWN; break;
-				}
-				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-				break;
-			}
-
-			usage->code = usage->hid & 0xf;
-
-			if (field->report_size == 1) {
-				usage->code = BTN_MISC;
-				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-				break;
-			}
-
-			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
-				break;
-			} 
-
-			usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
-
-			if (usage->hid == HID_GD_HATSWITCH) {
-				usage->code = ABS_HAT0X;
-				usage->hat = 1 + (field->logical_maximum == 4);
-			}
-			break;
-
-		case HID_UP_LED:
-
-			usage->code = (usage->hid - 1) & 0xf;
-			usage->type = EV_LED; bit = input->ledbit; max = LED_MAX; 
-			break;
-
-		case HID_UP_DIGITIZER:
-
-			switch (usage->hid & 0xff) {
-
-				case 0x30: /* TipPressure */
-
-					if (!test_bit(BTN_TOUCH, input->keybit)) {
-						device->quirks |= HID_QUIRK_NOTOUCH;
-						set_bit(EV_KEY, input->evbit);
-						set_bit(BTN_TOUCH, input->keybit);
-					}
-					usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX; 
-					usage->code = ABS_PRESSURE;
-					clear_bit(usage->code, bit);
-					break;
-
-				case 0x32: /* InRange */
-
-					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-					switch (field->physical & 0xff) {	
-						case 0x21: usage->code = BTN_TOOL_MOUSE; break;
-						case 0x22: usage->code = BTN_TOOL_FINGER; break;
-						default: usage->code = BTN_TOOL_PEN; break;
-					}
-					break;
-
-				case 0x3c: /* Invert */
-
-					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-					usage->code = BTN_TOOL_RUBBER;
-					clear_bit(usage->code, bit);
-					break;
-
-				case 0x33: /* Touch */
-				case 0x42: /* TipSwitch */
-				case 0x43: /* TipSwitch2 */
-
-					device->quirks &= ~HID_QUIRK_NOTOUCH;
-					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-					usage->code = BTN_TOUCH;
-					clear_bit(usage->code, bit);
-					break;
-
-				case 0x44: /* BarrelSwitch */
-
-					usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-					usage->code = BTN_STYLUS;
-					clear_bit(usage->code, bit);
-					break;
-
-				default:  goto unknown;
-			}
-			break;
-
-		case HID_UP_CONSUMER:	/* USB HUT v1.1, pages 56-62 */
-			
-			switch (usage->hid & HID_USAGE) {
-				case 0x000: usage->code = 0; break; 
-				case 0x034: usage->code = KEY_SLEEP;		break;
-				case 0x036: usage->code = BTN_MISC;		break;
-				case 0x08a: usage->code = KEY_WWW;		break;
-				case 0x095: usage->code = KEY_HELP;		break;
-
-				case 0x0b4: usage->code = KEY_REWIND;		break;
-				case 0x0b5: usage->code = KEY_NEXTSONG;		break;
-				case 0x0b6: usage->code = KEY_PREVIOUSSONG;	break;
-				case 0x0b7: usage->code = KEY_STOPCD;		break;
-				case 0x0b8: usage->code = KEY_EJECTCD;		break;
-				case 0x0cd: usage->code = KEY_PLAYPAUSE;	break;
-
-				case 0x0e2: usage->code = KEY_MUTE;		break;
-				case 0x0e9: usage->code = KEY_VOLUMEUP;		break;
-				case 0x0ea: usage->code = KEY_VOLUMEDOWN;	break;
-
-				case 0x183: usage->code = KEY_CONFIG;		break;
-				case 0x18a: usage->code = KEY_MAIL;		break;
-				case 0x192: usage->code = KEY_CALC;		break;
-				case 0x194: usage->code = KEY_FILE;		break;
-
-				case 0x21a: usage->code = KEY_UNDO;		break;
-				case 0x21b: usage->code = KEY_COPY;		break;
-				case 0x21c: usage->code = KEY_CUT;		break;
-				case 0x21d: usage->code = KEY_PASTE;		break;
-
-				case 0x221: usage->code = KEY_FIND;		break;
-				case 0x223: usage->code = KEY_HOMEPAGE;		break;
-				case 0x224: usage->code = KEY_BACK;		break;
-				case 0x225: usage->code = KEY_FORWARD;		break;
-				case 0x226: usage->code = KEY_STOP;		break;
-				case 0x227: usage->code = KEY_REFRESH;		break;
-				case 0x22a: usage->code = KEY_BOOKMARKS;	break;
-
-				default:    usage->code = KEY_UNKNOWN;		break;
-
-			}
-		
-			usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-			break;
-
-		default:
-		unknown:
-
-			if (field->report_size == 1) {
-				usage->code = BTN_MISC;
-				usage->type = EV_KEY; bit = input->keybit; max = KEY_MAX;
-				break;
-			}
-
-			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				usage->code = REL_MISC;
-				usage->type = EV_REL; bit = input->relbit; max = REL_MAX;
-				break;
-			}
-
-			usage->code = ABS_MISC;
-			usage->type = EV_ABS; bit = input->absbit; max = ABS_MAX;
-			break;
-	}
-
-	set_bit(usage->type, input->evbit);
-
-	while (usage->code <= max && test_and_set_bit(usage->code, bit)) {
-		usage->code = find_next_zero_bit(bit, max + 1, usage->code);
-	}
-
-	if (usage->code > max) return;
-
-	if (usage->type == EV_ABS) {
-		int a = field->logical_minimum;
-		int b = field->logical_maximum;
-
-		input->absmin[usage->code] = a; 
-		input->absmax[usage->code] = b;
-		input->absfuzz[usage->code] = (b - a) >> 8;
-		input->absflat[usage->code] = (b - a) >> 4;
-	}
-
-	if (usage->hat) {
-		int i;
-		for (i = usage->code; i < usage->code + 2 && i <= max; i++) {
-			input->absmax[i] = 1;
-			input->absmin[i] = -1;
-			input->absfuzz[i] = 0;
-			input->absflat[i] = 0;
-		}
-		set_bit(usage->code + 1, input->absbit);
-	}
-}
-
-static void hid_process_event(struct input_dev *input, int *quirks, struct hid_field *field, struct hid_usage *usage, __s32 value)
-{
-	hid_dump_input(usage, value);
-
-	if (usage->hat) {
-		if (usage->hat == 2) value = value * 2;
-		if (value > 8) value = 8;
-		input_event(input, usage->type, usage->code    , hid_hat_to_axis[value].x);
-		input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[value].y);
-		return;
-	}
-
-	if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */
-		*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
-		return;
-	}
-
-	if (usage->hid == (HID_UP_DIGITIZER | 0x0032)) { /* InRange */
-		if (value) {
-			input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
-			return;
-		}
-		input_event(input, usage->type, usage->code, 0);
-		input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
-		return;
-	}
-
-	if (usage->hid == (HID_UP_DIGITIZER | 0x0030) && (*quirks & HID_QUIRK_NOTOUCH)) { /* Pressure */
-		int a = field->logical_minimum;
-		int b = field->logical_maximum;
-		input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
-	}
-
-	if((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UKNOWN */
-		return;
-
-	input_event(input, usage->type, usage->code, value);
-
-	if ((field->flags & HID_MAIN_ITEM_RELATIVE) && (usage->type == EV_KEY))
-		input_event(input, usage->type, usage->code, 0);
-}
-
-/*
- * Search an array for a value.
- */
-
-static __inline__ int search(__s32 *array, __s32 value, unsigned n)
-{
-	while (n--) if (*array++ == value) return 0;
-	return -1;
-}
-
-/*
- * Analyse a received field, and fetch the data from it. The field
- * content is stored for next report processing (we do differential
- * reporting to the layer).
- */
-
-static void hid_input_field(struct hid_device *dev, struct hid_field *field, __u8 *data)
-{
-	unsigned n;
-	unsigned count = field->report_count;
-	unsigned offset = field->report_offset;
-	unsigned size = field->report_size;
-	__s32 min = field->logical_minimum;
-	__s32 max = field->logical_maximum;
-	__s32 value[count]; /* WARNING: gcc specific */
-   
-	for (n = 0; n < count; n++) {
-			value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) : 
-						    extract(data, offset + n * size, size);
-			/* Handle the ErrorRollOver code (1) by simply ignoring this report */
-			if (!(field->flags & HID_MAIN_ITEM_VARIABLE)
-			    && value[n] >= min && value[n] <= max
-			    && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
-				return;
-	}
-
-	for (n = 0; n < count; n++) {
-
-		if (HID_MAIN_ITEM_VARIABLE & field->flags) {
-
-			if (field->flags & HID_MAIN_ITEM_RELATIVE) {
-				if (!value[n]) continue;
-			} else {
-				if (value[n] == field->value[n]) continue;
-			}
-			hid_process_event(&dev->input, &dev->quirks, field, &field->usage[n], value[n]);
-
-		} else {
-
-			if (field->value[n] >= min && field->value[n] <= max			/* non-NULL value */
-				&& field->usage[field->value[n] - min].hid			/* nonzero usage */
-				&& search(value, field->value[n], count))
-					hid_process_event(&dev->input, &dev->quirks, field,
-						&field->usage[field->value[n] - min], 0);
-
-			if (value[n] >= min && value[n] <= max					/* non-NULL value */
-				&& field->usage[value[n] - min].hid				/* nonzero usage */
-				&& search(field->value, value[n], count))
-					hid_process_event(&dev->input, &dev->quirks,
-						field, &field->usage[value[n] - min], 1);
-		}
-	}
-
-	memcpy(field->value, value, count * sizeof(__s32));
-}
-
-/*
- * Interrupt input handler - analyse a received report.
- */
-
-static void hid_irq(struct urb *urb)
-{
-	struct hid_device *device = urb->context;
-	struct hid_report_enum *report_enum = device->report_enum + HID_INPUT_REPORT;
-	struct hid_report *report;
-	__u8 *data = urb->transfer_buffer;
-	int len = urb->actual_length;
-	int n;
-
-	if (urb->status) {
-		dbg("nonzero status in irq %d", urb->status);
-		return;
-	}
-
-	if (!len) {
-		dbg("empty report");
-		return;
-	}
-
-#ifdef DEBUG_DATA
-	printk(KERN_DEBUG __FILE__ ": report (size %u) (%snumbered) = ", len, report_enum->numbered ? "" : "un");
-	for (n = 0; n < len; n++)
-		printk(" %02x", data[n]);
-	printk("\n");
-#endif
-
-	n = 0;				/* Normally report number is 0 */
-
-	if (report_enum->numbered) {	/* Device uses numbered reports, data[0] is report number */
-		n = *data++;
-		len--;
-	} 
-
-	if (!(report = report_enum->report_id_hash[n])) {
-		dbg("undefined report_id %d received", n);
-#ifdef DEBUG
-			printk(KERN_DEBUG __FILE__ ": report (size %u) = ", len);
-			for (n = 0; n < len; n++)
-				printk(" %02x", data[n]);
-			printk("\n");
-#endif
-	
-		return;
-	}
-
-	if (len < ((report->size - 1) >> 3) + 1) {
-		dbg("report %d is too short, (%d < %d)", report->id, len, ((report->size - 1) >> 3) + 1);
-		return;
-	}
-
-	for (n = 0; n < report->maxfield; n++)
-		hid_input_field(device, report->field[n], data);
-
-	return;
-}
-
-/*
- * hid_read_report() s intended to read the hid devices values even
- * before the input device is registered, so that the userland interface
- * modules start with real values. This is especially important for joydev.c
- * automagic calibration. Doesn't work yet, though. Don't know why, the control
- * request just times out on most devices I have and returns nonsense on others.
- */
-
-static void hid_read_report(struct hid_device *hid, struct hid_report *report)
-{
-#if 0
-	int rlen = ((report->size - 1) >> 3) + 1;
-	char rdata[rlen];
-	struct urb urb;
-	int read, j;
-
-	memset(&urb, 0, sizeof(struct urb));
-	memset(rdata, 0, rlen);
-
-	urb.transfer_buffer = rdata;
-	urb.actual_length = rlen;
-	urb.context = hid;
-
-	dbg("getting report type %d id %d len %d", report->type + 1, report->id, rlen);
-
-	if ((read = usb_get_report(hid->dev, hid->ifnum, report->type + 1, report->id, rdata, rlen)) != rlen) {
-		dbg("reading report failed rlen %d read %d", rlen, read);
-#ifdef DEBUG
-		printk(KERN_DEBUG __FILE__ ": report = ");
-		for (j = 0; j < rlen; j++) printk(" %02x", rdata[j]);
-		printk("\n");
-#endif
-		return;
-	}
-
-	hid_irq(&urb);
-#endif
-}
-
-/*
- * Output the field into the report.
- */
-
-static void hid_output_field(struct hid_field *field, __u8 *data)
-{
-	unsigned count = field->report_count;
-	unsigned offset = field->report_offset;
-	unsigned size = field->report_size;
-	unsigned n;
-   
-	for (n = 0; n < count; n++) {
-		if (field->logical_minimum < 0)	/* signed values */
-			implement(data, offset + n * size, size, s32ton(field->value[n], size));
-		 else				/* unsigned values */
-			implement(data, offset + n * size, size, field->value[n]);
-       	}
-}
-
-/*
- * Create a report.
- */
-
-void hid_output_report(struct hid_report *report, __u8 *data)
-{
-	unsigned n;
-	for (n = 0; n < report->maxfield; n++)
-		hid_output_field(report->field[n], data);
-};
-
-/*
- * Set a field value. The report this field belongs to has to be
- * created and transfered to the device, to set this value in the
- * device.
- */
-
-int hid_set_field(struct hid_field *field, unsigned offset, __s32 value)
-{
-	unsigned size = field->report_size;
-
-	hid_dump_input(field->usage + offset, value);
-	
-	if (offset >= field->report_count) {
-		dbg("offset exceeds report_count");
-		return -1;
-	}
-	if (field->logical_minimum < 0) {
-		if (value != snto32(s32ton(value, size), size)) {
-			dbg("value %d is out of range", value);
-			return -1;
-		}
-	}
-	if (   (value > field->logical_maximum)
-	    || (value < field->logical_minimum)) {
-		dbg("value %d is invalid", value);
-		return -1;
-	}
-	field->value[offset] = value;
-	return 0;
-}
-
-static int hid_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field)
-{
-	struct hid_report_enum *report_enum = hid->report_enum + HID_OUTPUT_REPORT;
-	struct list_head *list = report_enum->report_list.next;
-	int i, j;
-
-	while (list != &report_enum->report_list) {
-		struct hid_report *report = (struct hid_report *) list;
-		list = list->next;
-		for (i = 0; i < report->maxfield; i++) {
-			*field = report->field[i];
-			for (j = 0; j < (*field)->maxusage; j++)
-				if ((*field)->usage[j].type == type && (*field)->usage[j].code == code)
-					return j;
-		}
-	}
-	return -1;
-}
-
-static int hid_submit_out(struct hid_device *hid)
-{
-	hid->urbout.transfer_buffer_length = le16_to_cpup(&hid->out[hid->outtail].dr.length);
-	hid->urbout.transfer_buffer = hid->out[hid->outtail].buffer;
-	hid->urbout.setup_packet = (void *) &(hid->out[hid->outtail].dr);
-	hid->urbout.dev = hid->dev;
-
-	if (usb_submit_urb(&hid->urbout)) {
-		err("usb_submit_urb(out) failed");
-		return -1;
-	}
-
-	return 0;
-}
-
-static void hid_ctrl(struct urb *urb)
-{
-	struct hid_device *hid = urb->context;
-
-        if (urb->status)
-		warn("ctrl urb status %d received", urb->status);
-	
-	hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
-
-	if (hid->outhead != hid->outtail)
-		hid_submit_out(hid);
-}       
-
-static int hid_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
-	struct hid_device *hid = dev->private;
-	struct hid_field *field = NULL;
-	int offset;
-
-	if ((offset = hid_find_field(hid, type, code, &field)) == -1) {
-		warn("event field not found");
-		return -1;
-	}
-
-	hid_set_field(field, offset, value);
-	hid_output_report(field->report, hid->out[hid->outhead].buffer);
-
-	hid->out[hid->outhead].dr.value = cpu_to_le16(0x200 | field->report->id);
-	hid->out[hid->outhead].dr.length = cpu_to_le16((field->report->size + 7) >> 3);
-
-	hid->outhead = (hid->outhead + 1) & (HID_CONTROL_FIFO_SIZE - 1);
-
-	if (hid->outhead == hid->outtail)
-		hid->outtail = (hid->outtail + 1) & (HID_CONTROL_FIFO_SIZE - 1);
-
-	if (hid->urbout.status != -EINPROGRESS)
-		hid_submit_out(hid);
-
-	return 0;
-}
-
-static int hid_open(struct input_dev *dev)
-{
-	struct hid_device *hid = dev->private;
-
-	if (hid->open++)
-		return 0;
-
-	hid->urb.dev = hid->dev;
-
-	if (usb_submit_urb(&hid->urb))
-		return -EIO;
-
-	return 0;
-}
-
-static void hid_close(struct input_dev *dev)
-{
-	struct hid_device *hid = dev->private;
-
-	if (!--hid->open)
-		usb_unlink_urb(&hid->urb);
-}
-
-/*
- * Configure the input layer interface
- * Read all reports and initalize the absoulte field values.
- */
-
-static void hid_init_input(struct hid_device *hid)
-{
-	struct hid_report_enum *report_enum;
-	struct list_head *list;
-	int i, j, k;
-
-	hid->input.private = hid;
-	hid->input.event = hid_event;
-	hid->input.open = hid_open;
-	hid->input.close = hid_close;
-
-	for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
-
-		report_enum = hid->report_enum + k;
-		list = report_enum->report_list.next;
-
-		while (list != &report_enum->report_list) {
-
-			struct hid_report *report = (struct hid_report *) list;
-
-			list = list->next;
-
-			for (i = 0; i < report->maxfield; i++)
-				for (j = 0; j < report->field[i]->maxusage; j++)
-					hid_configure_usage(hid, report->field[i], report->field[i]->usage + j);
-
-			if (k == HID_INPUT_REPORT)  {
-				usb_set_idle(hid->dev, hid->ifnum, 0, report->id);
-				hid_read_report(hid, report);
-			}
-		}
-	}
-}
-
-#define USB_VENDOR_ID_WACOM		0x056a
-#define USB_DEVICE_ID_WACOM_GRAPHIRE	0x0010
-#define USB_DEVICE_ID_WACOM_INTUOS	0x0020
-
-struct hid_blacklist {
-	__u16 idVendor;
-	__u16 idProduct;
-} hid_blacklist[] = {
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE },
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS },
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 1},
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 2},
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 3},
-	{ USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS + 4},
-	{ 0, 0 }
-};
-
-static struct hid_device *usb_hid_configure(struct usb_device *dev, int ifnum, char *name)
-{
-	struct usb_interface_descriptor *interface = dev->actconfig->interface[ifnum].altsetting + 0;
-	struct hid_descriptor *hdesc;
-	struct hid_device *hid;
-	unsigned rsize = 0;
-	int n;
-
-	for (n = 0; hid_blacklist[n].idVendor; n++)
-		if ((hid_blacklist[n].idVendor == dev->descriptor.idVendor) &&
-			(hid_blacklist[n].idProduct == dev->descriptor.idProduct)) return NULL;
-
-	if (usb_get_extra_descriptor(interface, USB_DT_HID, &hdesc)
-		&& usb_get_extra_descriptor(&interface->endpoint[0], USB_DT_HID, &hdesc)) {
-			dbg("class descriptor not present\n");
-			return NULL;
-	}
-
-	for (n = 0; n < hdesc->bNumDescriptors; n++)
-		if (hdesc->desc[n].bDescriptorType == USB_DT_REPORT)
-			rsize = le16_to_cpu(hdesc->desc[n].wDescriptorLength);
-
-	if (!rsize || rsize > HID_MAX_DESCRIPTOR_SIZE) {
-		dbg("weird size of report descriptor (%u)", rsize);
-		return NULL;
-	}
-
-	{
-		__u8 rdesc[rsize];
-
-		if ((n = usb_get_class_descriptor(dev, interface->bInterfaceNumber, USB_DT_REPORT, 0, rdesc, rsize)) < 0) {
-			dbg("reading report descriptor failed");
-			return NULL;
-		}
-
-#ifdef DEBUG_DATA
-		printk(KERN_DEBUG __FILE__ ": report (size %u, read %d) = ", rsize, n);
-		for (n = 0; n < rsize; n++)
-			printk(" %02x", (unsigned) rdesc[n]);
-		printk("\n");
-#endif
-
-		if (!(hid = hid_parse_report(rdesc, rsize))) {
-			dbg("parsing report descriptor failed");
-			return NULL;
-		}
-	}
-
-	for (n = 0; n < interface->bNumEndpoints; n++) {
-
-		struct usb_endpoint_descriptor *endpoint = &interface->endpoint[n];
-		int pipe, maxp;
-
-		if ((endpoint->bmAttributes & 3) != 3)		/* Not an interrupt endpoint */
-			continue;
-
-		if (!(endpoint->bEndpointAddress & 0x80)) 	/* Not an input endpoint */
-			continue;
-
-		pipe = usb_rcvintpipe(dev, endpoint->bEndpointAddress);
-		maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
-		FILL_INT_URB(&hid->urb, dev, pipe, hid->buffer, maxp > 32 ? 32 : maxp, hid_irq, hid, endpoint->bInterval);
-	
-		break;
-	}
-
-	if (n == interface->bNumEndpoints) {
-		dbg("couldn't find an input interrupt endpoint");
-		hid_free_device(hid);
-		return NULL;
-	}
-
-	hid->version = hdesc->bcdHID;
-	hid->country = hdesc->bCountryCode;
-	hid->dev = dev;
-	hid->ifnum = interface->bInterfaceNumber;
-
-	for (n = 0; n < HID_CONTROL_FIFO_SIZE; n++) {
-		hid->out[n].dr.requesttype = USB_TYPE_CLASS | USB_RECIP_INTERFACE;
-		hid->out[n].dr.request = USB_REQ_SET_REPORT;
-		hid->out[n].dr.index = cpu_to_le16(hid->ifnum);
-	}
-
-	hid->input.name = hid->name;
-	hid->input.idbus = BUS_USB;
-	hid->input.idvendor = dev->descriptor.idVendor;
-	hid->input.idproduct = dev->descriptor.idProduct;
-	hid->input.idversion = dev->descriptor.bcdDevice;
-
-	if (strlen(name)) 
-		strcpy(hid->name, name);
-	else
-		sprintf(hid->name, "USB HID %s %04x:%04x",
-			((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ?
-			hid_types[hid->application & 0xffff] : "Device",
-			hid->input.idvendor, hid->input.idproduct);
-
-	FILL_CONTROL_URB(&hid->urbout, dev, usb_sndctrlpipe(dev, 0),
-		(void*) &hid->out[0].dr, hid->out[0].buffer, 1, hid_ctrl, hid);
-
-	if (interface->bInterfaceSubClass == 1)
-        	usb_set_protocol(dev, hid->ifnum, 1);
-
-	return hid;
-}
-
-static void* hid_probe(struct usb_device *dev, unsigned int ifnum,
-		       const struct usb_device_id *id)
-{
-	struct hid_device *hid;
-	char name[128];
-	char *buf;
-
-	dbg("HID probe called for ifnum %d", ifnum);
-
-	name[0] = 0;
-
-	if (!(buf = kmalloc(63, GFP_KERNEL)))
-		return NULL;
-
-	if (dev->descriptor.iManufacturer &&
-		usb_string(dev, dev->descriptor.iManufacturer, buf, 63) > 0)
-			strcat(name, buf);
-	if (dev->descriptor.iProduct &&
-		usb_string(dev, dev->descriptor.iProduct, buf, 63) > 0)
-			sprintf(name, "%s %s", name, buf);
-
-	kfree(buf);
-
-	if (!(hid = usb_hid_configure(dev, ifnum, name)))
-		return NULL;
-
-	hid_dump_device(hid);
-
-	hid_init_input(hid);
-	input_register_device(&hid->input);
-
-	printk(KERN_INFO "input%d: USB HID v%x.%02x %s",
-		hid->input.number,
-		hid->version >> 8, hid->version & 0xff,
-		((hid->application >= 0x00010000) && (hid->application <= 0x00010008)) ?
-		hid_types[hid->application & 0xffff] : "Device");
-
-	if (strlen(name))
-		printk(" [%s]", name);
-	else
-		printk(" [%04x:%04x]", hid->input.idvendor, hid->input.idproduct);
-	
-	printk(" on usb%d:%d.%d\n", dev->bus->busnum, dev->devnum, ifnum);
-
-	return hid;
-}
-
-static void hid_disconnect(struct usb_device *dev, void *ptr)
-{
-	struct hid_device *hid = ptr;
-
-	dbg("cleanup called");
-	usb_unlink_urb(&hid->urb);
-	input_unregister_device(&hid->input);
-	hid_free_device(hid);
-}
-
-static struct usb_device_id hid_usb_ids [] = {
-    { match_flags: USB_DEVICE_ID_MATCH_INT_CLASS,
-      bInterfaceClass: USB_INTERFACE_CLASS_HID},
-    { }						/* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, hid_usb_ids);
-
-static struct usb_driver hid_driver = {
-	name:		"hid",
-	probe:		hid_probe,
-	disconnect:	hid_disconnect,
-	id_table:	hid_usb_ids,
-};
-
-static int __init hid_init(void)
-{
-	usb_register(&hid_driver);
-	info(DRIVER_VERSION ":" DRIVER_DESC);
-	return 0;
-}
-
-static void __exit hid_exit(void)
-{
-	usb_deregister(&hid_driver);
-}
-
-module_init(hid_init);
-module_exit(hid_exit);
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-
diff -urN linux-2.4.10-pre8/drivers/usb/hid.h linux/drivers/usb/hid.h
--- linux-2.4.10-pre8/drivers/usb/hid.h	Wed Apr 18 11:49:12 2001
+++ linux/drivers/usb/hid.h	Mon Dec  3 23:09:49 2001
@@ -2,10 +2,10 @@
 #define __HID_H
 
 /*
- * $Id: hid.h,v 1.7 2000/05/31 22:57:48 vojtech Exp $
+ * $Id: hid.h,v 1.10 2001/05/10 15:56:07 vojtech Exp $
  *
  *  Copyright (c) 1999 Andreas Gal
- *  Copyright (c) 2000 Vojtech Pavlik
+ *  Copyright (c) 2000-2001 Vojtech Pavlik
  *
  *  Sponsored by SuSE
  */
@@ -210,6 +210,7 @@
 
 #define HID_MAX_DESCRIPTOR_SIZE		4096
 #define HID_MAX_USAGES			1024
+#define HID_MAX_APPLICATIONS		16
 
 struct hid_local {
 	unsigned usage[HID_MAX_USAGES]; /* usage array */
@@ -239,6 +240,7 @@
 struct hid_field {
 	unsigned  physical;		/* physical usage for this field */
 	unsigned  logical;		/* logical usage for this field */
+	unsigned  application;		/* application usage for this field */
 	struct hid_usage *usage;	/* usage table for this function */
 	unsigned  maxusage;		/* maximum usage index */
 	unsigned  flags;		/* main-item flags (i.e. volatile,array,constant) */
@@ -265,6 +267,8 @@
 	struct hid_field *field[HID_MAX_FIELDS];	/* fields of the report */
 	unsigned maxfield;				/* maximum valid field index */
 	unsigned size;					/* size of the report (bits) */
+	unsigned idx;					/* where we're in data */
+	unsigned char *data;				/* data for multi-packet reports */
 	struct hid_device *device;			/* associated device */
 };
 
@@ -284,10 +288,14 @@
 	char buffer[HID_BUFFER_SIZE];
 };
 
+#define HID_CLAIMED_INPUT	1
+#define HID_CLAIMED_HIDDEV	2
+
 struct hid_device {							/* device report descriptor */
 	 __u8 *rdesc;
 	unsigned rsize;
-	unsigned application;						/* HID application, i.e. Digitizer */
+	unsigned application[HID_MAX_APPLICATIONS];			/* List of HID applications */
+	unsigned maxapplication;					/* Number of applications */
 	unsigned version;						/* HID version */
 	unsigned country;						/* HID country */
 	struct hid_report_enum report_enum[HID_REPORT_TYPES];
@@ -302,9 +310,14 @@
 	struct hid_control_fifo out[HID_CONTROL_FIFO_SIZE];		/* Transmit buffer */
 	unsigned char outhead, outtail;					/* Tx buffer head & tail */
 
-	struct input_dev input;						/* input device structure */
-	int open;							/* is the device open by input? */
-	int quirks;							/* Various nasty tricks the device can pull on us */
+	unsigned claimed;						/* Claimed by hidinput, hiddev? */	
+	unsigned quirks;						/* Various quirks the device can pull on us */
+
+	struct input_dev input;						/* The input structure */
+	void *hiddev;							/* The hiddev structure */
+	int minor;							/* Hiddev minor number */
+
+	int open;							/* is the device open by anyone? */
 	char name[128];							/* Device name */
 };
 
@@ -336,6 +349,25 @@
 	struct hid_class_descriptor desc[1];
 } __attribute__ ((packed));
 
+void hidinput_hid_event(struct hid_device *, struct hid_field *, struct hid_usage *, __s32);
+int hidinput_connect(struct hid_device *);
+void hidinput_disconnect(struct hid_device *);
+
+#ifdef DEBUG
+#include "hid-debug.h"
+#else
+#define hid_dump_input(a,b)	do { } while (0)
+#define hid_dump_device(c)	do { } while (0)
+#endif
 
 #endif
 
+#define IS_INPUT_APPLICATION(a) ((a >= 0x00010000) && (a <= 0x00010008))
+
+int hid_open(struct hid_device *);
+void hid_close(struct hid_device *);
+int hid_find_field(struct hid_device *, unsigned int, unsigned int, struct hid_field **);
+int hid_set_field(struct hid_field *, unsigned, __s32);
+void hid_write_report(struct hid_device *, struct hid_report *);
+void hid_read_report(struct hid_device *, struct hid_report *);
+void hid_init_reports(struct hid_device *hid);
diff -urN linux-2.4.10-pre8/drivers/usb/hiddev.c linux/drivers/usb/hiddev.c
--- linux-2.4.10-pre8/drivers/usb/hiddev.c	Wed Dec 31 16:00:00 1969
+++ linux/drivers/usb/hiddev.c	Mon Dec  3 23:09:49 2001
@@ -0,0 +1,677 @@
+/*
+ *  Copyright (c) 2001 Paul Stewart
+ *  Copyright (c) 2001 Vojtech Pavlik
+ *
+ *  HID char devices, giving access to raw HID device events.
+ *
+ */
+
+/*
+ * 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 Paul Stewart <stewart@wetlogic.net>
+ */
+
+#define HIDDEV_MINOR_BASE	96
+#define HIDDEV_MINORS		16
+#define HIDDEV_BUFFER_SIZE	64
+
+#include <linux/poll.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/smp_lock.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+#include "hid.h"
+#include <linux/hiddev.h>
+
+struct hiddev {
+	int exist;
+	int open;
+	int minor;
+	wait_queue_head_t wait;
+	devfs_handle_t devfs;
+	struct hid_device *hid;
+	struct hiddev_list *list;
+};
+
+struct hiddev_list {
+	struct hiddev_event buffer[HIDDEV_BUFFER_SIZE];
+	int head;
+	int tail;
+	struct fasync_struct *fasync;
+	struct hiddev *hiddev;
+	struct hiddev_list *next;
+};
+
+static struct hiddev *hiddev_table[HIDDEV_MINORS];
+static devfs_handle_t hiddev_devfs_handle;
+
+/*
+ * Find a report, given the report's type and ID.  The ID can be specified
+ * indirectly by REPORT_ID_FIRST (which returns the first report of the given
+ * type) or by (REPORT_ID_NEXT | old_id), which returns the next report of the
+ * given type which follows old_id.
+ */
+static struct hid_report *
+hiddev_lookup_report(struct hid_device *hid, struct hiddev_report_info *rinfo)
+{
+	struct hid_report_enum *report_enum;
+	struct list_head *list;
+
+	if (rinfo->report_type < HID_REPORT_TYPE_MIN ||
+	    rinfo->report_type > HID_REPORT_TYPE_MAX) return NULL;
+
+	report_enum = hid->report_enum +
+		(rinfo->report_type - HID_REPORT_TYPE_MIN);
+	if ((rinfo->report_id & ~HID_REPORT_ID_MASK) != 0) {
+		switch (rinfo->report_id & ~HID_REPORT_ID_MASK) {
+		case HID_REPORT_ID_FIRST:
+			list = report_enum->report_list.next;
+			if (list == &report_enum->report_list) return NULL;
+			rinfo->report_id = ((struct hid_report *) list)->id;
+			break;
+
+		case HID_REPORT_ID_NEXT:
+			list = (struct list_head *)
+				report_enum->report_id_hash[rinfo->report_id &
+							   HID_REPORT_ID_MASK];
+			if (list == NULL) return NULL;
+			list = list->next;
+			if (list == &report_enum->report_list) return NULL;
+			rinfo->report_id = ((struct hid_report *) list)->id;
+			break;
+
+		default:
+			return NULL;
+		}
+	}
+
+	return report_enum->report_id_hash[rinfo->report_id];
+}
+
+/*
+ * Perform an exhaustive search of the report table for a usage, given its
+ * type and usage id.
+ */
+static struct hid_field *
+hiddev_lookup_usage(struct hid_device *hid, struct hiddev_usage_ref *uref)
+{
+	int i, j;
+	struct hid_report *report;
+	struct hid_report_enum *report_enum;
+	struct list_head *list;
+	struct hid_field *field;
+
+	if (uref->report_type < HID_REPORT_TYPE_MIN ||
+	    uref->report_type > HID_REPORT_TYPE_MAX) return NULL;
+
+	report_enum = hid->report_enum +
+		(uref->report_type - HID_REPORT_TYPE_MIN);
+	list = report_enum->report_list.next;
+	while (list != &report_enum->report_list) {
+		report = (struct hid_report *) list;
+		for (i = 0; i < report->maxfield; i++) {
+			field = report->field[i];
+			for (j = 0; j < field->maxusage; j++) {
+				if (field->usage[j].hid == uref->usage_code) {
+					uref->report_id = report->id;
+					uref->field_index = i;
+					uref->usage_index = j;
+					return field;
+				}
+			}
+		}
+		list = list->next;
+	}
+
+	return NULL;
+}
+
+/*
+ * This is where hid.c calls into hiddev to pass an event that occurred over
+ * the interrupt pipe
+ */
+void hiddev_hid_event(struct hid_device *hid, unsigned int usage, int value)
+{
+	struct hiddev *hiddev = hid->hiddev;
+	struct hiddev_list *list = hiddev->list;
+
+	while (list) {
+		list->buffer[list->head].hid = usage;
+		list->buffer[list->head].value = value;
+		list->head = (list->head + 1) & (HIDDEV_BUFFER_SIZE - 1);
+
+		kill_fasync(&list->fasync, SIGIO, POLL_IN);
+
+		list = list->next;
+	}
+
+	wake_up_interruptible(&hiddev->wait);
+}
+
+/*
+ * fasync file op
+ */
+static int hiddev_fasync(int fd, struct file *file, int on)
+{
+	int retval;
+	struct hiddev_list *list = file->private_data;
+	retval = fasync_helper(fd, file, on, &list->fasync);
+	return retval < 0 ? retval : 0;
+}
+
+/*
+ * De-allocate a hiddev structure
+ */
+static void hiddev_cleanup(struct hiddev *hiddev)
+{
+	devfs_unregister(hiddev->devfs);
+	hiddev_table[hiddev->minor] = NULL;
+	kfree(hiddev);
+}
+
+/*
+ * release file op
+ */
+static int hiddev_release(struct inode * inode, struct file * file)
+{
+	struct hiddev_list *list = file->private_data;
+	struct hiddev_list **listptr;
+
+	lock_kernel();
+	listptr = &list->hiddev->list;
+	hiddev_fasync(-1, file, 0);
+
+	while (*listptr && (*listptr != list))
+		listptr = &((*listptr)->next);
+	*listptr = (*listptr)->next;
+
+	if (!--list->hiddev->open) {
+		if (list->hiddev->exist) 
+			hid_close(list->hiddev->hid);
+		else
+			hiddev_cleanup(list->hiddev);
+	}
+
+	kfree(list);
+	unlock_kernel();
+
+	return 0;
+}
+
+/*
+ * open file op
+ */
+static int hiddev_open(struct inode * inode, struct file * file) {
+	struct hiddev_list *list;
+
+	int i = MINOR(inode->i_rdev) - HIDDEV_MINOR_BASE;
+
+	if (i >= HIDDEV_MINORS || !hiddev_table[i])
+		return -ENODEV;
+
+	if (!(list = kmalloc(sizeof(struct hiddev_list), GFP_KERNEL)))
+		return -ENOMEM;
+	memset(list, 0, sizeof(struct hiddev_list));
+
+	list->hiddev = hiddev_table[i];
+	list->next = hiddev_table[i]->list;
+	hiddev_table[i]->list = list;
+
+	file->private_data = list;
+
+	if (!list->hiddev->open++)
+		if (list->hiddev->exist)
+			hid_open(hiddev_table[i]->hid);
+
+	return 0;
+}
+
+/*
+ * "write" file op
+ */
+static ssize_t hiddev_write(struct file * file, const char * buffer,
+			    size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+/*
+ * "read" file op
+ */
+static ssize_t hiddev_read(struct file * file, char * buffer, size_t count,
+			   loff_t *ppos)
+{
+	DECLARE_WAITQUEUE(wait, current);
+	struct hiddev_list *list = file->private_data;
+	int retval = 0;
+
+	if (list->head == list->tail) {
+
+		add_wait_queue(&list->hiddev->wait, &wait);
+		current->state = TASK_INTERRUPTIBLE;
+
+		while (list->head == list->tail) {
+
+			if (file->f_flags & O_NONBLOCK) {
+				retval = -EAGAIN;
+				break;
+			}
+			if (signal_pending(current)) {
+				retval = -ERESTARTSYS;
+				break;
+			}
+			if (!list->hiddev->exist) {
+				retval = -EIO;
+				break;
+			}
+
+			schedule();
+		}
+
+		current->state = TASK_RUNNING;
+		remove_wait_queue(&list->hiddev->wait, &wait);
+	}
+
+	if (retval)
+		return retval;
+
+	while (list->head != list->tail && retval + sizeof(struct hiddev_event) <= count) {
+		if (copy_to_user(buffer + retval, list->buffer + list->tail,
+				 sizeof(struct hiddev_event))) return -EFAULT;
+		list->tail = (list->tail + 1) & (HIDDEV_BUFFER_SIZE - 1);
+		retval += sizeof(struct hiddev_event);
+	}
+
+	return retval;
+}
+
+/*
+ * "poll" file op
+ * No kernel lock - fine
+ */
+static unsigned int hiddev_poll(struct file *file, poll_table *wait)
+{
+	struct hiddev_list *list = file->private_data;
+	poll_wait(file, &list->hiddev->wait, wait);
+	if (list->head != list->tail)
+		return POLLIN | POLLRDNORM;
+	if (!list->hiddev->exist)
+		return POLLERR | POLLHUP;
+	return 0;
+}
+
+#define GET_TIMEOUT 3
+#define SET_TIMEOUT 3
+
+/*
+ * "ioctl" file op
+ */
+static int hiddev_ioctl(struct inode *inode, struct file *file,
+			unsigned int cmd, unsigned long arg)
+{
+	struct hiddev_list *list = file->private_data;
+	struct hiddev *hiddev = list->hiddev;
+	struct hid_device *hid = hiddev->hid;
+	struct usb_device *dev = hid->dev;
+	struct hiddev_report_info rinfo;
+	struct hiddev_usage_ref uref;
+	struct hid_report *report;
+	struct hid_field *field;
+
+	if (!hiddev->exist) return -EIO;
+
+	switch (cmd) {
+
+	case HIDIOCGVERSION:
+		return put_user(HID_VERSION, (int *) arg);
+
+	case HIDIOCAPPLICATION:
+		if (arg < 0 || arg >= hid->maxapplication)
+			return -EINVAL;
+		return hid->application[arg];
+
+	case HIDIOCGDEVINFO:
+	{
+		struct hiddev_devinfo dinfo;
+		dinfo.bustype = BUS_USB;
+		dinfo.busnum = dev->bus->busnum;
+		dinfo.devnum = dev->devnum;
+		dinfo.ifnum = hid->ifnum;
+		dinfo.vendor = dev->descriptor.idVendor;
+		dinfo.product = dev->descriptor.idProduct;
+		dinfo.version = dev->descriptor.bcdDevice;
+		dinfo.num_applications = hid->maxapplication;
+		return copy_to_user((void *) arg, &dinfo, sizeof(dinfo));
+	}
+
+	case HIDIOCGSTRING:
+		{
+			int idx, len;
+			char *buf;
+
+			if (get_user(idx, (int *) arg))
+				return -EFAULT;
+
+			if ((buf = kmalloc(HID_STRING_SIZE, GFP_KERNEL)) == NULL)
+				return -ENOMEM;
+
+			if ((len = usb_string(dev, idx, buf, HID_STRING_SIZE-1)) < 0) {
+				kfree(buf);
+				return -EINVAL;
+			}
+
+			if (copy_to_user((void *) (arg+sizeof(int)), buf, len+1)) {
+				kfree(buf);
+				return -EFAULT;
+			}
+
+			kfree(buf);
+
+			return len;
+		}
+
+	case HIDIOCINITREPORT:
+
+		hid_init_reports(hid);
+
+		return 0;
+
+	case HIDIOCGREPORT:
+		if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo)))
+			return -EFAULT;
+
+		if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
+			return -EINVAL;
+
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		hid_read_report(hid, report);
+
+		return 0;
+
+	case HIDIOCSREPORT:
+		if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo)))
+			return -EFAULT;
+
+		if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
+			return -EINVAL;
+
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		hid_write_report(hid, report);
+
+		return 0;
+
+	case HIDIOCGREPORTINFO:
+		if (copy_from_user(&rinfo, (void *) arg, sizeof(rinfo)))
+			return -EFAULT;
+
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		rinfo.num_fields = report->maxfield;
+
+		return copy_to_user((void *) arg, &rinfo, sizeof(rinfo));
+
+	case HIDIOCGFIELDINFO:
+	{
+		struct hiddev_field_info finfo;
+		if (copy_from_user(&finfo, (void *) arg, sizeof(finfo)))
+			return -EFAULT;
+		rinfo.report_type = finfo.report_type;
+		rinfo.report_id = finfo.report_id;
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		if (finfo.field_index >= report->maxfield)
+			return -EINVAL;
+
+		field = report->field[finfo.field_index];
+		memset(&finfo, 0, sizeof(finfo));
+		finfo.report_type = rinfo.report_type;
+		finfo.report_id = rinfo.report_id;
+		finfo.field_index = field->report_count - 1;
+		finfo.maxusage = field->maxusage;
+		finfo.flags = field->flags;
+		finfo.physical = field->physical;
+		finfo.logical = field->logical;
+		finfo.application = field->application;
+		finfo.logical_minimum = field->logical_minimum;
+		finfo.logical_maximum = field->logical_maximum;
+		finfo.physical_minimum = field->physical_minimum;
+		finfo.physical_maximum = field->physical_maximum;
+		finfo.unit_exponent = field->unit_exponent;
+		finfo.unit = field->unit;
+
+		return copy_to_user((void *) arg, &finfo, sizeof(finfo));
+	}
+
+	case HIDIOCGUCODE:
+		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
+			return -EFAULT;
+
+		rinfo.report_type = uref.report_type;
+		rinfo.report_id = uref.report_id;
+		if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+			return -EINVAL;
+
+		if (uref.field_index >= report->maxfield)
+			return -EINVAL;
+
+		field = report->field[uref.field_index];
+		if (uref.usage_index >= field->maxusage)
+			return -EINVAL;
+
+		uref.usage_code = field->usage[uref.usage_index].hid;
+
+		return copy_to_user((void *) arg, &uref, sizeof(uref));
+
+	case HIDIOCGUSAGE:
+		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
+			return -EFAULT;
+
+		if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
+			field = hiddev_lookup_usage(hid, &uref);
+			if (field == NULL)
+				return -EINVAL;
+		} else {
+			rinfo.report_type = uref.report_type;
+			rinfo.report_id = uref.report_id;
+			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+				return -EINVAL;
+
+			if (uref.field_index >= report->maxfield)
+				return -EINVAL;
+
+			field = report->field[uref.field_index];
+			if (uref.usage_index >= field->maxusage)
+				return -EINVAL;
+		}
+
+		uref.value = field->value[uref.usage_index];
+
+		return copy_to_user((void *) arg, &uref, sizeof(uref));
+
+	case HIDIOCSUSAGE:
+		if (copy_from_user(&uref, (void *) arg, sizeof(uref)))
+			return -EFAULT;
+
+		if (uref.report_type == HID_REPORT_TYPE_INPUT)
+			return -EINVAL;
+
+		if (uref.report_id == HID_REPORT_ID_UNKNOWN) {
+			field = hiddev_lookup_usage(hid, &uref);
+			if (field == NULL)
+				return -EINVAL;
+		} else {
+			rinfo.report_type = uref.report_type;
+			rinfo.report_id = uref.report_id;
+			if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
+				return -EINVAL;
+
+			if (uref.field_index >= report->maxfield)
+				return -EINVAL;
+
+			field = report->field[uref.field_index];
+			if (uref.usage_index >= field->maxusage)
+				return -EINVAL;
+		}
+
+		field->value[uref.usage_index] = uref.value;
+
+		return 0;
+
+	default:
+
+		if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
+			return -EINVAL;
+
+		if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
+			int len;
+			if (!hid->name) return 0;
+			len = strlen(hid->name) + 1;
+			if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
+			return copy_to_user((char *) arg, hid->name, len) ?
+				-EFAULT : len;
+		}
+	}
+	return -EINVAL;
+}
+
+static struct file_operations hiddev_fops = {
+	owner:		THIS_MODULE,
+	read:		hiddev_read,
+	write:		hiddev_write,
+	poll:		hiddev_poll,
+	open:		hiddev_open,
+	release:	hiddev_release,
+	ioctl:		hiddev_ioctl,
+	fasync:		hiddev_fasync,
+};
+
+/*
+ * This is where hid.c calls us to connect a hid device to the hiddev driver
+ */
+int hiddev_connect(struct hid_device *hid)
+{
+	struct hiddev *hiddev;
+	int minor, i;
+	char devfs_name[16];
+
+	for (i = 0; i < hid->maxapplication; i++)
+		if (!IS_INPUT_APPLICATION(hid->application[i]))
+			break;
+
+	if (i == hid->maxapplication)
+		return -1;
+
+	for (minor = 0; minor < HIDDEV_MINORS && hiddev_table[minor]; minor++);
+	if (minor == HIDDEV_MINORS) {
+		printk(KERN_ERR "hiddev: no more free hiddev devices\n");
+		return -1;
+	}
+
+	if (!(hiddev = kmalloc(sizeof(struct hiddev), GFP_KERNEL)))
+		return -1;
+	memset(hiddev, 0, sizeof(struct hiddev));
+
+	init_waitqueue_head(&hiddev->wait);
+
+	hiddev->minor = minor;
+	hiddev_table[minor] = hiddev;
+
+	hiddev->hid = hid;
+	hiddev->exist = 1;
+
+	sprintf(devfs_name, "hiddev%d", minor);
+	hiddev->devfs = devfs_register(hiddev_devfs_handle, devfs_name,
+				       DEVFS_FL_DEFAULT, USB_MAJOR,
+				       minor + HIDDEV_MINOR_BASE,
+				       S_IFCHR | S_IRUGO | S_IWUSR,
+				       &hiddev_fops, NULL);
+	hid->minor = minor;
+	hid->hiddev = hiddev;
+
+	return 0;
+}
+
+/*
+ * This is where hid.c calls us to disconnect a hiddev device from the
+ * corresponding hid device (usually because the usb device has disconnected)
+ */
+void hiddev_disconnect(struct hid_device *hid)
+{
+	struct hiddev *hiddev = hid->hiddev;
+
+	hiddev->exist = 0;
+
+	if (hiddev->open) {
+		hid_close(hiddev->hid);
+		wake_up_interruptible(&hiddev->wait);
+	} else {
+		hiddev_cleanup(hiddev);
+	}
+}
+
+/* Currently this driver is a USB driver.  It's not a conventional one in
+ * the sense that it doesn't probe at the USB level.  Instead it waits to
+ * be connected by HID through the hiddev_connect / hiddev_disconnect
+ * routines.  The reason to register as a USB device is to gain part of the
+ * minor number space from the USB major.
+ *
+ * In theory, should the HID code be generalized to more than one physical
+ * medium (say, IEEE 1384), this driver will probably need to register its
+ * own major number, and in doing so, no longer need to register with USB.
+ * At that point the probe routine and hiddev_driver struct below will no
+ * longer be useful.
+ */
+
+
+/* We never attach in this manner, and rely on HID to connect us.  This
+ * is why there is no disconnect routine defined in the usb_driver either.
+ */
+static void *hiddev_usbd_probe(struct usb_device *dev, unsigned int ifnum,
+			  const struct usb_device_id *hiddev_info)
+{
+	return NULL;
+}
+
+
+static /* const */ struct usb_driver hiddev_driver = {
+	name:	"hiddev",
+	probe:	hiddev_usbd_probe,
+	fops:	&hiddev_fops,
+	minor:	HIDDEV_MINOR_BASE
+};
+
+int __init hiddev_init(void)
+{
+	hiddev_devfs_handle =
+		devfs_mk_dir(devfs_find_handle(NULL, "usb", 0, 0, 0, 0), "hid", NULL);
+	usb_register(&hiddev_driver);
+	return 0;
+}
+
+void __exit hiddev_exit(void)
+{
+	devfs_unregister(hiddev_devfs_handle);
+	usb_deregister(&hiddev_driver);
+}
diff -urN linux-2.4.10-pre8/drivers/usb/serial/digi_acceleport.c linux/drivers/usb/serial/digi_acceleport.c
--- linux-2.4.10-pre8/drivers/usb/serial/digi_acceleport.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/usb/serial/digi_acceleport.c	Mon Dec  3 23:09:49 2001
@@ -670,7 +670,7 @@
 		}
 
 		/* len must be a multiple of 4, so commands are not split */
-		len = min_t(int, count, oob_port->bulk_out_size );
+		len = min(count, oob_port->bulk_out_size );
 		if( len > 4 )
 			len &= ~3;
 
@@ -747,7 +747,7 @@
 		/* len must be a multiple of 4 and small enough to */
 		/* guarantee the write will send buffered data first, */
 		/* so commands are in order with data and not split */
-		len = min_t(int, count, port->bulk_out_size-2-priv->dp_out_buf_len );
+		len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len );
 		if( len > 4 )
 			len &= ~3;
 
@@ -951,7 +951,7 @@
 	spin_lock_irqsave( &priv->dp_port_lock, flags );
 
 	/* send any buffered chars from throttle time on to tty subsystem */
-	len = min_t(int, priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
+	len = min(priv->dp_in_buf_len, TTY_FLIPBUF_SIZE - tty->flip.count );
 	if( len > 0 ) {
 		memcpy( tty->flip.char_buf_ptr, priv->dp_in_buf, len );
 		memcpy( tty->flip.flag_buf_ptr, priv->dp_in_flag_buf, len );
@@ -1272,7 +1272,8 @@
 priv->dp_port_num, count, from_user, in_interrupt() );
 
 	/* copy user data (which can sleep) before getting spin lock */
-	count = min_t(int, 64, min_t(int, count, port->bulk_out_size-2 ) );
+	count = min( count, port->bulk_out_size-2 );
+	count = min( 64, count);
 	if( from_user && copy_from_user( user_buf, buf, count ) ) {
 		return( -EFAULT );
 	}
@@ -1303,7 +1304,7 @@
 
 	/* allow space for any buffered data and for new data, up to */
 	/* transfer buffer size - 2 (for command and length bytes) */
-	new_len = min_t(int, count, port->bulk_out_size-2-priv->dp_out_buf_len );
+	new_len = min(count, port->bulk_out_size-2-priv->dp_out_buf_len);
 	data_len = new_len + priv->dp_out_buf_len;
 
 	if( data_len == 0 ) {
@@ -1929,7 +1930,7 @@
 
 		if( throttled ) {
 
-			len = min_t( int, len,
+			len = min( len,
 				DIGI_IN_BUF_SIZE - priv->dp_in_buf_len );
 
 			if( len > 0 ) {
@@ -1942,7 +1943,7 @@
 
 		} else {
 
-			len = min_t( int, len, TTY_FLIPBUF_SIZE - tty->flip.count );
+			len = min( len, TTY_FLIPBUF_SIZE - tty->flip.count );
 
 			if( len > 0 ) {
 				memcpy( tty->flip.char_buf_ptr, data, len );
diff -urN linux-2.4.10-pre8/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- linux-2.4.10-pre8/drivers/usb/serial/empeg.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/usb/serial/empeg.c	Mon Dec  3 23:09:49 2001
@@ -276,7 +276,7 @@
 			}
 		}
 
-		transfer_size = min_t (int, count, URB_TRANSFER_BUFFER_SIZE);
+		transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
 
 		if (from_user) {
 			if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) {
diff -urN linux-2.4.10-pre8/drivers/usb/serial/io_edgeport.c linux/drivers/usb/serial/io_edgeport.c
--- linux-2.4.10-pre8/drivers/usb/serial/io_edgeport.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/usb/serial/io_edgeport.c	Mon Dec  3 23:09:49 2001
@@ -1311,7 +1311,7 @@
 	fifo = &edge_port->txfifo;
 
 	// calculate number of bytes to put in fifo
-	copySize = min_t (int, count, (edge_port->txCredits - fifo->count));
+	copySize = min ((unsigned int)count, (edge_port->txCredits - fifo->count));
 
 	dbg(__FUNCTION__"(%d) of %d byte(s) Fifo room  %d -- will copy %d bytes", 
 	    port->number, count, edge_port->txCredits - fifo->count, copySize);
@@ -1329,7 +1329,7 @@
 	// then copy the reset from the start of the buffer 
 
 	bytesleft = fifo->size - fifo->head;
-	firsthalf = min_t (int, bytesleft, copySize);
+	firsthalf = min (bytesleft, copySize);
 	dbg (__FUNCTION__" - copy %d bytes of %d into fifo ", firsthalf, bytesleft);
 
 	/* now copy our data */
@@ -1454,7 +1454,7 @@
 
 	/* now copy our data */
 	bytesleft =  fifo->size - fifo->tail;
-	firsthalf = min_t (int, bytesleft, count);
+	firsthalf = min (bytesleft, count);
 	memcpy(&buffer[2], &fifo->fifo[fifo->tail], firsthalf);
 	fifo->tail  += firsthalf;
 	fifo->count -= firsthalf;
diff -urN linux-2.4.10-pre8/drivers/usb/serial/io_usbvend.h linux/drivers/usb/serial/io_usbvend.h
--- linux-2.4.10-pre8/drivers/usb/serial/io_usbvend.h	Mon Dec  3 23:09:38 2001
+++ linux/drivers/usb/serial/io_usbvend.h	Mon Dec  3 23:09:49 2001
@@ -115,7 +115,7 @@
 
 // TxCredits value below which driver won't bother sending (to prevent too many small writes).
 // Send only if above 25%
-#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit)	(max_t(int, ((InitialCredit) / 4), EDGE_FW_BULK_MAX_PACKET_SIZE))
+#define EDGE_FW_GET_TX_CREDITS_SEND_THRESHOLD(InitialCredit)	(max(((InitialCredit) / 4), EDGE_FW_BULK_MAX_PACKET_SIZE))
 
 #define	EDGE_FW_BULK_MAX_PACKET_SIZE		64	// Max Packet Size for Bulk In Endpoint (EP1)
 #define EDGE_FW_BULK_READ_BUFFER_SIZE		1024	// Size to use for Bulk reads
diff -urN linux-2.4.10-pre8/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- linux-2.4.10-pre8/drivers/usb/serial/usbserial.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/usb/serial/usbserial.c	Mon Dec  3 23:09:49 2001
@@ -1259,9 +1259,9 @@
 
 	/* initialize some parts of the port structures */
 	/* we don't use num_ports here cauz some devices have more endpoint pairs than ports */
-	max_endpoints = max_t(int, num_bulk_in, num_bulk_out);
-	max_endpoints = max_t(int, max_endpoints, num_interrupt_in);
-	max_endpoints = max_t(int, max_endpoints, serial->num_ports);
+	max_endpoints = max(num_bulk_in, num_bulk_out);
+	max_endpoints = max(max_endpoints, num_interrupt_in);
+	max_endpoints = max(max_endpoints, (int)serial->num_ports);
 	dbg (__FUNCTION__ " - setting up %d port structures for this device", max_endpoints);
 	for (i = 0; i < max_endpoints; ++i) {
 		port = &serial->port[i];
diff -urN linux-2.4.10-pre8/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- linux-2.4.10-pre8/drivers/usb/serial/visor.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/usb/serial/visor.c	Mon Dec  3 23:09:49 2001
@@ -441,7 +441,7 @@
 			}
 		}
 		
-		transfer_size = min_t (int, count, URB_TRANSFER_BUFFER_SIZE);
+		transfer_size = min (count, URB_TRANSFER_BUFFER_SIZE);
 		if (from_user) {
 			if (copy_from_user (urb->transfer_buffer, current_position, transfer_size)) {
 				bytes_sent = -EFAULT;
diff -urN linux-2.4.10-pre8/drivers/video/S3triofb.c linux/drivers/video/S3triofb.c
--- linux-2.4.10-pre8/drivers/video/S3triofb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/S3triofb.c	Mon Dec  3 23:09:49 2001
@@ -858,3 +858,5 @@
    fontwidthmask:	FONTWIDTH(8)
 };
 #endif
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/acornfb.c linux/drivers/video/acornfb.c
--- linux-2.4.10-pre8/drivers/video/acornfb.c	Sun Aug 12 17:37:53 2001
+++ linux/drivers/video/acornfb.c	Mon Dec  3 23:09:49 2001
@@ -1771,3 +1771,5 @@
 		return -EINVAL;
 	return 0;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/amifb.c linux/drivers/video/amifb.c
--- linux-2.4.10-pre8/drivers/video/amifb.c	Wed Aug 15 01:22:16 2001
+++ linux/drivers/video/amifb.c	Mon Dec  3 23:09:49 2001
@@ -911,7 +911,7 @@
 
 #define NUM_TOTAL_MODES  ARRAY_SIZE(ami_modedb)
 
-static const char *mode_option __initdata = NULL;
+static char *mode_option __initdata = NULL;
 static int round_down_bpp = 1;	/* for mode probing */
 
 	/*
@@ -3334,6 +3334,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	return amifb_init();
diff -urN linux-2.4.10-pre8/drivers/video/atafb.c linux/drivers/video/atafb.c
--- linux-2.4.10-pre8/drivers/video/atafb.c	Wed Apr 18 11:49:12 2001
+++ linux/drivers/video/atafb.c	Mon Dec  3 23:09:49 2001
@@ -3137,6 +3137,8 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	return atafb_init();
diff -urN linux-2.4.10-pre8/drivers/video/aty/atyfb_base.c linux/drivers/video/aty/atyfb_base.c
--- linux-2.4.10-pre8/drivers/video/aty/atyfb_base.c	Tue Aug  7 08:30:50 2001
+++ linux/drivers/video/aty/atyfb_base.c	Mon Dec  3 23:09:49 2001
@@ -52,7 +52,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/mm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/vmalloc.h>
 #include <linux/delay.h>
 #include <linux/selection.h>
diff -urN linux-2.4.10-pre8/drivers/video/bwtwofb.c linux/drivers/video/bwtwofb.c
--- linux-2.4.10-pre8/drivers/video/bwtwofb.c	Sun Feb 18 19:49:55 2001
+++ linux/drivers/video/bwtwofb.c	Mon Dec  3 23:09:49 2001
@@ -263,3 +263,5 @@
 	
 	return idstring;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/cgfourteenfb.c linux/drivers/video/cgfourteenfb.c
--- linux-2.4.10-pre8/drivers/video/cgfourteenfb.c	Sat Jul 28 12:12:38 2001
+++ linux/drivers/video/cgfourteenfb.c	Mon Dec  3 23:09:49 2001
@@ -72,6 +72,8 @@
 #define CG14_MCR_PIXMODE_16		2
 #define CG14_MCR_PIXMODE_32		3
 
+MODULE_LICENSE("GPL");
+
 struct cg14_regs{
 	volatile u8 mcr;	/* Master Control Reg */
 	volatile u8 ppr;	/* Packed Pixel Reg */
diff -urN linux-2.4.10-pre8/drivers/video/cgsixfb.c linux/drivers/video/cgsixfb.c
--- linux-2.4.10-pre8/drivers/video/cgsixfb.c	Sun Feb 18 19:49:55 2001
+++ linux/drivers/video/cgsixfb.c	Mon Dec  3 23:09:49 2001
@@ -128,6 +128,8 @@
 #define CG6_THC_MISC_INT             (1 << 4)
 #define CG6_THC_MISC_INIT            0x9f
 
+MODULE_LICENSE("GPL");
+
 /* The contents are unknown */
 struct cg6_tec {
 	volatile int tec_matrix;
diff -urN linux-2.4.10-pre8/drivers/video/cgthreefb.c linux/drivers/video/cgthreefb.c
--- linux-2.4.10-pre8/drivers/video/cgthreefb.c	Sun Feb 18 19:49:55 2001
+++ linux/drivers/video/cgthreefb.c	Mon Dec  3 23:09:49 2001
@@ -44,6 +44,8 @@
 #define CG3_SR_ID_MONO          0x02
 #define CG3_SR_ID_MONO_ECL      0x03
 
+MODULE_LICENSE("GPL");
+
 enum cg3_type {
 	CG3_AT_66HZ = 0,
 	CG3_AT_76HZ,
diff -urN linux-2.4.10-pre8/drivers/video/chipsfb.c linux/drivers/video/chipsfb.c
--- linux-2.4.10-pre8/drivers/video/chipsfb.c	Sat May 19 18:14:38 2001
+++ linux/drivers/video/chipsfb.c	Mon Dec  3 23:09:49 2001
@@ -739,3 +739,5 @@
 	return PBOOK_SLEEP_OK;
 }
 #endif /* CONFIG_PMAC_PBOOK */
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/controlfb.c linux/drivers/video/controlfb.c
--- linux-2.4.10-pre8/drivers/video/controlfb.c	Sun Aug 12 10:51:42 2001
+++ linux/drivers/video/controlfb.c	Mon Dec  3 23:09:49 2001
@@ -236,6 +236,8 @@
 /********************  The functions for controlfb_ops ********************/
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	struct device_node *dp;
diff -urN linux-2.4.10-pre8/drivers/video/creatorfb.c linux/drivers/video/creatorfb.c
--- linux-2.4.10-pre8/drivers/video/creatorfb.c	Tue Jun 12 11:08:46 2001
+++ linux/drivers/video/creatorfb.c	Mon Dec  3 23:09:49 2001
@@ -920,3 +920,5 @@
 
 	return idstring;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/cyber2000fb.c linux/drivers/video/cyber2000fb.c
--- linux-2.4.10-pre8/drivers/video/cyber2000fb.c	Sun Aug 12 17:37:53 2001
+++ linux/drivers/video/cyber2000fb.c	Mon Dec  3 23:09:49 2001
@@ -1673,6 +1673,7 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 module_init(cyber2000fb_init);
 #endif
 module_exit(cyberpro_exit);
diff -urN linux-2.4.10-pre8/drivers/video/cyberfb.c linux/drivers/video/cyberfb.c
--- linux-2.4.10-pre8/drivers/video/cyberfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/cyberfb.c	Mon Dec  3 23:09:49 2001
@@ -1251,6 +1251,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	return cyberfb_init();
diff -urN linux-2.4.10-pre8/drivers/video/dn_cfb4.c linux/drivers/video/dn_cfb4.c
--- linux-2.4.10-pre8/drivers/video/dn_cfb4.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/dn_cfb4.c	Mon Dec  3 23:09:49 2001
@@ -505,3 +505,5 @@
     revc:		rev_char_apollofb,
     fontwidthmask:	FONTWIDTH(8)
 };
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/dn_cfb8.c linux/drivers/video/dn_cfb8.c
--- linux-2.4.10-pre8/drivers/video/dn_cfb8.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/dn_cfb8.c	Mon Dec  3 23:09:49 2001
@@ -553,3 +553,5 @@
     revc:		rev_char_apollofb,
     fontwidthmask:	FONTWIDTH(8)
 };
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/dnfb.c linux/drivers/video/dnfb.c
--- linux-2.4.10-pre8/drivers/video/dnfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/dnfb.c	Mon Dec  3 23:09:49 2001
@@ -509,3 +509,5 @@
     revc:		rev_char_apollofb,
     fontwidthmask:	FONTWIDTH(8)
 };
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/epson1355fb.c linux/drivers/video/epson1355fb.c
--- linux-2.4.10-pre8/drivers/video/epson1355fb.c	Sun May 20 12:11:39 2001
+++ linux/drivers/video/epson1355fb.c	Mon Dec  3 23:09:49 2001
@@ -25,7 +25,7 @@
 #include <linux/fb.h>
 #include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/sched.h>
@@ -538,3 +538,4 @@
 	/* ... */
 }
 
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-afb.c linux/drivers/video/fbcon-afb.c
--- linux-2.4.10-pre8/drivers/video/fbcon-afb.c	Mon Jul 24 18:24:25 2000
+++ linux/drivers/video/fbcon-afb.c	Mon Dec  3 23:09:49 2001
@@ -422,6 +422,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-cfb16.c linux/drivers/video/fbcon-cfb16.c
--- linux-2.4.10-pre8/drivers/video/fbcon-cfb16.c	Mon Jul 24 18:24:25 2000
+++ linux/drivers/video/fbcon-cfb16.c	Mon Dec  3 23:09:49 2001
@@ -292,6 +292,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-cfb2.c linux/drivers/video/fbcon-cfb2.c
--- linux-2.4.10-pre8/drivers/video/fbcon-cfb2.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-cfb2.c	Mon Dec  3 23:09:49 2001
@@ -201,6 +201,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-cfb24.c linux/drivers/video/fbcon-cfb24.c
--- linux-2.4.10-pre8/drivers/video/fbcon-cfb24.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-cfb24.c	Mon Dec  3 23:09:49 2001
@@ -304,6 +304,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-cfb32.c linux/drivers/video/fbcon-cfb32.c
--- linux-2.4.10-pre8/drivers/video/fbcon-cfb32.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-cfb32.c	Mon Dec  3 23:09:49 2001
@@ -278,6 +278,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-cfb4.c linux/drivers/video/fbcon-cfb4.c
--- linux-2.4.10-pre8/drivers/video/fbcon-cfb4.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-cfb4.c	Mon Dec  3 23:09:49 2001
@@ -205,6 +205,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-cfb8.c linux/drivers/video/fbcon-cfb8.c
--- linux-2.4.10-pre8/drivers/video/fbcon-cfb8.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-cfb8.c	Mon Dec  3 23:09:49 2001
@@ -268,6 +268,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-hga.c linux/drivers/video/fbcon-hga.c
--- linux-2.4.10-pre8/drivers/video/fbcon-hga.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-hga.c	Mon Dec  3 23:09:49 2001
@@ -225,6 +225,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-ilbm.c linux/drivers/video/fbcon-ilbm.c
--- linux-2.4.10-pre8/drivers/video/fbcon-ilbm.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-ilbm.c	Mon Dec  3 23:09:49 2001
@@ -270,6 +270,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c
--- linux-2.4.10-pre8/drivers/video/fbcon-iplan2p2.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-iplan2p2.c	Mon Dec  3 23:09:49 2001
@@ -450,6 +450,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c
--- linux-2.4.10-pre8/drivers/video/fbcon-iplan2p4.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-iplan2p4.c	Mon Dec  3 23:09:49 2001
@@ -470,6 +470,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c
--- linux-2.4.10-pre8/drivers/video/fbcon-iplan2p8.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-iplan2p8.c	Mon Dec  3 23:09:49 2001
@@ -507,6 +507,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-mac.c linux/drivers/video/fbcon-mac.c
--- linux-2.4.10-pre8/drivers/video/fbcon-mac.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-mac.c	Mon Dec  3 23:09:49 2001
@@ -458,6 +458,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-mfb.c linux/drivers/video/fbcon-mfb.c
--- linux-2.4.10-pre8/drivers/video/fbcon-mfb.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-mfb.c	Mon Dec  3 23:09:49 2001
@@ -190,6 +190,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-sti.c linux/drivers/video/fbcon-sti.c
--- linux-2.4.10-pre8/drivers/video/fbcon-sti.c	Sun Aug 12 10:51:42 2001
+++ linux/drivers/video/fbcon-sti.c	Mon Dec  3 23:09:49 2001
@@ -332,3 +332,5 @@
 	clear_margins:	fbcon_sti_clear_margins,
 	fontwidthmask:	FONTWIDTH(8)
 };
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-vga-planes.c linux/drivers/video/fbcon-vga-planes.c
--- linux-2.4.10-pre8/drivers/video/fbcon-vga-planes.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-vga-planes.c	Mon Dec  3 23:09:49 2001
@@ -347,6 +347,8 @@
 };
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fbcon-vga.c linux/drivers/video/fbcon-vga.c
--- linux-2.4.10-pre8/drivers/video/fbcon-vga.c	Mon Jul 24 18:24:26 2000
+++ linux/drivers/video/fbcon-vga.c	Mon Dec  3 23:09:49 2001
@@ -188,6 +188,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return 0;
diff -urN linux-2.4.10-pre8/drivers/video/fm2fb.c linux/drivers/video/fm2fb.c
--- linux-2.4.10-pre8/drivers/video/fm2fb.c	Tue Nov  7 10:59:43 2000
+++ linux/drivers/video/fm2fb.c	Mon Dec  3 23:09:49 2001
@@ -528,3 +528,5 @@
     else
 	fb_set_cmap(fb_default_cmap(256), 1, fm2fb_setcolreg, info);
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/g364fb.c linux/drivers/video/g364fb.c
--- linux-2.4.10-pre8/drivers/video/g364fb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/g364fb.c	Mon Dec  3 23:09:49 2001
@@ -487,3 +487,5 @@
 	fb_set_cmap(fb_default_cmap(1<<fb_display[con].var.bits_per_pixel), 1,
 		    g364fb_setcolreg, info);
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/hgafb.c linux/drivers/video/hgafb.c
--- linux-2.4.10-pre8/drivers/video/hgafb.c	Fri Jul  6 16:48:50 2001
+++ linux/drivers/video/hgafb.c	Mon Dec  3 23:09:49 2001
@@ -845,6 +845,7 @@
 
 MODULE_AUTHOR("Ferenc Bakonyi (fero@drama.obuda.kando.hu)");
 MODULE_DESCRIPTION("FBDev driver for Hercules Graphics Adaptor");
+MODULE_LICENSE("GPL");
 
 MODULE_PARM(font, "s");
 MODULE_PARM_DESC(font, "Specifies one of the compiled-in fonts (VGA8x8, VGA8x16, SUN8x16, Acorn8x8, PEARL8x8) (default=none)");
diff -urN linux-2.4.10-pre8/drivers/video/hitfb.c linux/drivers/video/hitfb.c
--- linux-2.4.10-pre8/drivers/video/hitfb.c	Wed Apr 11 21:24:52 2001
+++ linux/drivers/video/hitfb.c	Mon Dec  3 23:09:49 2001
@@ -378,6 +378,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return hitfb_init();
diff -urN linux-2.4.10-pre8/drivers/video/hpfb.c linux/drivers/video/hpfb.c
--- linux-2.4.10-pre8/drivers/video/hpfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/hpfb.c	Mon Dec  3 23:09:49 2001
@@ -397,3 +397,5 @@
 
 	return 0;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/igafb.c linux/drivers/video/igafb.c
--- linux-2.4.10-pre8/drivers/video/igafb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/igafb.c	Mon Dec  3 23:09:49 2001
@@ -789,3 +789,5 @@
     }
     return 0;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/imsttfb.c linux/drivers/video/imsttfb.c
--- linux-2.4.10-pre8/drivers/video/imsttfb.c	Sun Jul  8 13:17:30 2001
+++ linux/drivers/video/imsttfb.c	Mon Dec  3 23:09:49 2001
@@ -2039,6 +2039,7 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 module_init(imsttfb_init);
 #endif
 module_exit(imsttfb_exit);
diff -urN linux-2.4.10-pre8/drivers/video/leofb.c linux/drivers/video/leofb.c
--- linux-2.4.10-pre8/drivers/video/leofb.c	Sun Feb 18 19:49:55 2001
+++ linux/drivers/video/leofb.c	Mon Dec  3 23:09:49 2001
@@ -756,3 +756,5 @@
 		    
 	return idstring;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/macfb.c linux/drivers/video/macfb.c
--- linux-2.4.10-pre8/drivers/video/macfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/macfb.c	Mon Dec  3 23:09:49 2001
@@ -1237,3 +1237,5 @@
 	printk("fb%d: %s frame buffer device\n",
 	       GET_FB_IDX(fb_info.node), fb_info.modename);
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/maxinefb.c linux/drivers/video/maxinefb.c
--- linux-2.4.10-pre8/drivers/video/maxinefb.c	Wed Jul  4 11:50:39 2001
+++ linux/drivers/video/maxinefb.c	Mon Dec  3 23:09:49 2001
@@ -31,7 +31,7 @@
 #include <linux/string.h>
 #include <linux/mm.h>
 #include <linux/tty.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
 #include <linux/fb.h>
@@ -382,6 +382,7 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 module_init(maxinefb_init);
 #endif
 module_exit(maxinefb_exit);
diff -urN linux-2.4.10-pre8/drivers/video/mdacon.c linux/drivers/video/mdacon.c
--- linux-2.4.10-pre8/drivers/video/mdacon.c	Wed Jun 27 17:10:55 2001
+++ linux/drivers/video/mdacon.c	Mon Dec  3 23:09:49 2001
@@ -615,6 +615,8 @@
 
 #ifdef MODULE
 
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	mda_console_init();
diff -urN linux-2.4.10-pre8/drivers/video/platinumfb.c linux/drivers/video/platinumfb.c
--- linux-2.4.10-pre8/drivers/video/platinumfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/platinumfb.c	Mon Dec  3 23:09:49 2001
@@ -878,3 +878,5 @@
 	}
 	return 0;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/pm2fb.c linux/drivers/video/pm2fb.c
--- linux-2.4.10-pre8/drivers/video/pm2fb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/pm2fb.c	Mon Dec  3 23:09:49 2001
@@ -2152,6 +2152,8 @@
 
 #ifdef MODULE
 
+MODULE_LICENSE("GPL");
+
 static char *mode = NULL;
 
 MODULE_PARM(mode, "s");
diff -urN linux-2.4.10-pre8/drivers/video/q40fb.c linux/drivers/video/q40fb.c
--- linux-2.4.10-pre8/drivers/video/q40fb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/q40fb.c	Mon Dec  3 23:09:49 2001
@@ -368,3 +368,5 @@
 static void q40con_blank(int blank, struct fb_info *info)
 {
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/retz3fb.c linux/drivers/video/retz3fb.c
--- linux-2.4.10-pre8/drivers/video/retz3fb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/retz3fb.c	Mon Dec  3 23:09:49 2001
@@ -1534,6 +1534,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	return retz3fb_init();
diff -urN linux-2.4.10-pre8/drivers/video/sa1100fb.c linux/drivers/video/sa1100fb.c
--- linux-2.4.10-pre8/drivers/video/sa1100fb.c	Sun Aug 12 17:37:53 2001
+++ linux/drivers/video/sa1100fb.c	Mon Dec  3 23:09:49 2001
@@ -2332,3 +2332,5 @@
 #endif
 	return 0;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/sbusfb.c linux/drivers/video/sbusfb.c
--- linux-2.4.10-pre8/drivers/video/sbusfb.c	Thu Apr 26 22:17:27 2001
+++ linux/drivers/video/sbusfb.c	Mon Dec  3 23:09:49 2001
@@ -1210,4 +1210,6 @@
 		sbusfb_init_fb(sbdp->prom_node, sbdp->bus->prom_node, type, sbdp);
 	}
 	return 0;
-}	
+}
+
+MODULE_LICENSE("GPL");	
diff -urN linux-2.4.10-pre8/drivers/video/skeletonfb.c linux/drivers/video/skeletonfb.c
--- linux-2.4.10-pre8/drivers/video/skeletonfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/skeletonfb.c	Mon Dec  3 23:09:49 2001
@@ -402,6 +402,7 @@
      */
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 int init_module(void)
 {
     return xxxfb_init();
diff -urN linux-2.4.10-pre8/drivers/video/sticon-bmode.c linux/drivers/video/sticon-bmode.c
--- linux-2.4.10-pre8/drivers/video/sticon-bmode.c	Sun Aug 12 10:51:42 2001
+++ linux/drivers/video/sticon-bmode.c	Mon Dec  3 23:09:49 2001
@@ -905,3 +905,5 @@
 }
 
 module_init(sti_init)
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/sticore.c linux/drivers/video/sticore.c
--- linux-2.4.10-pre8/drivers/video/sticore.c	Sun Aug 12 10:51:42 2001
+++ linux/drivers/video/sticore.c	Mon Dec  3 23:09:49 2001
@@ -597,3 +597,5 @@
 }
 
 __setup("sti=", sti_setup);
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/tcxfb.c linux/drivers/video/tcxfb.c
--- linux-2.4.10-pre8/drivers/video/tcxfb.c	Sun Feb 18 19:49:55 2001
+++ linux/drivers/video/tcxfb.c	Mon Dec  3 23:09:49 2001
@@ -362,3 +362,5 @@
 
 	return idstring;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/tgafb.c linux/drivers/video/tgafb.c
--- linux-2.4.10-pre8/drivers/video/tgafb.c	Wed Jul  4 14:41:33 2001
+++ linux/drivers/video/tgafb.c	Mon Dec  3 23:09:49 2001
@@ -1003,6 +1003,7 @@
      */
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 module_init(tgafb_init);
 #endif
 
diff -urN linux-2.4.10-pre8/drivers/video/valkyriefb.c linux/drivers/video/valkyriefb.c
--- linux-2.4.10-pre8/drivers/video/valkyriefb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/valkyriefb.c	Mon Dec  3 23:09:49 2001
@@ -841,3 +841,5 @@
 	}
 	return 0;
 }
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/vfb.c linux/drivers/video/vfb.c
--- linux-2.4.10-pre8/drivers/video/vfb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/vfb.c	Mon Dec  3 23:09:49 2001
@@ -601,6 +601,8 @@
 
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
     return vfb_init();
diff -urN linux-2.4.10-pre8/drivers/video/vga16fb.c linux/drivers/video/vga16fb.c
--- linux-2.4.10-pre8/drivers/video/vga16fb.c	Mon Dec  3 23:09:38 2001
+++ linux/drivers/video/vga16fb.c	Mon Dec  3 23:09:49 2001
@@ -954,6 +954,7 @@
 }
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
 module_init(vga16fb_init);
 #endif
 module_exit(vga16fb_exit);
diff -urN linux-2.4.10-pre8/drivers/video/vgacon.c linux/drivers/video/vgacon.c
--- linux-2.4.10-pre8/drivers/video/vgacon.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/vgacon.c	Mon Dec  3 23:09:49 2001
@@ -34,6 +34,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/sched.h>
 #include <linux/fs.h>
@@ -1057,3 +1058,5 @@
 	con_build_attr:		vgacon_build_attr,
 	con_invert_region:	vgacon_invert_region,
 };
+
+MODULE_LICENSE("GPL");
diff -urN linux-2.4.10-pre8/drivers/video/virgefb.c linux/drivers/video/virgefb.c
--- linux-2.4.10-pre8/drivers/video/virgefb.c	Fri Feb  9 11:30:23 2001
+++ linux/drivers/video/virgefb.c	Mon Dec  3 23:09:49 2001
@@ -1392,6 +1392,8 @@
 #endif
 
 #ifdef MODULE
+MODULE_LICENSE("GPL");
+
 int init_module(void)
 {
 	return virgefb_init();
diff -urN linux-2.4.10-pre8/fs/affs/Changes linux/fs/affs/Changes
--- linux-2.4.10-pre8/fs/affs/Changes	Mon Dec  3 23:09:38 2001
+++ linux/fs/affs/Changes	Mon Dec  3 23:09:49 2001
@@ -28,6 +28,12 @@
 
 Please direct bug reports to: zippel@linux-m68k.org
 
+Version 3.18
+------------
+
+- change to global min macro + warning fixes
+- add module tags
+
 Version 3.17
 ------------
 
diff -urN linux-2.4.10-pre8/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c
--- linux-2.4.10-pre8/fs/affs/amigaffs.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/affs/amigaffs.c	Mon Dec  3 23:09:49 2001
@@ -507,7 +507,7 @@
 int
 affs_copy_name(unsigned char *bstr, struct dentry *dentry)
 {
-	int len = MIN(dentry->d_name.len, 30);
+	int len = min(dentry->d_name.len, 30u);
 
 	*bstr++ = len;
 	memcpy(bstr, dentry->d_name.name, len);
diff -urN linux-2.4.10-pre8/fs/affs/dir.c linux/fs/affs/dir.c
--- linux-2.4.10-pre8/fs/affs/dir.c	Sun Jul 15 16:34:14 2001
+++ linux/fs/affs/dir.c	Mon Dec  3 23:09:49 2001
@@ -135,7 +135,7 @@
 				goto readdir_done;
 			}
 
-			namelen = MIN(AFFS_TAIL(sb, fh_bh)->name[0], 30);
+			namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
 			name = AFFS_TAIL(sb, fh_bh)->name + 1;
 			pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
 				 namelen, name, ino, hash_pos, f_pos);
diff -urN linux-2.4.10-pre8/fs/affs/file.c linux/fs/affs/file.c
--- linux-2.4.10-pre8/fs/affs/file.c	Sun Aug 12 10:56:56 2001
+++ linux/fs/affs/file.c	Mon Dec  3 23:09:49 2001
@@ -528,7 +528,7 @@
 		bh = affs_bread_ino(inode, bidx, 0);
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
-		tmp = MIN(bsize - boff, from - to);
+		tmp = min(bsize - boff, from - to);
 		memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
 		affs_brelse(bh);
 		bidx++;
@@ -558,7 +558,7 @@
 		bh = affs_bread_ino(inode, bidx, 0);
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
-		tmp = MIN(bsize - boff, newsize - size);
+		tmp = min(bsize - boff, newsize - size);
 		memset(AFFS_DATA(bh) + boff, 0, tmp);
 		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
 		affs_fix_checksum(sb, bh);
@@ -576,7 +576,7 @@
 		bh = affs_getzeroblk_ino(inode, bidx);
 		if (IS_ERR(bh))
 			goto out;
-		tmp = MIN(bsize, newsize - size);
+		tmp = min(bsize, newsize - size);
 		AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
 		AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
 		AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
@@ -685,7 +685,7 @@
 		bh = affs_bread_ino(inode, bidx, 0);
 		if (IS_ERR(bh))
 			return PTR_ERR(bh);
-		tmp = MIN(bsize - boff, to - from);
+		tmp = min(bsize - boff, to - from);
 		memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
 		AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
 		affs_fix_checksum(sb, bh);
@@ -731,7 +731,7 @@
 		bh = affs_bread_ino(inode, bidx, 1);
 		if (IS_ERR(bh))
 			goto out;
-		tmp = MIN(bsize, to - from);
+		tmp = min(bsize, to - from);
 		memcpy(AFFS_DATA(bh), data + from, tmp);
 		if (bh->b_state & (1UL << BH_New)) {
 			AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
diff -urN linux-2.4.10-pre8/fs/affs/namei.c linux/fs/affs/namei.c
--- linux-2.4.10-pre8/fs/affs/namei.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/affs/namei.c	Mon Dec  3 23:09:49 2001
@@ -81,7 +81,7 @@
 		return i;
 
 	hash = init_name_hash();
-	i = MIN(qstr->len, 30);
+	i = min(qstr->len, 30u);
 	for (; i > 0; name++, i--)
 		hash = partial_name_hash(toupper(*name), hash);
 	qstr->hash = end_name_hash(hash);
@@ -172,7 +172,7 @@
 	toupper_t toupper = affs_get_toupper(sb);
 	int hash;
 
-	hash = len = MIN(len, 30);
+	hash = len = min(len, 30u);
 	for (; len > 0; len--)
 		hash = (hash * 13 + toupper(*name++)) & 0x7ff;
 
diff -urN linux-2.4.10-pre8/fs/affs/super.c linux/fs/affs/super.c
--- linux-2.4.10-pre8/fs/affs/super.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/affs/super.c	Mon Dec  3 23:09:49 2001
@@ -505,5 +505,8 @@
 
 EXPORT_NO_SYMBOLS;
 
+MODULE_DESCRIPTION("Amiga filesystem support for Linux");
+MODULE_LICENSE("GPL");
+
 module_init(init_affs_fs)
 module_exit(exit_affs_fs)
diff -urN linux-2.4.10-pre8/fs/binfmt_aout.c linux/fs/binfmt_aout.c
--- linux-2.4.10-pre8/fs/binfmt_aout.c	Thu Jul 19 20:33:38 2001
+++ linux/fs/binfmt_aout.c	Mon Dec  3 23:09:49 2001
@@ -90,7 +90,7 @@
 #	define START_DATA(u)	((u.u_tsize << PAGE_SHIFT) + u.start_code)
 #elif defined(__sparc__)
 #       define START_DATA(u)    (u.u_tsize)
-#elif defined(__i386__) || defined(__mc68000__)
+#elif defined(__i386__) || defined(__mc68000__) || defined(__arch_um__)
 #       define START_DATA(u)	(u.u_tsize << PAGE_SHIFT)
 #endif
 #ifdef __sparc__
@@ -219,7 +219,7 @@
 	envp = (char **) sp;
 	sp -= argc+1;
 	argv = (char **) sp;
-#if defined(__i386__) || defined(__mc68000__) || defined(__arm__)
+#if defined(__i386__) || defined(__mc68000__) || defined(__arm__) || defined(__arch_um__)
 	put_user((unsigned long) envp,--sp);
 	put_user((unsigned long) argv,--sp);
 #endif
diff -urN linux-2.4.10-pre8/fs/binfmt_elf.c linux/fs/binfmt_elf.c
--- linux-2.4.10-pre8/fs/binfmt_elf.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/binfmt_elf.c	Mon Dec  3 23:09:49 2001
@@ -115,6 +115,7 @@
 	char *k_platform, *u_platform;
 	long hwcap;
 	size_t platform_len = 0;
+	size_t len;
 
 	/*
 	 * Get hold of platform and hardware capabilities masks for
@@ -197,13 +198,19 @@
 	current->mm->arg_start = (unsigned long) p;
 	while (argc-->0) {
 		__put_user((elf_caddr_t)(unsigned long)p,argv++);
-		p += strlen_user(p);
+		len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES);
+		if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+			return NULL;
+		p += len;
 	}
 	__put_user(NULL, argv);
 	current->mm->arg_end = current->mm->env_start = (unsigned long) p;
 	while (envc-->0) {
 		__put_user((elf_caddr_t)(unsigned long)p,envp++);
-		p += strlen_user(p);
+		len = strnlen_user(p, PAGE_SIZE*MAX_ARG_PAGES);
+		if (!len || len > PAGE_SIZE*MAX_ARG_PAGES)
+			return NULL;
+		p += len;
 	}
 	__put_user(NULL, envp);
 	current->mm->env_end = (unsigned long) p;
@@ -406,14 +413,15 @@
 	struct elf_phdr * elf_ppnt, *elf_phdata;
 	unsigned long elf_bss, k, elf_brk;
 	int elf_exec_fileno;
-	int retval, size, i;
+	int retval, i;
+	unsigned int size;
 	unsigned long elf_entry, interp_load_addr = 0;
 	unsigned long start_code, end_code, start_data, end_data;
 	struct elfhdr elf_ex;
 	struct elfhdr interp_elf_ex;
   	struct exec interp_ex;
 	char passed_fileno[6];
-
+	
 	/* Get the exec-header */
 	elf_ex = *((struct elfhdr *) bprm->buf);
 
@@ -432,7 +440,7 @@
 	/* Now read in all of the header information */
 
 	retval = -ENOMEM;
-	size = elf_ex.e_phentsize * elf_ex.e_phnum;
+	size = ((unsigned int)elf_ex.e_phentsize) * elf_ex.e_phnum;
 	if (size > 65536)
 		goto out;
 	elf_phdata = (struct elf_phdr *) kmalloc(size, GFP_KERNEL);
@@ -548,7 +556,8 @@
 		/* Make sure only one type was selected */
 		if ((interpreter_type & INTERPRETER_ELF) &&
 		     interpreter_type != INTERPRETER_ELF) {
-			printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n");
+	     		// FIXME - ratelimit this before re-enabling
+			// printk(KERN_WARNING "ELF: Ambiguous type, using ELF\n");
 			interpreter_type = INTERPRETER_ELF;
 		}
 	}
diff -urN linux-2.4.10-pre8/fs/dquot.c linux/fs/dquot.c
--- linux-2.4.10-pre8/fs/dquot.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/dquot.c	Mon Dec  3 23:09:49 2001
@@ -627,27 +627,11 @@
 	return dquot;
 }
 
-/* Check whether this inode is quota file */
-static inline int is_quotafile(struct inode *inode)
-{
-	int cnt;
-	struct quota_mount_options *dqopt = sb_dqopt(inode->i_sb);
-	struct file **files;
-
-	if (!dqopt)
-		return 0;
-	files = dqopt->files;
-	for (cnt = 0; cnt < MAXQUOTAS; cnt++)
-		if (files[cnt] && files[cnt]->f_dentry->d_inode == inode)
-			return 1;
-	return 0;
-}
-
 static int dqinit_needed(struct inode *inode, short type)
 {
 	int cnt;
 
-	if (is_quotafile(inode))
+	if (IS_NOQUOTA(inode))
 		return 0;
 	if (type != -1)
 		return inode->i_dquot[type] == NODQUOT;
@@ -674,7 +658,6 @@
 			struct dentry *dentry = dget(filp->f_dentry);
 			file_list_unlock();
 			sb->dq_op->initialize(inode, type);
-			inode->i_flags |= S_QUOTA;
 			dput(dentry);
 			mntput(mnt);
 			/* As we may have blocked we had better restart... */
@@ -1018,8 +1001,7 @@
 	short cnt;
 
 	lock_kernel();
-	/* We don't want to have quotas on quota files - nasty deadlocks possible */
-	if (is_quotafile(inode)) {
+	if (IS_NOQUOTA(inode)) {
 		unlock_kernel();
 		return;
 	}
@@ -1473,7 +1455,9 @@
 	error = -EINVAL;
 	if (inode->i_size == 0 || !check_quotafile_size(inode->i_size))
 		goto out_f;
-	dquot_drop(inode);	/* We don't want quota on quota files */
+	/* We don't want quota on quota files */
+	dquot_drop(inode);
+	inode->i_flags |= S_NOQUOTA;
 
 	set_enable_flags(dqopt, type);
 	dqopt->files[type] = f;
diff -urN linux-2.4.10-pre8/fs/exec.c linux/fs/exec.c
--- linux-2.4.10-pre8/fs/exec.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/exec.c	Mon Dec  3 23:09:49 2001
@@ -347,7 +347,8 @@
 	if (!err) {
 		inode = nd.dentry->d_inode;
 		file = ERR_PTR(-EACCES);
-		if (!IS_NOEXEC(inode) && S_ISREG(inode->i_mode)) {
+		if (!(nd.mnt->mnt_flags & MNT_NOEXEC) &&
+		    S_ISREG(inode->i_mode)) {
 			int err = permission(inode, MAY_EXEC);
 			file = ERR_PTR(err);
 			if (!err) {
@@ -607,7 +608,10 @@
 	struct inode * inode = bprm->file->f_dentry->d_inode;
 
 	mode = inode->i_mode;
-	/* Huh? We had already checked for MAY_EXEC, WTF do we check this? */
+	/*
+	 * Check execute perms again - if the caller has CAP_DAC_OVERRIDE,
+	 * vfs_permission lets a non-executable through
+	 */
 	if (!(mode & 0111))	/* with at least _one_ execute bit set */
 		return -EACCES;
 	if (bprm->file->f_op == NULL)
@@ -616,7 +620,7 @@
 	bprm->e_uid = current->euid;
 	bprm->e_gid = current->egid;
 
-	if(!IS_NOSUID(inode)) {
+	if(!(bprm->file->f_vfsmnt->mnt_flags & MNT_NOSUID)) {
 		/* Set-uid? */
 		if (mode & S_ISUID)
 			bprm->e_uid = inode->i_uid;
diff -urN linux-2.4.10-pre8/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c
--- linux-2.4.10-pre8/fs/ext2/ialloc.c	Tue Jul  3 07:58:47 2001
+++ linux/fs/ext2/ialloc.c	Mon Dec  3 23:09:49 2001
@@ -194,9 +194,11 @@
 	 * Note: we must free any quota before locking the superblock,
 	 * as writing the quota to disk may need the lock as well.
 	 */
-	DQUOT_INIT(inode);
-	DQUOT_FREE_INODE(sb, inode);
-	DQUOT_DROP(inode);
+	if (!is_bad_inode(inode)) {
+		/* Quota is already initialized in iput() */
+	    	DQUOT_FREE_INODE(sb, inode);
+		DQUOT_DROP(inode);
+	}
 
 	lock_super (sb);
 	es = sb->u.ext2_sb.s_es;
@@ -453,7 +455,8 @@
 
 	unlock_super (sb);
 	if(DQUOT_ALLOC_INODE(sb, inode)) {
-		sb->dq_op->drop(inode);
+		DQUOT_DROP(inode);
+		inode->i_flags |= S_NOQUOTA;
 		inode->i_nlink = 0;
 		iput(inode);
 		return ERR_PTR(-EDQUOT);
@@ -463,6 +466,7 @@
 
 fail:
 	unlock_super(sb);
+	make_bad_inode(inode);
 	iput(inode);
 	return ERR_PTR(err);
 }
diff -urN linux-2.4.10-pre8/fs/fat/inode.c linux/fs/fat/inode.c
--- linux-2.4.10-pre8/fs/fat/inode.c	Sun Aug 12 12:39:02 2001
+++ linux/fs/fat/inode.c	Mon Dec  3 23:09:49 2001
@@ -919,9 +919,8 @@
 	} else { /* not a directory */
 		inode->i_generation |= 1;
 		inode->i_mode = MSDOS_MKMODE(de->attr,
-		    ((IS_NOEXEC(inode) || 
-		      (sbi->options.showexec &&
-		       !is_exec(de->ext)))
+		    ((sbi->options.showexec &&
+		       !is_exec(de->ext))
 		    	? S_IRUGO|S_IWUGO : S_IRWXUGO)
 		    & ~sbi->options.fs_umask) | S_IFREG;
 		MSDOS_I(inode)->i_start = CF_LE_W(de->start);
@@ -1039,9 +1038,7 @@
 
 	inode_setattr(inode, attr);
 
-	if (IS_NOEXEC(inode) && !S_ISDIR(inode->i_mode))
-		inode->i_mode &= S_IFMT | S_IRUGO | S_IWUGO;
-	else
+	if (S_ISDIR(inode->i_mode))
 		inode->i_mode |= S_IXUGO;
 
 	inode->i_mode = ((inode->i_mode & S_IFMT) | ((((inode->i_mode & S_IRWXU
diff -urN linux-2.4.10-pre8/fs/hfs/inode.c linux/fs/hfs/inode.c
--- linux-2.4.10-pre8/fs/hfs/inode.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/hfs/inode.c	Mon Dec  3 23:09:49 2001
@@ -38,7 +38,7 @@
 	struct hfs_fork *fk;
 	struct hfs_cat_entry *entry = HFS_I(inode)->entry;
 
-	if (!IS_NOEXEC(inode) && (fork == HFS_FK_DATA)) {
+	if (fork == HFS_FK_DATA) {
 		inode->i_mode = S_IRWXUGO | S_IFREG;
 	} else {
 		inode->i_mode = S_IRUGO | S_IWUGO | S_IFREG;
diff -urN linux-2.4.10-pre8/fs/inode.c linux/fs/inode.c
--- linux-2.4.10-pre8/fs/inode.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/inode.c	Mon Dec  3 23:09:49 2001
@@ -513,8 +513,7 @@
 	if (inode->i_state & I_CLEAR)
 		BUG();
 	wait_on_inode(inode);
-	if (IS_QUOTAINIT(inode))
-		DQUOT_DROP(inode);
+	DQUOT_DROP(inode);
 	if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->clear_inode)
 		inode->i_sb->s_op->clear_inode(inode);
 	if (inode->i_bdev) {
@@ -1049,7 +1048,8 @@
 
 			if (op && op->delete_inode) {
 				void (*delete)(struct inode *) = op->delete_inode;
-				DQUOT_INIT(inode);
+				if (!is_bad_inode(inode))
+					DQUOT_INIT(inode);
 				/* s_op->delete_inode internally recalls clear_inode() */
 				delete(inode);
 			} else
diff -urN linux-2.4.10-pre8/fs/locks.c linux/fs/locks.c
--- linux-2.4.10-pre8/fs/locks.c	Wed Jul  4 15:39:28 2001
+++ linux/fs/locks.c	Mon Dec  3 23:09:49 2001
@@ -473,21 +473,26 @@
 		fl->fl_insert(fl);
 }
 
-/* Delete a lock and then free it.
- * Remove our lock from the lock lists, wake up processes that are blocked
- * waiting for this lock, notify the FS that the lock has been cleared and
- * finally free the lock.
+/*
+ * Remove lock from the lock lists
  */
-static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
+static inline void _unhash_lock(struct file_lock **thisfl_p)
 {
 	struct file_lock *fl = *thisfl_p;
 
 	*thisfl_p = fl->fl_next;
 	fl->fl_next = NULL;
 
-	list_del(&fl->fl_link);
-	INIT_LIST_HEAD(&fl->fl_link);
+	list_del_init(&fl->fl_link);
+}
 
+/*
+ * Wake up processes that are blocked waiting for this lock,
+ * notify the FS that the lock has been cleared and
+ * finally free the lock.
+ */
+static inline void _delete_lock(struct file_lock *fl, unsigned int wait)
+{
 	fasync_helper(0, fl->fl_file, 0, &fl->fl_fasync);
 	if (fl->fl_fasync != NULL){
 		printk(KERN_ERR "locks_delete_lock: fasync == %p\n", fl->fl_fasync);
@@ -502,6 +507,17 @@
 }
 
 /*
+ * Delete a lock and then free it.
+ */
+static void locks_delete_lock(struct file_lock **thisfl_p, unsigned int wait)
+{
+	struct file_lock *fl = *thisfl_p;
+
+	_unhash_lock(thisfl_p);
+	_delete_lock(fl, wait);
+}
+
+/*
  * Call back client filesystem in order to get it to unregister a lock,
  * then delete lock. Essentially useful only in locks_remove_*().
  * Note: this must be called with the semaphore already held!
@@ -511,12 +527,13 @@
 	struct file_lock *fl = *thisfl_p;
 	int (*lock)(struct file *, int, struct file_lock *);
 
+	_unhash_lock(thisfl_p);
 	if (fl->fl_file->f_op &&
 	    (lock = fl->fl_file->f_op->lock) != NULL) {
 		fl->fl_type = F_UNLCK;
 		lock(fl->fl_file, F_SETLK, fl);
 	}
-	locks_delete_lock(thisfl_p, 0);
+	_delete_lock(fl, 0);
 }
 
 /* Determine if lock sys_fl blocks lock caller_fl. Common functionality
@@ -1661,6 +1678,7 @@
 	while ((fl = *before) != NULL) {
 		if ((fl->fl_flags & FL_POSIX) && fl->fl_owner == owner) {
 			locks_unlock_delete(before);
+			before = &inode->i_flock;
 			continue;
 		}
 		before = &fl->fl_next;
diff -urN linux-2.4.10-pre8/fs/namei.c linux/fs/namei.c
--- linux-2.4.10-pre8/fs/namei.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/namei.c	Mon Dec  3 23:09:49 2001
@@ -1062,7 +1062,7 @@
 	    	flag &= ~O_TRUNC;
 	} else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
 		error = -EACCES;
-		if (IS_NODEV(inode))
+		if (nd->mnt->mnt_flags & MNT_NODEV)
 			goto exit;
 
 		flag &= ~O_TRUNC;
diff -urN linux-2.4.10-pre8/fs/ntfs/Makefile linux/fs/ntfs/Makefile
--- linux-2.4.10-pre8/fs/ntfs/Makefile	Mon Dec  3 23:09:38 2001
+++ linux/fs/ntfs/Makefile	Mon Dec  3 23:09:49 2001
@@ -5,7 +5,7 @@
 obj-y   := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o unistr.o
 obj-m   := $(O_TARGET)
 # New version format started 3 February 2001.
-EXTRA_CFLAGS = -DNTFS_VERSION=\"1.1.18\" #-DDEBUG
+EXTRA_CFLAGS = -DNTFS_VERSION=\"1.1.19\" #-DDEBUG
 
 include $(TOPDIR)/Rules.make
 
diff -urN linux-2.4.10-pre8/fs/ntfs/dir.c linux/fs/ntfs/dir.c
--- linux-2.4.10-pre8/fs/ntfs/dir.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/ntfs/dir.c	Mon Dec  3 23:09:49 2001
@@ -94,15 +94,15 @@
 #endif
 
 /* True if the entry points to another block of entries. */
-static inline int ntfs_entry_has_subnodes(char* entry)
+static inline int ntfs_entry_has_subnodes(char *entry)
 {
-	return (int)NTFS_GETU8(entry + 12) & 1;
+	return (NTFS_GETU16(entry + 0xc) & 1);
 }
 
 /* True if it is not the 'end of dir' entry. */
-static inline int ntfs_entry_is_used(char* entry)
+static inline int ntfs_entry_is_used(char *entry)
 {
-	return (int)(NTFS_GETU8(entry + 12) & 2) == 0;
+	return !(NTFS_GETU16(entry + 0xc) & 2);
 }
 
 /*
@@ -791,12 +791,14 @@
 int ntfs_getdir_unsorted(ntfs_inode *ino, u32 *p_high, u32 *p_low,
 		int (*cb)(ntfs_u8 *, void *), void *param)
 {
+	s64 ib_ofs;
 	char *buf = 0, *entry = 0;
 	ntfs_attribute *attr;
 	ntfs_volume *vol;
-	int length, block, byte, bit, error = 0;
-	u32 start, finish;
+	int byte, bit, err = 0;
+	u32 start, finish, ibs, max_size;
 	ntfs_io io;
+	u8 ibs_bits;
 
 	if (!ino) {
 		ntfs_error(__FUNCTION__ "(): No inode! Returning -EINVAL.\n");
@@ -804,60 +806,64 @@
 	}
 	vol = ino->vol;
 	if (!vol) {
-		ntfs_error(__FUNCTION__ "(): Inode %lx has no volume. "
+		ntfs_error(__FUNCTION__ "(): Inode 0x%lx has no volume. "
 				"Returning -EINVAL.\n", ino->i_number);
 		return -EINVAL;
 	}
 	ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 1: Entering for "
 			"inode 0x%lx, p_high = 0x%x, p_low = 0x%x.\n",
 			ino->i_number, *p_high, *p_low);
-	if (*p_high == 0) {
+	if (!*p_high) {
 		/* We are still in the index root. */
-		buf = ntfs_malloc(length = vol->mft_record_size);
+		buf = ntfs_malloc(io.size = vol->mft_record_size);
 		if (!buf)
 			return -ENOMEM;
 		io.fn_put = ntfs_put;
 		io.param = buf;
-		io.size = length;
-		error = ntfs_read_attr(ino, vol->at_index_root, I30, 0, &io);
-		if (error)
+		err = ntfs_read_attr(ino, vol->at_index_root, I30, 0, &io);
+		if (err || !io.size)
 			goto read_err_ret;
-		ino->u.index.recordsize = NTFS_GETU32(buf + 0x8);
+		ino->u.index.recordsize = ibs = NTFS_GETU32(buf + 0x8);
 		ino->u.index.clusters_per_record = NTFS_GETU32(buf + 0xC);
 		entry = buf + 0x20;
 		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 2: In index "
 				"root.\n");
+		ibs_bits = ffs(ibs) - 1;
 		/* Compensate for faked "." and "..". */
 		start = 2;
 	} else { /* We are in an index record. */
-		length = ino->u.index.recordsize;
-		buf = ntfs_malloc(length);
+		io.size = ibs = ino->u.index.recordsize;
+		buf = ntfs_malloc(ibs);
 		if (!buf)
 			return -ENOMEM;
+		ibs_bits = ffs(ibs) - 1;
 		io.fn_put = ntfs_put;
 		io.param = buf;
-		io.size = length;
-		/* 0 is index root, index allocation starts with 4. */
-		block = *p_high - ino->u.index.clusters_per_record;
-		error = ntfs_read_attr(ino, vol->at_index_allocation, I30,
-				(__s64)block << vol->cluster_size_bits, &io);
-		if (error || io.size != length)
+		/*
+		 * 0 is index root, index allocation starts at 1 and works in
+		 * units of index block size (ibs).
+		 */
+		ib_ofs = (s64)(*p_high - 1) << ibs_bits;
+		err = ntfs_read_attr(ino, vol->at_index_allocation, I30, ib_ofs,
+				&io);
+		if (err || io.size != ibs)
 			goto read_err_ret;
 		if (!ntfs_check_index_record(ino, buf)) {
-			ntfs_error(__FUNCTION__ "(): Block 0x%x is not an "
-					"index record. Returning -ENOTDIR.\n",
-					block);
+			ntfs_error(__FUNCTION__ "(): Index block 0x%x is not "
+					"an index record. Returning "
+					"-ENOTDIR.\n", *p_high - 1);
 			ntfs_free(buf);
 			return -ENOTDIR;
 		}
-		entry = buf + NTFS_GETU16(buf + 0x18) + 0x18;
+		entry = buf + 0x18 + NTFS_GETU16(buf + 0x18);
 		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 3: In index "
 				"allocation.\n");
 		start = 0;
 	}
 	/* Process the entries. */
 	finish = *p_low;
-	for (; ntfs_entry_is_used(entry); entry += NTFS_GETU16(entry + 8)) {
+	for (; entry < (buf + ibs) && ntfs_entry_is_used(entry);
+			entry += NTFS_GETU16(entry + 8)) {
 		if (start < finish) {
 			/* Skip entries that were already processed. */
 			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 4: "
@@ -870,7 +876,7 @@
 		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 5: "
 				"Processing entry p_high 0x%x, p_low 0x%x.\n",
 				*p_high, *p_low);
-		if ((error = cb(entry, param))) {
+		if ((err = cb(entry, param))) {
 			/* filldir signalled us to stop. */
 			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): "
 					"Unsorted 6: cb returned %i, "
@@ -889,20 +895,26 @@
 	*p_low = 0;
 	attr = ntfs_find_attr(ino, vol->at_bitmap, I30);
 	if (!attr) {
-		/* Directory does not have index allocation. */
+		/* Directory does not have index bitmap and index allocation. */
 		*p_high = 0x7fff;
 		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 8: No index "
 				"allocation. Returning 0, p_high 0x7fff, "
 				"p_low 0x0.\n");
 		return 0;
 	}
-	buf = ntfs_malloc(length = attr->size);
+	max_size = attr->size;
+	if (max_size > 0x7fff >> 3) {
+		ntfs_error(__FUNCTION__ "(): Directory too large. Visible "
+				"length is truncated.\n");
+		max_size = 0x7fff >> 3;
+	}
+	buf = ntfs_malloc(max_size);
 	if (!buf)
 		return -ENOMEM;
 	io.param = buf;
-	io.size = length;
-	error = ntfs_read_attr(ino, vol->at_bitmap, I30, 0, &io);
-	if (error || io.size != length)
+	io.size = max_size;
+	err = ntfs_read_attr(ino, vol->at_bitmap, I30, 0, &io);
+	if (err || io.size != max_size)
 		goto read_err_ret;
 	attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
 	if (!attr) {
@@ -911,35 +923,55 @@
 				"attr failed. Returning -EIO.\n");
 		return -EIO;
 	}
+	if (attr->resident) {
+		ntfs_free(buf);
+		ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 9.5: IA is "
+				"resident. Not allowed. Returning EINVAL.\n");
+		return -EINVAL;
+	}
 	/* Loop while going through non-allocated index records. */
-	do {
-		if ((s64)*p_high << vol->cluster_size_bits >
+	max_size <<= 3;
+	while (1) {
+		if (++*p_high >= 0x7fff) {
+			ntfs_error(__FUNCTION__ "(): Unsorted 10: Directory "
+					"inode 0x%lx overflowed the maximum "
+					"number of index allocation buffers "
+					"the driver can cope with. Pretending "
+					"to be at end of directory.\n",
+					ino->i_number);
+			goto fake_eod;
+		}
+		if (*p_high > max_size || (s64)*p_high << ibs_bits >
 				attr->initialized) {
+fake_eod:
 			/* No more index records. */
 			*p_high = 0x7fff;
+			*p_low = 0;
 			ntfs_free(buf);
-			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 10: "
-					"No more index records. Returning 0, "
-					"p_high 0x7fff, p_low 0x%x.\n", *p_low);
+			ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted "
+					"10.5: No more index records. "
+					"Returning 0, p_high 0x7fff, p_low "
+					"0.\n");
 			return 0;
 		}
-		*p_high += ino->u.index.clusters_per_record;
-		byte = *p_high / ino->u.index.clusters_per_record - 1;
+		byte = (ntfs_cluster_t)(*p_high - 1);
 		bit = 1 << (byte & 7);
-		byte = byte >> 3;
-	} while (!(buf[byte] & bit));
+		byte >>= 3;
+		if ((buf[byte] & bit))
+			break;
+	};
 	ntfs_debug(DEBUG_DIR3, __FUNCTION__ "(): Unsorted 11: Done. "
 			"Returning 0, p_high 0x%x, p_low 0x%x.\n", *p_high,
 			*p_low);
 	ntfs_free(buf);
 	return 0;
 read_err_ret:
-	if (!error)
-		error = -EIO;
+	if (!err)
+		err = -EIO;
 	ntfs_error(__FUNCTION__ "(): Read failed. Returning error code %i.\n",
-			error);
+			err);
 	ntfs_free(buf);
-	return error;
+	return err;
 }
 
 int ntfs_dir_add(ntfs_inode *dir, ntfs_inode *new, ntfs_attribute *name)
diff -urN linux-2.4.10-pre8/fs/ntfs/fs.c linux/fs/ntfs/fs.c
--- linux-2.4.10-pre8/fs/ntfs/fs.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/ntfs/fs.c	Mon Dec  3 23:09:49 2001
@@ -192,23 +192,25 @@
 	default:
 		BUG();
 	}
-	if (ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52),
-			name_len, &nf->name, &nf->namelen)) {
+	err = ntfs_encodeuni(NTFS_INO2VOL(nf->dir), (ntfs_u16*)(entry + 0x52),
+			name_len, &nf->name, &nf->namelen);
+	if (err) {
 		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping "
 				"unrepresentable file.\n");
-		if (nf->name)
-			ntfs_free(nf->name);
-		return 0;
+		err = 0;
+		goto err_ret;
 	}
 	if (!show_sys_files && inum < 0x10UL) {
 		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping system "
 				"file (%s).\n", nf->name);
-		return 0;
+		err = 0;
+		goto err_ret;
 	}
 	/* Do not return ".", as this is faked. */
 	if (nf->namelen == 1 && nf->name[0] == '.') {
 		ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): Skipping \".\"\n");
-		return 0;
+		err = 0;
+		goto err_ret;
 	}
 	nf->name[nf->namelen] = 0;
 	if (flags & 0x10000000) /* FILE_ATTR_DUP_FILE_NAME_INDEX_PRESENT */
@@ -229,7 +231,10 @@
 			(loff_t)(nf->ph << 16) | nf->pl, inum, file_type);
 	if (err)
 		nf->ret_code = err;
+err_ret:
+	nf->namelen = 0;
 	ntfs_free(nf->name);
+	nf->name = NULL;
 	return err;
 }
 
@@ -292,7 +297,7 @@
 				"0x%Lx.\n", (loff_t)(cb.ph << 16) | cb.pl);
 		err = ntfs_getdir_unsorted(NTFS_LINO2NINO(dir), &cb.ph, &cb.pl,
 				ntfs_printcb, &cb);
-	} while (!err && cb.ph < 0x7fff);
+	} while (!err && !cb.ret_code && cb.ph < 0x7fff);
 	filp->f_pos = (loff_t)(cb.ph << 16) | cb.pl;
 	ntfs_debug(DEBUG_OTHER, __FUNCTION__ "(): After ntfs_getdir_unsorted()"
 			" calls, f_pos 0x%Lx.\n", filp->f_pos);
@@ -520,18 +525,22 @@
 	struct inode *res = 0;
 	char *item = 0;
 	ntfs_iterate_s walk;
-	int error;
+	int err;
 	
 	ntfs_debug(DEBUG_NAME1, __FUNCTION__ "(): Looking up %s in directory "
 			"ino 0x%x.\n", d->d_name.name, (unsigned)dir->i_ino);
+	walk.name = NULL;
+	walk.namelen = 0;
 	/* Convert to wide string. */
-	error = ntfs_decodeuni(NTFS_INO2VOL(dir), (char*)d->d_name.name,
+	err = ntfs_decodeuni(NTFS_INO2VOL(dir), (char*)d->d_name.name,
 			       d->d_name.len, &walk.name, &walk.namelen);
-	if (error)
-		return ERR_PTR(error);
+	if (err)
+		goto err_ret;
 	item = ntfs_malloc(ITEM_SIZE);
-	if (!item)
-		return ERR_PTR(-ENOMEM);
+	if (!item) {
+		err = -ENOMEM;
+		goto err_ret;
+	}
 	/* ntfs_getdir will place the directory entry into item, and the first
 	 * long long is the MFT record number. */
 	walk.type = BY_NAME;
@@ -544,6 +553,9 @@
 	ntfs_free(walk.name);
 	/* Always return success, the dcache will handle negative entries. */
 	return NULL;
+err_ret:
+	ntfs_free(walk.name);
+	return ERR_PTR(err);
 }
 
 static struct file_operations ntfs_file_operations = {
diff -urN linux-2.4.10-pre8/fs/ntfs/support.c linux/fs/ntfs/support.c
--- linux-2.4.10-pre8/fs/ntfs/support.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/ntfs/support.c	Mon Dec  3 23:09:49 2001
@@ -242,8 +242,8 @@
 			if (chl > 1) {
 				buf = ntfs_malloc(*out_len + chl - 1);
 				if (!buf) {
-					ntfs_free(result);
-					return -ENOMEM;
+					i = -ENOMEM;
+					goto err_ret;
 				}
 				memcpy(buf, result, o);
 				ntfs_free(result);
@@ -259,13 +259,18 @@
 					"to chosen character set. Remount "
 					"with utf8 encoding and this should "
 					"work.\n");
-			ntfs_free(result);
-			return -EILSEQ;
+			i = -EILSEQ;
+			goto err_ret;
 		}
 	}
 	result[*out_len] = '\0';
 	*out = result;
 	return 0;
+err_ret:
+	ntfs_free(result);
+	*out_len = 0;
+	*out = NULL;
+	return i;
 }
 
 int ntfs_dupmap2uni(ntfs_volume *vol, char* in, int in_len, ntfs_u16 **out,
@@ -276,8 +281,10 @@
 	struct nls_table *nls = vol->nls_map;
 
 	*out = result = ntfs_malloc(2 * in_len);
-	if (!result)
+	if (!result) {
+		*out_len = 0;
 		return -ENOMEM;
+	}
 	*out_len = in_len;
 	for (i = o = 0; i < in_len; i++, o++) {
 		wchar_t uni;
@@ -285,22 +292,25 @@
 
 		charlen = nls->char2uni(&in[i], in_len - i, &uni);
 		if (charlen < 0) {
-			printk(KERN_ERR "NTFS: Name contains a character that "
-					"cannot be converted to Unicode.\n");
-			ntfs_free(result);
-			return charlen;
+			i = charlen;
+			goto err_ret;
 		}
 		*out_len -= charlen - 1;
 		i += charlen - 1;
 		/* FIXME: Byte order? */
 		result[o] = uni;
 		if (!result[o]) {
-			printk(KERN_ERR "NTFS: Name contains a character that "
-					"cannot be converted to Unicode.\n");
-			ntfs_free(result);
-			return -EILSEQ;
+			i = -EILSEQ;
+			goto err_ret;
 		}
 	}
 	return 0;
+err_ret:
+	printk(KERN_ERR "NTFS: Name contains a character that cannot be "
+			"converted to Unicode.\n");
+	ntfs_free(result);
+	*out_len = 0;
+	*out = NULL;
+	return i;
 }
 
diff -urN linux-2.4.10-pre8/fs/proc/kcore.c linux/fs/proc/kcore.c
--- linux-2.4.10-pre8/fs/proc/kcore.c	Mon Jan 15 16:54:20 2001
+++ linux/fs/proc/kcore.c	Mon Dec  3 23:09:49 2001
@@ -42,7 +42,7 @@
 	ssize_t count1;
 	char * pnt;
 	struct user dump;
-#if defined (__i386__) || defined (__mc68000__)
+#if defined (__i386__) || defined (__mc68000__) || defined(__x86_64__)
 #	define FIRST_MAPPED	PAGE_SIZE	/* we don't have page 0 mapped on x86.. */
 #else
 #	define FIRST_MAPPED	0
@@ -51,7 +51,7 @@
 	memset(&dump, 0, sizeof(struct user));
 	dump.magic = CMAGIC;
 	dump.u_dsize = (virt_to_phys(high_memory) >> PAGE_SHIFT);
-#if defined (__i386__)
+#if defined (__i386__) || defined(__x86_64__)
 	dump.start_code = PAGE_OFFSET;
 #endif
 #ifdef __alpha__
@@ -361,7 +361,7 @@
 		read_unlock(&vmlist_lock);
 
 	/* where page 0 not mapped, write zeros into buffer */
-#if defined (__i386__) || defined (__mc68000__)
+#if defined (__i386__) || defined (__mc68000__) || defined(__x86_64__)
 	if (*fpos < PAGE_SIZE + elf_buflen) {
 		/* work out how much to clear */
 		tsz = PAGE_SIZE + elf_buflen - *fpos;
diff -urN linux-2.4.10-pre8/fs/stat.c linux/fs/stat.c
--- linux-2.4.10-pre8/fs/stat.c	Wed Apr 18 11:49:12 2001
+++ linux/fs/stat.c	Mon Dec  3 23:09:49 2001
@@ -26,7 +26,7 @@
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -127,7 +127,7 @@
 }
 
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
 /*
  * For backward compatibility?  Maybe this should be moved
  * into arch/i386 instead?
@@ -163,7 +163,7 @@
 	return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -201,7 +201,7 @@
 	return error;
 }
 
-#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__)
+#if !defined(__alpha__) && !defined(__sparc__) && !defined(__ia64__) && !defined(CONFIG_ARCH_S390) && !defined(__hppa__) && !defined(__x86_64__)
 
 /*
  * For backward compatibility?  Maybe this should be moved
@@ -268,7 +268,7 @@
 
 
 /* ---------- LFS-64 ----------- */
-#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(CONFIG_ARCH_S390X)
+#if !defined(__alpha__) && !defined(__ia64__) && !defined(__mips64) && !defined(__x86_64__) && !defined(CONFIG_ARCH_S390X)
 
 static long cp_new_stat64(struct inode * inode, struct stat64 * statbuf)
 {
diff -urN linux-2.4.10-pre8/fs/super.c linux/fs/super.c
--- linux-2.4.10-pre8/fs/super.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/super.c	Mon Dec  3 23:09:49 2001
@@ -410,6 +410,7 @@
 	mnt->mnt_root = dget(root);
 	mnt->mnt_mountpoint = mnt->mnt_root;
 	mnt->mnt_parent = mnt;
+	mnt->mnt_flags = old->mnt_flags;
 
 	atomic_inc(&sb->s_active);
 out:
@@ -520,16 +521,17 @@
 	int flag;
 	char *str;
 } fs_info[] = {
-	{ MS_NOEXEC, ",noexec" },
-	{ MS_NOSUID, ",nosuid" },
-	{ MS_NODEV, ",nodev" },
 	{ MS_SYNCHRONOUS, ",sync" },
 	{ MS_MANDLOCK, ",mand" },
 	{ MS_NOATIME, ",noatime" },
 	{ MS_NODIRATIME, ",nodiratime" },
-#ifdef MS_NOSUB			/* Can't find this except in mount.c */
-	{ MS_NOSUB, ",nosub" },
-#endif
+	{ 0, NULL }
+};
+
+static struct proc_fs_info mnt_info[] = {
+	{ MNT_NOSUID, ",nosuid" },
+	{ MNT_NODEV, ",nodev" },
+	{ MNT_NOEXEC, ",noexec" },
 	{ 0, NULL }
 };
 
@@ -580,6 +582,10 @@
 			if (tmp->mnt_sb->s_flags & fs_infop->flag)
 				MANGLE(fs_infop->str);
 		}
+		for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) {
+			if (tmp->mnt_flags & fs_infop->flag)
+				MANGLE(fs_infop->str);
+		}
 		if (!strcmp("nfs", tmp->mnt_sb->s_type->name)) {
 			nfss = &tmp->mnt_sb->u.nfs_sb.s_server;
 			len += sprintf(buf+len, ",v%d", nfss->rpc_ops->version);
@@ -917,7 +923,7 @@
 	if (!S_ISBLK(inode->i_mode))
 		goto out;
 	error = -EACCES;
-	if (IS_NODEV(inode))
+	if (nd.mnt->mnt_flags & MNT_NODEV)
 		goto out;
 	bdev = inode->i_bdev;
 	bdops = devfs_get_ops ( devfs_get_handle_from_inode (inode) );
@@ -1382,7 +1388,7 @@
  * on it - tough luck.
  */
 
-static int do_remount(struct nameidata *nd, int flags, char *data)
+static int do_remount(struct nameidata *nd,int flags,int mnt_flags,char *data)
 {
 	int err;
 	struct super_block * sb = nd->mnt->mnt_sb;
@@ -1395,6 +1401,8 @@
 
 	down_write(&sb->s_umount);
 	err = do_remount_sb(sb, flags, data);
+	if (!err)
+		nd->mnt->mnt_flags=mnt_flags;
 	up_write(&sb->s_umount);
 	return err;
 }
@@ -1463,7 +1471,7 @@
 }
 
 static int do_add_mount(struct nameidata *nd, char *type, int flags,
-			char *name, void *data)
+			int mnt_flags, char *name, void *data)
 {
 	struct vfsmount *mnt = do_kern_mount(type, flags, name, data);
 	int retval = PTR_ERR(mnt);
@@ -1471,6 +1479,8 @@
 	if (IS_ERR(mnt))
 		goto out;
 
+	mnt->mnt_flags = mnt_flags;
+
 	down(&mount_sem);
 	/* Something was mounted here while we slept */
 	while(d_mountpoint(nd->dentry) && follow_down(&nd->mnt, &nd->dentry))
@@ -1539,6 +1549,7 @@
 {
 	struct nameidata nd;
 	int retval = 0;
+	int mnt_flags = 0;
 
 	/* Discard magic */
 	if ((flags & MS_MGC_MSK) == MS_MGC_VAL)
@@ -1551,6 +1562,15 @@
 	if (dev_name && !memchr(dev_name, 0, PAGE_SIZE))
 		return -EINVAL;
 
+	/* Separate the per-mountpoint flags */
+	if (flags & MS_NOSUID)
+		mnt_flags |= MNT_NOSUID;
+	if (flags & MS_NODEV)
+		mnt_flags |= MNT_NODEV;
+	if (flags & MS_NOEXEC)
+		mnt_flags |= MNT_NOEXEC;
+	flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV);
+
 	/* ... and get the mountpoint */
 	if (path_init(dir_name, LOOKUP_FOLLOW|LOOKUP_POSITIVE, &nd))
 		retval = path_walk(dir_name, &nd);
@@ -1558,12 +1578,12 @@
 		return retval;
 
 	if (flags & MS_REMOUNT)
-		retval = do_remount(&nd, flags&~MS_REMOUNT,
+		retval = do_remount(&nd, flags&~MS_REMOUNT, mnt_flags,
 				  (char *)data_page);
 	else if (flags & MS_BIND)
 		retval = do_loopback(&nd, dev_name);
 	else
-		retval = do_add_mount(&nd, type_page, flags,
+		retval = do_add_mount(&nd, type_page, flags, mnt_flags,
 				      dev_name, data_page);
 	path_release(&nd);
 	return retval;
diff -urN linux-2.4.10-pre8/fs/ufs/balloc.c linux/fs/ufs/balloc.c
--- linux-2.4.10-pre8/fs/ufs/balloc.c	Mon Dec  3 23:09:38 2001
+++ linux/fs/ufs/balloc.c	Mon Dec  3 23:09:49 2001
@@ -271,6 +271,7 @@
 		if (!tmp) {
 			ufs_error (sb, "ufs_new_fragments", "internal error, "
 				"fragment %u, tmp %u\n", fragment, tmp);
+			unlock_super (sb);
 			return (unsigned)-1;
 		}
 		if (fragment < inode->u.ufs_i.i_lastfrag) {
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_apecs.h linux/include/asm-alpha/core_apecs.h
--- linux-2.4.10-pre8/include/asm-alpha/core_apecs.h	Fri Mar 17 13:01:37 2000
+++ linux/include/asm-alpha/core_apecs.h	Mon Dec  3 23:09:49 2001
@@ -495,11 +495,18 @@
 	*(vulp)addr = b;
 }
 
-__EXTERN_INLINE unsigned long apecs_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long apecs_ioremap(unsigned long addr,
+					    unsigned long size
+					    __attribute__((unused)))
 {
 	return addr + APECS_DENSE_MEM;
 }
 
+__EXTERN_INLINE void apecs_iounmap(unsigned addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int apecs_is_ioaddr(unsigned long addr)
 {
 	return addr >= IDENT_ADDR + 0x180000000UL;
@@ -525,7 +532,8 @@
 #define __writew(x,a)		apecs_writew((x),(unsigned long)(a))
 #define __writel(x,a)		apecs_writel((x),(unsigned long)(a))
 #define __writeq(x,a)		apecs_writeq((x),(unsigned long)(a))
-#define __ioremap(a)		apecs_ioremap((unsigned long)(a))
+#define __ioremap(a,s)		apecs_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		apecs_iounmap((unsigned long)(a))
 #define __is_ioaddr(a)		apecs_is_ioaddr((unsigned long)(a))
 
 #define __raw_readl(a)		__readl(a)
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_cia.h linux/include/asm-alpha/core_cia.h
--- linux-2.4.10-pre8/include/asm-alpha/core_cia.h	Sun Mar 19 10:26:21 2000
+++ linux/include/asm-alpha/core_cia.h	Mon Dec  3 23:09:49 2001
@@ -470,11 +470,18 @@
 	*(vulp)addr = b;
 }
 
-__EXTERN_INLINE unsigned long cia_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long cia_ioremap(unsigned long addr,
+					  unsigned long size
+					  __attribute__((unused)))
 {
 	return addr + CIA_DENSE_MEM;
 }
 
+__EXTERN_INLINE void cia_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE unsigned long cia_bwx_readb(unsigned long addr)
 {
 	return __kernel_ldbu(*(vucp)addr);
@@ -515,11 +522,17 @@
 	*(vulp)addr = b;
 }
 
-__EXTERN_INLINE unsigned long cia_bwx_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long cia_bwx_ioremap(unsigned long addr,
+					      unsigned long size)
 {
 	return addr + CIA_BW_MEM;
 }
 
+__EXTERN_INLINE void cia_bwx_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int cia_is_ioaddr(unsigned long addr)
 {
 	return addr >= IDENT_ADDR + 0x8000000000UL;
@@ -548,7 +561,8 @@
 # define __writew(x,a)		cia_bwx_writew((x),(unsigned long)(a))
 # define __writel(x,a)		cia_bwx_writel((x),(unsigned long)(a))
 # define __writeq(x,a)		cia_bwx_writeq((x),(unsigned long)(a))
-# define __ioremap(a)		cia_bwx_ioremap((unsigned long)(a))
+# define __ioremap(a,s)		cia_bwx_ioremap((unsigned long)(a),(s))
+# define __iounmap(a)           cia_bwx_iounmap((unsigned long)(a))
 # define inb(p)			__inb(p)
 # define inw(p)			__inw(p)
 # define inl(p)			__inl(p)
@@ -578,7 +592,8 @@
 # define __writew(x,a)		cia_writew((x),(unsigned long)(a))
 # define __writel(x,a)		cia_writel((x),(unsigned long)(a))
 # define __writeq(x,a)		cia_writeq((x),(unsigned long)(a))
-# define __ioremap(a)		cia_ioremap((unsigned long)(a))
+# define __ioremap(a,s)		cia_ioremap((unsigned long)(a),(s))
+# define __iounmap(a)           cia_iounmap((unsigned long)(a))
 # define __raw_readl(a)		__readl(a)
 # define __raw_readq(a)		__readq(a)
 # define __raw_writel(v,a)	__writel((v),(a))
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_irongate.h linux/include/asm-alpha/core_irongate.h
--- linux-2.4.10-pre8/include/asm-alpha/core_irongate.h	Mon Aug 28 21:21:57 2000
+++ linux/include/asm-alpha/core_irongate.h	Mon Dec  3 23:09:49 2001
@@ -267,10 +267,8 @@
 	*(vulp)addr = b;
 }
 
-__EXTERN_INLINE unsigned long irongate_ioremap(unsigned long addr)
-{
-	return addr + IRONGATE_MEM;
-}
+extern unsigned long irongate_ioremap(unsigned long addr, unsigned long size);
+extern void irongate_iounmap(unsigned long addr);
 
 __EXTERN_INLINE int irongate_is_ioaddr(unsigned long addr)
 {
@@ -298,7 +296,8 @@
 #define __writew(x,a)		irongate_writew((x),(unsigned long)(a))
 #define __writel(x,a)		irongate_writel((x),(unsigned long)(a))
 #define __writeq(x,a)		irongate_writeq((x),(unsigned long)(a))
-#define __ioremap(a)		irongate_ioremap((unsigned long)(a))
+#define __ioremap(a,s)		irongate_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		irongate_iounmap((unsigned long)(a))
 #define __is_ioaddr(a)		irongate_is_ioaddr((unsigned long)(a))
 
 #define inb(p)			__inb(p)
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_lca.h linux/include/asm-alpha/core_lca.h
--- linux-2.4.10-pre8/include/asm-alpha/core_lca.h	Fri Mar 17 13:01:38 2000
+++ linux/include/asm-alpha/core_lca.h	Mon Dec  3 23:09:49 2001
@@ -344,11 +344,18 @@
 	*(vulp)addr = b;
 }
 
-__EXTERN_INLINE unsigned long lca_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long lca_ioremap(unsigned long addr,
+					  unsigned long size
+					  __attribute__((unused)))
 {
 	return addr + LCA_DENSE_MEM;
 }
 
+__EXTERN_INLINE void lca_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int lca_is_ioaddr(unsigned long addr)
 {
 	return addr >= IDENT_ADDR + 0x120000000UL;
@@ -374,7 +381,8 @@
 #define __writew(x,a)		lca_writew((x),(unsigned long)(a))
 #define __writel(x,a)		lca_writel((x),(unsigned long)(a))
 #define __writeq(x,a)		lca_writeq((x),(unsigned long)(a))
-#define __ioremap(a)		lca_ioremap((unsigned long)(a))
+#define __ioremap(a,s)		lca_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		lca_iounmap((unsigned long)(a))
 #define __is_ioaddr(a)		lca_is_ioaddr((unsigned long)(a))
 
 #define __raw_readl(a)		__readl(a)
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_mcpcia.h linux/include/asm-alpha/core_mcpcia.h
--- linux-2.4.10-pre8/include/asm-alpha/core_mcpcia.h	Fri Mar 17 13:01:38 2000
+++ linux/include/asm-alpha/core_mcpcia.h	Mon Dec  3 23:09:49 2001
@@ -326,11 +326,18 @@
  *
  */
 
-__EXTERN_INLINE unsigned long mcpcia_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long mcpcia_ioremap(unsigned long addr,
+					     unsigned long size
+					     __attribute__((unused)))
 {
 	return addr + MCPCIA_MEM_BIAS;
 }
 
+__EXTERN_INLINE void mcpcia_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int mcpcia_is_ioaddr(unsigned long addr)
 {
 	return addr >= MCPCIA_SPARSE(0);
@@ -452,7 +459,8 @@
 #define __writew(x,a)		mcpcia_writew((x),(unsigned long)(a))
 #define __writel(x,a)		mcpcia_writel((x),(unsigned long)(a))
 #define __writeq(x,a)		mcpcia_writeq((x),(unsigned long)(a))
-#define __ioremap(a)		mcpcia_ioremap((unsigned long)(a))
+#define __ioremap(a,s)		mcpcia_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		mcpcia_iounmap((unsigned long)(a))
 #define __is_ioaddr(a)		mcpcia_is_ioaddr((unsigned long)(a))
 
 #define __raw_readl(a)		__readl(a)
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_polaris.h linux/include/asm-alpha/core_polaris.h
--- linux-2.4.10-pre8/include/asm-alpha/core_polaris.h	Fri Mar 17 13:01:38 2000
+++ linux/include/asm-alpha/core_polaris.h	Mon Dec  3 23:09:49 2001
@@ -153,11 +153,18 @@
 	*(vulp)addr = b;
 }
 
-__EXTERN_INLINE unsigned long polaris_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long polaris_ioremap(unsigned long addr,
+					      unsigned long size
+					      __attribute__((unused)))
 {
 	return addr + POLARIS_DENSE_MEM_BASE;
 }
 
+__EXTERN_INLINE void polaris_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int polaris_is_ioaddr(unsigned long addr)
 {
 	return addr >= POLARIS_SPARSE_MEM_BASE;
@@ -184,7 +191,8 @@
 #define __writew(x,a)		polaris_writew((x),(unsigned long)(a))
 #define __writel(x,a)		polaris_writel((x),(unsigned long)(a))
 #define __writeq(x,a)		polaris_writeq((x),(unsigned long)(a))
-#define __ioremap(a)		polaris_ioremap((unsigned long)(a))
+#define __ioremap(a,s)		polaris_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		polaris_iounmap((unsigned long)(a))
 #define __is_ioaddr(a)		polaris_is_ioaddr((unsigned long)(a))
 
 #define inb(p)			__inb(p)
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_t2.h linux/include/asm-alpha/core_t2.h
--- linux-2.4.10-pre8/include/asm-alpha/core_t2.h	Fri Mar 17 13:01:38 2000
+++ linux/include/asm-alpha/core_t2.h	Mon Dec  3 23:09:49 2001
@@ -501,11 +501,18 @@
 	*(vuip)(work + (4 << 5)) = b >> 32;
 }
 
-__EXTERN_INLINE unsigned long t2_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long t2_ioremap(unsigned long addr, 
+					 unsigned long size
+					 __attribute__((unused)))
 {
 	return addr;
 }
 
+__EXTERN_INLINE void t2_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int t2_is_ioaddr(unsigned long addr)
 {
 	return (long)addr >= 0;
@@ -530,7 +537,8 @@
 #define __writew(x,a)		t2_writew((x),(unsigned long)(a))
 #define __writel(x,a)		t2_writel((x),(unsigned long)(a))
 #define __writeq(x,a)		t2_writeq((x),(unsigned long)(a))
-#define __ioremap(a)		t2_ioremap((unsigned long)(a))
+#define __ioremap(a,s)		t2_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		t2_iounmap((unsigned long)(a))
 #define __is_ioaddr(a)		t2_is_ioaddr((unsigned long)(a))
 
 #endif /* __WANT_IO_DEF */
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_titan.h linux/include/asm-alpha/core_titan.h
--- linux-2.4.10-pre8/include/asm-alpha/core_titan.h	Mon Jun 19 17:59:33 2000
+++ linux/include/asm-alpha/core_titan.h	Mon Dec  3 23:09:49 2001
@@ -423,11 +423,18 @@
  * Memory functions.  all accesses are done through linear space.
  */
 
-__EXTERN_INLINE unsigned long titan_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long titan_ioremap(unsigned long addr, 
+					    unsigned long size
+					    __attribute__((unused)))
 {
 	return addr + TITAN_MEM_BIAS;
 }
 
+__EXTERN_INLINE void titan_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int titan_is_ioaddr(unsigned long addr)
 {
 	return addr >= TITAN_BASE;
@@ -480,29 +487,30 @@
 
 #ifdef __WANT_IO_DEF
 
-#define __inb		titan_inb
-#define __inw		titan_inw
-#define __inl		titan_inl
-#define __outb		titan_outb
-#define __outw		titan_outw
-#define __outl		titan_outl
-#define __readb		titan_readb
-#define __readw		titan_readw
-#define __writeb	titan_writeb
-#define __writew	titan_writew
-#define __readl		titan_readl
-#define __readq		titan_readq
-#define __writel	titan_writel
-#define __writeq	titan_writeq
-#define __ioremap	titan_ioremap
-#define __is_ioaddr	titan_is_ioaddr
-
-#define inb(port) 	__inb((port))
-#define inw(port) 	__inw((port))
-#define inl(port) 	__inl((port))
-#define outb(v, port) 	__outb((v),(port))
-#define outw(v, port) 	__outw((v),(port))
-#define outl(v, port) 	__outl((v),(port))
+#define __inb(p)		titan_inb((unsigned long)(p))
+#define __inw(p)		titan_inw((unsigned long)(p))
+#define __inl(p)		titan_inl((unsigned long)(p))
+#define __outb(x,p)		titan_outb((x),(unsigned long)(p))
+#define __outw(x,p)		titan_outw((x),(unsigned long)(p))
+#define __outl(x,p)		titan_outl((x),(unsigned long)(p))
+#define __readb(a)		titan_readb((unsigned long)(a))
+#define __readw(a)		titan_readw((unsigned long)(a))
+#define __readl(a)		titan_readl((unsigned long)(a))
+#define __readq(a)		titan_readq((unsigned long)(a))
+#define __writeb(x,a)		titan_writeb((x),(unsigned long)(a))
+#define __writew(x,a)		titan_writew((x),(unsigned long)(a))
+#define __writel(x,a)		titan_writel((x),(unsigned long)(a))
+#define __writeq(x,a)		titan_writeq((x),(unsigned long)(a))
+#define __ioremap(a,s)		titan_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		titan_iounmap((unsigned long)(a))
+#define __is_ioaddr(a)		titan_is_ioaddr((unsigned long)(a))
+
+#define inb(port) 		__inb((port))
+#define inw(port) 		__inw((port))
+#define inl(port) 		__inl((port))
+#define outb(v, port) 		__outb((v),(port))
+#define outw(v, port) 		__outw((v),(port))
+#define outl(v, port) 		__outl((v),(port))
 
 #define __raw_readb(a)		__readb((unsigned long)(a))
 #define __raw_readw(a)		__readw((unsigned long)(a))
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_tsunami.h linux/include/asm-alpha/core_tsunami.h
--- linux-2.4.10-pre8/include/asm-alpha/core_tsunami.h	Thu May 24 15:24:37 2001
+++ linux/include/asm-alpha/core_tsunami.h	Mon Dec  3 23:09:49 2001
@@ -352,11 +352,18 @@
  * Memory functions.  all accesses are done through linear space.
  */
 
-__EXTERN_INLINE unsigned long tsunami_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long tsunami_ioremap(unsigned long addr, 
+					      unsigned long size
+					      __attribute__((unused)))
 {
 	return addr + TSUNAMI_MEM_BIAS;
 }
 
+__EXTERN_INLINE void tsunami_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int tsunami_is_ioaddr(unsigned long addr)
 {
 	return addr >= TSUNAMI_BASE;
@@ -423,7 +430,8 @@
 #define __writew(x,a)		tsunami_writew((x),(unsigned long)(a))
 #define __writel(x,a)		tsunami_writel((x),(unsigned long)(a))
 #define __writeq(x,a)		tsunami_writeq((x),(unsigned long)(a))
-#define __ioremap(a)		tsunami_ioremap((unsigned long)(a))
+#define __ioremap(a,s)		tsunami_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		tsunami_iounmap((unsigned long)(a))
 #define __is_ioaddr(a)		tsunami_is_ioaddr((unsigned long)(a))
 
 #define inb(p)			__inb(p)
diff -urN linux-2.4.10-pre8/include/asm-alpha/core_wildfire.h linux/include/asm-alpha/core_wildfire.h
--- linux-2.4.10-pre8/include/asm-alpha/core_wildfire.h	Mon Jun 19 17:59:33 2000
+++ linux/include/asm-alpha/core_wildfire.h	Mon Dec  3 23:09:49 2001
@@ -326,11 +326,18 @@
  * Memory functions.  all accesses are done through linear space.
  */
 
-__EXTERN_INLINE unsigned long wildfire_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long wildfire_ioremap(unsigned long addr, 
+					       unsigned long size
+					       __attribute__((unused)))
 {
 	return addr + WILDFIRE_MEM_BIAS;
 }
 
+__EXTERN_INLINE void wildfire_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int wildfire_is_ioaddr(unsigned long addr)
 {
 	return addr >= WILDFIRE_BASE;
@@ -397,7 +404,8 @@
 #define __writew(x,a)		wildfire_writew((x),(unsigned long)(a))
 #define __writel(x,a)		wildfire_writel((x),(unsigned long)(a))
 #define __writeq(x,a)		wildfire_writeq((x),(unsigned long)(a))
-#define __ioremap(a)		wildfire_ioremap((unsigned long)(a))
+#define __ioremap(a,s)		wildfire_ioremap((unsigned long)(a),(s))
+#define __iounmap(a)		wildfire_iounmap((unsigned long)(a))
 #define __is_ioaddr(a)		wildfire_is_ioaddr((unsigned long)(a))
 
 #define inb(p)			__inb(p)
diff -urN linux-2.4.10-pre8/include/asm-alpha/hw_irq.h linux/include/asm-alpha/hw_irq.h
--- linux-2.4.10-pre8/include/asm-alpha/hw_irq.h	Mon Feb 28 07:18:20 2000
+++ linux/include/asm-alpha/hw_irq.h	Mon Dec  3 23:09:49 2001
@@ -5,6 +5,8 @@
 
 static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) {}
 
+extern volatile unsigned long irq_err_count;
+
 #ifdef CONFIG_ALPHA_GENERIC
 #define ACTUAL_NR_IRQS	alpha_mv.nr_irqs
 #else
diff -urN linux-2.4.10-pre8/include/asm-alpha/io.h linux/include/asm-alpha/io.h
--- linux-2.4.10-pre8/include/asm-alpha/io.h	Fri Apr 13 20:26:07 2001
+++ linux/include/asm-alpha/io.h	Mon Dec  3 23:09:49 2001
@@ -127,7 +127,8 @@
 # define __writel(v,a)	alpha_mv.mv_writel((v),(unsigned long)(a))
 # define __writeq(v,a)	alpha_mv.mv_writeq((v),(unsigned long)(a))
 
-# define __ioremap(a)	alpha_mv.mv_ioremap((unsigned long)(a))
+# define __ioremap(a,s)	alpha_mv.mv_ioremap((unsigned long)(a),(s))
+# define __iounmap(a)   alpha_mv.mv_iounmap((unsigned long)(a))
 # define __is_ioaddr(a)	alpha_mv.mv_is_ioaddr((unsigned long)(a))
 
 # define inb		__inb
@@ -280,15 +281,24 @@
  * discontinuities are all across busses, so we need not care for that
  * for any one device.
  *
+ * The DRM drivers need to be able to map contiguously a (potentially)
+ * discontiguous set of I/O pages. This set of pages is scatter-gather
+ * mapped contiguously from the perspective of the bus, but we can't
+ * directly access DMA addresses from the CPU, these addresses need to
+ * have a real ioremap. Therefore, iounmap and the size argument to
+ * ioremap are needed to give the platforms the ability to fully implement
+ * ioremap.
+ *
  * Map the I/O space address into the kernel's virtual address space.
  */
 static inline void * ioremap(unsigned long offset, unsigned long size)
 {
-	return (void *) __ioremap(offset);
+	return (void *) __ioremap(offset, size);
 } 
 
 static inline void iounmap(void *addr)
 {
+	__iounmap(addr);
 }
 
 static inline void * ioremap_nocache(unsigned long offset, unsigned long size)
@@ -444,15 +454,15 @@
  * ISA space is mapped to some machine-specific location on Alpha.
  * Call into the existing hooks to get the address translated.
  */
-#define isa_readb(a)			readb(__ioremap(a))
-#define isa_readw(a)			readw(__ioremap(a))
-#define isa_readl(a)			readl(__ioremap(a))
-#define isa_writeb(b,a)			writeb((b),__ioremap(a))
-#define isa_writew(w,a)			writew((w),__ioremap(a))
-#define isa_writel(l,a)			writel((l),__ioremap(a))
-#define isa_memset_io(a,b,c)		memset_io(__ioremap(a),(b),(c))
-#define isa_memcpy_fromio(a,b,c)	memcpy_fromio((a),__ioremap(b),(c))
-#define isa_memcpy_toio(a,b,c)		memcpy_toio(__ioremap(a),(b),(c))
+#define isa_readb(a)			readb(__ioremap((a),1))
+#define isa_readw(a)			readw(__ioremap((a),2))
+#define isa_readl(a)			readl(__ioremap((a),4))
+#define isa_writeb(b,a)			writeb((b),__ioremap((a),1))
+#define isa_writew(w,a)			writew((w),__ioremap((a),2))
+#define isa_writel(l,a)			writel((l),__ioremap((a),4))
+#define isa_memset_io(a,b,c)		memset_io(__ioremap((a),(c)),(b),(c))
+#define isa_memcpy_fromio(a,b,c)	memcpy_fromio((a),__ioremap((b),(c)),(c))
+#define isa_memcpy_toio(a,b,c)		memcpy_toio(__ioremap((a),(c)),(b),(c))
 
 static inline int
 isa_check_signature(unsigned long io_addr, const unsigned char *signature,
diff -urN linux-2.4.10-pre8/include/asm-alpha/jensen.h linux/include/asm-alpha/jensen.h
--- linux-2.4.10-pre8/include/asm-alpha/jensen.h	Mon Feb  7 20:09:05 2000
+++ linux/include/asm-alpha/jensen.h	Mon Dec  3 23:09:49 2001
@@ -274,11 +274,17 @@
 	*(vuip) (addr + (4 << 7)) = b >> 32;
 }
 
-__EXTERN_INLINE unsigned long jensen_ioremap(unsigned long addr)
+__EXTERN_INLINE unsigned long jensen_ioremap(unsigned long addr, 
+					     unsigned long size)
 {
 	return addr;
 }
 
+__EXTERN_INLINE void jensen_iounmap(unsigned long addr)
+{
+	return;
+}
+
 __EXTERN_INLINE int jensen_is_ioaddr(unsigned long addr)
 {
 	return (long)addr >= 0;
@@ -303,6 +309,7 @@
 #define __writel	jensen_writel
 #define __writeq	jensen_writeq
 #define __ioremap	jensen_ioremap
+#define __iounmap(a)	jensen_iounmap((unsigned long)a)
 #define __is_ioaddr	jensen_is_ioaddr
 
 /*
diff -urN linux-2.4.10-pre8/include/asm-alpha/keyboard.h linux/include/asm-alpha/keyboard.h
--- linux-2.4.10-pre8/include/asm-alpha/keyboard.h	Mon Dec  3 23:09:38 2001
+++ linux/include/asm-alpha/keyboard.h	Mon Dec  3 23:09:49 2001
@@ -13,8 +13,13 @@
 
 #ifdef __KERNEL__
 
-#define KEYBOARD_IRQ			1
-#define DISABLE_KBD_DURING_INTERRUPTS	0
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/kd.h>
+#include <asm/io.h>
+
+#define KEYBOARD_IRQ                    1
+#define DISABLE_KBD_DURING_INTERRUPTS   0
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
diff -urN linux-2.4.10-pre8/include/asm-alpha/machvec.h linux/include/asm-alpha/machvec.h
--- linux-2.4.10-pre8/include/asm-alpha/machvec.h	Fri Mar  2 11:12:07 2001
+++ linux/include/asm-alpha/machvec.h	Mon Dec  3 23:09:49 2001
@@ -61,7 +61,8 @@
 	void (*mv_writel)(unsigned int, unsigned long);
 	void (*mv_writeq)(unsigned long, unsigned long);
 
-	unsigned long (*mv_ioremap)(unsigned long);
+	unsigned long (*mv_ioremap)(unsigned long, unsigned long);
+	void (*mv_iounmap)(unsigned long);
 	int (*mv_is_ioaddr)(unsigned long);
 
 	void (*mv_switch_mm)(struct mm_struct *, struct mm_struct *,
diff -urN linux-2.4.10-pre8/include/asm-alpha/module.h linux/include/asm-alpha/module.h
--- linux-2.4.10-pre8/include/asm-alpha/module.h	Tue Nov  7 10:46:04 2000
+++ linux/include/asm-alpha/module.h	Mon Dec  3 23:09:49 2001
@@ -6,6 +6,23 @@
 
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
-#define module_arch_init(x)	(0)
+#define module_arch_init(x)	alpha_module_init(x)
+#define arch_init_modules(x)	alpha_init_modules(x)
+
+static inline int
+alpha_module_init(struct module *mod)
+{
+        if (!mod_bound(mod->gp - 0x8000, 0, mod)) {
+                printk(KERN_ERR "module_arch_init: mod->gp out of bounds.\n");
+                return 1;
+        }
+	return 0;
+}
+
+static inline void
+alpha_init_modules(struct module *mod)
+{
+	__asm__("stq $29,%0" : "=m" (mod->gp));
+}
 
 #endif /* _ASM_ALPHA_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-alpha/pgtable.h linux/include/asm-alpha/pgtable.h
--- linux-2.4.10-pre8/include/asm-alpha/pgtable.h	Sun Aug 12 10:38:47 2001
+++ linux/include/asm-alpha/pgtable.h	Mon Dec  3 23:09:49 2001
@@ -346,7 +346,7 @@
 #endif
 
 #define io_remap_page_range(start, busaddr, size, prot) \
-	remap_page_range(start, virt_to_phys(__ioremap(busaddr)), size, prot)
+    remap_page_range(start, virt_to_phys(__ioremap(busaddr, size)), size, prot)
 
 #define pte_ERROR(e) \
 	printk("%s:%d: bad pte %016lx.\n", __FILE__, __LINE__, pte_val(e))
@@ -358,5 +358,10 @@
 extern void paging_init(void);
 
 #include <asm-generic/pgtable.h>
+
+/*
+ * No page table caches to initialise
+ */
+#define pgtable_cache_init()	do { } while (0)
 
 #endif /* _ALPHA_PGTABLE_H */
diff -urN linux-2.4.10-pre8/include/asm-alpha/smp.h linux/include/asm-alpha/smp.h
--- linux-2.4.10-pre8/include/asm-alpha/smp.h	Thu May 24 15:20:18 2001
+++ linux/include/asm-alpha/smp.h	Mon Dec  3 23:09:49 2001
@@ -60,6 +60,12 @@
 extern unsigned long cpu_present_mask;
 #define cpu_online_map cpu_present_mask
 
+extern int smp_call_function_on_cpu(void (*func) (void *info), void *info,int retry, int wait, unsigned long cpu);
+
+#else /* CONFIG_SMP */
+
+#define smp_call_function_on_cpu(func,info,retry,wait,cpu)    ({ 0; })
+
 #endif /* CONFIG_SMP */
 
 #define NO_PROC_ID	(-1)
diff -urN linux-2.4.10-pre8/include/asm-arm/module.h linux/include/asm-arm/module.h
--- linux-2.4.10-pre8/include/asm-arm/module.h	Tue Nov  7 10:46:04 2000
+++ linux/include/asm-arm/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_ARM_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-cris/module.h linux/include/asm-cris/module.h
--- linux-2.4.10-pre8/include/asm-cris/module.h	Thu Feb  8 16:32:44 2001
+++ linux/include/asm-cris/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_CRIS_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-i386/module.h linux/include/asm-i386/module.h
--- linux-2.4.10-pre8/include/asm-i386/module.h	Tue Nov  7 10:46:04 2000
+++ linux/include/asm-i386/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_I386_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-i386/semaphore.h linux/include/asm-i386/semaphore.h
--- linux-2.4.10-pre8/include/asm-i386/semaphore.h	Wed Aug 15 14:21:11 2001
+++ linux/include/asm-i386/semaphore.h	Mon Dec  3 23:09:49 2001
@@ -131,6 +131,10 @@
 		:"memory");
 }
 
+/*
+ * Interruptible try to acquire a semaphore.  If we obtained
+ * it, return zero.  If we were interrupted, returns -EINTR
+ */
 static inline int down_interruptible(struct semaphore * sem)
 {
 	int result;
@@ -155,6 +159,10 @@
 	return result;
 }
 
+/*
+ * Non-blockingly attempt to down() a semaphore.
+ * Returns zero if we acquired it
+ */
 static inline int down_trylock(struct semaphore * sem)
 {
 	int result;
diff -urN linux-2.4.10-pre8/include/asm-i386/uaccess.h linux/include/asm-i386/uaccess.h
--- linux-2.4.10-pre8/include/asm-i386/uaccess.h	Mon Dec  3 23:09:38 2001
+++ linux/include/asm-i386/uaccess.h	Mon Dec  3 23:09:49 2001
@@ -6,6 +6,7 @@
  */
 #include <linux/config.h>
 #include <linux/sched.h>
+#include <linux/prefetch.h>
 #include <asm/page.h>
 
 #define VERIFY_READ 0
@@ -545,6 +546,7 @@
 static inline unsigned long
 __constant_copy_to_user(void *to, const void *from, unsigned long n)
 {
+	prefetch(from);
 	if (access_ok(VERIFY_WRITE, to, n))
 		__constant_copy_user(to,from,n);
 	return n;
diff -urN linux-2.4.10-pre8/include/asm-ia64/module.h linux/include/asm-ia64/module.h
--- linux-2.4.10-pre8/include/asm-ia64/module.h	Thu Apr 12 12:16:36 2001
+++ linux/include/asm-ia64/module.h	Mon Dec  3 23:09:49 2001
@@ -14,6 +14,7 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		ia64_module_unmap(x)
 #define module_arch_init(x)	ia64_module_init(x)
+#define arch_init_modules(x)	do { } while (0)
 
 /*
  * This must match in size and layout the data created by
@@ -46,27 +47,27 @@
 
 	if (archdata->unw_table)
 	{
-		printk(KERN_ERR "arch_init_module: archdata->unw_table must be zero.\n");
+		printk(KERN_ERR "module_arch_init: archdata->unw_table must be zero.\n");
 		return 1;
 	}
 	if (!mod_bound(archdata->gp, 0, mod))
 	{
-		printk(KERN_ERR "arch_init_module: archdata->gp out of bounds.\n");
+		printk(KERN_ERR "module_arch_init: archdata->gp out of bounds.\n");
 		return 1;
 	}
 	if (!mod_bound(archdata->unw_start, 0, mod))
 	{
-		printk(KERN_ERR "arch_init_module: archdata->unw_start out of bounds.\n");
+		printk(KERN_ERR "module_arch_init: archdata->unw_start out of bounds.\n");
 		return 1;
 	}
 	if (!mod_bound(archdata->unw_end, 0, mod))
 	{
-		printk(KERN_ERR "arch_init_module: archdata->unw_end out of bounds.\n");
+		printk(KERN_ERR "module_arch_init: archdata->unw_end out of bounds.\n");
 		return 1;
 	}
 	if (!mod_bound(archdata->segment_base, 0, mod))
 	{
-		printk(KERN_ERR "arch_init_module: archdata->unw_table out of bounds.\n");
+		printk(KERN_ERR "module_arch_init: archdata->unw_table out of bounds.\n");
 		return 1;
 	}
 
diff -urN linux-2.4.10-pre8/include/asm-m68k/module.h linux/include/asm-m68k/module.h
--- linux-2.4.10-pre8/include/asm-m68k/module.h	Tue Nov  7 10:46:04 2000
+++ linux/include/asm-m68k/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_M68K_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-ppc/module.h linux/include/asm-ppc/module.h
--- linux-2.4.10-pre8/include/asm-ppc/module.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/module.h	Mon Dec  3 23:09:49 2001
@@ -10,5 +10,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_PPC_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-ppc/uaccess.h linux/include/asm-ppc/uaccess.h
--- linux-2.4.10-pre8/include/asm-ppc/uaccess.h	Mon May 21 15:02:06 2001
+++ linux/include/asm-ppc/uaccess.h	Mon Dec  3 23:09:49 2001
@@ -1,5 +1,5 @@
 /*
- * BK Id: SCCS/s.uaccess.h 1.5 05/17/01 18:14:26 cort
+ * BK Id: SCCS/s.uaccess.h 1.8 09/11/01 18:10:06 paulus
  */
 #ifdef __KERNEL__
 #ifndef _PPC_UACCESS_H
@@ -116,6 +116,7 @@
 	  case 1: __put_user_asm(x,ptr,retval,"stb"); break;	\
 	  case 2: __put_user_asm(x,ptr,retval,"sth"); break;	\
 	  case 4: __put_user_asm(x,ptr,retval,"stw"); break;	\
+	  case 8: __put_user_asm2(x,ptr,retval); break;		\
 	  default: __put_user_bad();				\
 	}							\
 } while (0)
@@ -143,6 +144,22 @@
 		: "=r"(err)					\
 		: "r"(x), "b"(addr), "i"(-EFAULT), "0"(err))
 
+#define __put_user_asm2(x, addr, err)				\
+	__asm__ __volatile__(					\
+		"1:	stw %1,0(%2)\n"				\
+		"2:	stw %1+1,4(%2)\n"				\
+		"3:\n"						\
+		".section .fixup,\"ax\"\n"			\
+		"4:	li %0,%3\n"				\
+		"	b 3b\n"					\
+		".previous\n"					\
+		".section __ex_table,\"a\"\n"			\
+		"	.align 2\n"				\
+		"	.long 1b,4b\n"				\
+		"	.long 2b,4b\n"				\
+		".previous"					\
+		: "=r"(err)					\
+		: "r"(x), "b"(addr), "i"(-EFAULT), "0"(err))
 
 #define __get_user_nocheck(x,ptr,size)				\
 ({								\
@@ -171,6 +188,7 @@
 	  case 1: __get_user_asm(x,ptr,retval,"lbz"); break;	\
 	  case 2: __get_user_asm(x,ptr,retval,"lhz"); break;	\
 	  case 4: __get_user_asm(x,ptr,retval,"lwz"); break;	\
+	  case 8: __get_user_asm2(x, ptr, retval);		\
 	  default: (x) = __get_user_bad();			\
 	}							\
 } while (0)
@@ -189,6 +207,25 @@
 		"	.long 1b,3b\n"			\
 		".previous"				\
 		: "=r"(err), "=r"(x)			\
+		: "b"(addr), "i"(-EFAULT), "0"(err))
+
+#define __get_user_asm2(x, addr, err)			\
+	__asm__ __volatile__(				\
+		"1:	lwz %1,0(%2)\n"			\
+		"2:	lwz %1+1,4(%2)\n"		\
+		"3:\n"					\
+		".section .fixup,\"ax\"\n"		\
+		"4:	li %0,%3\n"			\
+		"	li %1,0\n"			\
+		"	li %1+1,0\n"			\
+		"	b 3b\n"				\
+		".previous\n"				\
+		".section __ex_table,\"a\"\n"		\
+		"	.align 2\n"			\
+		"	.long 1b,4b\n"			\
+		"	.long 2b,4b\n"			\
+		".previous"				\
+		: "=r"(err), "=&r"(x)			\
 		: "b"(addr), "i"(-EFAULT), "0"(err))
 
 /* more complex routines */
diff -urN linux-2.4.10-pre8/include/asm-s390/module.h linux/include/asm-s390/module.h
--- linux-2.4.10-pre8/include/asm-s390/module.h	Tue Nov  7 10:46:04 2000
+++ linux/include/asm-s390/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_S390_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-s390x/module.h linux/include/asm-s390x/module.h
--- linux-2.4.10-pre8/include/asm-s390x/module.h	Tue Feb 13 14:13:44 2001
+++ linux/include/asm-s390x/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_S390_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-sh/module.h linux/include/asm-sh/module.h
--- linux-2.4.10-pre8/include/asm-sh/module.h	Tue Nov  7 10:46:04 2000
+++ linux/include/asm-sh/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_SH_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-sparc/module.h linux/include/asm-sparc/module.h
--- linux-2.4.10-pre8/include/asm-sparc/module.h	Tue Nov  7 10:46:04 2000
+++ linux/include/asm-sparc/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 #define module_map(x)		vmalloc(x)
 #define module_unmap(x)		vfree(x)
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_SPARC_MODULE_H */
diff -urN linux-2.4.10-pre8/include/asm-sparc64/module.h linux/include/asm-sparc64/module.h
--- linux-2.4.10-pre8/include/asm-sparc64/module.h	Thu Nov  9 15:57:41 2000
+++ linux/include/asm-sparc64/module.h	Mon Dec  3 23:09:49 2001
@@ -7,5 +7,6 @@
 extern void * module_map (unsigned long size);
 extern void module_unmap (void *addr);
 #define module_arch_init(x)	(0)
+#define arch_init_modules(x)	do { } while (0)
 
 #endif /* _ASM_SPARC64_MODULE_H */
diff -urN linux-2.4.10-pre8/include/linux/amigaffs.h linux/include/linux/amigaffs.h
--- linux-2.4.10-pre8/include/linux/amigaffs.h	Sun Jul 15 16:34:15 2001
+++ linux/include/linux/amigaffs.h	Mon Dec  3 23:09:49 2001
@@ -121,13 +121,6 @@
 	up(&AFFS_INODE->i_ext_lock);
 }
 
-
-#define MIN(a, b) ({		\
-	typeof(a) _a = (a);	\
-	typeof(b) _b = (b);	\
-	_a < _b ? _a : _b;	\
-})	
-
 #ifdef __LITTLE_ENDIAN
 #define BO_EXBITS	0x18UL
 #elif defined(__BIG_ENDIAN)
diff -urN linux-2.4.10-pre8/include/linux/dp83840.h linux/include/linux/dp83840.h
--- linux-2.4.10-pre8/include/linux/dp83840.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/dp83840.h	Mon Dec  3 23:09:49 2001
@@ -0,0 +1,41 @@
+/*
+ * linux/dp83840.h: definitions for DP83840 MII-compatible transceivers
+ *
+ * Copyright (C) 1996, 1999 David S. Miller (davem@redhat.com)
+ */
+#ifndef __LINUX_DP83840_H
+#define __LINUX_DP83840_H
+
+#include <linux/mii.h>
+
+/*
+ * Data sheets and programming docs for the DP83840 are available at
+ * from http://www.national.com/
+ *
+ * The DP83840 is capable of both 10 and 100Mbps ethernet, in both
+ * half and full duplex mode.  It also supports auto negotiation.
+ *
+ * But.... THIS THING IS A PAIN IN THE ASS TO PROGRAM!
+ * Debugging eeprom burnt code is more fun than programming this chip!
+ */
+
+/* First, the MII register numbers (actually DP83840 register numbers). */
+#define MII_CSCONFIG        0x17        /* CS configuration            */
+
+/* The Carrier Sense config register. */
+#define CSCONFIG_RESV1          0x0001  /* Unused...                   */
+#define CSCONFIG_LED4           0x0002  /* Pin for full-dplx LED4      */
+#define CSCONFIG_LED1           0x0004  /* Pin for conn-status LED1    */
+#define CSCONFIG_RESV2          0x0008  /* Unused...                   */
+#define CSCONFIG_TCVDISAB       0x0010  /* Turns off the transceiver   */
+#define CSCONFIG_DFBYPASS       0x0020  /* Bypass disconnect function  */
+#define CSCONFIG_GLFORCE        0x0040  /* Good link force for 100mbps */
+#define CSCONFIG_CLKTRISTATE    0x0080  /* Tristate 25m clock          */
+#define CSCONFIG_RESV3          0x0700  /* Unused...                   */
+#define CSCONFIG_ENCODE         0x0800  /* 1=MLT-3, 0=binary           */
+#define CSCONFIG_RENABLE        0x1000  /* Repeater mode enable        */
+#define CSCONFIG_TCDISABLE      0x2000  /* Disable timeout counter     */
+#define CSCONFIG_RESV4          0x4000  /* Unused...                   */
+#define CSCONFIG_NDISABLE       0x8000  /* Disable NRZI                */
+
+#endif /* __LINUX_DP83840_H */
diff -urN linux-2.4.10-pre8/include/linux/eeprom.h linux/include/linux/eeprom.h
--- linux-2.4.10-pre8/include/linux/eeprom.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/eeprom.h	Mon Dec  3 23:09:49 2001
@@ -0,0 +1,135 @@
+/* credit winbond-840.c
+ */
+struct eeprom_ops {
+	void	(*set_cs)(void *ee);
+	void	(*clear_cs)(void *ee);
+};
+
+#define EEPOL_EEDI	0x01
+#define EEPOL_EEDO	0x02
+#define EEPOL_EECLK	0x04
+#define EEPOL_EESEL	0x08
+
+struct eeprom {
+	void *dev;
+	struct eeprom_ops *ops;
+
+	long		addr;
+
+	unsigned	ee_addr_bits;
+
+	unsigned	eesel;
+	unsigned	eeclk;
+	unsigned	eedo;
+	unsigned	eedi;
+	unsigned	polarity;
+	unsigned	ee_state;
+
+	spinlock_t	*lock;
+	u32		*cache;
+};
+
+
+u8   eeprom_readb(struct eeprom *ee, unsigned address);
+void eeprom_read(struct eeprom *ee, unsigned address, u8 *bytes,
+		unsigned count);
+void eeprom_writeb(struct eeprom *ee, unsigned address, u8 data);
+void eeprom_write(struct eeprom *ee, unsigned address, u8 *bytes,
+		unsigned count);
+
+/* The EEPROM commands include the alway-set leading bit. */
+enum EEPROM_Cmds {
+        EE_WriteCmd=(5 << 6), EE_ReadCmd=(6 << 6), EE_EraseCmd=(7 << 6),
+};
+
+void setup_ee_mem_bitbanger(struct eeprom *ee, long memaddr, int eesel_bit, int eeclk_bit, int eedo_bit, int eedi_bit, unsigned polarity)
+{
+	ee->addr = memaddr;
+	ee->eesel = 1 << eesel_bit;
+	ee->eeclk = 1 << eeclk_bit;
+	ee->eedo = 1 << eedo_bit;
+	ee->eedi = 1 << eedi_bit;
+
+	ee->polarity = polarity;
+
+	*ee->cache = readl(ee->addr);
+}
+
+/* foo. put this in a .c file */
+static inline void eeprom_update(struct eeprom *ee, u32 mask, int pol)
+{
+	long flags;
+	u32 data;
+
+	spin_lock_irqsave(ee->lock, flags);
+	data = *ee->cache;
+
+	data &= ~mask;
+	if (pol)
+		data |= mask;
+
+	*ee->cache = data;
+//printk("update: %08x\n", data);
+	writel(data, ee->addr);
+	spin_unlock_irqrestore(ee->lock, flags);
+}
+
+void eeprom_clk_lo(struct eeprom *ee)
+{
+	int pol = !!(ee->polarity & EEPOL_EECLK);
+
+	eeprom_update(ee, ee->eeclk, pol);
+	udelay(2);
+}
+
+void eeprom_clk_hi(struct eeprom *ee)
+{
+	int pol = !!(ee->polarity & EEPOL_EECLK);
+
+	eeprom_update(ee, ee->eeclk, !pol);
+	udelay(2);
+}
+
+void eeprom_send_addr(struct eeprom *ee, unsigned address)
+{
+	int pol = !!(ee->polarity & EEPOL_EEDI);
+	unsigned i;
+	address |= 6 << 6;
+
+        /* Shift the read command bits out. */
+        for (i=0; i<11; i++) {
+		eeprom_update(ee, ee->eedi, ((address >> 10) & 1) ^ pol);
+		address <<= 1;
+		eeprom_clk_hi(ee);
+		eeprom_clk_lo(ee);
+        }
+	eeprom_update(ee, ee->eedi, pol);
+}
+
+u16   eeprom_readw(struct eeprom *ee, unsigned address)
+{
+	unsigned i;
+	u16	res = 0;
+
+	eeprom_clk_lo(ee);
+	eeprom_update(ee, ee->eesel, 1 ^ !!(ee->polarity & EEPOL_EESEL));
+	eeprom_send_addr(ee, address);
+
+	for (i=0; i<16; i++) {
+		u32 data;
+		eeprom_clk_hi(ee);
+		res <<= 1;
+		data = readl(ee->addr);
+//printk("eeprom_readw: %08x\n", data);
+		res |= !!(data & ee->eedo) ^ !!(ee->polarity & EEPOL_EEDO);
+		eeprom_clk_lo(ee);
+	}
+	eeprom_update(ee, ee->eesel, 0 ^ !!(ee->polarity & EEPOL_EESEL));
+
+	return res;
+}
+
+
+void eeprom_writeb(struct eeprom *ee, unsigned address, u8 data)
+{
+}
diff -urN linux-2.4.10-pre8/include/linux/fs.h linux/include/linux/fs.h
--- linux-2.4.10-pre8/include/linux/fs.h	Mon Dec  3 23:09:39 2001
+++ linux/include/linux/fs.h	Mon Dec  3 23:09:49 2001
@@ -111,10 +111,10 @@
 #define MS_NOUSER	(1<<31)
 
 /*
- * Flags that can be altered by MS_REMOUNT
+ * Superblock flags that can be altered by MS_REMOUNT
  */
-#define MS_RMT_MASK	(MS_RDONLY|MS_NOSUID|MS_NODEV|MS_NOEXEC|\
-			MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|MS_NODIRATIME)
+#define MS_RMT_MASK	(MS_RDONLY|MS_SYNCHRONOUS|MS_MANDLOCK|MS_NOATIME|\
+			 MS_NODIRATIME)
 
 /*
  * Old magic mount flag and mask
@@ -130,6 +130,7 @@
 #define S_APPEND	8	/* Append-only file */
 #define S_IMMUTABLE	16	/* Immutable file */
 #define S_DEAD		32	/* removed, but still open directory */
+#define S_NOQUOTA	64	/* Inode is not counted to quota */
 
 /*
  * Note that nosuid etc flags are inode-specific: setting some file-system
@@ -147,13 +148,11 @@
 #define __IS_FLG(inode,flg) ((inode)->i_sb->s_flags & (flg))
 
 #define IS_RDONLY(inode) ((inode)->i_sb->s_flags & MS_RDONLY)
-#define IS_NOSUID(inode)	__IS_FLG(inode, MS_NOSUID)
-#define IS_NODEV(inode)		__IS_FLG(inode, MS_NODEV)
-#define IS_NOEXEC(inode)	__IS_FLG(inode, MS_NOEXEC)
 #define IS_SYNC(inode)		(__IS_FLG(inode, MS_SYNCHRONOUS) || ((inode)->i_flags & S_SYNC))
 #define IS_MANDLOCK(inode)	__IS_FLG(inode, MS_MANDLOCK)
 
 #define IS_QUOTAINIT(inode)	((inode)->i_flags & S_QUOTA)
+#define IS_NOQUOTA(inode)	((inode)->i_flags & S_NOQUOTA)
 #define IS_APPEND(inode)	((inode)->i_flags & S_APPEND)
 #define IS_IMMUTABLE(inode)	((inode)->i_flags & S_IMMUTABLE)
 #define IS_NOATIME(inode)	(__IS_FLG(inode, MS_NOATIME) || ((inode)->i_flags & S_NOATIME))
diff -urN linux-2.4.10-pre8/include/linux/gameport.h linux/include/linux/gameport.h
--- linux-2.4.10-pre8/include/linux/gameport.h	Wed Aug 15 14:23:33 2001
+++ linux/include/linux/gameport.h	Mon Dec  3 23:09:49 2001
@@ -2,7 +2,7 @@
 #define _GAMEPORT_H
 
 /*
- * $Id: gameport.h,v 1.8 2000/06/03 20:18:52 vojtech Exp $
+ * $Id: gameport.h,v 1.11 2001/04/26 10:24:46 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
@@ -12,24 +12,25 @@
 /*
  * 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 <vojtech@ucw.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
  */
 
 #include <linux/sched.h>
+#include <linux/delay.h>
 #include <asm/io.h>
 
 struct gameport;
@@ -37,26 +38,21 @@
 struct gameport {
 
 	void *private;
-	void *driver;
 
 	int number;
 
 	int io;
-	int size;
 	int speed;
 	int fuzz;
-	int type;
-	struct pci_dev *pci;
 
 	void (*trigger)(struct gameport *);
 	unsigned char (*read)(struct gameport *);
-	int (*cooked_read)(struct gameport *, int *, int *);	
-	int (*calibrate)(struct gameport *, int *, int *); 
+	int (*cooked_read)(struct gameport *, int *, int *);
+	int (*calibrate)(struct gameport *, int *, int *);
 	int (*open)(struct gameport *, int);
 	void (*close)(struct gameport *);
 
 	struct gameport_dev *dev;
-
 	struct gameport *next;
 };
 
@@ -74,18 +70,20 @@
 void gameport_close(struct gameport *gameport);
 void gameport_rescan(struct gameport *gameport);
 
+#if defined(CONFIG_INPUT_GAMEPORT) || defined(CONFIG_INPUT_GAMEPORT_MODULE)
 void gameport_register_port(struct gameport *gameport);
 void gameport_unregister_port(struct gameport *gameport);
+#else
+void __inline__ gameport_register_port(struct gameport *gameport) { return; }
+void __inline__ gameport_unregister_port(struct gameport *gameport) { return; }
+#endif
+
 void gameport_register_device(struct gameport_dev *dev);
 void gameport_unregister_device(struct gameport_dev *dev);
 
 #define GAMEPORT_MODE_DISABLED		0
 #define GAMEPORT_MODE_RAW		1
 #define GAMEPORT_MODE_COOKED		2
-
-#define GAMEPORT_ISA       0
-#define GAMEPORT_PNP       1
-#define GAMEPORT_EXT       2
 
 #define GAMEPORT_ID_VENDOR_ANALOG	0x0001
 #define GAMEPORT_ID_VENDOR_MADCATZ	0x0002
diff -urN linux-2.4.10-pre8/include/linux/hiddev.h linux/include/linux/hiddev.h
--- linux-2.4.10-pre8/include/linux/hiddev.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/hiddev.h	Mon Dec  3 23:09:49 2001
@@ -0,0 +1,194 @@
+#ifndef _HIDDEV_H
+#define _HIDDEV_H
+
+/*
+ * $Id: hiddev.h,v 1.2 2001/04/26 11:26:09 vojtech Exp $
+ *
+ *  Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ *  Sponsored by SuSE
+ */
+
+/*
+ * 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 <vojtech@suse.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+/*
+ * The event structure itself
+ */
+
+struct hiddev_event {
+	unsigned hid;
+	signed int value;
+};
+
+struct hiddev_devinfo {
+	unsigned int bustype;
+	unsigned int busnum;
+	unsigned int devnum;
+	unsigned int ifnum;
+	short vendor;
+	short product;
+	short version;
+	unsigned num_applications;
+};
+
+#define HID_STRING_SIZE 256
+struct hiddev_string_descriptor {
+	int index;
+	char value[HID_STRING_SIZE];
+};
+
+struct hiddev_report_info {
+	unsigned report_type;
+	unsigned report_id;
+	unsigned num_fields;
+};
+
+/* To do a GUSAGE/SUSAGE, fill in at least usage_code,  report_type and 
+ * report_id.  Set report_id to REPORT_ID_UNKNOWN if the rest of the fields 
+ * are unknown.  Otherwise use a usage_ref struct filled in from a previous 
+ * successful GUSAGE/SUSAGE call to save time.  To actually send a value
+ * to the device, perform a SUSAGE first, followed by a SREPORT.  If an
+ * INITREPORT is done, a GREPORT isn't necessary before a GUSAGE.
+ */
+#define HID_REPORT_ID_UNKNOWN 0xffffffff
+#define HID_REPORT_ID_FIRST   0x00000100
+#define HID_REPORT_ID_NEXT    0x00000200
+#define HID_REPORT_ID_MASK    0x000000ff
+#define HID_REPORT_ID_MAX     0x000000ff
+
+#define HID_REPORT_TYPE_INPUT	1
+#define HID_REPORT_TYPE_OUTPUT	2
+#define HID_REPORT_TYPE_FEATURE	3
+#define HID_REPORT_TYPE_MIN     1
+#define HID_REPORT_TYPE_MAX     3
+
+struct hiddev_field_info {
+	unsigned report_type;
+	unsigned report_id;
+	unsigned field_index;
+	unsigned maxusage;
+	unsigned flags;
+	unsigned physical;		/* physical usage for this field */
+	unsigned logical;		/* logical usage for this field */
+	unsigned application;		/* application usage for this field */
+	__s32 logical_minimum;
+	__s32 logical_maximum;
+	__s32 physical_minimum;
+	__s32 physical_maximum;
+	unsigned unit_exponent;
+	unsigned unit;
+};
+
+/* Fill in report_type, report_id and field_index to get the information on a
+ * field.
+ */
+#define HID_FIELD_CONSTANT		0x001
+#define HID_FIELD_VARIABLE		0x002
+#define HID_FIELD_RELATIVE		0x004
+#define HID_FIELD_WRAP			0x008	
+#define HID_FIELD_NONLINEAR		0x010
+#define HID_FIELD_NO_PREFERRED		0x020
+#define HID_FIELD_NULL_STATE		0x040
+#define HID_FIELD_VOLATILE		0x080
+#define HID_FIELD_BUFFERED_BYTE		0x100
+
+struct hiddev_usage_ref {
+	unsigned report_type;
+	unsigned report_id;
+	unsigned field_index;
+	unsigned usage_index;
+	unsigned usage_code;
+	__s32 value;
+};
+
+
+/*
+ * Protocol version.
+ */
+
+#define HID_VERSION		0x010002
+
+/*
+ * IOCTLs (0x00 - 0x7f)
+ */
+
+#define HIDIOCGVERSION		_IOR('H', 0x01, int)
+#define HIDIOCAPPLICATION	_IO('H', 0x02)
+#define HIDIOCGDEVINFO		_IOR('H', 0x03, struct hiddev_devinfo)
+#define HIDIOCGSTRING		_IOR('H', 0x04, struct hiddev_string_descriptor)
+#define HIDIOCINITREPORT	_IO('H', 0x05)
+#define HIDIOCGNAME(len)	_IOC(_IOC_READ, 'H', 0x06, len)
+#define HIDIOCGREPORT		_IOW('H', 0x07, struct hiddev_report_info)
+#define HIDIOCSREPORT		_IOW('H', 0x08, struct hiddev_report_info)
+#define HIDIOCGREPORTINFO       _IOWR('H', 0x09, struct hiddev_report_info)
+#define HIDIOCGFIELDINFO        _IOWR('H', 0x0A, struct hiddev_field_info)
+#define HIDIOCGUSAGE            _IOWR('H', 0x0B, struct hiddev_usage_ref)
+#define HIDIOCSUSAGE            _IOW('H', 0x0C, struct hiddev_usage_ref)
+#define HIDIOCGUCODE            _IOWR('H', 0x0D, struct hiddev_usage_ref)
+
+/* To traverse the input report descriptor info for a HID device, perform the 
+ * following:
+ *
+ *  rinfo.report_type = HID_REPORT_TYPE_INPUT;
+ *  rinfo.report_id = HID_REPORT_ID_FIRST;
+ *  ret = ioctl(fd, HIDIOCGREPORTINFO, &rinfo);
+ *
+ *  while (ret >= 0) {
+ *      for (i = 0; i < rinfo.num_fields; i++) { 
+ *	    finfo.report_type = rinfo.report_type;
+ *          finfo.report_id = rinfo.report_id;
+ *          finfo.field_index = i;
+ *          ioctl(fd, HIDIOCGFIELDINFO, &finfo);
+ *          for (j = 0; j < finfo.maxusage; j++) {
+ *              uref.field_index = i;
+ *		uref.usage_index = j;
+ *		ioctl(fd, HIDIOCGUCODE, &uref);
+ *		ioctl(fd, HIDIOCGUSAGE, &uref);
+ *          }
+ *	}
+ *	uref.report_id |= HID_REPORT_ID_NEXT;
+ *	ret = ioctl(fd, HIDIOCGREPORTINFO, &uref);
+ *  }
+ */
+
+
+#ifdef __KERNEL__
+
+/*
+ * In-kernel definitions.
+ */
+
+#ifdef CONFIG_USB_HIDDEV
+int hiddev_connect(struct hid_device *);
+void hiddev_disconnect(struct hid_device *);
+void hiddev_hid_event(struct hid_device *, unsigned int usage, int value);
+int __init hiddev_init(void);
+void __exit hiddev_exit(void);
+#else
+static inline void *hiddev_connect(struct hid_device *hid) { return NULL; }
+static inline void hiddev_disconnect(struct hid_device *hid) { }
+static inline void hiddev_event(struct hid_device *hid, unsigned int usage, int value) { }
+static inline int hiddev_init(void) { return 0; }
+static inline void hiddev_exit(void) { }
+#endif
+
+#endif
+#endif
diff -urN linux-2.4.10-pre8/include/linux/input.h linux/include/linux/input.h
--- linux-2.4.10-pre8/include/linux/input.h	Mon Dec 11 12:50:53 2000
+++ linux/include/linux/input.h	Mon Dec  3 23:09:49 2001
@@ -2,7 +2,7 @@
 #define _INPUT_H
 
 /*
- * $Id: input.h,v 1.18 2000/07/25 21:36:56 vojtech Exp $
+ * $Id: input.h,v 1.34 2001/05/28 09:06:44 vojtech Exp $
  *
  *  Copyright (c) 1999-2000 Vojtech Pavlik
  *
@@ -12,18 +12,18 @@
 /*
  * 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 <vojtech@suse.cz>, or by paper mail:
  * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
@@ -34,6 +34,7 @@
 #else
 #include <sys/time.h>
 #include <sys/ioctl.h>
+#include <asm/types.h>
 #endif
 
 /*
@@ -57,7 +58,7 @@
  * IOCTLs (0x00 - 0x7f)
  */
 
-#define EVIOCGVERSION		_IOR('E', 0x01, int)                    /* get driver version */
+#define EVIOCGVERSION		_IOR('E', 0x01, int)			/* get driver version */
 #define EVIOCGID		_IOR('E', 0x02, short[4])		/* get device ID */
 #define EVIOCGREP		_IOR('E', 0x03, int[2])			/* get repeat settings */
 #define EVIOCSREP		_IOW('E', 0x03, int[2])			/* get repeat settings */
@@ -65,9 +66,16 @@
 #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 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 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 */
 
 /*
  * Event types
@@ -77,187 +85,189 @@
 #define EV_KEY			0x01
 #define EV_REL			0x02
 #define EV_ABS			0x03
+#define EV_MSC			0x04
 #define EV_LED			0x11
 #define EV_SND			0x12
 #define EV_REP			0x14
+#define EV_FF			0x15
 #define EV_MAX			0x1f
 
 /*
  * Keys and buttons
  */
 
-#define KEY_RESERVED		0		
-#define KEY_ESC			1		
-#define KEY_1			2		
-#define KEY_2			3		
-#define KEY_3			4		
-#define KEY_4			5		
-#define KEY_5			6		
-#define KEY_6			7		
-#define KEY_7			8		
-#define KEY_8			9		
-#define KEY_9			10		
-#define KEY_0			11		
-#define KEY_MINUS		12		
-#define KEY_EQUAL		13		
-#define KEY_BACKSPACE		14		
-#define KEY_TAB			15		
-#define KEY_Q			16		
-#define KEY_W			17		
-#define KEY_E			18		
-#define KEY_R			19		
-#define KEY_T			20		
-#define KEY_Y			21		
-#define KEY_U			22		
-#define KEY_I			23		
-#define KEY_O			24		
-#define KEY_P			25		
-#define KEY_LEFTBRACE		26		
-#define KEY_RIGHTBRACE		27		
-#define KEY_ENTER		28		
-#define KEY_LEFTCTRL		29		
-#define KEY_A			30		
-#define KEY_S			31		
-#define KEY_D			32		
-#define KEY_F			33		
-#define KEY_G			34		
-#define KEY_H			35		
-#define KEY_J			36		
-#define KEY_K			37		
-#define KEY_L			38		
-#define KEY_SEMICOLON		39		
-#define KEY_APOSTROPHE		40		
-#define KEY_GRAVE		41		
-#define KEY_LEFTSHIFT		42		
-#define KEY_BACKSLASH		43		
-#define KEY_Z			44		
-#define KEY_X			45		
-#define KEY_C			46		
-#define KEY_V			47		
-#define KEY_B			48		
-#define KEY_N			49		
-#define KEY_M			50		
-#define KEY_COMMA		51		
-#define KEY_DOT			52		
-#define KEY_SLASH		53		
-#define KEY_RIGHTSHIFT		54		
-#define KEY_KPASTERISK		55		
-#define KEY_LEFTALT		56		
-#define KEY_SPACE		57		
-#define KEY_CAPSLOCK		58		
-#define KEY_F1			59		
-#define KEY_F2			60		
-#define KEY_F3			61		
-#define KEY_F4			62		
-#define KEY_F5			63		
-#define KEY_F6			64		
-#define KEY_F7			65		
-#define KEY_F8			66		
-#define KEY_F9			67		
-#define KEY_F10			68		
-#define KEY_NUMLOCK		69		
-#define KEY_SCROLLLOCK		70		
-#define KEY_KP7			71		
-#define KEY_KP8			72		
-#define KEY_KP9			73		
-#define KEY_KPMINUS		74		
-#define KEY_KP4			75		
-#define KEY_KP5			76		
-#define KEY_KP6			77		
-#define KEY_KPPLUS		78		
-#define KEY_KP1			79		
-#define KEY_KP2			80		
-#define KEY_KP3			81		
-#define KEY_KP0			82		
-#define KEY_KPDOT		83		
+#define KEY_RESERVED		0
+#define KEY_ESC			1
+#define KEY_1			2
+#define KEY_2			3
+#define KEY_3			4
+#define KEY_4			5
+#define KEY_5			6
+#define KEY_6			7
+#define KEY_7			8
+#define KEY_8			9
+#define KEY_9			10
+#define KEY_0			11
+#define KEY_MINUS		12
+#define KEY_EQUAL		13
+#define KEY_BACKSPACE		14
+#define KEY_TAB			15
+#define KEY_Q			16
+#define KEY_W			17
+#define KEY_E			18
+#define KEY_R			19
+#define KEY_T			20
+#define KEY_Y			21
+#define KEY_U			22
+#define KEY_I			23
+#define KEY_O			24
+#define KEY_P			25
+#define KEY_LEFTBRACE		26
+#define KEY_RIGHTBRACE		27
+#define KEY_ENTER		28
+#define KEY_LEFTCTRL		29
+#define KEY_A			30
+#define KEY_S			31
+#define KEY_D			32
+#define KEY_F			33
+#define KEY_G			34
+#define KEY_H			35
+#define KEY_J			36
+#define KEY_K			37
+#define KEY_L			38
+#define KEY_SEMICOLON		39
+#define KEY_APOSTROPHE		40
+#define KEY_GRAVE		41
+#define KEY_LEFTSHIFT		42
+#define KEY_BACKSLASH		43
+#define KEY_Z			44
+#define KEY_X			45
+#define KEY_C			46
+#define KEY_V			47
+#define KEY_B			48
+#define KEY_N			49
+#define KEY_M			50
+#define KEY_COMMA		51
+#define KEY_DOT			52
+#define KEY_SLASH		53
+#define KEY_RIGHTSHIFT		54
+#define KEY_KPASTERISK		55
+#define KEY_LEFTALT		56
+#define KEY_SPACE		57
+#define KEY_CAPSLOCK		58
+#define KEY_F1			59
+#define KEY_F2			60
+#define KEY_F3			61
+#define KEY_F4			62
+#define KEY_F5			63
+#define KEY_F6			64
+#define KEY_F7			65
+#define KEY_F8			66
+#define KEY_F9			67
+#define KEY_F10			68
+#define KEY_NUMLOCK		69
+#define KEY_SCROLLLOCK		70
+#define KEY_KP7			71
+#define KEY_KP8			72
+#define KEY_KP9			73
+#define KEY_KPMINUS		74
+#define KEY_KP4			75
+#define KEY_KP5			76
+#define KEY_KP6			77
+#define KEY_KPPLUS		78
+#define KEY_KP1			79
+#define KEY_KP2			80
+#define KEY_KP3			81
+#define KEY_KP0			82
+#define KEY_KPDOT		83
 #define KEY_103RD		84
-#define KEY_F13			85		
-#define KEY_102ND		86		
-#define KEY_F11			87		
-#define KEY_F12			88		
-#define KEY_F14			89		
-#define KEY_F15			90		
-#define KEY_F16			91		
-#define KEY_F17			92		
-#define KEY_F18			93		
-#define KEY_F19			94		
-#define KEY_F20			95		
-#define KEY_KPENTER		96		
-#define KEY_RIGHTCTRL		97		
-#define KEY_KPSLASH		98		
-#define KEY_SYSRQ		99		
-#define KEY_RIGHTALT		100		
-#define KEY_LINEFEED		101		
-#define KEY_HOME		102		
-#define KEY_UP			103		
-#define KEY_PAGEUP		104		
-#define KEY_LEFT		105		
-#define KEY_RIGHT		106		
-#define KEY_END			107		
-#define KEY_DOWN		108		
-#define KEY_PAGEDOWN		109		
-#define KEY_INSERT		110		
-#define KEY_DELETE		111		
-#define KEY_MACRO		112		
-#define KEY_MUTE		113		
-#define KEY_VOLUMEDOWN		114		
-#define KEY_VOLUMEUP		115		
-#define KEY_POWER		116		
-#define KEY_KPEQUAL		117		
-#define KEY_KPPLUSMINUS		118		
-#define KEY_PAUSE		119		
-#define KEY_F21			120		
-#define KEY_F22			121		
-#define KEY_F23			122		
-#define KEY_F24			123		
+#define KEY_F13			85
+#define KEY_102ND		86
+#define KEY_F11			87
+#define KEY_F12			88
+#define KEY_F14			89
+#define KEY_F15			90
+#define KEY_F16			91
+#define KEY_F17			92
+#define KEY_F18			93
+#define KEY_F19			94
+#define KEY_F20			95
+#define KEY_KPENTER		96
+#define KEY_RIGHTCTRL		97
+#define KEY_KPSLASH		98
+#define KEY_SYSRQ		99
+#define KEY_RIGHTALT		100
+#define KEY_LINEFEED		101
+#define KEY_HOME		102
+#define KEY_UP			103
+#define KEY_PAGEUP		104
+#define KEY_LEFT		105
+#define KEY_RIGHT		106
+#define KEY_END			107
+#define KEY_DOWN		108
+#define KEY_PAGEDOWN		109
+#define KEY_INSERT		110
+#define KEY_DELETE		111
+#define KEY_MACRO		112
+#define KEY_MUTE		113
+#define KEY_VOLUMEDOWN		114
+#define KEY_VOLUMEUP		115
+#define KEY_POWER		116
+#define KEY_KPEQUAL		117
+#define KEY_KPPLUSMINUS		118
+#define KEY_PAUSE		119
+#define KEY_F21			120
+#define KEY_F22			121
+#define KEY_F23			122
+#define KEY_F24			123
 #define KEY_KPCOMMA		124
-#define KEY_LEFTMETA		125		
-#define KEY_RIGHTMETA		126		
-#define KEY_COMPOSE		127		
-
-#define KEY_STOP		128		
-#define KEY_AGAIN		129		
-#define KEY_PROPS		130		
-#define KEY_UNDO		131		
-#define KEY_FRONT		132		
-#define KEY_COPY		133		
-#define KEY_OPEN		134		
-#define KEY_PASTE		135		
-#define KEY_FIND		136		
-#define KEY_CUT			137		
-#define KEY_HELP		138		
-#define KEY_MENU		139		
-#define KEY_CALC		140		
-#define KEY_SETUP		141		
-#define KEY_SLEEP		142		
-#define KEY_WAKEUP		143		
-#define KEY_FILE		144		
-#define KEY_SENDFILE		145		
-#define KEY_DELETEFILE		146		
-#define KEY_XFER		147		
-#define KEY_PROG1		148		
-#define KEY_PROG2		149		
-#define KEY_WWW			150		
-#define KEY_MSDOS		151		
-#define KEY_COFFEE		152		
-#define KEY_DIRECTION		153		
-#define KEY_CYCLEWINDOWS	154		
+#define KEY_LEFTMETA		125
+#define KEY_RIGHTMETA		126
+#define KEY_COMPOSE		127
+
+#define KEY_STOP		128
+#define KEY_AGAIN		129
+#define KEY_PROPS		130
+#define KEY_UNDO		131
+#define KEY_FRONT		132
+#define KEY_COPY		133
+#define KEY_OPEN		134
+#define KEY_PASTE		135
+#define KEY_FIND		136
+#define KEY_CUT			137
+#define KEY_HELP		138
+#define KEY_MENU		139
+#define KEY_CALC		140
+#define KEY_SETUP		141
+#define KEY_SLEEP		142
+#define KEY_WAKEUP		143
+#define KEY_FILE		144
+#define KEY_SENDFILE		145
+#define KEY_DELETEFILE		146
+#define KEY_XFER		147
+#define KEY_PROG1		148
+#define KEY_PROG2		149
+#define KEY_WWW			150
+#define KEY_MSDOS		151
+#define KEY_COFFEE		152
+#define KEY_DIRECTION		153
+#define KEY_CYCLEWINDOWS	154
 #define KEY_MAIL		155
 #define KEY_BOOKMARKS		156
 #define KEY_COMPUTER		157
 #define KEY_BACK		158
 #define KEY_FORWARD		159
-#define KEY_CLOSECD		160		
-#define KEY_EJECTCD		161		
-#define KEY_EJECTCLOSECD	162		
-#define KEY_NEXTSONG		163		
-#define KEY_PLAYPAUSE		164		
-#define KEY_PREVIOUSSONG	165		
-#define KEY_STOPCD		166		
-#define KEY_RECORD		167		
-#define KEY_REWIND		168		
+#define KEY_CLOSECD		160
+#define KEY_EJECTCD		161
+#define KEY_EJECTCLOSECD	162
+#define KEY_NEXTSONG		163
+#define KEY_PLAYPAUSE		164
+#define KEY_PREVIOUSSONG	165
+#define KEY_STOPCD		166
+#define KEY_RECORD		167
+#define KEY_REWIND		168
 #define KEY_PHONE		169
-
+#define KEY_ISO			170
 #define KEY_CONFIG		171
 #define KEY_HOMEPAGE		172
 #define KEY_REFRESH		173
@@ -288,7 +298,14 @@
 #define KEY_LANG8		197
 #define KEY_LANG9		198
 
-#define KEY_UNKNOWN		200
+#define KEY_PLAYCD		200
+#define KEY_PAUSECD		201
+#define KEY_PROG3		202
+#define KEY_PROG4		203
+#define KEY_SUSPEND		205
+#define KEY_CLOSE		206
+
+#define KEY_UNKNOWN		220
 
 #define BTN_MISC		0x100
 #define BTN_0			0x100
@@ -324,6 +341,7 @@
 #define BTN_BASE4		0x129
 #define BTN_BASE5		0x12a
 #define BTN_BASE6		0x12b
+#define BTN_DEAD		0x12f
 
 #define BTN_GAMEPAD		0x130
 #define BTN_A			0x130
@@ -339,6 +357,8 @@
 #define BTN_SELECT		0x13a
 #define BTN_START		0x13b
 #define BTN_MODE		0x13c
+#define BTN_THUMBL		0x13d
+#define BTN_THUMBR		0x13e
 
 #define BTN_DIGI		0x140
 #define BTN_TOOL_PEN		0x140
@@ -399,6 +419,13 @@
 #define ABS_MAX			0x1f
 
 /*
+ * Misc events
+ */
+
+#define MSC_SERIAL		0x00
+#define MSC_MAX			0x07
+
+/*
  * LEDs
  */
 
@@ -407,6 +434,10 @@
 #define LED_SCROLLL		0x02
 #define LED_COMPOSE		0x03
 #define LED_KANA		0x04
+#define LED_SLEEP		0x05
+#define LED_SUSPEND		0x06
+#define LED_MUTE		0x07
+#define LED_MISC		0x08
 #define LED_MAX			0x0f
 
 /*
@@ -448,6 +479,135 @@
 #define BUS_ADB			0x17
 #define BUS_I2C			0x18
 
+/*
+ * 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 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 */
+};
+
+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 */
+};
+
+/* FF_CONSTANT */
+struct ff_constant_effect {
+	__s16 level;		/* Strength of effect */
+	__u16 direction;	/* Direction of effect (see periodic effects) */
+	struct ff_shape shape;
+};
+
+/* 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;
+
+	__s16 right_saturation; /* Max level when joystick is on the right */
+	__s16 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 */
+
+};
+
+/* FF_PERIODIC */
+struct ff_periodic_effect {
+	__u16 waveform;		/* Kind of wave (sine, square...) */
+	__u16 period;
+	__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;
+};
+
+/*
+ * Structure sent through ioctl from the application to the driver
+ */
+struct ff_effect {
+	__u16 type;
+/* Following field denotes the unique id assigned to an effect.
+ * It is set by the driver.
+ */
+	__s16 id;
+
+	struct ff_trigger trigger;
+	struct ff_replay replay;
+
+	union {
+		struct ff_constant_effect constant;
+		struct ff_periodic_effect periodic;
+		struct ff_interactive_effect interactive;
+	} 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
+ */
+
+#define FF_RUMBLE	0x50
+#define FF_PERIODIC	0x51
+#define FF_CONSTANT	0x52
+#define FF_SPRING	0x53
+#define FF_FRICTION	0x54
+
+/*
+ * Force feedback periodic effect types
+ */
+
+#define FF_SQUARE	0x58
+#define FF_TRIANGLE	0x59
+#define FF_SINE		0x5a
+#define FF_SAW_UP	0x5b
+#define FF_SAW_DOWN	0x5c
+#define FF_CUSTOM	0x5d
+
+/*
+ * Set ff device properties
+ */
+
+#define FF_GAIN		0x60
+#define FF_AUTOCENTER	0x61
+
+#define FF_MAX		0x7f
+
 #ifdef __KERNEL__
 
 /*
@@ -476,8 +636,11 @@
 	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)];
+	int ff_effects_max;
 
 	unsigned int keycodemax;
 	unsigned int keycodesize;
@@ -492,7 +655,7 @@
 	unsigned long key[NBITS(KEY_MAX)];
 	unsigned long led[NBITS(LED_MAX)];
 	unsigned long snd[NBITS(SND_MAX)];
-	
+
 	int absmax[ABS_MAX + 1];
 	int absmin[ABS_MAX + 1];
 	int absfuzz[ABS_MAX + 1];
@@ -501,6 +664,8 @@
 	int (*open)(struct input_dev *dev);
 	void (*close)(struct input_dev *dev);
 	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);
 
 	struct input_handle *handle;
 	struct input_dev *next;
@@ -526,7 +691,7 @@
 	void *private;
 
 	int open;
-	
+
 	struct input_dev *dev;
 	struct input_handler *handler;
 
diff -urN linux-2.4.10-pre8/include/linux/irda.h linux/include/linux/irda.h
--- linux-2.4.10-pre8/include/linux/irda.h	Sat Nov 11 18:11:22 2000
+++ linux/include/linux/irda.h	Mon Dec  3 23:09:49 2001
@@ -92,10 +92,15 @@
 
 #define IRTTP_MAX_SDU_SIZE IRLMP_MAX_SDU_SIZE /* Compatibility */
 
-#define IAS_MAX_STRING         256
-#define IAS_MAX_OCTET_STRING  1024
-#define IAS_MAX_CLASSNAME       64
-#define IAS_MAX_ATTRIBNAME     256
+#define IAS_MAX_STRING         256	/* See IrLMP 1.1, 4.3.3.2 */
+#define IAS_MAX_OCTET_STRING  1024	/* See IrLMP 1.1, 4.3.3.2 */
+#define IAS_MAX_CLASSNAME       60	/* See IrLMP 1.1, 4.3.1 */
+#define IAS_MAX_ATTRIBNAME      60	/* See IrLMP 1.1, 4.3.3.1 */
+#define IAS_MAX_ATTRIBNUMBER   256	/* See IrLMP 1.1, 4.3.3.1 */
+/* For user space backward compatibility - may be fixed in kernel 2.5.X
+ * Note : need 60+1 ('\0'), make it 64 for alignement - Jean II */
+#define IAS_EXPORT_CLASSNAME       64
+#define IAS_EXPORT_ATTRIBNAME     256
 
 /* Attribute type needed for struct irda_ias_set */
 #define IAS_MISSING 0
@@ -126,8 +131,8 @@
 };
 
 struct irda_ias_set {
-	char irda_class_name[IAS_MAX_CLASSNAME];
-	char irda_attrib_name[IAS_MAX_ATTRIBNAME];
+	char irda_class_name[IAS_EXPORT_CLASSNAME];
+	char irda_attrib_name[IAS_EXPORT_ATTRIBNAME];
 	unsigned int irda_attrib_type;
 	union {
 		unsigned int irda_attrib_int;
diff -urN linux-2.4.10-pre8/include/linux/ite_gpio.h linux/include/linux/ite_gpio.h
--- linux-2.4.10-pre8/include/linux/ite_gpio.h	Wed Dec 31 16:00:00 1969
+++ linux/include/linux/ite_gpio.h	Mon Dec  3 23:09:49 2001
@@ -0,0 +1,66 @@
+/*
+ * FILE NAME ite_gpio.h
+ *
+ * BRIEF MODULE DESCRIPTION
+ *	Generic gpio.
+ *
+ *  Author: MontaVista Software, Inc.  <source@mvista.com>
+ *          Hai-Pao Fan <haipao@mvista.com>
+ *
+ * Copyright 2001 MontaVista Software Inc.
+ *
+ *  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  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  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.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __ITE_GPIO_H
+#define __ITE_GPIO_H
+
+#include <linux/ioctl.h>
+
+struct ite_gpio_ioctl_data {
+	__u32 device;
+	__u32 mask;
+	__u32 data;
+};
+
+#define ITE_GPIO_IOCTL_BASE	'Z'
+
+#define ITE_GPIO_IN		_IOWR(ITE_GPIO_IOCTL_BASE, 0, struct ite_gpio_ioctl_data)
+#define ITE_GPIO_OUT		_IOW (ITE_GPIO_IOCTL_BASE, 1, struct ite_gpio_ioctl_data)
+#define	ITE_GPIO_INT_CTRL	_IOW (ITE_GPIO_IOCTL_BASE, 2, struct ite_gpio_ioctl_data)
+#define	ITE_GPIO_IN_STATUS	_IOW (ITE_GPIO_IOCTL_BASE, 3, struct ite_gpio_ioctl_data)
+#define	ITE_GPIO_OUT_STATUS	_IOW (ITE_GPIO_IOCTL_BASE, 4, struct ite_gpio_ioctl_data)
+#define ITE_GPIO_GEN_CTRL	_IOW (ITE_GPIO_IOCTL_BASE, 5, struct ite_gpio_ioctl_data)
+#define ITE_GPIO_INT_WAIT	_IOW (ITE_GPIO_IOCTL_BASE, 6, struct ite_gpio_ioctl_data)
+
+#define	ITE_GPIO_PORTA	0x01
+#define	ITE_GPIO_PORTB	0x02
+#define	ITE_GPIO_PORTC	0x04
+
+extern int ite_gpio_in(__u32 device, __u32 mask, volatile __u32 *data);
+extern int ite_gpio_out(__u32 device, __u32 mask, __u32 data);
+extern int ite_gpio_int_ctrl(__u32 device, __u32 mask, __u32 data);
+extern int ite_gpio_in_status(__u32 device, __u32 mask, volatile __u32 *data);
+extern int ite_gpio_out_status(__u32 device, __u32 mask, __u32 data);
+extern int ite_gpio_gen_ctrl(__u32 device, __u32 mask, __u32 data);
+extern int ite_gpio_int_wait(__u32 device, __u32 mask, __u32 data);
+
+#endif
diff -urN linux-2.4.10-pre8/include/linux/ixjuser.h linux/include/linux/ixjuser.h
--- linux-2.4.10-pre8/include/linux/ixjuser.h	Sat Dec 30 11:23:14 2000
+++ linux/include/linux/ixjuser.h	Mon Dec  3 23:09:49 2001
@@ -1,11 +1,16 @@
+#ifndef __LINUX_IXJUSER_H
+#define __LINUX_IXJUSER_H
+
 /******************************************************************************
  *
  *    ixjuser.h
  *
- *    Device Driver for the Internet PhoneJACK and
- *    Internet LineJACK Telephony Cards.
+ * Device Driver for Quicknet Technologies, Inc.'s Telephony cards
+ * including the Internet PhoneJACK, Internet PhoneJACK Lite,
+ * Internet PhoneJACK PCI, Internet LineJACK, Internet PhoneCARD and
+ * SmartCABLE
  *
- *    (c) Copyright 1999 Quicknet Technologies, Inc.
+ *    (c) Copyright 1999-2001  Quicknet Technologies, Inc.
  *
  *    This program is free software; you can redistribute it and/or
  *    modify it under the terms of the GNU General Public License
@@ -37,14 +42,14 @@
  *
  *****************************************************************************/
 
-static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 3.11 2000/03/30 22:06:48 eokerson Exp $";
+static char ixjuser_h_rcsid[] = "$Id: ixjuser.h,v 4.1 2001/08/05 00:17:37 craigs Exp $";
 
-#include "telephony.h"
+#include <linux/telephony.h>
 
 
 /******************************************************************************
 *
-* IOCTL's used for the Quicknet Cards
+* IOCTL's used for the Quicknet Telephony Cards
 *
 * If you use the IXJCTL_TESTRAM command, the card must be power cycled to
 * reset the SRAM values before futher use.
@@ -135,6 +140,7 @@
 } IXJ_FILTER_CADENCE;
 
 #define IXJCTL_SET_FILTER		_IOW ('q', 0xC7, IXJ_FILTER *)
+#define IXJCTL_SET_FILTER_RAW		_IOW ('q', 0xDD, IXJ_FILTER_RAW *)
 #define IXJCTL_GET_FILTER_HIST		_IOW ('q', 0xC8, int)
 #define IXJCTL_FILTER_CADENCE		_IOW ('q', 0xD6, IXJ_FILTER_CADENCE *)
 #define IXJCTL_PLAY_CID			_IO  ('q', 0xD7)
@@ -366,7 +372,7 @@
 * This group of IOCTLs deal with the Acoustic Echo Cancellation settings
 * of the DSP
 *
-* Issueing the IXJCTL_AEC_START command with a value of AEC_OFF has the
+* Issuing the IXJCTL_AEC_START command with a value of AEC_OFF has the
 * same effect as IXJCTL_AEC_STOP.  This is to simplify slider bar
 * controls.  IXJCTL_AEC_GET_LEVEL returns the current setting of the AEC.
 ******************************************************************************/
@@ -379,11 +385,12 @@
 #define AEC_MED   2
 #define AEC_HIGH  3
 #define AEC_AUTO  4
+#define AEC_AGC   5
 /******************************************************************************
 *
 * Call Progress Tones, DTMF, etc.
-* IXJCTL_DTMF_OOB determines if dtmf signaling is sent as Out-Of-Band
-* only.  If you pass a 1, dtmf is suppressed from the audio stream.
+* IXJCTL_DTMF_OOB determines if DTMF signaling is sent as Out-Of-Band
+* only.  If you pass a 1, DTMF is suppressed from the audio stream.
 * Tone on and off times are in 250 microsecond intervals so
 * ioctl(ixj1, IXJCTL_SET_TONE_ON_TIME, 360);
 * will set the tone on time of board ixj1 to 360 * 250us = 90ms
@@ -407,10 +414,10 @@
 #define IXJCTL_CPT_STOP			PHONE_CPT_STOP
 
 /******************************************************************************
-* LineJack specific IOCTLs
+* LineJACK specific IOCTLs
 *
 * The lsb 4 bits of the LED argument represent the state of each of the 4
-* LED's on the LineJack
+* LED's on the LineJACK
 ******************************************************************************/
 
 #define IXJCTL_SET_LED			_IOW ('q', 0xCE, int)
@@ -423,8 +430,8 @@
 * as the parameter to the mixer command to change the mixer settings.
 * 
 ******************************************************************************/
-#define MIXER_MASTER_L		0x0100
-#define MIXER_MASTER_R		0x0200
+#define MIXER_MASTER_L		0x0000
+#define MIXER_MASTER_R		0x0100
 #define ATT00DB			0x00
 #define ATT02DB			0x01
 #define ATT04DB			0x02
@@ -535,9 +542,9 @@
 ******************************************************************************/
 #define IXJCTL_DAA_COEFF_SET		_IOW ('q', 0xD0, int)
 
-#define DAA_US 		1	//PITA 8kHz
-#define DAA_UK 		2	//ISAR34 8kHz
-#define DAA_FRANCE 	3	//
+#define DAA_US 		1	/*PITA 8kHz */
+#define DAA_UK 		2	/*ISAR34 8kHz */
+#define DAA_FRANCE 	3	/* */
 #define DAA_GERMANY	4
 #define DAA_AUSTRALIA	5
 #define DAA_JAPAN	6
@@ -575,14 +582,14 @@
 ******************************************************************************/
 #define IXJCTL_DAA_AGAIN		_IOW ('q', 0xD2, int)
 
-#define AGRR00DB	0x00	// Analog gain in receive direction 0dB
-#define AGRR3_5DB	0x10	// Analog gain in receive direction 3.5dB
-#define AGRR06DB	0x30	// Analog gain in receive direction 6dB
-
-#define AGX00DB		0x00	// Analog gain in transmit direction 0dB
-#define AGX_6DB		0x04	// Analog gain in transmit direction -6dB
-#define AGX3_5DB	0x08	// Analog gain in transmit direction 3.5dB
-#define AGX_2_5B	0x0C	// Analog gain in transmit direction -2.5dB
+#define AGRR00DB	0x00	/* Analog gain in receive direction 0dB */
+#define AGRR3_5DB	0x10	/* Analog gain in receive direction 3.5dB */
+#define AGRR06DB	0x30	/* Analog gain in receive direction 6dB */
+
+#define AGX00DB		0x00	/* Analog gain in transmit direction 0dB */
+#define AGX_6DB		0x04	/* Analog gain in transmit direction -6dB */
+#define AGX3_5DB	0x08	/* Analog gain in transmit direction 3.5dB */
+#define AGX_2_5B	0x0C	/* Analog gain in transmit direction -2.5dB */
 
 #define IXJCTL_PSTN_LINETEST		_IO  ('q', 0xD3)
 
@@ -639,6 +646,52 @@
 #define IXJCTL_WRITE_WAIT		_IOR ('q', 0xE5, unsigned long)
 #define IXJCTL_DRYBUFFER_READ		_IOR ('q', 0xE6, unsigned long)
 #define IXJCTL_DRYBUFFER_CLEAR		_IO  ('q', 0xE7)
+#define IXJCTL_DTMF_PRESCALE		_IOW ('q', 0xE8, int)
+
+/******************************************************************************
+*
+* This ioctl allows the user application to control what events the driver
+* will send signals for, and what signals it will send for which event.
+* By default, if signaling is enabled, all events will send SIGIO when
+* they occur.  To disable signals for an event set the signal to 0.
+*
+******************************************************************************/
+typedef enum {
+	SIG_DTMF_READY,
+	SIG_HOOKSTATE,
+	SIG_FLASH,
+	SIG_PSTN_RING,
+	SIG_CALLER_ID,
+	SIG_PSTN_WINK,
+	SIG_F0, SIG_F1, SIG_F2, SIG_F3,
+	SIG_FC0, SIG_FC1, SIG_FC2, SIG_FC3,
+	SIG_READ_READY = 33,
+	SIG_WRITE_READY = 34
+} IXJ_SIGEVENT;
+
+typedef struct {
+	unsigned int event;
+	int signal;
+} IXJ_SIGDEF;
+
+#define IXJCTL_SIGCTL			_IOW ('q', 0xE9, IXJ_SIGDEF *)
+
+/******************************************************************************
+*
+* These ioctls allow the user application to change the gain in the 
+* Smart Cable of the Internet Phone Card.  Sending -1 as a value will cause
+* return value to be the current setting.  Valid values to set are 0x00 - 0x1F
+*
+* 11111 = +12 dB
+* 10111 =   0 dB
+* 00000 = -34.5 dB
+*
+* IXJCTL_SC_RXG sets the Receive gain
+* IXJCTL_SC_TXG sets the Transmit gain
+*
+******************************************************************************/
+#define IXJCTL_SC_RXG			_IOW ('q', 0xEA, int)
+#define IXJCTL_SC_TXG			_IOW ('q', 0xEB, int)
 
 /******************************************************************************
 *
@@ -653,3 +706,17 @@
 
 #define IXJCTL_INTERCOM_START 		_IOW ('q', 0xFD, int)
 #define IXJCTL_INTERCOM_STOP  		_IOW ('q', 0xFE, int)
+
+/******************************************************************************
+ *
+ * new structure for accessing raw filter information
+ *
+ ******************************************************************************/
+
+typedef struct {
+	unsigned int filter;
+	char enable;
+	unsigned int coeff[19];
+} IXJ_FILTER_RAW;
+
+#endif
diff -urN linux-2.4.10-pre8/include/linux/kernel.h linux/include/linux/kernel.h
--- linux-2.4.10-pre8/include/linux/kernel.h	Mon Dec  3 23:09:39 2001
+++ linux/include/linux/kernel.h	Mon Dec  3 23:09:49 2001
@@ -64,6 +64,11 @@
 extern int vsprintf(char *buf, const char *, va_list);
 extern int snprintf(char * buf, size_t size, const char *fmt, ...);
 extern int vsnprintf(char *buf, size_t size, const char *fmt, va_list args);
+
+extern int sscanf(const char *, const char *, ...)
+	__attribute__ ((format (scanf,2,3)));
+extern int vsscanf(const char *, const char *, va_list);
+
 extern int get_option(char **str, int *pint);
 extern char *get_options(char *str, int nints, int *ints);
 extern unsigned long long memparse(char *ptr, char **retptr);
diff -urN linux-2.4.10-pre8/include/linux/module.h linux/include/linux/module.h
--- linux-2.4.10-pre8/include/linux/module.h	Mon Dec  3 23:09:39 2001
+++ linux/include/linux/module.h	Mon Dec  3 23:09:49 2001
@@ -130,6 +130,16 @@
 	((unsigned long)(&((struct module *)0L)->member + 1)		\
 	 <= (mod)->size_of_struct)
 
+/*
+ * Ditto for archdata.  Assumes mod->archdata_start and mod->archdata_end
+ * are validated elsewhere.
+ */
+#define mod_archdata_member_present(mod, type, member)			\
+	(((unsigned long)(&((type *)0L)->member) +			\
+	  sizeof(((type *)0L)->member)) <=				\
+	 ((mod)->archdata_end - (mod)->archdata_start))
+	 
+
 /* Check if an address p with number of entries n is within the body of module m */
 #define mod_bound(p, n, m) ((unsigned long)(p) >= ((unsigned long)(m) + ((m)->size_of_struct)) && \
 	         (unsigned long)((p)+(n)) <= (unsigned long)(m) + (m)->size)
diff -urN linux-2.4.10-pre8/include/linux/mount.h linux/include/linux/mount.h
--- linux-2.4.10-pre8/include/linux/mount.h	Thu Aug  9 16:41:36 2001
+++ linux/include/linux/mount.h	Mon Dec  3 23:09:49 2001
@@ -12,6 +12,10 @@
 #define _LINUX_MOUNT_H
 #ifdef __KERNEL__
 
+#define MNT_NOSUID	1
+#define MNT_NODEV	2
+#define MNT_NOEXEC	4
+
 struct vfsmount
 {
 	struct list_head mnt_hash;
diff -urN linux-2.4.10-pre8/include/linux/quotaops.h linux/include/linux/quotaops.h
--- linux-2.4.10-pre8/include/linux/quotaops.h	Wed Aug 15 14:24:14 2001
+++ linux/include/linux/quotaops.h	Mon Dec  3 23:09:49 2001
@@ -37,8 +37,10 @@
  */
 static __inline__ void DQUOT_INIT(struct inode *inode)
 {
-	if (inode->i_sb && inode->i_sb->dq_op)
-		inode->i_sb->dq_op->initialize(inode, -1);
+	if (!IS_NOQUOTA(inode)) {
+		if (inode->i_sb && inode->i_sb->dq_op)
+			inode->i_sb->dq_op->initialize(inode, -1);
+	}
 }
 
 static __inline__ void DQUOT_DROP(struct inode *inode)
@@ -70,7 +72,7 @@
 static __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
 {
 	if (sb->dq_op) {
-		sb->dq_op->initialize (inode, -1);
+		DQUOT_INIT(inode);
 		if (sb->dq_op->alloc_inode (inode, 1))
 			return 1;
 	}
@@ -94,8 +96,8 @@
 {
 	int error = -EDQUOT;
 
-	if (dentry->d_inode->i_sb->dq_op) {
-		dentry->d_inode->i_sb->dq_op->initialize(dentry->d_inode, -1);
+	if (dentry->d_inode->i_sb->dq_op && !IS_NOQUOTA(dentry->d_inode)) {
+		DQUOT_INIT(dentry->d_inode);
 		error = dentry->d_inode->i_sb->dq_op->transfer(dentry, iattr);
 	} else {
 		error = notify_change(dentry, iattr);
diff -urN linux-2.4.10-pre8/include/linux/sysctl.h linux/include/linux/sysctl.h
--- linux-2.4.10-pre8/include/linux/sysctl.h	Mon Dec  3 23:09:39 2001
+++ linux/include/linux/sysctl.h	Mon Dec  3 23:09:49 2001
@@ -61,7 +61,7 @@
 	CTL_FS=5,		/* Filesystems */
 	CTL_DEBUG=6,		/* Debugging */
 	CTL_DEV=7,		/* Devices */
-	CTL_BUS=8,		/* Buses */
+	CTL_BUS=8,		/* Busses */
 	CTL_ABI=9		/* Binary emulation */
 };
 
@@ -119,7 +119,8 @@
 	KERN_SHMPATH=48,	/* string: path to shm fs */
 	KERN_HOTPLUG=49,	/* string: path to hotplug policy agent */
 	KERN_IEEE_EMULATION_WARNINGS=50, /* int: unimplemented ieee instructions */
-	KERN_S390_USER_DEBUG_LOGGING=51  /* int: dumps of user faults */
+	KERN_S390_USER_DEBUG_LOGGING=51,  /* int: dumps of user faults */
+	KERN_CORE_USES_PID=52,		/* int: use core or core.%pid */
 };
 
 
@@ -473,6 +474,7 @@
 	NET_DECNET_DR_COUNT = 8,
 	NET_DECNET_DST_GC_INTERVAL = 9,
 	NET_DECNET_CONF = 10,
+	NET_DECNET_NO_FC_MAX_CWND = 11,
 	NET_DECNET_DEBUG_LEVEL = 255
 };
 
diff -urN linux-2.4.10-pre8/include/linux/wait.h linux/include/linux/wait.h
--- linux-2.4.10-pre8/include/linux/wait.h	Wed Aug 15 14:21:11 2001
+++ linux/include/linux/wait.h	Mon Dec  3 23:09:49 2001
@@ -14,6 +14,7 @@
 #include <linux/list.h>
 #include <linux/stddef.h>
 #include <linux/spinlock.h>
+#include <linux/config.h>
 
 #include <asm/page.h>
 #include <asm/processor.h>
@@ -21,7 +22,11 @@
 /*
  * Debug control.  Slow but useful.
  */
+#if defined(CONFIG_DEBUG_WAITQ)
+#define WAITQUEUE_DEBUG 1
+#else
 #define WAITQUEUE_DEBUG 0
+#endif
 
 struct __wait_queue {
 	unsigned int flags;
diff -urN linux-2.4.10-pre8/include/net/irda/irda-usb.h linux/include/net/irda/irda-usb.h
--- linux-2.4.10-pre8/include/net/irda/irda-usb.h	Tue May  1 16:05:00 2001
+++ linux/include/net/irda/irda-usb.h	Mon Dec  3 23:09:49 2001
@@ -1,13 +1,14 @@
 /*****************************************************************************
  *
  * Filename:      irda-usb.h
- * Version:       0.8
+ * Version:       0.9a
  * Description:   IrDA-USB Driver
  * Status:        Experimental 
  * Author:        Dag Brattli <dag@brattli.net>
  *
- *      Copyright (C) 2001, Dag Brattli <dag@brattli.net>
- *	Copyright (C) 2000, Roman Weissgaerber <weissg@vienna.at>
+ *	Copyright (C) 2001, Roman Weissgaerber <weissg@vienna.at>
+ *      Copyright (C) 2000, Dag Brattli <dag@brattli.net>
+ *      Copyright (C) 2001, Jean Tourrilhes <jt@hpl.hp.com>
  *          
  *	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
@@ -35,13 +36,44 @@
 #define IRDA_USB_MAX_MTU 2051
 #define IRDA_USB_SPEED_MTU 64		/* Weird, but work like this */
 
-/*
- * Maximum number of URB on the Rx and Tx path, a number larger than 1
- * is required for handling back-to-back (brickwalled) frames 
- */
-#define IU_MAX_ACTIVE_RX_URBS 1
-#define IU_MAX_RX_URBS	(IU_MAX_ACTIVE_RX_URBS + 1) 
-#define IU_MAX_TX_URBS  1
+/* Maximum number of active URB on the Rx path
+ * This is the amount of buffers the we keep between the USB harware and the
+ * IrDA stack.
+ *
+ * Note : the network layer does also queue the packets between us and the
+ * IrDA stack, and is actually pretty fast and efficient in doing that.
+ * Therefore, we don't need to have a large number of URBs, and we can
+ * perfectly live happy with only one. We certainly don't need to keep the
+ * full IrTTP window around here...
+ * I repeat for those who have trouble to understand : 1 URB is plenty
+ * good enough to handle back-to-back (brickwalled) frames. I tried it,
+ * it works (it's the hardware that has trouble doing it).
+ *
+ * Having 2 URBs would allow the USB stack to process one URB while we take
+ * care of the other and then swap the URBs...
+ * On the other hand, increasing the number of URB will have penalities
+ * in term of latency and will interact with the link management in IrLAP...
+ * Jean II */
+#define IU_MAX_ACTIVE_RX_URBS	1	/* Don't touch !!! */
+
+/* When a Rx URB is passed back to us, we can't reuse it immediately,
+ * because it may still be referenced by the USB layer. Therefore we
+ * need to keep one extra URB in the Rx path.
+ * Jean II */
+#define IU_MAX_RX_URBS	(IU_MAX_ACTIVE_RX_URBS + 1)
+
+/* Various ugly stuff to try to workaround generic problems */
+/* The USB layer should send empty frames at the end of packets multiple
+ * of the frame size. As it doesn't do it by default, we need to do it
+ * ourselves... See also following option. */
+#undef IU_BUG_KICK_TX
+/* Use the USB_ZERO_PACKET flag instead of sending empty frame (above)
+ * Work only with usb-uhci.o so far. Please fix uhic.c and usb-ohci.c */
+#define IU_USE_USB_ZERO_FLAG
+/* Send speed command in case of timeout, just for trying to get things sane */
+#define IU_BUG_KICK_TIMEOUT
+/* Show the USB class descriptor */
+#undef IU_DUMP_CLASS_DESC 
 
 /* Inbound header */
 #define MEDIA_BUSY    0x80
@@ -56,15 +88,19 @@
 #define SPEED_1152000 0x08
 #define SPEED_4000000 0x09
 
-/* device_info flags in struct usb_device_id */
+/* Basic capabilities */
 #define IUC_DEFAULT	0x00	/* Basic device compliant with 1.0 spec */
+/* Main bugs */
 #define IUC_SPEED_BUG	0x01	/* Device doesn't set speed after the frame */
-#define IUC_SIR_ONLY	0x02	/* Device doesn't behave at FIR speeds */
-#define IUC_SMALL_PKT	0x04	/* Device doesn't behave with big Rx packets */
-#define IUC_NO_WINDOW	0x08	/* Device doesn't behave with big Rx window */
-#define IUC_MAX_WINDOW	0x10	/* Device underestimate the Rx window */
-#define IUC_MAX_XBOFS	0x20	/* Device need more xbofs than advertised */
+#define IUC_NO_WINDOW	0x02	/* Device doesn't behave with big Rx window */
+#define IUC_NO_TURN	0x04	/* Device doesn't do turnaround by itself */
+/* Not currently used */
+#define IUC_SIR_ONLY	0x08	/* Device doesn't behave at FIR speeds */
+#define IUC_SMALL_PKT	0x10	/* Device doesn't behave with big Rx packets */
+#define IUC_MAX_WINDOW	0x20	/* Device underestimate the Rx window */
+#define IUC_MAX_XBOFS	0x40	/* Device need more xbofs than advertised */
 
+/* USB class definitions */
 #define USB_IRDA_HEADER   0x01
 #define USB_CLASS_IRDA    0x02 /* USB_CLASS_APP_SPEC subclass */ 
 #define USB_DT_IRDA       0x21
@@ -89,23 +125,29 @@
 	int netopen;			/* Device is active for network */
 	int present;			/* Device is present on the bus */
 	__u32 capability;		/* Capability of the hardware */
-	__u8  bulk_in_ep, bulk_out_ep;	/* Endpoint assignments */
-	__u16 bulk_out_mtu;
-	
+	__u8  bulk_in_ep;		/* Rx Endpoint assignments */
+	__u8  bulk_out_ep;		/* Tx Endpoint assignments */
+	__u16 bulk_out_mtu;		/* Max Tx packet size in bytes */
+	__u8  bulk_int_ep;		/* Interrupt Endpoint assignments */
+
 	wait_queue_head_t wait_q;	/* for timeouts */
 
-	struct urb rx_urb[IU_MAX_RX_URBS];  /* URBs used to receive data frames */
-	struct urb *rx_idle_urb;         /* Pointer to idle URB in Rx path */
+	struct urb rx_urb[IU_MAX_RX_URBS];	/* URBs used to receive data frames */
+	struct urb *idle_rx_urb;	/* Pointer to idle URB in Rx path */
 	struct urb tx_urb;		/* URB used to send data frames */
 	struct urb speed_urb;		/* URB used to send speed commands */
+#ifdef IU_BUG_KICK_TX
+	struct urb empty_urb;		/* URB used to send empty commands */
+#endif IU_BUG_KICK_TX
 	
 	struct net_device *netdev;	/* Yes! we are some kind of netdev. */
 	struct net_device_stats stats;
 	struct irlap_cb   *irlap;	/* The link layer we are binded to */
-	struct qos_info qos;		 
+	struct qos_info qos;
 	hashbin_t *tx_list;		/* Queued transmit skb's */
+	char *speed_buff;		/* Buffer for speed changes */
 
-        struct timeval stamp;
+	struct timeval stamp;
 	struct timeval now;
 
 	spinlock_t lock;		/* For serializing operations */
@@ -116,5 +158,4 @@
 	__s32 new_speed;		/* speed we need to set */
 	__u32 flags;			/* Interface flags */
 };
-
 
diff -urN linux-2.4.10-pre8/include/net/irda/irias_object.h linux/include/net/irda/irias_object.h
--- linux-2.4.10-pre8/include/net/irda/irias_object.h	Mon Dec 11 13:33:09 2000
+++ linux/include/net/irda/irias_object.h	Mon Dec  3 23:09:49 2001
@@ -78,7 +78,7 @@
 	struct ias_value *value; /* Attribute value */
 };
 
-char *strdup(char *str);
+char *strndup(char *str, int max);
 
 struct ias_object *irias_new_object(char *name, int id);
 void irias_insert_object(struct ias_object *obj);
diff -urN linux-2.4.10-pre8/include/net/irda/irlap.h linux/include/net/irda/irlap.h
--- linux-2.4.10-pre8/include/net/irda/irlap.h	Wed Jul  4 11:50:38 2001
+++ linux/include/net/irda/irlap.h	Mon Dec  3 23:09:49 2001
@@ -66,7 +66,9 @@
 	irda_queue_t q;     /* Must be first */
 	magic_t magic;
 
+	/* Device we are attached to */
 	struct net_device  *netdev;
+	char		hw_name[2*IFNAMSIZ + 1];
 
 	/* Connection state */
 	volatile IRLAP_STATE state;       /* Current state */
@@ -163,7 +165,8 @@
 int irlap_init(void);
 void irlap_cleanup(void);
 
-struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos);
+struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
+			    char *	hw_name);
 void irlap_close(struct irlap_cb *self);
 
 void irlap_connect_request(struct irlap_cb *self, __u32 daddr, 
diff -urN linux-2.4.10-pre8/include/net/irda/irlmp.h linux/include/net/irda/irlmp.h
--- linux-2.4.10-pre8/include/net/irda/irlmp.h	Mon Dec 11 12:59:38 2000
+++ linux/include/net/irda/irlmp.h	Mon Dec  3 23:09:49 2001
@@ -217,6 +217,7 @@
 void irlmp_discovery_confirm(hashbin_t *discovery_log);
 void irlmp_discovery_request(int nslots);
 struct irda_device_info *irlmp_get_discoveries(int *pn, __u16 mask);
+void irlmp_do_expiry(void);
 void irlmp_do_discovery(int nslots);
 discovery_t *irlmp_get_discovery_response(void);
 void irlmp_discovery_expiry(discovery_t *expiry);
@@ -246,6 +247,7 @@
 extern int sysctl_discovery_timeout;
 extern int sysctl_discovery_slots;
 extern int sysctl_discovery;
+extern int sysctl_lap_keepalive_time;	/* in ms, default is LM_IDLE_TIMEOUT */
 extern struct irlmp_cb *irlmp;
 
 static inline hashbin_t *irlmp_get_cachelog(void) { return irlmp->cachelog; }
diff -urN linux-2.4.10-pre8/include/video/fbcon.h linux/include/video/fbcon.h
--- linux-2.4.10-pre8/include/video/fbcon.h	Mon Nov 27 17:11:26 2000
+++ linux/include/video/fbcon.h	Mon Dec  3 23:09:49 2001
@@ -206,7 +206,7 @@
 #define fb_writel sbus_writel
 #define fb_memset sbus_memset_io
 
-#elif defined(__i386__) || defined(__alpha__)
+#elif defined(__i386__) || defined(__alpha__) || defined(__x86_64__)
 
 #define fb_readb __raw_readb
 #define fb_readw __raw_readw
diff -urN linux-2.4.10-pre8/kernel/ksyms.c linux/kernel/ksyms.c
--- linux-2.4.10-pre8/kernel/ksyms.c	Mon Dec  3 23:09:39 2001
+++ linux/kernel/ksyms.c	Mon Dec  3 23:09:49 2001
@@ -452,8 +452,10 @@
 EXPORT_SYMBOL(printk);
 EXPORT_SYMBOL(sprintf);
 EXPORT_SYMBOL(snprintf);
+EXPORT_SYMBOL(sscanf);
 EXPORT_SYMBOL(vsprintf);
 EXPORT_SYMBOL(vsnprintf);
+EXPORT_SYMBOL(vsscanf);
 EXPORT_SYMBOL(kdevname);
 EXPORT_SYMBOL(bdevname);
 EXPORT_SYMBOL(cdevname);
diff -urN linux-2.4.10-pre8/kernel/module.c linux/kernel/module.c
--- linux-2.4.10-pre8/kernel/module.c	Sun Aug 12 11:13:59 2001
+++ linux/kernel/module.c	Mon Dec  3 23:09:49 2001
@@ -246,9 +246,7 @@
 {
 	kernel_module.nsyms = __stop___ksymtab - __start___ksymtab;
 
-#ifdef __alpha__
-	__asm__("stq $29,%0" : "=m"(kernel_module.gp));
-#endif
+	arch_init_modules(&kernel_module);
 }
 
 /*
@@ -440,12 +438,6 @@
 		printk(KERN_ERR "init_module: mod->flags invalid.\n");
 		goto err2;
 	}
-#ifdef __alpha__
-	if (!mod_bound(mod->gp - 0x8000, 0, mod)) {
-		printk(KERN_ERR "init_module: mod->gp out of bounds.\n");
-		goto err2;
-	}
-#endif
 	if (mod_member_present(mod, can_unload)
 	    && mod->can_unload && !mod_bound(mod->can_unload, 0, mod)) {
 		printk(KERN_ERR "init_module: mod->can_unload out of bounds.\n");
diff -urN linux-2.4.10-pre8/kernel/sys.c linux/kernel/sys.c
--- linux-2.4.10-pre8/kernel/sys.c	Thu Jul 26 13:43:33 2001
+++ linux/kernel/sys.c	Mon Dec  3 23:09:49 2001
@@ -1208,7 +1208,7 @@
 	switch (option) {
 		case PR_SET_PDEATHSIG:
 			sig = arg2;
-			if (sig > _NSIG) {
+			if (sig < 0 || sig > _NSIG) {
 				error = -EINVAL;
 				break;
 			}
diff -urN linux-2.4.10-pre8/kernel/sysctl.c linux/kernel/sysctl.c
--- linux-2.4.10-pre8/kernel/sysctl.c	Mon Dec  3 23:09:39 2001
+++ linux/kernel/sysctl.c	Mon Dec  3 23:09:49 2001
@@ -47,6 +47,7 @@
 extern int max_threads;
 extern int nr_queued_signals, max_queued_signals;
 extern int sysrq_enabled;
+extern int core_uses_pid;
 
 /* this is needed for the proc_dointvec_minmax for [fs_]overflow UID and GID */
 static int maxolduid = 65535;
@@ -165,6 +166,8 @@
 	{KERN_DOMAINNAME, "domainname", system_utsname.domainname, 64,
 	 0644, NULL, &proc_doutsstring, &sysctl_string},
 	{KERN_PANIC, "panic", &panic_timeout, sizeof(int),
+	 0644, NULL, &proc_dointvec},
+	{KERN_CORE_USES_PID, "core_uses_pid", &core_uses_pid, sizeof(int),
 	 0644, NULL, &proc_dointvec},
 	{KERN_CAP_BSET, "cap-bound", &cap_bset, sizeof(kernel_cap_t),
 	 0600, NULL, &proc_dointvec_bset},
diff -urN linux-2.4.10-pre8/lib/vsprintf.c linux/lib/vsprintf.c
--- linux-2.4.10-pre8/lib/vsprintf.c	Sun Aug  5 13:12:41 2001
+++ linux/lib/vsprintf.c	Mon Dec  3 23:09:49 2001
@@ -502,3 +502,187 @@
 	return i;
 }
 
+/**
+ * vsscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	format of buffer
+ * @args:	arguments
+ */
+int vsscanf(const char * buf, const char * fmt, va_list args)
+{
+	const char *str = buf;
+	char *next;
+	int num = 0;
+	int qualifier;
+	int base;
+	unsigned int field_width;
+	int is_sign = 0;
+
+	for (; *fmt; fmt++) {
+		/* skip any white space in format */
+		if (isspace(*fmt)) {
+			continue;
+		}
+
+		/* anything that is not a conversion must match exactly */
+		if (*fmt != '%') {
+			if (*fmt++ != *str++)
+				return num;
+			continue;
+		}
+		++fmt;
+		
+		/* skip this conversion.
+		 * advance both strings to next white space
+		 */
+		if (*fmt == '*') {
+			while (!isspace(*fmt))
+				fmt++;
+			while(!isspace(*str))
+				str++;
+			continue;
+		}
+
+		/* get field width */
+		field_width = 0xffffffffUL;
+		if (isdigit(*fmt))
+			field_width = skip_atoi(&fmt);
+
+		/* get conversion qualifier */
+		qualifier = -1;
+		if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'Z') {
+			qualifier = *fmt;
+			fmt++;
+		}
+		base = 10;
+		is_sign = 0;
+
+		switch(*fmt) {
+		case 'c':
+		{
+			char *s = (char *) va_arg(args,char*);
+			do {
+				*s++ = *str++;
+			} while(field_width-- > 0);
+			num++;
+		}
+		continue;
+		case 's':
+		{
+			char *s = (char *) va_arg(args, char *);
+			/* first, skip leading white space in buffer */
+			while (isspace(*str))
+				str++;
+
+			/* now copy until next white space */
+			while (!isspace(*str) && field_width--) {
+				*s++ = *str++;
+			}
+			*s = '\0';
+			num++;
+		}
+		continue;
+		case 'n':
+			/* return number of characters read so far */
+		{
+			int *i = (int *)va_arg(args,int*);
+			*i = str - buf;
+		}
+		continue;
+		case 'o':
+			base = 8;
+			break;
+		case 'x':
+		case 'X':
+			base = 16;
+			break;
+		case 'd':
+		case 'i':
+			is_sign = 1;
+		case 'u':
+			break;
+		case '%':
+			/* looking for '%' in str */
+			if (*str++ != '%') 
+				return num;
+			continue;
+		default:
+			/* invalid format; stop here */
+			return num;
+		}
+
+		/* have some sort of integer conversion.
+		 * first, skip white space in buffer.
+		 */
+		while (isspace(*str))
+			str++;
+
+		switch(qualifier) {
+		case 'h':
+			if (is_sign) {
+				short *s = (short *) va_arg(args,short *);
+				*s = (short) simple_strtol(str,&next,base);
+			} else {
+				unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
+				*s = (unsigned short) simple_strtoul(str, &next, base);
+			}
+			break;
+		case 'l':
+			if (is_sign) {
+				long *l = (long *) va_arg(args,long *);
+				*l = simple_strtol(str,&next,base);
+			} else {
+				unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
+				*l = simple_strtoul(str,&next,base);
+			}
+			break;
+		case 'L':
+			if (is_sign) {
+				long long *l = (long long*) va_arg(args,long long *);
+				*l = simple_strtoll(str,&next,base);
+			} else {
+				unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
+				*l = simple_strtoull(str,&next,base);
+			}
+			break;
+		case 'Z':
+		{
+			size_t *s = (size_t*) va_arg(args,size_t*);
+			*s = (size_t) simple_strtoul(str,&next,base);
+		}
+		break;
+		default:
+			if (is_sign) {
+				int *i = (int *) va_arg(args, int*);
+				*i = (int) simple_strtol(str,&next,base);
+			} else {
+				unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
+				*i = (unsigned int) simple_strtoul(str,&next,base);
+			}
+			break;
+		}
+		num++;
+
+		if (!next)
+			break;
+		str = next;
+	}
+	return num;
+}
+
+/**
+ * sscanf - Unformat a buffer into a list of arguments
+ * @buf:	input buffer
+ * @fmt:	formatting of buffer
+ * @...:	resulting arguments
+ */
+int sscanf(const char * buf, const char * fmt, ...)
+{
+	va_list args;
+	int i;
+
+	va_start(args,fmt);
+	i = vsscanf(buf,fmt,args);
+	va_end(args);
+	return i;
+}
diff -urN linux-2.4.10-pre8/net/ax25/af_ax25.c linux/net/ax25/af_ax25.c
--- linux-2.4.10-pre8/net/ax25/af_ax25.c	Mon Dec  3 23:09:39 2001
+++ linux/net/ax25/af_ax25.c	Mon Dec  3 23:09:49 2001
@@ -1841,7 +1841,7 @@
 EXPORT_SYMBOL(null_ax25_address);
 EXPORT_SYMBOL(ax25_display_timer);
 
-static const char banner[] __initdata = KERN_INFO "NET4: G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET4.0\n";
+static char banner[] __initdata = KERN_INFO "NET4: G4KLX/GW4PTS AX.25 for Linux. Version 0.37 for Linux NET4.0\n";
 
 static int __init ax25_init(void)
 {
diff -urN linux-2.4.10-pre8/net/ipx/af_ipx.c linux/net/ipx/af_ipx.c
--- linux-2.4.10-pre8/net/ipx/af_ipx.c	Mon Dec  3 23:09:39 2001
+++ linux/net/ipx/af_ipx.c	Mon Dec  3 23:09:50 2001
@@ -2536,7 +2536,7 @@
 
 static unsigned char ipx_8022_type = 0xE0;
 static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
-static const char banner[] __initdata =
+static char banner[] __initdata =
 	KERN_INFO "NET4: Linux IPX 0.47 for NET4.0\n"
 	KERN_INFO "IPX Portions Copyright (c) 1995 Caldera, Inc.\n" \
 	KERN_INFO "IPX Portions Copyright (c) 2000, 2001 Conectiva, Inc.\n";
diff -urN linux-2.4.10-pre8/net/ipx/af_spx.c linux/net/ipx/af_spx.c
--- linux-2.4.10-pre8/net/ipx/af_spx.c	Sat Jun 30 10:38:44 2001
+++ linux/net/ipx/af_spx.c	Mon Dec  3 23:09:50 2001
@@ -910,7 +910,7 @@
 	create:		spx_create,
 };
 
-static const char banner[] __initdata = KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n";
+static char banner[] __initdata = KERN_INFO "NET4: Sequenced Packet eXchange (SPX) 0.02 for Linux NET4.0\n";
 
 static int __init spx_proto_init(void)
 {
diff -urN linux-2.4.10-pre8/net/irda/af_irda.c linux/net/irda/af_irda.c
--- linux-2.4.10-pre8/net/irda/af_irda.c	Mon Dec  3 23:09:39 2001
+++ linux/net/irda/af_irda.c	Mon Dec  3 23:09:50 2001
@@ -98,6 +98,8 @@
 	struct sock *sk;
 	int err;
 
+	IRDA_DEBUG(3, __FUNCTION__ "()\n");
+
 	self = (struct irda_sock *) instance;
 	ASSERT(self != NULL, return -1;);
 
@@ -128,10 +130,10 @@
 	struct irda_sock *self;
 	struct sock *sk;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
 	self = (struct irda_sock *) instance;
 
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
+
 	sk = self->sk;
 	if (sk == NULL)
 		return;
@@ -155,8 +157,10 @@
 	 * Note : all socket function do check sk->state, so we are safe...
 	 * Jean II
 	 */
-	irttp_close_tsap(self->tsap);
-	self->tsap = NULL;
+	if (self->tsap) {
+		irttp_close_tsap(self->tsap);
+		self->tsap = NULL;
+	}
 
 	/* Note : once we are there, there is not much you want to do
 	 * with the socket anymore, apart from closing it.
@@ -180,10 +184,10 @@
 	struct irda_sock *self;
 	struct sock *sk;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
 	self = (struct irda_sock *) instance;
 
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
+
 	sk = self->sk;
 	if (sk == NULL)
 		return;
@@ -238,10 +242,10 @@
 	struct irda_sock *self;
 	struct sock *sk;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
  	self = (struct irda_sock *) instance;
 
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
+
 	sk = self->sk;
 	if (sk == NULL)
 		return;
@@ -358,14 +362,14 @@
 {
 	struct irda_sock *self;
 	
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
 	self = (struct irda_sock *) priv;
 	if (!self) {
 		WARNING(__FUNCTION__ "(), lost myself!\n");
 		return;
 	}
 
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
+
 	/* We probably don't need to make any more queries */
 	iriap_close(self->iriap);
 	self->iriap = NULL;
@@ -539,7 +543,7 @@
  */
 static int irda_find_lsap_sel(struct irda_sock *self, char *name)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "(), name=%s\n", name);
+	IRDA_DEBUG(2, __FUNCTION__ "(%p, %s)\n", self, name);
 
 	ASSERT(self != NULL, return -1;);
 
@@ -550,6 +554,8 @@
 
 	self->iriap = iriap_open(LSAP_ANY, IAS_CLIENT, self,
 				 irda_getvalue_confirm);
+	if(self->iriap == NULL)
+		return -ENOMEM;
 
 	/* Treat unexpected signals as disconnect */
 	self->errno = -EHOSTUNREACH;
@@ -777,11 +783,11 @@
 	struct irda_sock *self;
 	int err;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
 
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
+
 	if (addr_len != sizeof(struct sockaddr_irda))
 		return -EINVAL;
 
@@ -942,10 +948,10 @@
 	struct irda_sock *self;
 	int err;
 
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
-
 	self = sk->protinfo.irda;
 	
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
+
 	/* Don't allow connect for Ultra sockets */
 	if ((sk->type == SOCK_DGRAM) && (sk->protocol == IRDAPROTO_ULTRA))
 		return -ESOCKTNOSUPPORT;
@@ -1063,22 +1069,29 @@
 		return -ESOCKTNOSUPPORT;
 	}
 
-	/* Allocate socket */
+	/* Allocate networking socket */
 	if ((sk = sk_alloc(PF_IRDA, GFP_ATOMIC, 1)) == NULL)
 		return -ENOMEM;
-	
+
+	/* Allocate IrDA socket */
 	self = kmalloc(sizeof(struct irda_sock), GFP_ATOMIC);
 	if (self == NULL) {
-		kfree (sk);
+		sk_free(sk);
 		return -ENOMEM;
 	}
 	memset(self, 0, sizeof(struct irda_sock));
 
+	IRDA_DEBUG(2, __FUNCTION__ "() : self is %p\n", self);
+
 	init_waitqueue_head(&self->query_wait);
 
-	self->sk = sk;
+	/* Initialise networking socket struct */ 
+	sock_init_data(sock, sk);	/* Note : set sk->refcnt to 1 */
+	sk->family = PF_IRDA;
+	sk->protocol = protocol;
+	/* Link networking socket and IrDA socket structs together */
 	sk->protinfo.irda = self;
-	sock_init_data(sock, sk);
+	self->sk = sk;
 
 	switch (sock->type) {
 	case SOCK_STREAM:
@@ -1110,8 +1123,6 @@
 		return -ESOCKTNOSUPPORT;
 	}		
 
-	sk->protocol = protocol;
-
 	/* Register as a client with IrLMP */
 	self->ckey = irlmp_register_client(0, NULL, NULL, NULL);
 	self->mask = 0xffff;
@@ -1133,7 +1144,7 @@
  */
 void irda_destroy_socket(struct irda_sock *self)
 {
-	IRDA_DEBUG(2, __FUNCTION__ "()\n");
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
 
 	ASSERT(self != NULL, return;);
 
@@ -1187,12 +1198,47 @@
 	sk->state       = TCP_CLOSE;
 	sk->shutdown   |= SEND_SHUTDOWN;
 	sk->state_change(sk);
-	sk->dead        = 1;
 
+	/* Destroy IrDA socket */
 	irda_destroy_socket(sk->protinfo.irda);
+	/* Prevent sock_def_destruct() to create havoc */
+	sk->protinfo.irda = NULL;
 
+	sock_orphan(sk);
         sock->sk   = NULL;      
-        sk->socket = NULL;      /* Not used, but we should do this. */
+
+	/* Purge queues (see sock_init_data()) */
+	skb_queue_purge(&sk->receive_queue);
+
+	/* Destroy networking socket if we are the last reference on it,
+	 * i.e. if(sk->refcnt == 0) -> sk_free(sk) */
+	sock_put(sk);
+
+	/* Notes on socket locking and deallocation... - Jean II
+	 * In theory we should put pairs of sock_hold() / sock_put() to
+	 * prevent the socket to be destroyed whenever there is an
+	 * outstanding request or outstanding incomming packet or event.
+	 *
+	 * 1) This may include IAS request, both in connect and getsockopt.
+	 * Unfortunately, the situation is a bit more messy than it looks,
+	 * because we close iriap and kfree(self) above.
+	 * 
+	 * 2) This may include selective discovery in getsockopt.
+	 * Same stuff as above, irlmp registration and self are gone.
+	 *
+	 * Probably 1 and 2 may not matter, because it's all triggered
+	 * by a process and the socket layer already prevent the
+	 * socket to go away while a process is holding it, through
+	 * sockfd_put() and fput()...
+	 *
+	 * 3) This may include deferred TSAP closure. In particular,
+	 * we may receive a late irda_disconnect_indication()
+	 * Fortunately, (tsap_cb *)->close_pend should protect us
+	 * from that.
+	 *
+	 * I did some testing on SMP, and it looks solid. And the socket
+	 * memory leak is now gone... - Jean II
+	 */
 
         return 0;
 }
@@ -1585,11 +1631,11 @@
 	struct irda_sock *self;
 	struct sock *sk = sock->sk;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
-
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
 
+	IRDA_DEBUG(1, __FUNCTION__ "(%p)\n", self);
+
 	sk->state       = TCP_CLOSE;
 	sk->shutdown   |= SEND_SHUTDOWN;
 	sk->state_change(sk);
@@ -1763,6 +1809,8 @@
 	self = sk->protinfo.irda;
 	ASSERT(self != NULL, return -1;);
 
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
+
 	if (level != SOL_IRLMP)
 		return -ENOPROTOOPT;
 		
@@ -2028,6 +2076,8 @@
 	int offset, total;
 
 	self = sk->protinfo.irda;
+
+	IRDA_DEBUG(2, __FUNCTION__ "(%p)\n", self);
 
 	if (level != SOL_IRLMP)
 		return -ENOPROTOOPT;
diff -urN linux-2.4.10-pre8/net/irda/iriap.c linux/net/irda/iriap.c
--- linux-2.4.10-pre8/net/irda/iriap.c	Sat Nov 11 18:11:22 2000
+++ linux/net/irda/iriap.c	Mon Dec  3 23:09:50 2001
@@ -379,7 +379,7 @@
 				  char *name, char *attr)
 {
 	struct sk_buff *skb;
-	int name_len, attr_len;
+	int name_len, attr_len, skb_len;
 	__u8 *frame;
 
 	ASSERT(self != NULL, return -1;);
@@ -400,13 +400,14 @@
 	/* Give ourselves 10 secs to finish this operation */
 	iriap_start_watchdog_timer(self, 10*HZ);
 	
-	skb = dev_alloc_skb(64);
+	name_len = strlen(name);	/* Up to IAS_MAX_CLASSNAME = 60 */
+	attr_len = strlen(attr);	/* Up to IAS_MAX_ATTRIBNAME = 60 */
+
+	skb_len = self->max_header_size+2+name_len+1+attr_len+4;
+	skb = dev_alloc_skb(skb_len);
 	if (!skb)
 		return -ENOMEM;
 
-	name_len = strlen(name);
-	attr_len = strlen(attr);
-
 	/* Reserve space for MUX and LAP header */
  	skb_reserve(skb, self->max_header_size);
 	skb_put(skb, 3+name_len+attr_len);
@@ -500,20 +501,19 @@
 		}
 		value_len = fp[n++];
 		IRDA_DEBUG(4, __FUNCTION__ "(), strlen=%d\n", value_len);
-		ASSERT(value_len < 64, return;);
 		
 		/* Make sure the string is null-terminated */
 		fp[n+value_len] = 0x00;
-		
 		IRDA_DEBUG(4, "Got string %s\n", fp+n);
+
+		/* Will truncate to IAS_MAX_STRING bytes */
 		value = irias_new_string_value(fp+n);
 		break;
 	case IAS_OCT_SEQ:
 		value_len = be16_to_cpu(get_unaligned((__u16 *)(fp+n)));
 		n += 2;
 		
-		ASSERT(value_len <= 55, return;);      
-		
+		/* Will truncate to IAS_MAX_OCTET_STRING bytes */
 		value = irias_new_octseq_value(fp+n, value_len);
 		break;
 	default:
@@ -635,8 +635,8 @@
 	struct ias_attrib *attrib;
 	int name_len;
 	int attr_len;
-	char name[64];
-	char attr[64];
+	char name[IAS_MAX_CLASSNAME + 1];	/* 60 bytes */
+	char attr[IAS_MAX_ATTRIBNAME + 1];	/* 60 bytes */
 	__u8 *fp;
 	int n;
 
@@ -1013,7 +1013,7 @@
 					       attrib->value->t.string);
 				break;
 			case IAS_OCT_SEQ:
-				len += sprintf(buf+len, "octet sequence\n");
+				len += sprintf(buf+len, "octet sequence (%d bytes)\n", attrib->value->len);
 				break;
 			case IAS_MISSING:
 				len += sprintf(buf+len, "missing\n");
diff -urN linux-2.4.10-pre8/net/irda/irias_object.c linux/net/irda/irias_object.c
--- linux-2.4.10-pre8/net/irda/irias_object.c	Wed Jul  4 11:50:38 2001
+++ linux/net/irda/irias_object.c	Mon Dec  3 23:09:50 2001
@@ -37,25 +37,35 @@
 struct ias_value missing = { IAS_MISSING, 0, 0, 0, {0}};
 
 /*
- * Function strdup (str)
+ * Function strndup (str, max)
  *
- *    My own kernel version of strdup!
+ *    My own kernel version of strndup!
  *
+ * Faster, check boundary... Jean II
  */
-char *strdup(char *str)
+char *strndup(char *str, int max)
 {
 	char *new_str;
+	int len;
 	
+	/* Check string */
 	if (str == NULL)
 		return NULL;
-
-	ASSERT(strlen( str) < 64, return NULL;);
-	
-        new_str = kmalloc(strlen(str)+1, GFP_ATOMIC);
-        if (new_str == NULL)
+	/* Check length, truncate */
+	len = strlen(str);
+	if(len > max)
+		len = max;
+
+	/* Allocate new string */
+        new_str = kmalloc(len + 1, GFP_ATOMIC);
+        if (new_str == NULL) {
+		WARNING(__FUNCTION__"(), Unable to kmalloc!\n");
 		return NULL;
-	
-	strcpy(new_str, str);
+	}
+
+	/* Copy and truncate */
+	memcpy(new_str, str, len);
+	new_str[len] = '\0';
 	
 	return new_str;
 }
@@ -81,7 +91,7 @@
 	memset(obj, 0, sizeof( struct ias_object));
 
 	obj->magic = IAS_OBJECT_MAGIC;
-	obj->name = strdup( name);
+	obj->name = strndup(name, IAS_MAX_CLASSNAME);
 	obj->id = id;
 
 	obj->attribs = hashbin_new(HB_LOCAL);
@@ -315,7 +325,7 @@
 	memset(attrib, 0, sizeof( struct ias_attrib));
 
 	attrib->magic = IAS_ATTRIB_MAGIC;
-	attrib->name = strdup(name);
+	attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
 
 	/* Insert value */
 	attrib->value = irias_new_integer_value(value);
@@ -351,7 +361,7 @@
 	memset(attrib, 0, sizeof( struct ias_attrib));
 	
 	attrib->magic = IAS_ATTRIB_MAGIC;
-	attrib->name = strdup( name);
+	attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
 	
 	attrib->value = irias_new_octseq_value( octets, len);
 	
@@ -384,7 +394,7 @@
 	memset(attrib, 0, sizeof( struct ias_attrib));
 
 	attrib->magic = IAS_ATTRIB_MAGIC;
-	attrib->name = strdup(name);
+	attrib->name = strndup(name, IAS_MAX_ATTRIBNAME);
 
 	attrib->value = irias_new_string_value(value);
 
@@ -420,10 +430,13 @@
  *
  *    Create new IAS string value
  *
+ * Per IrLMP 1.1, 4.3.3.2, strings are up to 256 chars - Jean II
  */
 struct ias_value *irias_new_string_value(char *string)
 {
 	struct ias_value *value;
+	int len;
+	char *new_str;
 
 	value = kmalloc(sizeof(struct ias_value), GFP_ATOMIC);
 	if (value == NULL) {
@@ -434,8 +447,8 @@
 
 	value->type = IAS_STRING;
 	value->charset = CS_ASCII;
-	value->len = strlen(string);
-	value->t.string = strdup(string);
+	value->t.string = strndup(string, IAS_MAX_STRING);
+	value->len = strlen(value->t.string);
 
 	return value;
 }
@@ -446,6 +459,7 @@
  *
  *    Create new IAS octet-sequence value
  *
+ * Per IrLMP 1.1, 4.3.3.2, octet-sequence are up to 1024 bytes - Jean II
  */
 struct ias_value *irias_new_octseq_value(__u8 *octseq , int len)
 {
@@ -459,11 +473,15 @@
 	memset(value, 0, sizeof(struct ias_value));
 
 	value->type = IAS_OCT_SEQ;
+	/* Check length */
+	if(len > IAS_MAX_OCTET_STRING)
+		len = IAS_MAX_OCTET_STRING;
 	value->len = len;
 
 	value->t.oct_seq = kmalloc(len, GFP_ATOMIC);
 	if (value->t.oct_seq == NULL){
 		WARNING(__FUNCTION__"(), Unable to kmalloc!\n");
+		kfree(value);
 		return NULL;
 	}
 	memcpy(value->t.oct_seq, octseq , len);
diff -urN linux-2.4.10-pre8/net/irda/irlap.c linux/net/irda/irlap.c
--- linux-2.4.10-pre8/net/irda/irlap.c	Wed Jul  4 11:50:38 2001
+++ linux/net/irda/irlap.c	Mon Dec  3 23:09:50 2001
@@ -94,7 +94,8 @@
  *    Initialize IrLAP layer
  *
  */
-struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos)
+struct irlap_cb *irlap_open(struct net_device *dev, struct qos_info *qos,
+			    char *	hw_name)
 {
 	struct irlap_cb *self;
 
@@ -111,6 +112,13 @@
 	/* Make a binding between the layers */
 	self->netdev = dev;
 	self->qos_dev = qos;
+	/* Copy hardware name */
+	if(hw_name != NULL) {
+		strncpy(self->hw_name, hw_name, 2*IFNAMSIZ);
+		self->hw_name[2*IFNAMSIZ] = '\0';
+	} else {
+		self->hw_name[0] = '\0';
+	}
 
 	/* FIXME: should we get our own field? */
 	dev->atalk_ptr = self;
@@ -1101,6 +1109,10 @@
 		len += sprintf(buf+len, "state: %s\n", 
 			       irlap_state[self->state]);
 		
+		len += sprintf(buf+len, "  device name: %s, ",
+			       (self->netdev) ? self->netdev->name : "bug");
+		len += sprintf(buf+len, "hardware name: %s\n", self->hw_name);
+
 		len += sprintf(buf+len, "  caddr: %#02x, ", self->caddr);
 		len += sprintf(buf+len, "saddr: %#08x, ", self->saddr);
 		len += sprintf(buf+len, "daddr: %#08x\n", self->daddr);
diff -urN linux-2.4.10-pre8/net/irda/irlap_event.c linux/net/irda/irlap_event.c
--- linux-2.4.10-pre8/net/irda/irlap_event.c	Wed Jul  4 11:50:38 2001
+++ linux/net/irda/irlap_event.c	Mon Dec  3 23:09:50 2001
@@ -2018,7 +2018,7 @@
 {
 	int ret = 0;
 
-	IRDA_DEBUG(0, __FUNCTION__ "()\n");
+	IRDA_DEBUG(1, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return -ENODEV;);
 	ASSERT(self->magic == LAP_MAGIC, return -EBADR;);
@@ -2048,6 +2048,9 @@
 		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
 		break;
 	case WD_TIMER_EXPIRED:
+		/* Always switch state before calling upper layers */
+		irlap_next_state(self, LAP_NDM);
+
 		irlap_apply_default_connection_parameters(self);
 		
 		irlap_disconnect_indication(self, LAP_DISC_INDICATION);
diff -urN linux-2.4.10-pre8/net/irda/irlmp.c linux/net/irda/irlmp.c
--- linux-2.4.10-pre8/net/irda/irlmp.c	Wed Jul  4 11:50:38 2001
+++ linux/net/irda/irlmp.c	Mon Dec  3 23:09:50 2001
@@ -49,6 +49,7 @@
 int  sysctl_discovery         = 0;
 int  sysctl_discovery_timeout = 3; /* 3 seconds by default */
 int  sysctl_discovery_slots   = 6; /* 6 slots by default */
+int  sysctl_lap_keepalive_time = LM_IDLE_TIMEOUT * 1000 / HZ;
 char sysctl_devname[65];
 
 char *lmp_reasons[] = {
@@ -693,10 +694,43 @@
 }
 
 /*
+ * Function irlmp_do_expiry (void)
+ *
+ *    Do a cleanup of the discovery log (remove old entries)
+ *
+ * Note : separate from irlmp_do_discovery() so that we can handle
+ * passive discovery properly.
+ */
+void irlmp_do_expiry()
+{
+	struct lap_cb *lap;
+
+	/*
+	 * Expire discovery on all links which are *not* connected.
+	 * On links which are connected, we can't do discovery
+	 * anymore and can't refresh the log, so we freeze the
+	 * discovery log to keep info about the device we are
+	 * connected to. - Jean II
+	 */
+	lap = (struct lap_cb *) hashbin_get_first(irlmp->links);
+	while (lap != NULL) {
+		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
+		
+		if (lap->lap_state == LAP_STANDBY) {
+			/* Expire discoveries discovered on this link */
+			irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,
+						 FALSE);
+		}
+		lap = (struct lap_cb *) hashbin_get_next(irlmp->links);
+	}
+}
+
+/*
  * Function irlmp_do_discovery (nslots)
  *
  *    Do some discovery on all links
  *
+ * Note : log expiry is done above.
  */
 void irlmp_do_discovery(int nslots)
 {
@@ -731,10 +765,6 @@
 		ASSERT(lap->magic == LMP_LAP_MAGIC, return;);
 		
 		if (lap->lap_state == LAP_STANDBY) {
-			/* Expire discoveries discovered on this link */
-			irlmp_expire_discoveries(irlmp->cachelog, lap->saddr,
-						 FALSE);
-
 			/* Try to discover */
 			irlmp_do_lap_event(lap, LM_LAP_DISCOVERY_REQUEST, 
 					   NULL);
@@ -764,6 +794,9 @@
 	 */
 	if (!sysctl_discovery)
 		irlmp_do_discovery(nslots);
+	/* Note : we never do expiry here. Expiry will run on the
+	 * discovery timer regardless of the state of sysctl_discovery
+	 * Jean II */
 }
 
 /*
diff -urN linux-2.4.10-pre8/net/irda/irlmp_event.c linux/net/irda/irlmp_event.c
--- linux-2.4.10-pre8/net/irda/irlmp_event.c	Wed Jul  4 11:50:38 2001
+++ linux/net/irda/irlmp_event.c	Mon Dec  3 23:09:50 2001
@@ -150,6 +150,10 @@
 {
 	IRDA_DEBUG(4, __FUNCTION__ "()\n");
 	
+	/* We always cleanup the log (active & passive discovery) */ 
+	irlmp_do_expiry();
+
+	/* Active discovery is conditional */
 	if (sysctl_discovery)
 		irlmp_do_discovery(sysctl_discovery_slots);
 
@@ -205,10 +209,6 @@
 		
 		irlap_discovery_request(self->irlap, &irlmp->discovery_cmd);
 		break;
-	case LM_LAP_DISCOVERY_CONFIRM:
- 		/* irlmp_next_station_state( LMP_READY); */
-		irlmp_discovery_confirm(irlmp->cachelog);
- 		break;
 	case LM_LAP_CONNECT_INDICATION:
 		/*  It's important to switch state first, to avoid IrLMP to 
 		 *  think that the link is free since IrLMP may then start
@@ -274,6 +274,12 @@
 			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
 			lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
 		}
+		/* Note : by the time we get there (LAP retries and co),
+		 * the lsaps may already have gone. This avoid getting stuck
+		 * forever in LAP_ACTIVE state - Jean II */
+		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
+			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
+		}
 		break;
 	case LM_LAP_CONNECT_REQUEST:
 		/* Already trying to connect */
@@ -288,6 +294,12 @@
 			irlmp_do_lsap_event(lsap, LM_LAP_CONNECT_CONFIRM, NULL);
 			lsap = (struct lsap_cb*) hashbin_get_next(self->lsaps);
 		}
+		/* Note : by the time we get there (LAP retries and co),
+		 * the lsaps may already have gone. This avoid getting stuck
+		 * forever in LAP_ACTIVE state - Jean II */
+		if (HASHBIN_GET_SIZE(self->lsaps) == 0) {
+			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
+		}
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
 		irlmp_next_lap_state(self, LAP_STANDBY);
@@ -375,9 +387,15 @@
 		 *  must be the one that tries to close IrLAP. It will be 
 		 *  removed later and moved to the list of unconnected LSAPs
 		 */
-		if (HASHBIN_GET_SIZE(self->lsaps) > 0)
-			irlmp_start_idle_timer(self, LM_IDLE_TIMEOUT);
-		else {
+		if (HASHBIN_GET_SIZE(self->lsaps) > 0) {
+			/* Make sure the timer has sensible value (the user
+			 * may have set it) - Jean II */
+			if(sysctl_lap_keepalive_time < 100)	/* 100ms */
+				sysctl_lap_keepalive_time = 100;
+			if(sysctl_lap_keepalive_time > 10000)	/* 10s */
+				sysctl_lap_keepalive_time = 10000;
+			irlmp_start_idle_timer(self, sysctl_lap_keepalive_time * HZ / 1000);
+		} else {
 			/* No more connections, so close IrLAP */
 
 			/* We don't want to change state just yet, because
diff -urN linux-2.4.10-pre8/net/irda/irlmp_frame.c linux/net/irda/irlmp_frame.c
--- linux-2.4.10-pre8/net/irda/irlmp_frame.c	Fri Mar  2 11:12:12 2001
+++ linux/net/irda/irlmp_frame.c	Mon Dec  3 23:09:50 2001
@@ -359,8 +359,9 @@
 	self = (struct lap_cb *) priv;
 	ASSERT(self != NULL, return;);
 
-	/* Just handle it the same way as a discovery confirm */
-	irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
+	/* Just handle it the same way as a discovery confirm,
+	 * bypass the LM_LAP state machine (see below) */
+	irlmp_discovery_confirm(irlmp->cachelog);
 }
 
 /*
@@ -377,8 +378,12 @@
  *	  we always get ~100% of these.
  *	o Make faster discovery, statistically divide time of discovery
  *	  events by 2 (important for the latency aspect and user feel)
+ *	o Even is we do active discovery, the other node might not
+ *	  answer our discoveries (ex: Palm).
+ *
  * However, when both devices discover each other, they might attempt to
- * connect to each other, and it would create collisions on the medium.
+ * connect to each other following the discovery event, and it would create
+ * collisions on the medium (SNRM battle).
  * The trick here is to defer the event by a little delay to avoid both
  * devices to jump in exactly at the same time...
  *
@@ -387,6 +392,14 @@
  * period/timeout that may be set is 1s). The message triggering this
  * event was the last of the discovery, so the medium is now free...
  * Maybe more testing is needed to get the value right...
+
+ * One more problem : the other node might do only a single discovery
+ * and connect immediately to us, and we would receive only a single
+ * discovery indication event, and because of the delay, it will arrive
+ * while the LAP is connected. That's another good reason to
+ * bypass the LM_LAP state machine ;-)
+ *
+ * Jean II
  */
 void irlmp_link_discovery_indication(struct lap_cb *self, 
 				     discovery_t *discovery)
@@ -427,8 +440,13 @@
 	if(timer_pending(&disco_delay))
 		del_timer(&disco_delay);
 
-	/* Propagate event to the state machine */
-	irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
+	/* Propagate event to various LSAPs registered for it.
+	 * We bypass the LM_LAP state machine because
+	 *	1) We do it regardless of the LM_LAP state
+	 *	2) It doesn't affect the LM_LAP state
+	 *	3) Faster, slimer, simpler, ...
+	 * Jean II */
+	irlmp_discovery_confirm(irlmp->cachelog);
 }
 
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
diff -urN linux-2.4.10-pre8/net/irda/irnet/irnet.h linux/net/irda/irnet/irnet.h
--- linux-2.4.10-pre8/net/irda/irnet/irnet.h	Mon Jun 11 19:15:27 2001
+++ linux/net/irda/irnet/irnet.h	Mon Dec  3 23:09:50 2001
@@ -185,6 +185,13 @@
  *	  is transparently controlled from pppd lcp-max-configure.
  *	o Add ttp_connect flag to prevent rentry on the connect procedure
  *	o Test and fixups to eliminate side effects of retries
+ *
+ * v7 - 22/08/01 - Jean II
+ *	o Cleanup : Change "saddr = 0x0" to "saddr = DEV_ADDR_ANY"
+ *	o Fix bug in BLOCK_WHEN_CONNECT introduced in v6 : due to the
+ *	  asynchronous IAS query, self->tsap is NULL when PPP send the
+ *	  first packet.  This was preventing "connect-delay 0" to work.
+ *	  Change the test in ppp_irnet_send() to self->ttp_connect.
  */
 
 /***************************** INCLUDES *****************************/
diff -urN linux-2.4.10-pre8/net/irda/irnet/irnet_irda.c linux/net/irda/irnet/irnet_irda.c
--- linux-2.4.10-pre8/net/irda/irnet/irnet_irda.c	Mon Jun 11 19:15:27 2001
+++ linux/net/irda/irnet/irnet_irda.c	Mon Dec  3 23:09:50 2001
@@ -478,9 +478,9 @@
   self->ttp_connect = 0;	/* Not connecting yet */
   self->rname[0] = '\0';	/* May be set via control channel */
   self->rdaddr = DEV_ADDR_ANY;	/* May be set via control channel */
-  self->rsaddr = 0x0;		/* May be set via control channel */
+  self->rsaddr = DEV_ADDR_ANY;	/* May be set via control channel */
   self->daddr = DEV_ADDR_ANY;	/* Until we get connected */
-  self->saddr = 0x0;		/* Until we get connected */
+  self->saddr = DEV_ADDR_ANY;	/* Until we get connected */
   self->max_sdu_size_rx = TTP_SAR_UNBOUND;
 
   /* Register as a client with IrLMP */
diff -urN linux-2.4.10-pre8/net/irda/irnet/irnet_ppp.c linux/net/irda/irnet/irnet_ppp.c
--- linux-2.4.10-pre8/net/irda/irnet/irnet_ppp.c	Mon Jun 11 19:15:27 2001
+++ linux/net/irda/irnet/irnet_ppp.c	Mon Dec  3 23:09:50 2001
@@ -858,8 +858,8 @@
       irda_irnet_connect(self);
 #endif /* CONNECT_IN_SEND */
 
-      DEBUG(PPP_INFO, "IrTTP not ready ! (%d-0x%X)\n",
-	    self->ttp_open, (unsigned int) self->tsap);
+      DEBUG(PPP_INFO, "IrTTP not ready ! (%d-%d)\n",
+	    self->ttp_open, self->ttp_connect);
 
       /* Note : we can either drop the packet or block the packet.
        *
@@ -882,7 +882,7 @@
        */
 #ifdef BLOCK_WHEN_CONNECT
       /* If we are attempting to connect */
-      if(self->tsap)
+      if(self->ttp_connect)
 	{
 	  /* Blocking packet, ppp_generic will retry later */
 	  return 0;
diff -urN linux-2.4.10-pre8/net/irda/irsysctl.c linux/net/irda/irsysctl.c
--- linux-2.4.10-pre8/net/irda/irsysctl.c	Wed Jul  4 11:50:38 2001
+++ linux/net/irda/irsysctl.c	Mon Dec  3 23:09:50 2001
@@ -33,7 +33,7 @@
 
 #define NET_IRDA 412 /* Random number */
 enum { DISCOVERY=1, DEVNAME, DEBUG, SLOTS, DISCOVERY_TIMEOUT, 
-       SLOT_TIMEOUT, MAX_BAUD_RATE, MAX_INACTIVE_TIME };
+       SLOT_TIMEOUT, MAX_BAUD_RATE, MAX_INACTIVE_TIME, LAP_KEEPALIVE_TIME, };
 
 extern int  sysctl_discovery;
 extern int  sysctl_discovery_slots;
@@ -44,6 +44,7 @@
 extern char sysctl_devname[];
 extern int  sysctl_max_baud_rate;
 extern int  sysctl_max_inactive_time;
+extern int  sysctl_lap_keepalive_time;
 
 #ifdef CONFIG_IRDA_DEBUG
 extern unsigned int irda_debug;
@@ -88,6 +89,8 @@
 	{ MAX_BAUD_RATE, "max_baud_rate", &sysctl_max_baud_rate,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 	{ MAX_INACTIVE_TIME, "max_inactive_time", &sysctl_max_inactive_time,
+	  sizeof(int), 0644, NULL, &proc_dointvec },
+	{ LAP_KEEPALIVE_TIME, "lap_keepalive_time", &sysctl_lap_keepalive_time,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 	{ 0 }
 };
