## Automatically generated incremental diff
## From:   linux-2.2.7-pre3
## To:     linux-2.2.7-pre4
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.2.7-pre3/arch/alpha/kernel/setup.c linux-2.2.7-pre4/arch/alpha/kernel/setup.c
--- linux-2.2.7-pre3/arch/alpha/kernel/setup.c	1999-01-14 10:21:40.000000000 -0800
+++ linux-2.2.7-pre4/arch/alpha/kernel/setup.c	2003-08-15 15:05:52.000000000 -0700
@@ -183,6 +183,11 @@
 			vec = get_sysvec_byname(p+9);
 			continue;
 		}
+
+		if (strncmp(p, "cycle=", 6) == 0) {
+			est_cycle_freq = simple_strtol(p+6, NULL, 0);
+			continue;
+		}
 	}
 
 	/* Replace the command line, not that we've killed it with strtok.  */
@@ -721,8 +726,8 @@
 		       (char*)cpu->serial_no,
 		       systype_name, sysvariation_name, hwrpb->sys_revision,
 		       (char*)hwrpb->ssn,
-		       hwrpb->cycle_freq ? : est_cycle_freq,
-		       hwrpb->cycle_freq ? "" : "est.",
+		       est_cycle_freq ? : hwrpb->cycle_freq,
+		       est_cycle_freq ? "est." : "",
 		       hwrpb->intr_freq / 4096,
 		       (100 * hwrpb->intr_freq / 4096) % 100,
 		       hwrpb->pagesize,
diff -urN linux-2.2.7-pre3/arch/alpha/kernel/time.c linux-2.2.7-pre4/arch/alpha/kernel/time.c
--- linux-2.2.7-pre3/arch/alpha/kernel/time.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/arch/alpha/kernel/time.c	2003-08-15 15:05:52.000000000 -0700
@@ -226,7 +226,7 @@
 {
 	void (*irq_handler)(int, void *, struct pt_regs *);
 	unsigned int year, mon, day, hour, min, sec, cc1, cc2;
-	unsigned long cycle_freq;
+	unsigned long cycle_freq, diff, one_percent;
 
 	/*
 	 * The Linux interpretation of the CMOS clock register contents:
@@ -240,19 +240,30 @@
 	/* Read cycle counter exactly on falling edge of update flag */
 	cc1 = rpcc();
 
-	/* If our cycle frequency isn't valid, go another round and give
-	   a guess at what it should be.  */
-	cycle_freq = hwrpb->cycle_freq;
-	if (cycle_freq == 0) {
-		printk("HWRPB cycle frequency bogus.  Estimating... ");
-
+	if (!est_cycle_freq) {
+		/* Sometimes the hwrpb->cycle_freq value is bogus. 
+	   	Go another round to check up on it and see.  */
 		do { } while (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP));
 		do { } while (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP);
 		cc2 = rpcc();
-		est_cycle_freq = cycle_freq = cc2 - cc1;
+		est_cycle_freq = cc2 - cc1;
 		cc1 = cc2;
+	}
 
-		printk("%lu Hz\n", cycle_freq);
+	/* If the given value is within 1% of what we calculated, 
+	   accept it.  Otherwise, use what we found.  */
+	cycle_freq = hwrpb->cycle_freq;
+	one_percent = cycle_freq / 100;
+	diff = cycle_freq - est_cycle_freq;
+	if (diff < 0)
+		diff = -diff;
+	if (diff > one_percent) {
+		cycle_freq = est_cycle_freq;
+		printk("HWRPB cycle frequency bogus.  Estimated %lu Hz\n",
+		       cycle_freq);
+	}
+	else {
+		est_cycle_freq = 0;
 	}
 
 	/* From John Bowman <bowman@math.ualberta.ca>: allow the values
diff -urN linux-2.2.7-pre3/arch/alpha/lib/clear_user.S linux-2.2.7-pre4/arch/alpha/lib/clear_user.S
--- linux-2.2.7-pre3/arch/alpha/lib/clear_user.S	1997-11-30 10:59:02.000000000 -0800
+++ linux-2.2.7-pre4/arch/alpha/lib/clear_user.S	2003-08-15 15:05:52.000000000 -0700
@@ -80,6 +80,7 @@
 	ret	$31, ($28), 1	# .. e1 :
 
 __do_clear_user:
+	ldgp	$29,0($27)	# we do exceptions -- we need the gp.
 	and	$6, 7, $4	# e0    : find dest misalignment
 	beq	$0, $zerolength # .. e1 :
 	addq	$0, $4, $1	# e0    : bias counter
diff -urN linux-2.2.7-pre3/arch/alpha/lib/copy_user.S linux-2.2.7-pre4/arch/alpha/lib/copy_user.S
--- linux-2.2.7-pre3/arch/alpha/lib/copy_user.S	1998-04-25 22:35:18.000000000 -0700
+++ linux-2.2.7-pre4/arch/alpha/lib/copy_user.S	2003-08-15 15:05:52.000000000 -0700
@@ -46,6 +46,8 @@
 	.globl __copy_user
 	.ent __copy_user
 __copy_user:
+	ldgp $29,0($27)			# we do exceptions -- we need the gp.
+	.prologue 1
 	and $6,7,$3
 	beq $0,$35
 	beq $3,$36
diff -urN linux-2.2.7-pre3/arch/alpha/lib/strlen_user.S linux-2.2.7-pre4/arch/alpha/lib/strlen_user.S
--- linux-2.2.7-pre3/arch/alpha/lib/strlen_user.S	1998-06-24 14:30:08.000000000 -0700
+++ linux-2.2.7-pre4/arch/alpha/lib/strlen_user.S	2003-08-15 15:05:52.000000000 -0700
@@ -27,7 +27,8 @@
 
 	.align 3
 __strlen_user:
-	.prologue 0
+	ldgp	$29,0($27)	# we do exceptions -- we need the gp.
+	.prologue 1
 
 	EX( ldq_u t0, 0(a0) )	# load first quadword (a0 may be misaligned)
 	lda     t1, -1(zero)
diff -urN linux-2.2.7-pre3/arch/alpha/lib/strncpy_from_user.S linux-2.2.7-pre4/arch/alpha/lib/strncpy_from_user.S
--- linux-2.2.7-pre3/arch/alpha/lib/strncpy_from_user.S	1997-02-06 04:48:45.000000000 -0800
+++ linux-2.2.7-pre4/arch/alpha/lib/strncpy_from_user.S	2003-08-15 15:05:52.000000000 -0700
@@ -31,6 +31,7 @@
 	.globl __strncpy_from_user
 	.ent __strncpy_from_user
 	.frame $30, 0, $26
+	.prologue 1
 
 	.align 3
 $aligned:
@@ -99,6 +100,7 @@
 	/*** The Function Entry Point ***/
 	.align 3
 __strncpy_from_user:
+	ldgp	$29, 0($27)	# we do exceptions -- we need the gp.
 
 	mov	a0, v0		# save the string start
 	beq	a2, $zerolength
diff -urN linux-2.2.7-pre3/arch/i386/config.in linux-2.2.7-pre4/arch/i386/config.in
--- linux-2.2.7-pre3/arch/i386/config.in	1999-03-12 17:39:50.000000000 -0800
+++ linux-2.2.7-pre4/arch/i386/config.in	2003-08-15 15:05:52.000000000 -0700
@@ -168,6 +168,8 @@
 
 source drivers/char/Config.in
 
+# source drivers/usb/Config.in
+
 source fs/Config.in
 
 if [ "$CONFIG_VT" = "y" ]; then
diff -urN linux-2.2.7-pre3/arch/i386/kernel/bios32.c linux-2.2.7-pre4/arch/i386/kernel/bios32.c
--- linux-2.2.7-pre3/arch/i386/kernel/bios32.c	1999-03-21 07:24:54.000000000 -0800
+++ linux-2.2.7-pre4/arch/i386/kernel/bios32.c	2003-08-15 15:05:52.000000000 -0700
@@ -1095,6 +1095,8 @@
  * for buggy PCI BIOS'es :-[).
  */
 
+extern int skip_ioapic_setup;
+
 static void __init pcibios_fixup_devices(void)
 {
 	struct pci_dev *dev;
@@ -1147,6 +1149,7 @@
 		/*
 		 * Recalculate IRQ numbers if we use the I/O APIC
 		 */
+		if(!skip_ioapic_setup)
 		{
 			int irq;
 			unsigned char pin;
diff -urN linux-2.2.7-pre3/arch/m68k/atari/atakeyb.c linux-2.2.7-pre4/arch/m68k/atari/atakeyb.c
--- linux-2.2.7-pre3/arch/m68k/atari/atakeyb.c	1999-01-19 10:58:26.000000000 -0800
+++ linux-2.2.7-pre4/arch/m68k/atari/atakeyb.c	2003-08-15 15:05:52.000000000 -0700
@@ -291,7 +291,7 @@
 		atakeyb_rep_timer.prev = atakeyb_rep_timer.next = NULL;
 		add_timer( &atakeyb_rep_timer );
 
-		handle_scancode(rep_scancode);
+		handle_scancode(rep_scancode, 1);
 	}
 
 	atari_enable_irq( IRQ_MFP_ACIA );
@@ -448,7 +448,7 @@
 		    add_timer( &atakeyb_rep_timer );
 		}
 
-		handle_scancode(break_flag | scancode);
+		handle_scancode(scancode, !break_flag);
 		break;
 	    }
 	    break;
diff -urN linux-2.2.7-pre3/arch/m68k/hp300/hil.c linux-2.2.7-pre4/arch/m68k/hp300/hil.c
--- linux-2.2.7-pre3/arch/m68k/hp300/hil.c	1998-09-02 09:39:18.000000000 -0700
+++ linux-2.2.7-pre4/arch/m68k/hp300/hil.c	2003-08-15 15:05:52.000000000 -0700
@@ -223,12 +223,13 @@
   {
   case 0x40:
     {
-      unsigned char scode = (poll.data[1] >> 1) | ((poll.data[1] & 1)?0x80:0);
+      int down = (poll.data[1] & 1) == 0;
+      unsigned char scode = poll.data[1] >> 1;
 #if 0
-      if (scode & 0x80)
-	printk("[%02x]", scode & 0x7f);
+      if (down)
+	printk("[%02x]", scode);
 #endif
-      handle_scancode(scode);
+      handle_scancode(scode, down);
     }
     break;
   }
diff -urN linux-2.2.7-pre3/arch/m68k/mac/mackeyb.c linux-2.2.7-pre4/arch/m68k/mac/mackeyb.c
--- linux-2.2.7-pre3/arch/m68k/mac/mackeyb.c	1999-01-19 10:58:34.000000000 -0800
+++ linux-2.2.7-pre4/arch/m68k/mac/mackeyb.c	2003-08-15 15:05:52.000000000 -0700
@@ -60,7 +60,7 @@
 extern struct kbd_struct kbd_table[];
 
 extern void adb_bus_init(void);
-extern void handle_scancode(unsigned char);
+extern void handle_scancode(unsigned char, int);
 extern void put_queue(int);
 
 /* keyb */
@@ -387,7 +387,7 @@
 		 */
 		switch (keycode) {
 		case 0x39:
-			handle_scancode(keycode);	/* down */
+			handle_scancode(keycode, 1);	/* down */
 			up_flag = 0x80;			/* see below ... */
 		 	mark_bh(KEYBOARD_BH);
 			break;
@@ -397,7 +397,7 @@
 		}
 	}
 
-	handle_scancode(keycode + up_flag);
+	handle_scancode(keycode, !up_flag);
 }
 
 static void
diff -urN linux-2.2.7-pre3/Documentation/scsi-generic.txt linux-2.2.7-pre4/Documentation/scsi-generic.txt
--- linux-2.2.7-pre3/Documentation/scsi-generic.txt	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/Documentation/scsi-generic.txt	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,636 @@
+            Notes on Linux's SG driver version 2.1.30
+            -----------------------------------------
+                                                        990328
+
+Introduction
+============
+These are notes on the Linux SCSI generic packet device driver (sg)
+describing version 2.1.30 . The original driver was written by Lawrence
+Foard and has remained in place with minimal changes since circa 1992.
+Version 2 of this driver remains backward compatible (binary and
+source **) with the original. It adds scatter gather, command queuing,
+per file descriptor sequencing, asynchronous notification and better
+error reporting.
+
+Sg is one of the four "high level" SCSI device drivers along with
+sd, st and sr (disk, tape and CDROM respectively). Sg is more generalized
+(but lower level) than its sibling and tends to be used on SCSI devices
+that don't fit into the already serviced categories. Thus sg is used for
+scanners, cd writers and reading audio cds amongst other things.
+
+The interface and usage of the original sg driver has been documented
+by Heiko Eissfeldt in a HOWTO called SCSI-Programming-HOWTO. My copy
+of the document is version 1.5 dated 7th May 1996. It can found at
+ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/SCSI-Programming-HOWTO .
+Amongst other things it has a lot of tables from the SCSI-2 standard
+that are very useful for programming this interface.
+
+** It is possible to write applications that perform differently
+depending on whether they are using the original or this version of
+the sg device driver. The author is not aware of any useful applications
+that have problems with version 2 (yet).
+
+
+Architecture
+============
+The SCSI generic packet device driver (sg) is a character based device.
+It is one of the four high level device driver in the SCSI sub-system;
+the others are sd (for direct-access devices - disks), st (for tapes)
+and sr (for data cdroms). The other three devices are block devices.
+
+The unifying layer of the SCSI sub-system in the so-called mid-level.
+Below that are all the drivers for the various adapters supported by
+Linux.
+
+Since sg is a character device it supports the traditional Unix
+system calls of open(), close(), read(), write() and ioctl(). Two other
+related system calls: poll() and fcntl() are added to this list and
+how they interact with the sg device driver is documented later.
+ 
+An SG device is accessed by write()ing SCSI commands plus any associated 
+outgoing data to it; the resulting status codes and any incoming data are
+then obtained by a read() call. The device can be opened O_NONBLOCK
+(non-blocking) and poll() used to monitor its progress. The device may be
+opened O_EXCL which excludes other "sg" users from this device (but not 
+"sd", "st" or "sr" users). The buffer given to the write() call is made
+up as follows:
+        - struct sg_header image (see below)
+        - scsi command (6, 10 or 12 bytes long)
+        - data to be written to the device (if any)
+
+The buffer received from the corresponding read() call contains:
+        - struct sg_header image (check status/errors + sense_buffer)
+        - data read back from device (if any)
+
+The given SCSI command has its LUN field overwritten by the LUN value of
+the associated sg device that has been open()ed.
+
+
+sg_header
+=========
+This is the name of the control structure that conveys information
+about the length of data to be read/written by the associated SCSI
+command. It also conveys error and status information from the
+read() call. An instance of this structure is the first thing that
+is placed in the data buffers of both write() and read().
+
+In its original form it looked like this:
+struct sg_header {
+    int pack_len;
+    int reply_len;
+    int pack_id;
+    int result;
+    unsigned int twelve_byte:1;
+    unsigned int other_flags:31;
+    unsigned char sense_buffer[16];
+}; /* this structure is 36 bytes long */
+
+The 'pack_len' is bizzare and ends up having the 'reply_len' put in it
+(perhaps it had a use at some stage). 
+
+The 'reply_len' is the length of the data the corresponding read()
+will/should request (including the sg_header). 
+
+The 'pack_id' is not acted upon by the sg device driver but is conveyed
+back to the corresponding read() so it can be used for sequencing by an
+application. 
+
+The 'result' is also bizzare, turning certain types of host codes it 0 (no
+error), EBUSY or EIO. With better error reporting now available, the
+'result' is best ignored.
+
+The 'twelve_byte' field overrides the internal SCSI command length "guessing"
+algorithm for group 6 and 7 commands (ie when 1st byte >= 0xc0) and forces
+a command lenth of 12 bytes.
+The command length "guessing" algorithm is as follows:
+Group:  0    1    2    3    4    5    6    7
+Length: 6   10   10   12   12   12   10   10
+
+'other_flags' was originally documented as "not used" but some current
+applications assume it has 0 placed in it.
+
+The 'sense_buffer' is the first 16 bytes of SCSI sense buffer that is
+returned when the target returns a SCSI status code of CHECK_CONDITION
+or COMMAND_TERMINATED [or (driver_status & DRIVER_SENSE) is true]. This
+buffer should be at least 18 bytes long and arguably 32 bytes; unfortunately
+this is unlikely to happen in the 2.2.x series of kernels.
+
+The new sg_header offered in this driver is:
+#define SG_MAX_SENSE 16
+struct sg_header
+{
+    int pack_len;    /* [o] reply_len (ie useless) ignored as input */
+    int reply_len;   /* [i] max length of expected reply (inc. sg_header) */
+    int pack_id;     /* [io] id number of packet (use ints >= 0) */
+    int result;      /* [o] 0==ok, else (+ve) Unix errno code (e.g. EIO) */
+    unsigned int twelve_byte:1;
+        /* [i] Force 12 byte command length for group 6 & 7 commands  */
+    unsigned int target_status:5;   /* [o] scsi status from target */
+    unsigned int host_status:8;     /* [o] host status (see "DID" codes) */
+    unsigned int driver_status:8;   /* [o] driver status+suggestion */
+    unsigned int other_flags:10;    /* unused */
+    unsigned char sense_buffer[SG_MAX_SENSE]; /* [o] when target_status is
+               CHECK_CONDITION or COMMAND_TERMINATED this is output. */
+};      /* This structure is 36 bytes long on i386 */
+
+Firstly the new header is binary compatible with the original. This is
+important for keeping existing apps working without recompilation.
+
+Only those elements (or fields) that are new or in some way different
+from the original are documented below.
+
+'pack_id' becomes input to a read() when ioctl(sg_fd, SG_SET_FORCE_PACK_ID,
+&one) is active. A 'pack_id' of -1 is interpreted as fetch the oldest
+waiting packet; any other value will cause the read() to wait (or yield
+EAGAIN) until a packet with that 'pack_id' becomes available. In all cases
+the value of 'pack_id' available after a read() is the value given to that
+variable in the prior, corresponding write().
+
+The 'target_status' field is always output and is the (masked and shifted
+1 bit right) SCSI status code from the target device. The allowable
+values are (found in <scsi/scsi.h>):
+/* N.B. 1 bit offset from usual SCSI status values */
+#define GOOD                 0x00
+#define CHECK_CONDITION      0x01  
+#define CONDITION_GOOD       0x02
+#define BUSY                 0x04
+#define INTERMEDIATE_GOOD    0x08
+#define INTERMEDIATE_C_GOOD  0x0a
+#define RESERVATION_CONFLICT 0x0c
+#define COMMAND_TERMINATED   0x11
+#define QUEUE_FULL           0x14
+When the 'target_status' is CHECK_CONDITION or COMMAND_TERMINATED the
+'sense_buffer' is output. Note that when (driver_status & DRIVER_SENSE)
+is true then the 'sense_buffer' is also output (this seems to occur when
+the scsi ide emulation is used). When the 'sense_buffer' is output the 
+SCSI Sense Key can be found at (sense_buffer[2] & 0x0f) .
+
+The 'host_status' field is always output and has the following values
+whose "defines" are not visible outside the kernel (unfortunately):
+#define DID_OK          0x00 /* NO error                                */
+#define DID_NO_CONNECT  0x01 /* Couldn't connect before timeout period  */
+#define DID_BUS_BUSY    0x02 /* BUS stayed busy through time out period */
+#define DID_TIME_OUT    0x03 /* TIMED OUT for other reason              */
+#define DID_BAD_TARGET  0x04 /* BAD target.                             */
+#define DID_ABORT       0x05 /* Told to abort for some other reason     */
+#define DID_PARITY      0x06 /* Parity error                            */
+#define DID_ERROR       0x07 /* Internal error                          */
+#define DID_RESET       0x08 /* Reset by somebody.                      */
+#define DID_BAD_INTR    0x09 /* Got an interrupt we weren't expecting.  */
+#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer            */
+#define DID_SOFT_ERROR  0x0b /* The low level driver just wish a retry  */
+
+The 'driver_status' field is always output. When ('driver_status' &
+DRIVER_SENSE) is true the 'sense_buffer' is also output. The following
+values whose "defines" are not visible outside the kernel (unfortunately)
+can occur:
+#define DRIVER_OK           0x00 /* Typically no suggestion */
+#define DRIVER_BUSY         0x01
+#define DRIVER_SOFT         0x02
+#define DRIVER_MEDIA        0x03
+#define DRIVER_ERROR        0x04
+#define DRIVER_INVALID      0x05
+#define DRIVER_TIMEOUT      0x06
+#define DRIVER_HARD         0x07
+#define DRIVER_SENSE        0x08
+/* above status 'or'ed with one of the following suggestions */
+#define SUGGEST_RETRY       0x10
+#define SUGGEST_ABORT       0x20
+#define SUGGEST_REMAP       0x30
+#define SUGGEST_DIE         0x40
+#define SUGGEST_SENSE       0x80
+
+'other_flags' still remains as a 10 bit field, so code that places 0 in it
+will still be happy. It is not used.
+
+
+memory
+======
+Memory is a scarce resource in any computer. Sg needs to reserve memory
+suitable for DMA roughly equal in size to the maximum of the write and
+read data buffers for each packet. This DMA memory is obtained at the time
+of a write() and released when the corresponding read() is called (although
+if memory is tight it may be using the buffer reserved by the open() ).
+
+Linux obtaining memory a challenge for several reasons. The memory pool
+that sg uses is in common with all other device drivers and all user
+processes. In this environment the only way to 99.9% guarantee a driver
+will have memory in Linux is to build it into the kernel (ie not as a
+module) and then reserve it on initialization before user processes get
+a chance. [Of course, another driver initialized before sg could take
+all available memory ...] Another problem is the biggest contiguous
+chunk of memory that can be obtained from the kernel is 32 * PAGE_SIZE
+(which is 128KBytes on i386). As memory gets "splintered" there is a good
+chance that buffers won't be available (my machine has 64 MBytes of RAM
+and has 3 available at the moment).
+
+The original sg driver used the following technique: grab a SG_BIG_BUFF
+sized buffer at driver initialization and use it for all requests greater
+than PAGE_SIZE (4096 bytes on i386). By default SG_BIG_BUFF is set to
+32 KBytes in the origianl driver but many applications suggest that the
+user increases this number. Linux limits the biggest single buffer of
+this type to 32 * PAGE_SIZE (128KBytes on i386). Unfortunately if the
+sg driver is a module then there is a high chance a contiguous block of
+that large size will not be available at module initialization.
+
+The author has found no "silver bullet" solution but uses multiple
+techniques hoping that at least one is able provide memory at the critical
+time. Listed below are some of these techniques:
+        - use scatter gather: then instead of one large buffer needing to
+          be found, multiple smaller buffer can be used
+        - use memory above the 16MByte level: the original driver limited
+          itself to obtaining memory below the 16MByte level (on the i386)
+          due to the shortcomings of DMA on ISA adapters. Yet more and more
+          people use PCI adapters that don't have this problem. So make
+          the decision based on the capabilities of the host adpater
+          associated with the current SCSI device
+        - reserve some memory at open() for emergencies but otherwise
+          fetch and release it on a per packet basis
+        - if the kernel is short of memory then dip into the SCSI DMA
+          pool (maintained by the mid-level driver) to a limited amount
+
+
+
+System Calls
+============
+What follows are descriptions of the characteristics of the standard
+Unix operating system calls when applied to a SCSI generic device
+using this version of the device driver.
+
+open
+----
+The filename should be an 'sg' device such as
+/dev/sg[a-z]
+/dev/sg[0,1,2,...]
+or a symbolic link to one of these. [Devfs has its own sub-directory for
+sg devices.] It seems as though SCSI devices are allocated to sg minor
+numbers in the same order as they appear in 'cat /proc/scsi/scsi'.
+Sg is a "character" based Linux device driver. This means it has an
+open/close/read/write/ioctl type interface.
+
+Flags can be either O_RDONLY or O_RDWR or-ed with either
+O_EXCL          waits for other opens on sg device to be closed before
+                proceeding. If O_NONBLOCK is set then yields EBUSY when
+                someone else has the sg device open. The combination of
+                O_RDONLY and O_EXCL is disallowed.
+O_NONBLOCK      Sets non-blocking mode. Calls that would otherwise block
+                yield EAGAIN (eg read() ) or EBUSY (eg open() ).
+
+The original version of sg did not allow the O_RDONLY (yielding a EACCES
+error). This version allows it for accessing ioctls (e.g. doing an sg
+device scan with the SG_GET_SCSI_ID ioctl) but write()s will not be
+allowed.
+
+By default, sequencing is per file descriptor in this version of sg. This
+means, for example that 2 processes can independently manipulate the same
+sg device at the same time. This may or may not make sense depending on
+the application: 2 processes (logically) reading from the same direct access
+device (ie a disk) is ok while running 2 instances of cd writing software
+on the same device at the same time probably wouldn't be a good idea. The
+previous version of sg supported only per device sequencing and this can
+still be selected with the SG_SET_MERGE_FD,1 ioctl().
+
+The driver will attempt to reserve SG_SCATTER_SZ bytes (32KBytes in the
+current sg.h) on open() for "emergency" situations. If this is unavailable
+it will halve its request and try again. It gives up if PAGE_SIZE bytes
+(4096 bytes on i386) cannot be obtained so no memory is reserved. In this
+case open() will still return successfully. The actual amount of memory
+reserved can be found with the SG_GET_RESERVED_SIZE ioctl().
+
+Returns a file descriptor if >= 0 , otherwise -1 implies an error.
+
+Error codes (value in 'errno' after -1 returned):
+ENODEV          sg not compiled into kernel or the kernel cannot find the
+                sg module (or it can't initialize itself (low memory??))
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
+EBUSY           O_NONBLOCK set and some user of this sg device has O_EXCL
+                set while someone is already using this device
+EINTR           while waiting for an "exclusive" lock to clear, a signal
+                is received, just try again ...        
+ENOMEM          An attempt to get memory to store this open's context
+                failed (this was _not_ a request to reserve DMA memory)
+EACCES          An attempt to use both O_RDONLY and O_EXCL
+
+
+write
+-----
+Even though sg is a character-based device driver it sends and receives
+packets to/from the associated scsi device. Write() is used to send a
+packet containing 2 mandatory parts and 1 optional part. The mandatory
+parts are:
+  - a control block (an instance of struct sg_header)
+  - a SCSI command (6, 10 or 12 bytes long)
+The optional part is:
+  - outgoing data (eg if a SCSI write command is being sent)
+These should appear as one contiguous string in the buffer given to
+write() in the above order with no pad characters.
+
+If a write() accepts this packet then at some later time the user should
+call a read() to get the result of the SCSI command. The previous sg
+driver enforced a strict write()/read()/write()/read() regime so that a
+second write() would block until first read() was finished. This sg
+driver relaxes that condition and thereby allows command queuing
+(limit is SG_MAX_QUEUE (16) outstanding packets per file descriptor).
+However, for backward compatibility, command queuing is turned off
+by default (#define SG_DEF_COMMAND_Q 0 in sg.h). This can be changed
+via the the SG_SET_COMMAND_Q ioctl() [or by recompiling after changing
+the above define to 1].
+
+In this sg driver a write() should return more or less immediately.
+
+Returns number of bytes written if > 0 , otherwise -1 implies an error.
+
+Error codes (value in 'errno' after -1 returned):
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
+EACCES          opened with RD_ONLY flag
+EIO             incoming buffer too short. It should be at least (6 +
+                sizeof(struct sg_header))==42 bytes long
+EDOM            a) command queuing off: a packet is already queued
+                b) command queuing on: too many packets queued 
+                   (SG_MAX_QUEUE exceeded)
+EAGAIN          SCSI mid-level out of command blocks (rare), try again.
+                This is more likely to happen when queuing commands,
+                so wait a bit (eg usleep(10000) ) before trying again
+ENOMEM          can't get memory for DMA. Take evasive action ...
+                (see section on memory)
+
+
+read
+----
+Read() is used to receive a packet containing 1 mandatory part and 1 
+optional part. The mandatory part is:
+  - a control block (an instance of struct sg_header)
+The optional part is:
+  - incoming data (eg if a SCSI read command was sent by earlier write() )
+The buffer given to a read() and its corresponding count should be
+sufficient to accommodate this packet to avoid truncation. Truncation has
+occurred if count < sg_header::replylen .
+
+By default, read() will return the oldest packet queued up. If the 
+SG_SET_FORCE_PACK_ID,1 ioctl() is active then read() will attempt to
+fetch the packet whose pack_id (given earlier to write()) matches the
+sg_header::pack_id given to this read(). If not available it will either
+wait or yield EAGAIN. As a special case, -1 in sg_header::pack_id given
+to read() will match the oldest packet.
+
+
+Returns number of bytes read if > 0 , otherwise -1 implies an error.
+Unfortunately the return value in the non-error case is simply the
+same as the count argument. It is not the actual number of bytes
+DMA-ed by the SCSI device. This driver is currently unable to provide
+such an underrun indication.
+
+Error codes (value in 'errno' after -1 returned):
+ENXIO           either scsi sub-system is currently processing some error
+                (eg doing a device reset) or the sg driver/module removed
+                or corrupted
+EAGAIN          either no waiting packet or requested packet is not
+                available while O_NONBLOCK flag was set
+EINTR           while waiting for a packet, a signal is received, just
+                try again ...        
+EIO             if the 'count' given to read() is < sizeof(struct sg_header)
+                and the 'result' element in sg_header is non-zero. Not a
+                recommended error reporting technique
+
+
+close
+-----
+Preferably a close() should be done after all issued write()s have had
+their corresponding read() calls completed. Unfortunately this is not
+always possible. The semantics of close() in Unix are to return more
+or less immediately (ie not wait on any event) so the driver needs to
+arrange to an orderly cleanup of those packets that are still "in
+flight".
+
+A process that has an open file descriptor to an sg device may be aborted
+(eg by a kill signal). In this case, the kernel automatically calls close 
+(which is called 'sg_release()' in the version 2 driver) to facilitate
+the cleanup mentioned above.
+
+A problem persists in version 2.1.8 if the sg driver is a module and is
+removed while packets are still "in flight". Hopefully this will be soon
+fixed.
+
+Returns 0 if successful, otherwise -1 implies an error.
+
+Error codes (value in 'errno' after -1 returned):
+ENXIO           sg driver/module removed or corrupted
+
+ioctl (sg specific)
+-------------------
+Ken Thompson (or perhaps some other Unix luminary) described ioctl() as 
+the "garbage bin of Unix". This driver compounds the situation by adding
+around 18 more commands. These commands either yield state information (10
+of them), change the driver's characteristics (8 of them) or allow direct
+communication with the common SCSI mid-level driver.
+
+Those commands with an appended "+" are new in version 2.
+
+Those commands with an appended "W" are only accessible from file
+descriptors opened with O_RDWR. They will yield EACCES otherwise.
+
+SG_GET_TIMEOUT:
+Ignores its 3rd argument and _returns_ the timeout value (which will be
+>= 0 ). The unit of this timeout is "jiffies" which are currently 10
+millisecond intervals on i386 (less on an alpha). Linux supplies
+a manifest constant HZ which is the number of "jiffies" in 1 second.
+
+SG_SET_TIMEOUT:
+Assumes 3rd argument points to an int containing the new timeout value
+for this file descriptor. The unit is a "jiffy". Packets that are
+already "in flight" will not be effected. The default value is set
+on open() and is SG_DEFAULT_TIMEOUT (defined in sg.h).
+
+SG_EMULATED_HOST:
+Assumes 3rd argument points to an int and outputs a flag indicating
+whether the host (adapter) is connected to a real SCSI bus or is
+emulated one (eg ide-scsi device driver). A value of 1 means emulated
+while 0 is not.
+
+SG_SET_FORCE_LOW_DMA +:
+Assumes 3rd argument points to an int containing 0 or 1. 0 (default)
+means sg decides whether to use memory above 16 Mbyte level (on i386)
+based on the host adapter being used by this SCSI device. Typically
+PCI SCSI adapters will indicate they can DMA to the whole 32 bit address
+space. 
+If 1 is given then the host adapter is overridden and only memory below
+the 16MB level is used for DMA. A requirement for this should be
+extremely rare. If the "reserve" buffer allocated on open() is not in
+use then it will be de-allocated and re-allocated under the 16MB level
+(and the latter operation could fail yielding ENOMEM).
+Only the current file descriptor is effected.
+
+SG_GET_LOW_DMA +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0
+indicates the whole 32 bit address space is being used for DMA transfers
+on this file descriptor. 1 indicates the memory below the 16MB level
+(on i386) is being used (and this may be the case because the host
+adapters setting has been overridden by SG_SET_FORCE_LOW_DMA,1 .
+
+SG_GET_SCSI_ID +:
+Assumes 3rd argument is pointing to an object of type Sg_scsi_id and
+populates it. That structure contains ints for host_no, channel,
+scsi_id, lun and scsi_type. Most of this information is available from
+other sources (eg SCSI_IOCTL_GET_IDLUN and SCSI_IOCTL_GET_BUS_NUMBER)
+but tends to be awkward to collect.
+
+SG_SET_FORCE_PACK_ID +:
+Assumes 3rd argument is pointing to an int. 0 (default) instructs read()
+to return the oldest (written) packet if multiple packets are
+waiting to be read (when command queuing is being used). 
+1 instructs read() to view the sg_header::pack_id as input and return the
+oldest packet matching that pack_id or wait until it arrives (or yield
+EAGAIN if O_NONBLOCK is in force). As a special case the pack_id of -1
+given to read() in the mode will match the oldest packet.
+Only the current file descriptor is effected by this command.
+
+SG_GET_LOW_DMA +:
+Assumes 3rd argument points to an int and places the pack_id of the
+oldest (written) packet in it. If no packet is waiting to be read then
+yields -1.
+
+SG_GET_NUM_WAITING +:
+Assumes 3rd argument points to an int and places the number of packets
+waiting to be read in it.
+
+SG_GET_SG_TABLESIZE +:
+Assumes 3rd argument points to an int and places the maximum number of
+scatter gather elements supported by the host adapter. 0 indicates that
+the adapter does support scatter gather.
+
+SG_SET_RESERVED_SIZE +W:
+This is not currently implemented. It is intended for reserving either a
+large buffer or scatter gather list that will be available until the
+current file descriptor is closed. The requested amount of memory may
+not be available so SG_GET_RESERVED_SIZE should be used after this call
+to see how much was reserved. (EBUSY error possible)
+
+SG_GET_RESERVED_SIZE +:
+Assumes 3rd argument points to an int and places the size in bytes of
+the DMA buffer reserved on open() for emergencies. If this is 0 then it
+is probably not wise to attempt on operation like burning a CD on this
+file descriptor.
+
+SG_SET_MERGE_FD +W:
+Assumes 3rd argument is pointing to an int. 0 (the default) causes all
+subsequent sequencing to be per file descriptor. 1 causes all subsequent
+sequencing to be per device. If this command tries to change the current
+state and the is one or more _other_ file descriptors using this sg
+device then an EBUSY error occurs. Also if this file descriptor was not
+open()ed with the O_RDWR flag then an EACCES error occurs.
+Per device sequencing was the original semantics and allowed, for example
+different processes to "share" the device, one perhaps write()ing with
+the other one read()ing. This command is supplied if anyone needs those
+semantics. Per file descriptor sequencing, perhaps with the usage of
+the O_EXCL flag, seems more sensible.
+
+SG_GET_MERGE_FD +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
+sequencing is per file descriptor. 1 implies sequencing is per device
+(original sg driver's semantics).
+
+SG_SET_COMMAND_Q +:
+Assumes 3rd argument is pointing to an int. 0 (current default, set by
+SG_DEF_COMMAND_Q in sg.h) disables command queuing. Attempts to write()
+a packet while one is already queued will result in a EDOM error.
+1 turns command queuing on.
+Changing the queuing state only effects write()s done after the change.
+Only the current file descriptor is effected by this command.
+
+SG_GET_COMMAND_Q +:
+Assumes 3rd argument points to an int and places 0 or 1 in it. 0 implies
+that command queuing is off on this file descriptor. 1 implies command
+queuing is on.
+
+SG_SET_DEBUG +:
+Assumes 3rd argument is pointing to an int. 0 (default) turns debugging
+off. Values > 0 cause the SCSI sense buffer to be decoded and output
+to the console/log when a SCSI device error occurs. Values > 8 cause
+the current sg device driver's state to be output to the console/log
+(this is a "one off" effect).
+If you need a _lot_ of the SCSI sub-system debug information (mainly from
+the mid-level) then try 'echo "scsi dump 0" > /proc/scsi/scsi' and lots of
+debug will appear in your console/log.
+
+ioctl (in common with sd, st + sr)
+----------------------------------
+The following ioctl()s can be called from any high-level scsi device
+driver (ie sd, st, sr + sg). Access permissions may differ a bit from
+one device to another, the access information given below is specific to
+the sg device driver.
+
+SCSI_IOCTL_GET_IDLUN:
+SCSI_IOCTL_GET_BUS_NUMBER:
+
+SCSI_IOCTL_SEND_COMMAND:  W
+If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto
+the SCSI mid-level driver for processing.
+Don't know much about this one but it looks pretty powerful and
+dangerous. Some comments says it is also deprecated.
+
+<any_command_not matching_above>:  W
+If open()ed O_RDONLY yields an EACCESS error. Otherwise is forwarded onto
+the SCSI mid-level driver for processing.
+
+
+poll
+----
+This is a native call in Linux 2.2 but most of its capabilities are available
+through the older select() call. Given a choice poll() should probably be
+used. Typically poll() is used when a sg scsi device is open()ed O_NONBLOCK
+for polling; or alternatively with asynchronous notification using the
+fcntl() system call (below) and the SIGPOLL (aka SIGIO) signal.
+Only if something drastically is wrong (eg file handle gone stale) will
+POLLERR ever be set. POLLPRI, POLLHUP and POLLNVAL are never set.
+POLLIN is set when there is one or more packets waiting to be read.
+When POLLIN is set it implies that a read() will not block (or yield
+EAGAIN in non-blocking mode) but return a packet immediately.
+POLLOUT (aka POLLWRNORM) is set when write() is able to accept a packet
+(ie will _not_ yield an EDOM error). The setting of POLLOUT is effected
+by the SG_SET_COMMAND_Q state: if the state is on then POLLOUT will remain
+set until the number of queued packets reaches SG_MAX_QUEUE, if the
+state is off then POLLOUT is only set when no packets are queued.
+Note that a packet can be queued after write()ing but not available to be
+read(); this typically happens when a SCSI read command is issued while
+the data is being retreaved.
+Poll() is per file descriptor unless SG_SET_MERGE_FD is set in which case
+it is per device.
+
+
+fcntl
+-----
+There are several uses for this system call in association with a sg
+file descriptor. The first pseudo code shows code that is useful for
+scanning the sg devices, taking care not to be caught in a wait for
+an O_EXCL lock by another process, and when the appropriate device is
+found switching to normal blocked io. A working example of this logic
+is in the sg_scan.c utility program.
+
+open("/dev/sga", O_RDONLY | O_NONBLOCK)
+/* check device, EBUSY means some other process has O_EXCL lock on it */
+/* one the device you want is found then ... */
+flags = fcntl(sg_fd, F_GETFL)
+fcntl(sg_fd, F_SETFL, flags & (~ O_NONBLOCK))
+/* for simple apps is is easier to use normal blocked io */
+
+
+Some work has to be done in Linux to set up for asynchronous notification.
+This is a non-blocking mode of operation in which when the driver receives
+data back from a device so that a read() can be done, it sends a SIGPOLL
+(aka SIGIO) signal to the owning process. A working example of this logic
+is in the sg_poll.c test program.
+
+sigemptyset(&sig_set)
+sigaddset(&sig_set, SIGPOLL)
+sigaction(SIGPOLL, &s_action, 0)
+fcntl(sg_fd, F_SETOWN, getpid())
+flags = fcntl(sg_fd, F_GETFL);
+fcntl(sg_fd, F_SETFL, flags | O_ASYNC)
+
+
+Utility and Test Programs
+=========================
diff -urN linux-2.2.7-pre3/drivers/acorn/char/keyb_ps2.c linux-2.2.7-pre4/drivers/acorn/char/keyb_ps2.c
--- linux-2.2.7-pre3/drivers/acorn/char/keyb_ps2.c	1998-12-17 09:07:45.000000000 -0800
+++ linux-2.2.7-pre4/drivers/acorn/char/keyb_ps2.c	2003-08-15 15:05:52.000000000 -0700
@@ -221,11 +221,6 @@
 };
 #endif
 
-int ps2kbd_pretranslate(unsigned char scancode)
-{
-	return 1;
-}
-
 int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *uf_p)
 {
 	*uf_p = scancode & 0200;
@@ -235,7 +230,7 @@
 
 static void ps2kbd_key(unsigned int keycode, unsigned int up_flag)
 {
-	handle_scancode(keycode + (up_flag ? 0x80 : 0));
+	handle_scancode(keycode, !up_flag);
 }
 
 static inline void ps2kbd_sendbyte(unsigned char val)
diff -urN linux-2.2.7-pre3/drivers/block/ide-cd.h linux-2.2.7-pre4/drivers/block/ide-cd.h
--- linux-2.2.7-pre3/drivers/block/ide-cd.h	1999-04-16 14:28:08.000000000 -0700
+++ linux-2.2.7-pre4/drivers/block/ide-cd.h	2003-08-15 15:05:52.000000000 -0700
@@ -334,13 +334,13 @@
 
 #if defined(__BIG_ENDIAN_BITFIELD)
 	__u8 reserved3           : 2;
-	/* Drive can fake writes */
-	__u8 test_write          : 1;
-	__u8 reserved3a          : 1;
-	/* Drive can write DVD-R discs */
-	__u8 dvd_r_write         : 1;
 	/* Drive can write DVD-RAM discs */
 	__u8 dvd_ram_write       : 1;
+	/* Drive can write DVD-R discs */
+	__u8 dvd_r_write         : 1;
+	__u8 reserved3a          : 1;
+	/* Drive can fake writes */
+	__u8 test_write          : 1;
 	/* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
 	__u8 cd_rw_write	 : 1; /* reserved in 1.2 */
 	/* Drive supports write to CD-R discs (orange book, part II) */
@@ -350,13 +350,13 @@
 	__u8 cd_r_write          : 1; /* reserved in 1.2 */
 	/* Drive can write to CD-R/W (CD-E) discs (orange book, part III) */
 	__u8 cd_rw_write	 : 1; /* reserved in 1.2 */
-	/* Drive can write DVD-RAM discs */
-	__u8 dvd_ram_write       : 1;
-	/* Drive can write DVD-R discs */
-	__u8 dvd_r_write         : 1;
-	__u8 reserved3a          : 1;
 	/* Drive can fake writes */
 	__u8 test_write          : 1;
+	__u8 reserved3a          : 1;
+	/* Drive can write DVD-R discs */
+	__u8 dvd_r_write         : 1;
+	/* Drive can write DVD-RAM discs */
+	__u8 dvd_ram_write       : 1;
 	__u8 reserved3           : 2;
 #else
 #error "Please fix <asm/byteorder.h>"
diff -urN linux-2.2.7-pre3/drivers/cdrom/optcd.c linux-2.2.7-pre4/drivers/cdrom/optcd.c
--- linux-2.2.7-pre3/drivers/cdrom/optcd.c	1998-08-24 13:14:10.000000000 -0700
+++ linux-2.2.7-pre4/drivers/cdrom/optcd.c	2003-08-15 15:05:52.000000000 -0700
@@ -100,6 +100,10 @@
 #else
 #define DEBUG(x)
 #endif
+
+static int blksize = 2048;
+static int hsecsize = 2048;
+
 
 /* Drive hardware/firmware characteristics
    Identifiers in accordance with Optics Storage documentation */
@@ -2061,6 +2065,8 @@
 		return -EIO;
 	}
 
+	hardsect_size[MAJOR_NR] = &hsecsize;
+	blksize_size[MAJOR_NR] = &blksize;
 	blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
 	read_ahead[MAJOR_NR] = 4;
 	request_region(optcd_port, 4, "optcd");
diff -urN linux-2.2.7-pre3/drivers/char/amikeyb.c linux-2.2.7-pre4/drivers/char/amikeyb.c
--- linux-2.2.7-pre3/drivers/char/amikeyb.c	1998-07-30 11:17:11.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/amikeyb.c	2003-08-15 15:05:52.000000000 -0700
@@ -188,7 +188,7 @@
     amikeyb_rep_timer.expires = jiffies + key_repeat_rate;
     amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
     add_timer(&amikeyb_rep_timer);
-    handle_scancode(rep_scancode);
+    handle_scancode(rep_scancode, 1);
 
     restore_flags(flags);
 }
@@ -243,8 +243,8 @@
 
     if (keycode == AMIKEY_CAPS) {
 	/* if the key is CAPS, fake a press/release. */
-	handle_scancode(AMIKEY_CAPS);
-	handle_scancode(BREAK_MASK | AMIKEY_CAPS);
+	handle_scancode(AMIKEY_CAPS, 1);
+	handle_scancode(AMIKEY_CAPS, 0);
     } else if (keycode < 0x78) {
 	/* handle repeat */
 	if (break_flag) {
@@ -257,7 +257,7 @@
 	    amikeyb_rep_timer.prev = amikeyb_rep_timer.next = NULL;
 	    add_timer(&amikeyb_rep_timer);
 	}
-	handle_scancode(scancode);
+	handle_scancode(scancode, !break_flag);
     } else
 	switch (keycode) {
 	    case 0x78:
diff -urN linux-2.2.7-pre3/drivers/char/bttv.c linux-2.2.7-pre4/drivers/char/bttv.c
--- linux-2.2.7-pre3/drivers/char/bttv.c	1999-04-12 16:18:27.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/bttv.c	2003-08-15 15:05:52.000000000 -0700
@@ -2853,6 +2853,16 @@
 }
 #endif
 
+static void init_tea6300(struct i2c_bus *bus) 
+{
+        I2CWrite(bus, I2C_TEA6300, TEA6300_VL, 0x35, 1); /* volume left 0dB  */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_VR, 0x35, 1); /* volume right 0dB */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_BA, 0x07, 1); /* bass 0dB         */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_TR, 0x07, 1); /* treble 0dB       */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_FA, 0x0f, 1); /* fader off        */
+        I2CWrite(bus, I2C_TEA6300, TEA6300_SW, 0x01, 1); /* mute off input A */
+}
+
 static void init_tda8425(struct i2c_bus *bus) 
 {
         I2CWrite(bus, I2C_TDA8425, TDA8425_VL, 0xFC, 1); /* volume left 0dB  */
@@ -2978,6 +2988,14 @@
                         break;
         }
         
+        if (I2CRead(&(btv->i2c), I2C_TEA6300) >=0)
+        {
+		printk(KERN_INFO "bttv%d: fader chip: TEA6300\n",btv->nr);
+		btv->audio_chip = TEA6300;
+		init_tea6300(&(btv->i2c));
+        } else
+		printk(KERN_INFO "bttv%d: NO fader chip: TEA6300\n",btv->nr);
+
 	printk(KERN_INFO "bttv%d: model: ",btv->nr);
 
 	sprintf(btv->video_dev.name,"BT%d",btv->id);
diff -urN linux-2.2.7-pre3/drivers/char/bttv.h linux-2.2.7-pre4/drivers/char/bttv.h
--- linux-2.2.7-pre3/drivers/char/bttv.h	1999-04-12 16:18:27.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/bttv.h	2003-08-15 15:05:52.000000000 -0700
@@ -114,6 +114,7 @@
 	int type;            /* card type  */
 	int audio;           /* audio mode */
 	int audio_chip;
+	int fader_chip;
 	int radio;
 
 	u32 *risc_jmp;
@@ -222,6 +223,7 @@
 #define TDA9850            0x01
 #define TDA8425            0x02
 #define TDA9840            0x03
+#define TEA6300            0x04
 
 #define I2C_TSA5522        0xc2
 #define I2C_TDA9840	   0x84
@@ -230,6 +232,7 @@
 #define I2C_HAUPEE         0xa0
 #define I2C_STBEE          0xae
 #define I2C_VHX 	   0xc0
+#define I2C_TEA6300        0x80
 
 #define TDA9840_SW	   0x00
 #define TDA9840_LVADJ	   0x02
@@ -249,6 +252,12 @@
 #define TDA8425_BA         0x02
 #define TDA8425_TR         0x03
 #define TDA8425_S1         0x08
- 
+
+#define TEA6300_VL         0x00		/* volume control left */
+#define TEA6300_VR         0x01		/* volume control right */
+#define TEA6300_BA         0x02		/* bass control */
+#define TEA6300_TR         0x03		/* treble control */
+#define TEA6300_FA         0x04		/* fader control */
+#define TEA6300_SW         0x05		/* mute and source switch */
 
 #endif
diff -urN linux-2.2.7-pre3/drivers/char/dn_keyb.c linux-2.2.7-pre4/drivers/char/dn_keyb.c
--- linux-2.2.7-pre3/drivers/char/dn_keyb.c	1998-08-24 13:02:44.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/dn_keyb.c	2003-08-15 15:05:52.000000000 -0700
@@ -414,9 +414,9 @@
 	}
 	else if((scancode & (~BREAK_FLAG)) == DNKEY_CAPS) {
     	/* printk("handle_scancode: %02x\n",DNKEY_CAPS); */
-		handle_scancode(DNKEY_CAPS);
+		handle_scancode(DNKEY_CAPS, 1);
 		/*    printk("handle_scancode: %02x\n",BREAK_FLAG | DNKEY_CAPS); */
-		handle_scancode(BREAK_FLAG | DNKEY_CAPS);
+		handle_scancode(DNKEY_CAPS, 0);
 	}
 	else if( (scancode == DNKEY_REPEAT) && (prev_scancode < 0x7e) &&
    			!(prev_scancode==DNKEY_CTRL || prev_scancode==DNKEY_LSHIFT ||
@@ -424,13 +424,13 @@
        	  	prev_scancode==DNKEY_LALT || prev_scancode==DNKEY_RALT)) {
         		if(jiffies-lastkeypress > DNKEY_REPEAT_DELAY) {
 			/*    	printk("handle_scancode: %02x\n",prev_scancode); */
-           			handle_scancode(prev_scancode);
+           			handle_scancode(prev_scancode, 1);
 			  	}
 	   			lastscancode=prev_scancode;
   			}
   	else {
 	/*    	printk("handle_scancode: %02x\n",scancode);  */
-   			handle_scancode(scancode);
+   			handle_scancode(scancode & ~BREAK_FLAG, !(scancode & BREAK_FLAG));
    			lastkeypress=jiffies;
   	}
 }
diff -urN linux-2.2.7-pre3/drivers/char/keyboard.c linux-2.2.7-pre4/drivers/char/keyboard.c
--- linux-2.2.7-pre3/drivers/char/keyboard.c	1999-01-08 11:11:45.000000000 -0800
+++ linux-2.2.7-pre4/drivers/char/keyboard.c	2003-08-15 15:05:52.000000000 -0700
@@ -24,6 +24,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/module.h>
 #include <linux/sched.h>
 #include <linux/tty.h>
 #include <linux/tty_flip.h>
@@ -59,6 +60,8 @@
 #define KBD_DEFLOCK 0
 #endif
 
+EXPORT_SYMBOL(handle_scancode);
+
 extern void ctrl_alt_del(void);
 
 struct wait_queue * keypress_wait = NULL;
@@ -190,15 +193,15 @@
     return kbd_getkeycode(scancode);
 }
 
-void handle_scancode(unsigned char scancode)
+void handle_scancode(unsigned char scancode, int down)
 {
 	unsigned char keycode;
-	char up_flag;				 /* 0 or 0200 */
+	char up_flag = down ? 0 : 0200;
 	char raw_mode;
 
 	do_poke_blanked_console = 1;
 	mark_bh(CONSOLE_BH);
-	add_keyboard_randomness(scancode);
+	add_keyboard_randomness(scancode | up_flag);
 
 	tty = ttytab? ttytab[fg_console]: NULL;
 	if (tty && (!tty->driver_data)) {
@@ -213,20 +216,15 @@
 	}
 	kbd = kbd_table + fg_console;
 	if ((raw_mode = (kbd->kbdmode == VC_RAW))) {
- 		put_queue(scancode);
+		put_queue(scancode | up_flag);
 		/* we do not return yet, because we want to maintain
 		   the key_down array, so that we have the correct
 		   values when finishing RAW mode or when changing VT's */
- 	}
+	}
 
-	if (!kbd_pretranslate(scancode, raw_mode))
-	    return;
- 	/*
+	/*
 	 *  Convert scancode to keycode
- 	 */
-	up_flag = (scancode & 0200);
- 	scancode &= 0x7f;
-
+	 */
 	if (!kbd_translate(scancode, &keycode, raw_mode))
 	    return;
 
@@ -239,10 +237,10 @@
 
 	if (up_flag) {
 		rep = 0;
- 		if(!test_and_clear_bit(keycode, key_down))
+		if(!test_and_clear_bit(keycode, key_down))
 		    up_flag = kbd_unexpected_up(keycode);
 	} else
- 		rep = test_and_set_bit(keycode, key_down);
+		rep = test_and_set_bit(keycode, key_down);
 
 #ifdef CONFIG_MAGIC_SYSRQ		/* Handle the SysRq Hack */
 	if (keycode == SYSRQ_KEY) {
@@ -257,11 +255,11 @@
 
 	if (kbd->kbdmode == VC_MEDIUMRAW) {
 		/* soon keycodes will require more than one byte */
- 		put_queue(keycode + up_flag);
+		put_queue(keycode + up_flag);
 		raw_mode = 1;	/* Most key classes will be ignored */
- 	}
+	}
 
- 	/*
+	/*
 	 * Small change in philosophy: earlier we defined repetition by
 	 *	 rep = keycode == prev_keycode;
 	 *	 prev_keycode = keycode;
@@ -270,9 +268,9 @@
 	 */
 
 	/*
- 	 *  Repeat a key only if the input buffers are empty or the
- 	 *  characters get echoed locally. This makes key repeat usable
- 	 *  with slow applications and under heavy loads.
+	 *  Repeat a key only if the input buffers are empty or the
+	 *  characters get echoed locally. This makes key repeat usable
+	 *  with slow applications and under heavy loads.
 	 */
 	if (!rep ||
 	    (vc_kbd_mode(kbd,VC_REPEAT) && tty &&
diff -urN linux-2.2.7-pre3/drivers/char/Makefile linux-2.2.7-pre4/drivers/char/Makefile
--- linux-2.2.7-pre3/drivers/char/Makefile	1999-04-15 05:42:40.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/Makefile	2003-08-15 15:05:52.000000000 -0700
@@ -42,14 +42,15 @@
 
 ifndef CONFIG_SUN_KEYBOARD
 ifdef CONFIG_VT
-L_OBJS += keyboard.o
+LX_OBJS += keyboard.o
 endif
  ifneq ($(ARCH),m68k)
    L_OBJS += pc_keyb.o defkeymap.o
  endif
 else
 ifdef CONFIG_PCI
-L_OBJS += defkeymap.o keyboard.o
+L_OBJS += defkeymap.o
+LX_OBJS += keyboard.o
 endif
 endif
 
diff -urN linux-2.2.7-pre3/drivers/char/mem.c linux-2.2.7-pre4/drivers/char/mem.c
--- linux-2.2.7-pre3/drivers/char/mem.c	1999-04-12 10:35:41.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/mem.c	2003-08-15 15:05:52.000000000 -0700
@@ -51,6 +51,12 @@
 #if defined(CONFIG_PPC) || defined(CONFIG_MAC)
 extern void adbdev_init(void);
 #endif
+#ifdef CONFIG_USB_UHCI
+int uhci_init(void);
+#endif
+#ifdef CONFIG_USB_OHCI
+int ohci_init(void);
+#endif
 
 static ssize_t do_write_mem(struct file * file, void *p, unsigned long realp,
 			    const char * buf, size_t count, loff_t *ppos)
@@ -599,6 +605,12 @@
 	if (register_chrdev(MEM_MAJOR,"mem",&memory_fops))
 		printk("unable to get major %d for memory devs\n", MEM_MAJOR);
 	rand_initialize();
+#ifdef CONFIG_USB_UHCI
+	uhci_init();
+#endif
+#ifdef CONFIG_USB_OHCI
+	ohci_init();
+#endif
 #if defined (CONFIG_FB)
 	fbmem_init();
 #endif
diff -urN linux-2.2.7-pre3/drivers/char/n_tty.c linux-2.2.7-pre4/drivers/char/n_tty.c
--- linux-2.2.7-pre3/drivers/char/n_tty.c	1999-01-17 10:39:27.000000000 -0800
+++ linux-2.2.7-pre4/drivers/char/n_tty.c	2003-08-15 15:05:52.000000000 -0700
@@ -922,8 +922,14 @@
 		}
 	}
 
-	if (down_interruptible(&tty->atomic_read))
-		return -ERESTARTSYS;
+	if (file->f_flags & O_NONBLOCK) {
+		if (down_trylock(&tty->atomic_read))
+			return -EAGAIN;
+	}
+	else {
+		if (down_interruptible(&tty->atomic_read))
+			return -ERESTARTSYS;
+	}
 
 	add_wait_queue(&tty->read_wait, &wait);
 	set_bit(TTY_DONT_FLIP, &tty->flags);
diff -urN linux-2.2.7-pre3/drivers/char/pc_keyb.c linux-2.2.7-pre4/drivers/char/pc_keyb.c
--- linux-2.2.7-pre3/drivers/char/pc_keyb.c	1999-02-07 00:23:04.000000000 -0800
+++ linux-2.2.7-pre4/drivers/char/pc_keyb.c	2003-08-15 15:05:52.000000000 -0700
@@ -240,8 +240,6 @@
   0, 0, 0, 0, 0, 0, 0, 0			      /* 0x78-0x7f */
 };
 
-static unsigned int prev_scancode = 0;   /* remember E0, E1 */
-
 int pckbd_setkeycode(unsigned int scancode, unsigned int keycode)
 {
 	if (scancode < SC_LIM || scancode > 255 || keycode > 127)
@@ -284,41 +282,28 @@
 		       scancode);
 #endif
 	}
-	if (scancode == 0) {
-#ifdef KBD_REPORT_ERR
-		printk(KERN_INFO "Keyboard buffer overflow\n");
-#endif
-		prev_scancode = 0;
-		return 0;
-	}
 	return 1;
 }
 
-int pckbd_pretranslate(unsigned char scancode, char raw_mode)
+int pckbd_translate(unsigned char scancode, unsigned char *keycode,
+		    char raw_mode)
 {
-	if (scancode == 0xff) {
-		/* in scancode mode 1, my ESC key generates 0xff */
-		/* the calculator keys on a FOCUS 9000 generate 0xff */
-#ifndef KBD_IS_FOCUS_9000
-#ifdef KBD_REPORT_ERR
-		if (!raw_mode)
-		  printk(KERN_DEBUG "Keyboard error\n");
-#endif
-#endif
-		prev_scancode = 0;
-		return 0;
-	}
+	static int prev_scancode = 0;
 
+	/* special prefix scancodes.. */
 	if (scancode == 0xe0 || scancode == 0xe1) {
 		prev_scancode = scancode;
 		return 0;
- 	}
- 	return 1;
-}
+	}
+
+	/* 0xFF is sent by a few keyboards, ignore it. 0x00 is error */
+	if (scancode == 0x00 || scancode == 0xff) {
+		prev_scancode = 0;
+		return 0;
+	}
+
+	scancode &= 0x7f;
 
-int pckbd_translate(unsigned char scancode, unsigned char *keycode,
-		    char raw_mode)
-{
 	if (prev_scancode) {
 	  /*
 	   * usually it will be 0xe0, but a Pause key generates
@@ -452,7 +437,7 @@
 			handle_mouse_event(scancode);
 		} else {
 			if (do_acknowledge(scancode))
-				handle_scancode(scancode);
+				handle_scancode(scancode, !(scancode & 0x80));
 			mark_bh(KEYBOARD_BH);
 		}
 
diff -urN linux-2.2.7-pre3/drivers/char/radio-sf16fmi.c linux-2.2.7-pre4/drivers/char/radio-sf16fmi.c
--- linux-2.2.7-pre3/drivers/char/radio-sf16fmi.c	1999-04-15 05:42:40.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/radio-sf16fmi.c	2003-08-15 15:05:52.000000000 -0700
@@ -4,6 +4,7 @@
  * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
  *
  * Fitted to new interface by Alan Cox <alan.cox@linux.org>
+ * Made working and cleaned up functions <mikael.hedin@irf.se>
  *
  * Notes on the hardware
  *
@@ -74,9 +75,10 @@
 	outb(0x08, port);
 }
 
-static inline int fmi_setfreq(struct fmi_device *dev, unsigned long freq)
+static inline int fmi_setfreq(struct fmi_device *dev)
 {
         int myport = dev->port;
+	unsigned long freq = dev->curfreq;
 	int i;
 	
 	outbits(16, RSF16_ENCODE(freq), myport);
@@ -158,7 +160,6 @@
 			v.flags=fmi->flags;
 			v.mode=VIDEO_MODE_AUTO;
 			v.signal = fmi_getsigstr(fmi);
-			strcpy(v.name, "FM");
 			if(copy_to_user(arg,&v, sizeof(v)))
 				return -EFAULT;
 			return 0;
@@ -192,8 +193,10 @@
 				tmp *= 1000;
 			if ( tmp<RSF16_MINFREQ || tmp>RSF16_MAXFREQ )
 			  return -EINVAL;
-			fmi->curfreq = tmp;
-			fmi_setfreq(fmi, fmi->curfreq);
+			/*rounding in steps of 800 to match th freq
+			  that will be used */
+			fmi->curfreq = (tmp/800)*800; 
+			fmi_setfreq(fmi);
 			return 0;
 		}
 		case VIDIOCGAUDIO:
@@ -205,7 +208,7 @@
 			v.treble=0;
 			v.flags=( (!fmi->curvol)*VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
 			strcpy(v.name, "Radio");
-			v.mode=VIDEO_SOUND_MONO;
+			v.mode=VIDEO_SOUND_STEREO;
 			v.balance=0;
 			v.step=0; /* No volume, just (un)mute */
 			if(copy_to_user(arg,&v, sizeof(v)))
diff -urN linux-2.2.7-pre3/drivers/char/radio-typhoon.c linux-2.2.7-pre4/drivers/char/radio-typhoon.c
--- linux-2.2.7-pre3/drivers/char/radio-typhoon.c	1999-04-15 05:42:40.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/radio-typhoon.c	2003-08-15 15:05:52.000000000 -0700
@@ -196,7 +196,7 @@
 			v.flags = VIDEO_TUNER_LOW;
 			v.mode = VIDEO_MODE_AUTO;
 			v.signal = 0xFFFF;	/* We can't get the signal strength */
-			strcpy(v.tuner, "FM");
+			strcpy(v.name, "FM");
 			if (copy_to_user(arg, &v, sizeof(v)))
 				return -EFAULT;
 			return 0;
diff -urN linux-2.2.7-pre3/drivers/char/softdog.c linux-2.2.7-pre4/drivers/char/softdog.c
--- linux-2.2.7-pre3/drivers/char/softdog.c	1999-04-12 16:18:27.000000000 -0700
+++ linux-2.2.7-pre4/drivers/char/softdog.c	2003-08-15 15:05:52.000000000 -0700
@@ -132,7 +132,6 @@
 static int softdog_ioctl(struct inode *inode, struct file *file,
 	unsigned int cmd, unsigned long arg)
 {
-	int i;
 	static struct watchdog_info ident=
 	{
 		0,
diff -urN linux-2.2.7-pre3/drivers/macintosh/mac_keyb.c linux-2.2.7-pre4/drivers/macintosh/mac_keyb.c
--- linux-2.2.7-pre3/drivers/macintosh/mac_keyb.c	1999-03-10 21:48:46.000000000 -0800
+++ linux-2.2.7-pre4/drivers/macintosh/mac_keyb.c	2003-08-15 15:05:52.000000000 -0700
@@ -194,7 +194,7 @@
 extern struct kbd_struct kbd_table[];
 extern struct wait_queue * keypress_wait;
 
-extern void handle_scancode(unsigned char);
+extern void handle_scancode(unsigned char, int);
 
 static struct adb_ids keyboard_ids;
 static struct adb_ids mouse_ids;
@@ -234,11 +234,6 @@
 	return -EINVAL;
 }
 
-int mackbd_pretranslate(unsigned char scancode, char raw_mode)
-{
-	return 1;
-}
-
 int mackbd_translate(unsigned char keycode, unsigned char *keycodep,
 		     char raw_mode)
 {
@@ -338,8 +333,8 @@
 		 switch (keycode) {
 		 /*case 0xb9:*/
 		 case 0x39:
-			handle_scancode(0x39);
-			handle_scancode(0xb9);
+			handle_scancode(0x39, 1);
+			handle_scancode(0x39, 0);
 		 	mark_bh(KEYBOARD_BH);
 		 	return;
 		 case 0x47:
@@ -349,7 +344,7 @@
 		 }
 	}
 
-	handle_scancode(keycode + up_flag);
+	handle_scancode(keycode, !up_flag);
 }
 
 static void
diff -urN linux-2.2.7-pre3/drivers/Makefile linux-2.2.7-pre4/drivers/Makefile
--- linux-2.2.7-pre3/drivers/Makefile	1998-11-20 08:59:01.000000000 -0800
+++ linux-2.2.7-pre4/drivers/Makefile	2003-08-15 15:05:52.000000000 -0700
@@ -10,7 +10,7 @@
 SUB_DIRS     := block char net misc sound
 MOD_SUB_DIRS := $(SUB_DIRS)
 ALL_SUB_DIRS := $(SUB_DIRS) pci scsi sbus cdrom isdn pnp \
-				 macintosh video dio zorro fc4
+				 macintosh video dio zorro fc4 usb
 
 ifdef CONFIG_DIO
 SUB_DIRS += dio
@@ -44,6 +44,11 @@
 MOD_SUB_DIRS += macintosh
 endif
 
+ifeq ($(CONFIG_USB),y)
+SUB_DIRS += usb
+MOD_SUB_DIRS += usb
+endif
+
 # If CONFIG_SCSI is set, the core of SCSI support will be added to the kernel,
 # but some of the low-level things may also be modules.
 ifeq ($(CONFIG_SCSI),y)
diff -urN linux-2.2.7-pre3/drivers/net/3c523.c linux-2.2.7-pre4/drivers/net/3c523.c
--- linux-2.2.7-pre3/drivers/net/3c523.c	1999-01-17 18:28:06.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/3c523.c	2003-08-15 15:05:52.000000000 -0700
@@ -62,8 +62,8 @@
    search the MCA slots until it finds a 3c523 with the specified
    parameters.
 
-   This driver should support multiple ethernet cards, but I can't test
-   that.  If someone would I'd greatly appreciate it.
+   This driver does support multiple ethernet cards when used as a module
+   (up to MAX_3C523_CARDS, the default being 4)
 
    This has been tested with both BNC and TP versions, internal and
    external transceivers.  Haven't tested with the 64K version (that I
@@ -76,7 +76,12 @@
    update to 1.3.59, incorporated multicast diffs from ni52.c
    Feb 15th, 1996
    added shared irq support
-
+   Apr 1999
+   added support for multiple cards when used as a module
+   added option to disable multicast as is causes problems
+       Ganesh Sittampalam <ganesh.sittampalam@magdalen.oxford.ac.uk>
+       Stuart Adamson <stuart.adamson@compsoc.net>
+	
    $Header: /fsys2/home/chrisb/linux-1.3.59-MCA/drivers/net/RCS/3c523.c,v 1.1 1996/02/05 01:53:46 chrisb Exp chrisb $
  */
 
@@ -107,6 +112,7 @@
 /*************************************************************************/
 #define DEBUG			/* debug on */
 #define SYSBUSVAL 0		/* 1 = 8 Bit, 0 = 16 bit - 3c523 only does 16 bit */
+#undef ELMC_MULTICAST		/* Disable multicast support as it is somewhat seriously broken at the moment */
 
 #define make32(ptr16) (p->memtop + (short) (ptr16) )
 #define make24(ptr32) ((char *) (ptr32) - p->base)
@@ -180,7 +186,9 @@
 static int elmc_close(struct device *dev);
 static int elmc_send_packet(struct sk_buff *, struct device *);
 static struct net_device_stats *elmc_get_stats(struct device *dev);
+#ifdef ELMC_MULTICAST
 static void set_multicast_list(struct device *dev);
+#endif
 
 /* helper-functions */
 static int init586(struct device *dev);
@@ -432,21 +440,19 @@
 	while (slot != -1) {
 		status = mca_read_stored_pos(slot, 2);
 
+		dev->irq=irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
+		dev->base_addr=csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
+		
 		/*
 		   If we're trying to match a specified irq or IO address,
 		   we'll reject a match unless it's what we're looking for.
+		   Also reject it if the card is already in use.
 		 */
-		if (base_addr || irq) {
-			/* we're looking for a card at a particular place */
 
-			if (irq && irq != irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6]) {
-				slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
-				continue;
-			}
-			if (base_addr && base_addr != csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1]) {
-				slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
-				continue;
-			}
+		if((irq && irq != dev->irq) || (base_addr && base_addr != dev->base_addr)
+		   || check_region(dev->base_addr,ELMC_IO_EXTENT)) {
+			slot = mca_find_adapter(ELMC_MCA_ID, slot + 1);
+			continue;
 		}
 		/* found what we're looking for... */
 		break;
@@ -476,9 +482,6 @@
 	/* revision is stored in the first 4 bits of the revision register */
 	revision = inb(dev->base_addr + ELMC_REVISION) & 0xf;
 
-	/* figure out our irq */
-	dev->irq = irq_table[(status & ELMC_STATUS_IRQ_SELECT) >> 6];
-
 	/* according to docs, we read the interrupt and write it back to
 	   the IRQ select register, since the POST might not configure the IRQ
 	   properly. */
@@ -497,9 +500,6 @@
 		break;
 	}
 
-	/* Our IO address? */
-	dev->base_addr = csr_table[(status & ELMC_STATUS_CSR_SELECT) >> 1];
-
 	request_region(dev->base_addr, ELMC_IO_EXTENT, "3c523");
 
 	dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL);
@@ -565,7 +565,11 @@
 	dev->stop = &elmc_close;
 	dev->get_stats = &elmc_get_stats;
 	dev->hard_start_xmit = &elmc_send_packet;
+#ifdef ELMC_MULTICAST
 	dev->set_multicast_list = &set_multicast_list;
+#else
+	dev->set_multicast_list = NULL;
+#endif
 
 	ether_setup(dev);
 
@@ -577,6 +581,10 @@
 	   That gets done in elmc_open().  I'm not sure that's such a good idea,
 	   but it works, so I'll go with it. */
 
+#ifndef ELMC_MULTICAST
+        dev->flags&=~IFF_MULTICAST;     /* Multicast doesn't work */
+#endif
+
 	return 0;
 }
 
@@ -1210,6 +1218,7 @@
  * Set MC list ..
  */
 
+#ifdef ELMC_MULTICAST
 static void set_multicast_list(struct device *dev)
 {
 	if (!dev->start) {
@@ -1222,60 +1231,85 @@
 	startrecv586(dev);
 	dev->start = 1;
 }
+#endif
 
 /*************************************************************************/
 
 #ifdef MODULE
 
-static char devicename[9] = {0,};
+/* Increase if needed ;) */
+#define MAX_3C523_CARDS 4
+/* I'm not sure where this magic 9 comes from */
+#define NAMELEN 9
 
-static struct device dev_elmc =
-{
-	devicename /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, elmc_probe
+static char devicenames[NAMELEN * MAX_3C523_CARDS] = {0,};
+
+static struct device dev_elmc[MAX_3C523_CARDS] =
+{	
+	{
+	NULL /*"3c523" */ , 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL
+	},
 };
 
-static int irq = 0;
-static int io = 0;
-MODULE_PARM(irq, "i");
-MODULE_PARM(io, "i");
+static int irq[MAX_3C523_CARDS] = {0,};
+static int io[MAX_3C523_CARDS] = {0,};
+MODULE_PARM(irq, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
+MODULE_PARM(io, "1-" __MODULE_STRING(MAX_3C523_CARDS) "i");
 
 int init_module(void)
 {
-	struct device *dev = &dev_elmc;
+	int this_dev,found = 0;
 
-	dev->base_addr = io;
-	dev->irq = irq;
-	if (register_netdev(dev) != 0) {
-		return -EIO;
-	}
-	return 0;
+	/* Loop until we either can't find any more cards, or we have MAX_3C523_CARDS */	
+	for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) 
+		{
+		struct device *dev = &dev_elmc[this_dev];
+		dev->name=devicenames+(NAMELEN*this_dev);
+		dev->irq=irq[this_dev];
+		dev->base_addr=io[this_dev];
+		dev->init=elmc_probe;
+		if(register_netdev(dev)!=0) {
+			if(io[this_dev]==0) break;
+			printk(KERN_WARNING "3c523.c: No 3c523 card found at io=%#x\n",io[this_dev]);
+		} else found++;
+	}
+
+	if(found==0) {
+		if(io[0]==0) printk(KERN_NOTICE "3c523.c: No 3c523 cards found\n");
+		return -ENXIO;
+	} else return 0;
 }
 
 void cleanup_module(void)
 {
-	struct device *dev = &dev_elmc;
+	int this_dev;
+	for(this_dev=0; this_dev<MAX_3C523_CARDS; this_dev++) {
 
-	/* shutdown interrupts on the card */
-	elmc_id_reset586();
-	if (dev->irq != 0) {
-		/* this should be done by close, but if we failed to
-		   initialize properly something may have gotten hosed. */
-		free_irq(dev->irq, dev);
-		dev->irq = 0;
-	}
-	if (dev->base_addr != 0) {
-		release_region(dev->base_addr, ELMC_IO_EXTENT);
-		dev->base_addr = 0;
-	}
-	irq = 0;
-	io = 0;
-	unregister_netdev(dev);
+		struct device *dev = &dev_elmc[this_dev];
+		if(dev->priv) {
+			/* shutdown interrupts on the card */
+			elmc_id_reset586();
+			if (dev->irq != 0) {
+				/* this should be done by close, but if we failed to
+				   initialize properly something may have gotten hosed. */
+				free_irq(dev->irq, dev);
+				dev->irq = 0;
+			}
+			if (dev->base_addr != 0) {
+				release_region(dev->base_addr, ELMC_IO_EXTENT);
+				dev->base_addr = 0;
+			}
+			irq[this_dev] = 0;
+			io[this_dev] = 0;
+			unregister_netdev(dev);
 
-	mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot,
+			mca_set_adapter_procfn(((struct priv *) (dev->priv))->slot,
 			       NULL, NULL);
 
-	kfree_s(dev->priv, sizeof(struct priv));
-	dev->priv = NULL;
+			kfree_s(dev->priv, sizeof(struct priv));
+			dev->priv = NULL;
+		}
+	}
 }
 
 #endif				/* MODULE */
diff -urN linux-2.2.7-pre3/drivers/net/ibmtr.c linux-2.2.7-pre4/drivers/net/ibmtr.c
--- linux-2.2.7-pre3/drivers/net/ibmtr.c	1999-03-16 14:21:51.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/ibmtr.c	2003-08-15 15:05:52.000000000 -0700
@@ -70,6 +70,12 @@
  *      Changes by Joel Sloan (jjs@c-me.com) :
  *      + disable verbose debug messages by default - to enable verbose
  *	  debugging, edit the IBMTR_DEBUG_MESSAGES define below 
+ *	
+ *	Changes by Mike Phillips <phillim@amtrak.com> :
+ *	+ Added extra #ifdef's to work with new PCMCIA Token Ring Code.
+ *	  The PCMCIA code now just sets up the card so it can be recognized
+ *        by ibmtr_probe. Also checks allocated memory vs. on-board memory
+ *	  for correct figure to use.
  *
  *	Changes by Tim Hockin (thockin@isunix.it.ilstu.edu) :
  *	+ added spinlocks for SMP sanity (10 March 1999)
@@ -94,6 +100,7 @@
 #undef NO_AUTODETECT
 #undef ENABLE_PAGING
 
+
 #define FALSE 0
 #define TRUE (!FALSE)
 
@@ -191,6 +198,9 @@
 int		ibmtr_probe(struct device *dev);
 static int	ibmtr_probe1(struct device *dev, int ioaddr);
 static unsigned char	get_sram_size(struct tok_info *adapt_info);
+#ifdef PCMCIA
+extern unsigned char 	pcmcia_reality_check(unsigned char gss);
+#endif
 static int	tok_init_card(struct device *dev);
 void		tok_interrupt(int irq, void *dev_id, struct pt_regs *regs);
 static int	trdev_init(struct device *dev);
@@ -256,8 +266,10 @@
 	        if (ibmtr_probe1(dev, base_addr)) 
 	        {
 #ifndef MODULE
+#ifndef PCMCIA
 		       tr_freedev(dev);
 #endif
+#endif
 		       return -ENODEV;
 		} else
 		       return 0;
@@ -272,8 +284,10 @@
 		        continue;
                 if (ibmtr_probe1(dev, ioaddr)) {
 #ifndef MODULE
+#ifndef PCMCIA
 		        tr_freedev(dev);
 #endif
+#endif
 		} else
 			return 0;
         }
@@ -291,8 +305,10 @@
 	unsigned long timeout;
 
 #ifndef MODULE
+#ifndef PCMCIA
 	dev = init_trdev(dev,0);
 #endif
+#endif
 
 	/*	Query the adapter PIO base port which will return
 	 *	indication of where MMIO was placed. We also have a
@@ -300,7 +316,7 @@
 	 */
 
        	segment = inb(PIOaddr);
-	
+
 	/*
 	 *	Out of range values so we'll assume non-existent IO device 
 	 */
@@ -373,12 +389,19 @@
 	}
 
 	/* Now, allocate some of the pl0 buffers for this driver.. */
+
+	/* If called from PCMCIA, ti is already set up, so no need to 
+	   waste the memory, just use the existing structure */
+
+#ifndef PCMCIA
 	ti = (struct tok_info *)kmalloc(sizeof(struct tok_info), GFP_KERNEL);
 	if (ti == NULL) 
 		return -ENOMEM;
 
 	memset(ti, 0, sizeof(struct tok_info));
-
+#else
+	ti = dev->priv ; 
+#endif
 	ti->mmio= t_mmio;
 	ti->readlog_pending = 0;
 
@@ -388,6 +411,10 @@
                          should fit with out future hope of multiple
                          adapter support as well /dwm   */
 
+	/* if PCMCIA, then the card is recognized as TR_ISAPNP 
+	 * and there is no need to set up the interrupt, it is already done. */
+        
+#ifndef PCMCIA
 	switch (cardpresent) 
 	{
 		case TR_ISA:
@@ -428,7 +455,6 @@
 				irq=10;
 			if (intr==3)
 				irq=11;
-
 			timeout = jiffies + TR_SPIN_INTERVAL;
 			while(!readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN))
 				if (time_after(jiffies, timeout)) {
@@ -436,11 +462,13 @@
 					kfree_s(ti, sizeof(struct tok_info));
 					return -ENODEV;
 			        }
+
 			ti->sram=((__u32)readb(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)<<12);
 			ti->global_int_enable=PIOaddr+ADAPTINTREL;
 			ti->adapter_int_enable=PIOaddr+ADAPTINTREL;
 			break;
 	}
+#endif
 
 	if (ibmtr_debug_trace & TRC_INIT) { /* just report int */
 		DPRINTK("irq=%d",irq);
@@ -483,8 +511,11 @@
 	ti->token_release = readb(ti->mmio + AIPEARLYTOKEN);
 
 	/* How much shared RAM is on adapter ? */
+#ifdef PCMCIA
+	ti->avail_shared_ram = pcmcia_reality_check(get_sram_size(ti));
+#else
 	ti->avail_shared_ram = get_sram_size(ti);
-
+#endif
 	/* We need to set or do a bunch of work here based on previous results.. */
 	/* Support paging?  What sizes?:  F=no, E=16k, D=32k, C=16 & 32k */
 	ti->shared_ram_paging = readb(ti->mmio + AIPSHRAMPAGE);
@@ -593,7 +624,6 @@
 		}
 #endif
 	}
-
 	/* finish figuring the shared RAM address */
 	if (cardpresent==TR_ISA) {
 		static __u32 ram_bndry_mask[]={0xffffe000, 0xffffc000, 0xffff8000, 0xffff0000};
@@ -619,15 +649,20 @@
 	DPRINTK("Using %dK shared RAM\n",ti->mapped_ram_size/2);
 #endif
 
+	/* The PCMCIA has already got the interrupt line and the io port, 
+	   so no chance of anybody else getting it - MLP */
+
+#ifndef PCMCIA
 	if (request_irq (dev->irq = irq, &tok_interrupt,0,"ibmtr", dev) != 0) {
 		DPRINTK("Could not grab irq %d.  Halting Token Ring driver.\n",irq);
 		kfree_s(ti, sizeof(struct tok_info));
 		return -ENODEV;
 	}
+ 
+	/*?? Now, allocate some of the PIO PORTs for this driver.. */
+	request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr");  /* record PIOaddr range as busy */
+#endif
 
- /*?? Now, allocate some of the PIO PORTs for this driver.. */
-	request_region(PIOaddr,IBMTR_IO_EXTENT,"ibmtr");  /* record PIOaddr range
-								  as busy */
 #if !TR_NEWFORMAT
 	DPRINTK("%s",version); /* As we have passed card identification,
                                   let the world know we're here! */
@@ -717,7 +752,6 @@
 
 	unsigned char avail_sram_code;
 	static unsigned char size_code[]={ 0,16,32,64,127,128 };
-
 	/* Adapter gives
 	   'F' -- use RRR bits 3,2
 	   'E' -- 8kb   'D' -- 16kb
@@ -747,8 +781,10 @@
 	dev->change_mtu         = ibmtr_change_mtu;
 
 #ifndef MODULE
+#ifndef PCMCIA
 	tr_setup(dev);
 #endif
+#endif
 	return 0;
 }
 
@@ -842,7 +878,7 @@
 		          DPRINTK("PCMCIA card removed.\n");
 			  spin_unlock(&(ti->lock));
         		  dev->interrupt = 0;
-          		  return;
+         		  return;
        		}
 
     	        /* Check ISRP EVEN too. */
@@ -1186,7 +1222,6 @@
 	__u32 encoded_addr;
 	__u32 hw_encoded_addr;
 	struct tok_info *ti;
-
 	ti=(struct tok_info *) dev->priv;
 
 	ti->do_tok_int=NOT_FIRST;
diff -urN linux-2.2.7-pre3/drivers/net/irda/actisys.c linux-2.2.7-pre4/drivers/net/irda/actisys.c
--- linux-2.2.7-pre3/drivers/net/irda/actisys.c	1999-03-07 15:26:43.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/irda/actisys.c	2003-08-15 15:05:52.000000000 -0700
@@ -7,7 +7,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Tue Feb  9 15:38:16 1999
+ * Modified at:   Mon Apr 12 11:56:35 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -234,8 +234,8 @@
 	/* Remove support for 38400 if this is not a 220L+ dongle */
 	if ( idev->io.dongle_id == ACTISYS_DONGLE)
 		qos->baud_rate.bits &= ~IR_38400;
-		
-	qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */
+	
+	qos->min_turn_time.bits &= 0x40; /* Needs 0.01 ms */
 }
 
 #ifdef MODULE
diff -urN linux-2.2.7-pre3/drivers/net/irda/esi.c linux-2.2.7-pre4/drivers/net/irda/esi.c
--- linux-2.2.7-pre3/drivers/net/irda/esi.c	1999-03-07 15:26:43.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/irda/esi.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Thomas Davis, <ratbert@radiks.net>
  * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Tue Feb  9 15:36:47 1999
+ * Modified at:   Mon Apr 12 11:55:30 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:	  esi.c
  *
@@ -56,9 +56,9 @@
 	esi_qos_init,
 };
 
-__initfunc(void esi_init(void))
+__initfunc(int esi_init(void))
 {
-	irtty_register_dongle( &dongle);
+	return irtty_register_dongle(&dongle);
 }
 
 void esi_cleanup(void)
@@ -132,7 +132,7 @@
 	}
 	/* Change speed of serial driver */
 	tty->termios->c_cflag = cflag;
-	tty->driver.set_termios( tty, &old_termios);
+	tty->driver.set_termios(tty, &old_termios);
 
 	irtty_set_dtr_rts(tty, dtr, rts);
 }
@@ -151,6 +151,7 @@
 static void esi_qos_init( struct irda_device *idev, struct qos_info *qos)
 {
 	qos->baud_rate.bits &= IR_9600|IR_19200|IR_115200;
+	qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */
 }
 
 #ifdef MODULE
@@ -163,8 +164,7 @@
  */
 int init_module(void)
 {
-	esi_init();
-	return(0);
+	return esi_init();
 }
 
 /*
diff -urN linux-2.2.7-pre3/drivers/net/irda/girbil.c linux-2.2.7-pre4/drivers/net/irda/girbil.c
--- linux-2.2.7-pre3/drivers/net/irda/girbil.c	1999-03-07 15:26:43.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/irda/girbil.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Feb  6 21:02:33 1999
- * Modified at:   Tue Feb  9 15:36:36 1999
+ * Modified at:   Sat Apr 10 19:53:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -195,7 +195,7 @@
 {
 	struct irtty_cb *self;
 	struct tty_struct *tty;
-	__u8 control = GIRBIL_TXEN | GIRBIL_RXEN /* | GIRBIL_ECAN */;
+	__u8 control = GIRBIL_TXEN | GIRBIL_RXEN;
 
 	ASSERT(idev != NULL, return;);
 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
diff -urN linux-2.2.7-pre3/drivers/net/irda/irport.c linux-2.2.7-pre4/drivers/net/irda/irport.c
--- linux-2.2.7-pre3/drivers/net/irda/irport.c	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/drivers/net/irda/irport.c	2003-08-15 15:05:52.000000000 -0700
@@ -1,7 +1,7 @@
 /*********************************************************************
  *		  
  * Filename:	  irport.c
- * Version:	  0.8
+ * Version:	  0.9
  * Description:   Serial driver for IrDA. 
  * Status:	  Experimental.
  * Author:	  Dag Brattli <dagb@cs.uit.no>
@@ -9,7 +9,6 @@
  * Modified at:   Sat May 23 23:15:20 1998
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:	  serial.c by Linus Torvalds 
- *		  serial_serial.c by Aage Kvalnes <aage@cs.uit.no>
  * 
  *     Copyright (c) 1997,1998 Dag Brattli <dagb@cs.uit.no>
  *     All Rights Reserved.
@@ -25,10 +24,10 @@
  *
  *     NOTICE:
  *
- *     This driver is ment to be a small serial driver to be used for
- *     IR-chipsets that has a UART (16550) compatibility mode. If your
- *     chipset is is UART only, you should probably use IrTTY instead since
- *     the Linux serial driver is probably more robust and optimized.
+ *     This driver is ment to be a small half duplex serial driver to be
+ *     used for IR-chipsets that has a UART (16550) compatibility mode. If
+ *     your chipset is is UART only, you should probably use IrTTY instead
+ *     since the Linux serial driver is probably more robust and optimized.
  *
  *     The functions in this file may be used by FIR drivers, but this
  *     driver knows nothing about FIR drivers so don't ever insert such
@@ -64,7 +63,6 @@
 #include <net/irda/irport.h>
 
 #define IO_EXTENT 8
-#define CONFIG_HALF_DUPLEX
 
 /* static unsigned int io[]  = { 0x3e8, ~0, ~0, ~0 }; */
 /* static unsigned int irq[] = { 11, 0, 0, 0 }; */
@@ -114,7 +112,7 @@
  *    Start IO port 
  *
  */
-int irport_open( int iobase)
+int irport_open(int iobase)
 {
 	DEBUG(4, __FUNCTION__ "(), iobase=%#x\n", iobase);
 
@@ -134,7 +132,7 @@
  *    Stop IO port
  *
  */
-void irport_close( int iobase) 
+void irport_close(int iobase) 
 {
 	DEBUG(4, __FUNCTION__ "()\n");
 
@@ -142,7 +140,7 @@
 	outb(0, iobase+UART_MCR);
 
 	/* Turn off interrupts */
-	outb(0, iobase+UART_IER); 
+	outb(0, iobase+UART_IER);
 }
 
 /*
@@ -186,16 +184,22 @@
  *    more packets to send, we send them here.
  *
  */
-static void irport_write_wakeup( struct irda_device *idev)
+static void irport_write_wakeup(struct irda_device *idev)
 {
-	int actual = 0, count;
+	int actual = 0;
 	int iobase;
 
 	ASSERT(idev != NULL, return;);
 	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 
 	/* Finished with frame?  */
-	if (idev->tx_buff.offset == idev->tx_buff.len)  {
+	if (idev->tx_buff.len > 0)  {
+		/* Write data left in transmit buffer */
+		actual = irport_write(idev->io.iobase2, idev->io.fifo_size, 
+				      idev->tx_buff.data, idev->tx_buff.len);
+		idev->tx_buff.data += actual;
+		idev->tx_buff.len  -= actual;
+	} else {
 		iobase = idev->io.iobase2;
 		/* 
 		 *  Now serial buffer is almost free & we can start 
@@ -206,23 +210,14 @@
 
 		/* Schedule network layer, so we can get some more frames */
 		mark_bh(NET_BH);
-#ifdef CONFIG_HALF_DUPLEX
+
 		outb(UART_FCR_ENABLE_FIFO | 
 		     UART_FCR_TRIGGER_14  |
 		     UART_FCR_CLEAR_RCVR, iobase+UART_FCR); /* Enable FIFO's */
 
 		/* Turn on receive interrupts */
 		outb(UART_IER_RLSI|UART_IER_RDI, iobase+UART_IER); 
-#endif
-		return;
 	}
-
-	/* Write data left in transmit buffer */
-	count = idev->tx_buff.len - idev->tx_buff.offset;
-	actual = irport_write(idev->io.iobase2, idev->io.fifo_size, 
-			      idev->tx_buff.head, count);
-	idev->tx_buff.offset += actual;
-	idev->tx_buff.head += actual;
 }
 
 /*
@@ -283,22 +278,19 @@
 	if (irda_lock((void *) &dev->tbusy) == FALSE)
 		return -EBUSY;
 	
-        /*  
-	 *  Transfer skb to tx_buff while wrapping, stuffing and making CRC 
-	 */
+	/* Init tx buffer */
+	idev->tx_buff.data = idev->tx_buff.head;
+
+        /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
 	idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
 					   idev->tx_buff.truesize);
 	
-/* 	actual = irport_write(idev->io.iobase2, idev->io.fifo_size,  */
-/* 			      idev->tx_buff.data, idev->tx_buff.len); */
-	
-	idev->tx_buff.offset = actual;
-	idev->tx_buff.head = idev->tx_buff.data + actual;
+	idev->tx_buff.data += actual;
+	idev->tx_buff.len  -= actual;
 
-#ifdef CONFIG_HALF_DUPLEX
 	/* Turn on transmit finished interrupt. Will fire immediately!  */
 	outb(UART_IER_THRI, iobase+UART_IER); 
-#endif
+
 	dev_kfree_skb(skb);
 	
 	return 0;
@@ -318,44 +310,37 @@
 	if (!idev)
 		return;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
 	iobase = idev->io.iobase2;
 
-	if (idev->rx_buff.len == 0)
-		idev->rx_buff.head = idev->rx_buff.data;
-	
 	/*  
 	 * Receive all characters in Rx FIFO, unwrap and unstuff them. 
          * async_unwrap_char will deliver all found frames  
 	 */
 	do {
-		async_unwrap_char(idev, inb( iobase+UART_RX));
+		async_unwrap_char(idev, inb(iobase+UART_RX));
 
 		/* Make sure we don't stay here to long */
 		if (boguscount++ > 32) {
 			DEBUG(0,__FUNCTION__ "(), breaking!\n");
 			break;
 		}
-
 	} while (inb(iobase+UART_LSR) & UART_LSR_DR);	
 }
 
 /*
  * Function irport_interrupt (irq, dev_id, regs)
  *
- *    
+ *    Interrupt handler
  */
 void irport_interrupt(int irq, void *dev_id, struct pt_regs *regs) 
 {
 	struct irda_device *idev = (struct irda_device *) dev_id;
-
 	int iobase;
 	int iir, lsr;
 	int boguscount = 0;
 
-	DEBUG(5, __FUNCTION__ "(), irq %d\n", irq);
-	
 	if (!idev) {
 		printk(KERN_WARNING __FUNCTION__ 
 		       "() irq %d for unknown device.\n", irq);
@@ -368,19 +353,13 @@
 
 	iir = inb(iobase + UART_IIR) & UART_IIR_ID;
 	while (iir) {
-		DEBUG(4,__FUNCTION__ "(), iir=%#x\n", iir);
-
 		/* Clear interrupt */
 		lsr = inb(iobase+UART_LSR);
 
 		if ((iir & UART_IIR_THRI) && (lsr & UART_LSR_THRE)) {
 			/* Transmitter ready for data */
 			irport_write_wakeup(idev);
-		}
-#ifdef CONFIG_HALF_DUPLEX
-		else 
-#endif
-		if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) {
+		} else if ((iir & UART_IIR_RDI) && (lsr & UART_LSR_DR)) {
 	       		/* Receive interrupt */
 			irport_receive(idev);
 		}
@@ -394,7 +373,6 @@
 	idev->netdev.interrupt = 0;
 }
 
-
 #ifdef MODULE
 
 /*
diff -urN linux-2.2.7-pre3/drivers/net/irda/irtty.c linux-2.2.7-pre4/drivers/net/irda/irtty.c
--- linux-2.2.7-pre3/drivers/net/irda/irtty.c	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/drivers/net/irda/irtty.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:18:38 1997
- * Modified at:   Tue Apr  6 21:35:25 1999
+ * Modified at:   Thu Apr 22 09:20:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
  *                          Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
@@ -45,22 +45,22 @@
 
 static struct tty_ldisc irda_ldisc;
 
-static int irtty_hard_xmit( struct sk_buff *skb, struct device *dev);
-static void irtty_wait_until_sent( struct irda_device *driver);
-static int irtty_is_receiving( struct irda_device *idev);
-static int irtty_net_init( struct device *dev);
+static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev);
+static void irtty_wait_until_sent(struct irda_device *driver);
+static int irtty_is_receiving(struct irda_device *idev);
+static int irtty_net_init(struct device *dev);
 static int irtty_net_open(struct device *dev);
 static int irtty_net_close(struct device *dev);
 
-static int  irtty_open( struct tty_struct *tty);
-static void irtty_close( struct tty_struct *tty);
-static int  irtty_ioctl( struct tty_struct *, void *, int, void *);
-static int  irtty_receive_room( struct tty_struct *tty);
-static void irtty_change_speed( struct irda_device *dev, int baud);
-static void irtty_write_wakeup( struct tty_struct *tty);
+static int  irtty_open(struct tty_struct *tty);
+static void irtty_close(struct tty_struct *tty);
+static int  irtty_ioctl(struct tty_struct *, void *, int, void *);
+static int  irtty_receive_room(struct tty_struct *tty);
+static void irtty_change_speed(struct irda_device *dev, int baud);
+static void irtty_write_wakeup(struct tty_struct *tty);
 
-static void irtty_receive_buf( struct tty_struct *, const unsigned char *, 
-			       char *, int);
+static void irtty_receive_buf(struct tty_struct *, const unsigned char *, 
+			      char *, int);
 char *driver_name = "irtty";
 
 __initfunc(int irtty_init(void))
@@ -73,15 +73,15 @@
 		return -ENOMEM;
 	}
 
-	dongles = hashbin_new( HB_LOCAL);
-	if ( dongles == NULL) {
-		printk( KERN_WARNING 
-			"IrDA: Can't allocate dongles hashbin!\n");
+	dongles = hashbin_new(HB_LOCAL);
+	if (dongles == NULL) {
+		printk(KERN_WARNING 
+		       "IrDA: Can't allocate dongles hashbin!\n");
 		return -ENOMEM;
 	}
 
 	/* Fill in our line protocol discipline, and register it */
-	memset( &irda_ldisc, 0, sizeof( irda_ldisc));
+	memset(&irda_ldisc, 0, sizeof( irda_ldisc));
 
 	irda_ldisc.magic = TTY_LDISC_MAGIC;
  	irda_ldisc.name  = "irda";
@@ -97,10 +97,10 @@
 	irda_ldisc.receive_room = irtty_receive_room;
 	irda_ldisc.write_wakeup = irtty_write_wakeup;
 	
-	if (( status = tty_register_ldisc( N_IRDA, &irda_ldisc)) != 0)  {
-		printk( KERN_ERR 
-			"IrDA: can't register line discipline (err = %d)\n", 
-			status);
+	if (( status = tty_register_ldisc(N_IRDA, &irda_ldisc)) != 0)  {
+		printk(KERN_ERR 
+		       "IrDA: can't register line discipline (err = %d)\n", 
+		       status);
 	}
 	
 	return status;
@@ -120,10 +120,10 @@
 	/*
 	 *  Unregister tty line-discipline
 	 */
-	if (( ret = tty_register_ldisc( N_IRDA, NULL))) {
-		printk( KERN_ERR 
-			"IrTTY: can't unregister line discipline (err = %d)\n",
- 			ret);
+	if ((ret = tty_register_ldisc(N_IRDA, NULL))) {
+		ERROR(__FUNCTION__ 
+		      "(), can't unregister line discipline (err = %d)\n",
+		      ret);
 	}
 
 	/*
@@ -131,8 +131,8 @@
 	 *  callback to irtty_close(), therefore we do give any deallocation
 	 *  function to hashbin_destroy().
 	 */
-	hashbin_delete( irtty, NULL);
-	hashbin_delete( dongles, NULL);
+	hashbin_delete(irtty, NULL);
+	hashbin_delete(dongles, NULL);
 }
 #endif /* MODULE */
 
@@ -143,47 +143,45 @@
  *    discipline is called for.  Because we are sure the tty line exists,
  *    we only have to link it to a free IrDA channel.  
  */
-static int irtty_open( struct tty_struct *tty) 
+static int irtty_open(struct tty_struct *tty) 
 {
 	struct irtty_cb *self;
 	char name[16];
 	
-	ASSERT( tty != NULL, return -EEXIST;);
+	ASSERT(tty != NULL, return -EEXIST;);
 
 	/* First make sure we're not already connected. */
 	self = (struct irtty_cb *) tty->disc_data;
-	if ( self != NULL && self->magic == IRTTY_MAGIC)
+	if (self != NULL && self->magic == IRTTY_MAGIC)
 		return -EEXIST;
 	
 	/*
 	 *  Allocate new instance of the driver
 	 */
-	self = kmalloc( sizeof(struct irtty_cb), GFP_KERNEL);
-	if ( self == NULL) {
-		printk( KERN_ERR "IrDA: Can't allocate memory for "
-			"IrDA control block!\n");
+	self = kmalloc(sizeof(struct irtty_cb), GFP_KERNEL);
+	if (self == NULL) {
+		printk(KERN_ERR "IrDA: Can't allocate memory for "
+		       "IrDA control block!\n");
 		return -ENOMEM;
 	}
-	memset( self, 0, sizeof(struct irtty_cb));
+	memset(self, 0, sizeof(struct irtty_cb));
 	
 	self->tty = tty;
 	tty->disc_data = self;
 
 	/* Give self a name */
-	sprintf( name, "%s%d", tty->driver.name,
-		 MINOR(tty->device) - tty->driver.minor_start +
-		 tty->driver.name_base);
-
+	sprintf(name, "%s%d", tty->driver.name,
+		MINOR(tty->device) - tty->driver.minor_start +
+		tty->driver.name_base);
+	
 	/* hashbin_insert( irtty, (QUEUE*) self, 0, self->name); */
-	hashbin_insert( irtty, (QUEUE*) self, (int) self, NULL);
+	hashbin_insert(irtty, (QUEUE*) self, (int) self, NULL);
 
-	if (tty->driver.flush_buffer) {
+	if (tty->driver.flush_buffer)
 		tty->driver.flush_buffer(tty);
-	}
-
-	if (tty->ldisc.flush_buffer) {
+	
+	if (tty->ldisc.flush_buffer)
 		tty->ldisc.flush_buffer(tty);
-	}
 	
 	self->magic = IRTTY_MAGIC;
 
@@ -198,12 +196,12 @@
 	 *  that are not device dependent (such as link disconnect time) so
 	 *  this parameter can be set by IrLAP (or the user) instead. DB
 	 */
-	irda_init_max_qos_capabilies( &self->idev.qos);
+	irda_init_max_qos_capabilies(&self->idev.qos);
 
 	/* The only value we must override it the baudrate */
 	self->idev.qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
 		IR_115200;
-	self->idev.qos.min_turn_time.bits = 0x03;
+	self->idev.qos.min_turn_time.bits = 0x0f;
 	self->idev.flags = IFF_SIR | IFF_PIO;
 	irda_qos_bits_to_value(&self->idev.qos);
 
@@ -236,7 +234,7 @@
 }
 
 /* 
- *  Function irtty_close ( tty)
+ *  Function irtty_close (tty)
  *
  *    Close down a IrDA channel. This means flushing out any pending queues,
  *    and then restoring the TTY line discipline to what it was before it got
@@ -272,14 +270,40 @@
  	MOD_DEC_USE_COUNT;
 }
 
+/*
+ * Function irtty_stop_receiver (irda_device, stop)
+ *
+ *    
+ *
+ */
+static void irtty_stop_receiver(struct irda_device *idev, int stop)
+{
+	struct termios old_termios;
+	struct irtty_cb *self;
+	int cflag;
+
+	self = (struct irtty_cb *) idev->priv;
+
+	old_termios = *(self->tty->termios);
+	cflag = self->tty->termios->c_cflag;
+	
+	if (stop)
+		cflag &= ~CREAD;
+	else
+		cflag |= CREAD;
+
+	self->tty->termios->c_cflag = cflag;
+	self->tty->driver.set_termios(self->tty, &old_termios);
+}
+
 /* 
- *  Function irtty_change_speed ( self, baud)
+ *  Function irtty_change_speed (self, baud)
  *
  *    Change the speed of the serial port. The driver layer must check that
  *    all transmission has finished using the irtty_wait_until_sent() 
  *    function.
  */
-static void irtty_change_speed( struct irda_device *idev, int baud) 
+static void irtty_change_speed(struct irda_device *idev, int baud) 
 {
         struct termios old_termios;
 	struct irtty_cb *self;
@@ -287,22 +311,22 @@
 
 	DEBUG(4,__FUNCTION__ "(), <%ld>\n", jiffies); 
 
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 
 	self = (struct irtty_cb *) idev->priv;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRTTY_MAGIC, return;);
 
 	old_termios = *(self->tty->termios);
 	cflag = self->tty->termios->c_cflag;
 
 	cflag &= ~CBAUD;
 
-	DEBUG( 4, __FUNCTION__ "(), Setting speed to %d\n", baud);
+	DEBUG(4, __FUNCTION__ "(), Setting speed to %d\n", baud);
 
-	switch( baud) {
+	switch (baud) {
 	case 1200:
 		cflag |= B1200;
 		break;
@@ -331,7 +355,7 @@
 	}	
 
 	self->tty->termios->c_cflag = cflag;
-	self->tty->driver.set_termios( self->tty, &old_termios);
+	self->tty->driver.set_termios(self->tty, &old_termios);
 }
 
 /*
@@ -340,43 +364,42 @@
  *    Initialize attached dongle. Warning, must be called with a process
  *    context!
  */
-static void irtty_init_dongle( struct irtty_cb *self, int type)
+static void irtty_init_dongle(struct irtty_cb *self, int type)
 {
 	struct dongle_q *node;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRTTY_MAGIC, return;);
 
 #ifdef CONFIG_KMOD
 	/* Try to load the module needed */
 	switch( type) {
 	case ESI_DONGLE:
-		DEBUG( 0, __FUNCTION__ "(), ESI dongle!\n");
-		request_module( "esi");
+		MESSAGE("IrDA: Trying to initialize ESI dongle!\n");
+		request_module("esi");
 		break;
 	case TEKRAM_DONGLE:
-		DEBUG( 0, __FUNCTION__ "(), Tekram dongle!\n");
-		request_module( "tekram");
+		MESSAGE("IrDA: Trying to initialize Tekram dongle!\n");
+		request_module("tekram");
 		break;
 	case ACTISYS_DONGLE:     /* FALLTHROUGH */
 	case ACTISYS_PLUS_DONGLE:
-		DEBUG( 0, __FUNCTION__ "(), ACTiSYS dongle!\n");
-		request_module( "actisys");
+		MESSAGE("IrDA: Trying to initialize ACTiSYS dongle!\n");
+		request_module("actisys");
 		break;
 	case GIRBIL_DONGLE:
-		DEBUG( 0, __FUNCTION__ "(), GIrBIL dongle!\n");
-		request_module( "girbil");
+		MESSAGE("IrDA: Trying to initialize GIrBIL dongle!\n");
+		request_module("girbil");
 		break;
 	default:
-		DEBUG( 0, __FUNCTION__ "(), Unknown dongle type!\n");
+		ERROR("Unknown dongle type!\n");
 		return;
-		break;
 	}
 #endif /* CONFIG_KMOD */
 
-	node = hashbin_find( dongles, type, NULL);
+	node = hashbin_find(dongles, type, NULL);
 	if ( !node) {
-		DEBUG(0, __FUNCTION__ "(), Unable to find requested dongle\n");
+		ERROR("Unable to find requested dongle\n");
 		return;
 	}
 	self->dongle_q = node;
@@ -387,14 +410,14 @@
 	/*
 	 * Now initialize the dongle!
 	 */
-	node->dongle->open( &self->idev, type);
-	node->dongle->qos_init( &self->idev, &self->idev.qos);
+	node->dongle->open(&self->idev, type);
+	node->dongle->qos_init(&self->idev, &self->idev.qos);
 	
 	/* Reset dongle */
-	node->dongle->reset( &self->idev, 0);
+	node->dongle->reset(&self->idev, 0);
 
 	/* Set to default baudrate */
-	node->dongle->change_speed( &self->idev, 9600);
+	node->dongle->change_speed(&self->idev, 9600);
 }
 
 /*
@@ -411,25 +434,25 @@
 
 	self = (struct irtty_cb *) tty->disc_data;
 
-	ASSERT( self != NULL, return -ENODEV;);
-	ASSERT( self->magic == IRTTY_MAGIC, return -EBADR;);
+	ASSERT(self != NULL, return -ENODEV;);
+	ASSERT(self->magic == IRTTY_MAGIC, return -EBADR;);
 
-	if ( _IOC_DIR(cmd) & _IOC_READ)
+	if (_IOC_DIR(cmd) & _IOC_READ)
 		err = verify_area( VERIFY_WRITE, (void *) arg, size);
-	else if ( _IOC_DIR(cmd) & _IOC_WRITE)
+	else if (_IOC_DIR(cmd) & _IOC_WRITE)
 		err = verify_area( VERIFY_READ, (void *) arg, size);
-	if ( err)
+	if (err)
 		return err;
 	
 	switch(cmd) {
 	case TCGETS:
 	case TCGETA:
-		return n_tty_ioctl( tty, (struct file *) file, cmd, 
-				    (unsigned long) arg);
+		return n_tty_ioctl(tty, (struct file *) file, cmd, 
+				   (unsigned long) arg);
 		break;
 	case IRTTY_IOCTDONGLE:
 		/* Initialize dongle */
-		irtty_init_dongle( self, (int) arg);
+		irtty_init_dongle(self, (int) arg);
 		break;
 	default:
 		return -ENOIOCTLCMD;
@@ -450,8 +473,8 @@
 {
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRTTY_MAGIC, return;);
 	
 	/* Read the characters out of the buffer */
  	while (count--) {
@@ -461,19 +484,19 @@
  		if (fp && *fp++) { 
 			DEBUG( 0, "Framing or parity error!\n");
 			irda_device_set_media_busy( &self->idev, TRUE);
-			/* sl->rx_errors++; */
+
  			cp++;
  			continue;
  		}
 		/* Unwrap and destuff one byte */
-		async_unwrap_char( &self->idev, *cp++);
+		async_unwrap_char(&self->idev, *cp++);
 	}
 }
 
 /*
  * Function irtty_hard_xmit (skb, dev)
  *
- *    Transmit skb
+ *    Transmit frame
  *
  */
 static int irtty_hard_xmit(struct sk_buff *skb, struct device *dev)
@@ -482,9 +505,6 @@
 	struct irda_device *idev;
 	int actual = 0;
 
-	ASSERT( dev != NULL, return 0;);
-	ASSERT( skb != NULL, return 0;);
-
 	idev = (struct irda_device *) dev->priv;
 
 	ASSERT(idev != NULL, return 0;);
@@ -498,10 +518,11 @@
 	/* Lock transmit buffer */
 	if (irda_lock((void *) &dev->tbusy) == FALSE)
 		return -EBUSY;
-
-        /*  
-	 *  Transfer skb to tx_buff while wrapping, stuffing and making CRC 
-	 */
+	
+	/* Init tx buffer*/
+	idev->tx_buff.data = idev->tx_buff.head;
+	
+        /* Copy skb to tx_buff while wrapping, stuffing and making CRC */
         idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
 					   idev->tx_buff.truesize); 
 
@@ -509,13 +530,14 @@
 
 	dev->trans_start = jiffies;
 
-	if ( self->tty->driver.write)
+	if (self->tty->driver.write)
 		actual = self->tty->driver.write(self->tty, 0, 
 						 idev->tx_buff.data, 
 						 idev->tx_buff.len);
 
-	idev->tx_buff.offset = actual;
-	idev->tx_buff.head = idev->tx_buff.data + actual;
+	/* Hide the part we just transmitted */
+	idev->tx_buff.data += actual;
+	idev->tx_buff.len -= actual;
 
 	idev->stats.tx_packets++;
 	idev->stats.tx_bytes += idev->tx_buff.len;
@@ -524,7 +546,7 @@
 	 *  Did we transmit the whole frame? Commented out for now since
 	 *  I must check if this optimalization really works. DB.
 	 */
- 	if (( idev->tx.count - idev->tx.ptr) <= 0) {
+ 	if ((idev->tx_buff.len) == 0) {
  		DEBUG( 4, "irtty_xmit_buf: finished with frame!\n");
  		self->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
  		irda_unlock( &self->tbusy);
@@ -541,8 +563,9 @@
  *    Used by the TTY to find out how much data we can receive at a time
  * 
 */
-static int irtty_receive_room( struct tty_struct *tty) 
+static int irtty_receive_room(struct tty_struct *tty) 
 {
+	DEBUG(0, __FUNCTION__ "()\n");
 	return 65536;  /* We can handle an infinite amount of data. :-) */
 }
 
@@ -553,47 +576,42 @@
  *    more packets to send, we send them here.
  *
  */
-static void irtty_write_wakeup( struct tty_struct *tty) 
+static void irtty_write_wakeup(struct tty_struct *tty) 
 {
-	int actual = 0, count;
 	struct irtty_cb *self = (struct irtty_cb *) tty->disc_data;
 	struct irda_device *idev;
+	int actual = 0;
 	
 	/* 
 	 *  First make sure we're connected. 
 	 */
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRTTY_MAGIC, return;);
 
 	idev = &self->idev;
 
-	/*
-	 *  Finished with frame?
-	 */
-	if ( idev->tx_buff.offset == idev->tx_buff.len)  {
-
+	/* Finished with frame?  */
+	if (idev->tx_buff.len > 0)  {
+		/* Write data left in transmit buffer */
+		actual = tty->driver.write(tty, 0, idev->tx_buff.data, 
+					   idev->tx_buff.len);
+
+		idev->tx_buff.data += actual;
+		idev->tx_buff.len  -= actual;
+	} else {		
 		/* 
 		 *  Now serial buffer is almost free & we can start 
 		 *  transmission of another packet 
 		 */
 		DEBUG(5, __FUNCTION__ "(), finished with frame!\n");
-
+		
 		tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 
 		idev->netdev.tbusy = 0; /* Unlock */
-
+			
 		/* Tell network layer that we want more frames */
-		mark_bh( NET_BH);
-
-		return;
+		mark_bh(NET_BH);
 	}
-	/*
-	 *  Write data left in transmit buffer
-	 */
-	count = idev->tx_buff.len - idev->tx_buff.offset;
-	actual = tty->driver.write( tty, 0, idev->tx_buff.head, count);
-	idev->tx_buff.offset += actual;
-	idev->tx_buff.head += actual;
 }
 
 /*
@@ -602,9 +620,9 @@
  *    Return TRUE is we are currently receiving a frame
  *
  */
-static int irtty_is_receiving( struct irda_device *idev)
+static int irtty_is_receiving(struct irda_device *idev)
 {
-	return ( idev->rx_buff.state != OUTSIDE_FRAME);
+	return (idev->rx_buff.state != OUTSIDE_FRAME);
 }
 
 /*
@@ -614,20 +632,20 @@
  *    to change the speed of the serial port. Warning this function must
  *    be called with a process context!
  */
-static void irtty_wait_until_sent( struct irda_device *idev)
+static void irtty_wait_until_sent(struct irda_device *idev)
 {
 	struct irtty_cb *self = (struct irtty_cb *) idev->priv;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRTTY_MAGIC, return;);
 	
-	DEBUG( 4, "Chars in buffer %d\n", 
-	       self->tty->driver.chars_in_buffer( self->tty));
+	DEBUG(4, "Chars in buffer %d\n", 
+	      self->tty->driver.chars_in_buffer(self->tty));
 	
-	tty_wait_until_sent( self->tty, 0);
+	tty_wait_until_sent(self->tty, 0);
 }
 
-int irtty_register_dongle( struct dongle *dongle)
+int irtty_register_dongle(struct dongle *dongle)
 {
 	struct dongle_q *new;
 	
@@ -638,12 +656,11 @@
         }
 	
 	/* Make new IrDA dongle */
-        new = (struct dongle_q *)kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
-        if (new == NULL) {
-                return 1;
+        new = (struct dongle_q *) kmalloc(sizeof(struct dongle_q), GFP_KERNEL);
+        if (new == NULL)
+                return -1;
 		
-        }
-	memset( new, 0, sizeof( struct dongle_q));
+	memset(new, 0, sizeof( struct dongle_q));
         new->dongle = dongle;
 
 	/* Insert IrDA dongle into hashbin */
@@ -652,16 +669,16 @@
         return 0;
 }
 
-void irtty_unregister_dongle( struct dongle *dongle)
+void irtty_unregister_dongle(struct dongle *dongle)
 {
 	struct dongle_q *node;
 
-	node = hashbin_remove( dongles, dongle->type, NULL);
-	if ( !node) {
-		DEBUG( 0, __FUNCTION__ "(), dongle not found!\n");
+	node = hashbin_remove(dongles, dongle->type, NULL);
+	if (!node) {
+		ERROR(__FUNCTION__ "(), dongle not found!\n");
 		return;
 	}
-	kfree( node);
+	kfree(node);
 }
 
 
@@ -696,26 +713,24 @@
 	set_fs(get_ds());
 	
 	if (tty->driver.ioctl(tty, NULL, TIOCMSET, (unsigned long) &arg)) { 
-		DEBUG(0, __FUNCTION__ "(), error!\n");
+		ERROR(__FUNCTION__ "(), error doing ioctl!\n");
 	}
 	set_fs(fs);
 }
 
-
-static int irtty_net_init( struct device *dev)
+static int irtty_net_init(struct device *dev)
 {
 	/* Set up to be a normal IrDA network device driver */
-	irda_device_setup( dev);
+	irda_device_setup(dev);
 
 	/* Insert overrides below this line! */
 
 	return 0;
 }
 
-
-static int irtty_net_open( struct device *dev)
+static int irtty_net_open(struct device *dev)
 {
-	ASSERT( dev != NULL, return -1;);
+	ASSERT(dev != NULL, return -1;);
 
 	/* Ready to play! */
 	dev->tbusy = 0;
@@ -729,7 +744,7 @@
 
 static int irtty_net_close(struct device *dev)
 {
-	ASSERT( dev != NULL, return -1;);
+	ASSERT(dev != NULL, return -1;);
 	
 	/* Stop device */
 	dev->tbusy = 1;
diff -urN linux-2.2.7-pre3/drivers/net/irda/pc87108.c linux-2.2.7-pre4/drivers/net/irda/pc87108.c
--- linux-2.2.7-pre3/drivers/net/irda/pc87108.c	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/drivers/net/irda/pc87108.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Nov  7 21:43:15 1998
- * Modified at:   Sat Apr  3 15:54:47 1999
+ * Modified at:   Tue Apr 20 11:11:39 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
@@ -734,10 +734,9 @@
 
 	/* Decide if we should use PIO or DMA transfer */
 	if ( idev->io.baudrate > 115200) {
-		memcpy( idev->tx_buff.data, skb->data, skb->len);
+		idev->tx_buff.data = idev->tx_buff.head;
+		memcpy(idev->tx_buff.data, skb->data, skb->len);
 		idev->tx_buff.len = skb->len;
-		idev->tx_buff.head = idev->tx_buff.data;
-		idev->tx_buff.offset = 0;
 
 		mtt = irda_get_mtt( skb);
 	        if ( mtt > 50) {
@@ -767,11 +766,10 @@
 	     		pc87108_dma_write( idev, iobase);
 		}
         } else {
-	        idev->tx_buff.len = async_wrap_skb( skb, idev->tx_buff.data, 
-						    idev->tx_buff.truesize);
+	        idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
+						   idev->tx_buff.truesize);
 		
-		idev->tx_buff.offset = 0;
-		idev->tx_buff.head = idev->tx_buff.data;
+		idev->tx_buff.data = idev->tx_buff.head;
 		
 		/* Add interrupt on tx low level (will fire immediately) */
 		switch_bank( iobase, BANK0);
@@ -945,8 +943,7 @@
 	
 	/* driver->media_busy = FALSE; */
 	idev->io.direction = IO_RECV;
-	idev->rx_buff.head = idev->rx_buff.data;
-	idev->rx_buff.offset = 0;
+	idev->rx_buff.data = idev->rx_buff.head;
 
 	/* Reset Rx FIFO. This will also flush the ST_FIFO */
 	outb(FCR_RXTH|FCR_TXTH|FCR_RXSR|FCR_FIFO_EN, iobase+FCR);
@@ -1024,42 +1021,41 @@
 				/* Skip frame */
 				idev->stats.rx_errors++;
 				
-				idev->rx_buff.offset  += len;
-				idev->rx_buff.head += len;
+				idev->rx_buff.data += len;
 			
-				if ( status & FRM_ST_MAX_LEN)
+				if (status & FRM_ST_MAX_LEN)
 					idev->stats.rx_length_errors++;
 				
-				if ( status & FRM_ST_PHY_ERR) 
+				if (status & FRM_ST_PHY_ERR) 
 					idev->stats.rx_frame_errors++;
 				
-				if ( status & FRM_ST_BAD_CRC) 
+				if (status & FRM_ST_BAD_CRC) 
 					idev->stats.rx_crc_errors++;
 			}
 			/* The errors below can be reported in both cases */
-			if ( status & FRM_ST_OVR1)
+			if (status & FRM_ST_OVR1)
 				idev->stats.rx_fifo_errors++;
 			
-			if ( status & FRM_ST_OVR2)
+			if (status & FRM_ST_OVR2)
 				idev->stats.rx_fifo_errors++;
 			
 		} else {
 			/* Check if we have transfered all data to memory */
-			if ( inb( iobase+LSR) & LSR_RXDA) {
+			if (inb(iobase+LSR) & LSR_RXDA) {
 				/* Put this entry back in fifo */
 				st_fifo->head--;
 				st_fifo->len++;
 				st_fifo->entries[st_fifo->head].status = status;
-				st_fifo->entries[ st_fifo->head].len = len;
+				st_fifo->entries[st_fifo->head].len = len;
 
 				/* Restore bank register */
-				outb( bank, iobase+BSR);
+				outb(bank, iobase+BSR);
 			
 				return FALSE; 	/* I'll be back! */
 			}
 
 			/* Should be OK then */			
-			skb = dev_alloc_skb( len+1);
+			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
 				printk( KERN_INFO __FUNCTION__ 
 					"(), memory squeeze, dropping frame.\n");
@@ -1070,20 +1066,19 @@
 			}
 			
 			/* Make sure IP header gets aligned */
-			skb_reserve( skb, 1); 
+			skb_reserve(skb, 1); 
 
 			/* Copy frame without CRC */
-			if ( idev->io.baudrate < 4000000) {
-				skb_put( skb, len-2);
-				memcpy( skb->data, idev->rx_buff.head, len-2);
+			if (idev->io.baudrate < 4000000) {
+				skb_put(skb, len-2);
+				memcpy(skb->data, idev->rx_buff.data, len-2);
 			} else {
-				skb_put( skb, len-4);
-				memcpy( skb->data, idev->rx_buff.head, len-4);
+				skb_put(skb, len-4);
+				memcpy(skb->data, idev->rx_buff.data, len-4);
 			}
 
 			/* Move to next frame */
-			idev->rx_buff.offset += len;
-			idev->rx_buff.head += len;
+			idev->rx_buff.data += len;
 			idev->stats.rx_packets++;
 
 			skb->dev = &idev->netdev;
@@ -1093,7 +1088,7 @@
 		}
 	}
 	/* Restore bank register */
-	outb( bank, iobase+BSR);
+	outb(bank, iobase+BSR);
 
 	return TRUE;
 }
@@ -1109,23 +1104,19 @@
 	__u8 byte = 0x00;
 	int iobase;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 	
 	iobase = idev->io.iobase;
 	
-	if ( idev->rx_buff.len == 0) {
-		idev->rx_buff.head = idev->rx_buff.data;
-	}
-
 	/*  Receive all characters in Rx FIFO */
 	do {
-		byte = inb( iobase+RXD);
-		async_unwrap_char( idev, byte);
+		byte = inb(iobase+RXD);
+		async_unwrap_char(idev, byte);
 
-	} while ( inb( iobase+LSR) & LSR_RXDA); /* Data available */	
+	} while (inb(iobase+LSR) & LSR_RXDA); /* Data available */	
 }
 
 /*
@@ -1134,38 +1125,35 @@
  *    Handle SIR interrupt
  *
  */
-static __u8 pc87108_sir_interrupt( struct irda_device *idev, int eir)
+static __u8 pc87108_sir_interrupt(struct irda_device *idev, int eir)
 {
-	int len;
 	int actual;
 	__u8 new_ier = 0;
 
 	/* Transmit FIFO low on data */
 	if ( eir & EIR_TXLDL_EV) {
 		/* Write data left in transmit buffer */
-		len = idev->tx_buff.len - idev->tx_buff.offset;
-
-		ASSERT( len > 0, return 0;);
-		actual = pc87108_pio_write( idev->io.iobase, 
-					    idev->tx_buff.head, 
-					    len, idev->io.fifo_size);
-		idev->tx_buff.offset += actual;
-		idev->tx_buff.head += actual;
+		actual = pc87108_pio_write(idev->io.iobase, 
+					   idev->tx_buff.data, 
+					   idev->tx_buff.len, 
+					   idev->io.fifo_size);
+		idev->tx_buff.data += actual;
+		idev->tx_buff.len  -= actual;
 		
 		idev->io.direction = IO_XMIT;
-		ASSERT( actual <= len, return 0;);
 
 		/* Check if finished */
-		if ( actual == len) { 
-			DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
+		if (idev->tx_buff.len > 0)
+			new_ier |= IER_TXLDL_IE;
+		else { 
 			idev->netdev.tbusy = 0; /* Unlock */
 			idev->stats.tx_packets++;
-
+			
 		        mark_bh(NET_BH);	
 
 			new_ier |= IER_TXEMP_IE;
-		} else
-			new_ier |= IER_TXLDL_IE;
+		}
+			
 	}
 	/* Check if transmission has completed */
 	if ( eir & EIR_TXEMP_EV) {
diff -urN linux-2.2.7-pre3/drivers/net/irda/tekram.c linux-2.2.7-pre4/drivers/net/irda/tekram.c
--- linux-2.2.7-pre3/drivers/net/irda/tekram.c	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/drivers/net/irda/tekram.c	2003-08-15 15:05:52.000000000 -0700
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      tekram.c
- * Version:       0.5
+ * Version:       1.0
  * Description:   Implementation of the Tekram IrMate IR-210B dongle
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Oct 21 20:02:35 1998
- * Modified at:   Mon Feb 15 14:13:17 1999
+ * Modified at:   Tue Apr 13 16:33:54 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -33,16 +33,23 @@
 #include <asm/uaccess.h>
 
 #include <net/irda/irda.h>
-#include <net/irda/irmod.h>
 #include <net/irda/irda_device.h>
 #include <net/irda/irtty.h>
 #include <net/irda/dongle.h>
 
-static void tekram_reset( struct irda_device *dev, int unused);
-static void tekram_open( struct irda_device *dev, int type);
-static void tekram_close( struct irda_device *dev);
-static void tekram_change_speed( struct irda_device *dev, int baud);
-static void tekram_init_qos( struct irda_device *idev, struct qos_info *qos);
+static void tekram_reset(struct irda_device *dev, int unused);
+static void tekram_open(struct irda_device *dev, int type);
+static void tekram_close(struct irda_device *dev);
+static void tekram_change_speed(struct irda_device *dev, int baud);
+static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos);
+
+#define TEKRAM_115200 0x00
+#define TEKRAM_57600  0x01
+#define TEKRAM_38400  0x02
+#define TEKRAM_19200  0x03
+#define TEKRAM_9600   0x04
+
+#define TEKRAM_PW 0x10 /* Pulse select bit */
 
 static struct dongle dongle = {
 	TEKRAM_DONGLE,
@@ -53,9 +60,9 @@
 	tekram_init_qos,
 };
 
-__initfunc(void tekram_init(void))
+__initfunc(int tekram_init(void))
 {
-	irtty_register_dongle( &dongle);
+	return irtty_register_dongle(&dongle);
 }
 
 void tekram_cleanup(void)
@@ -102,17 +109,17 @@
 	int cflag;
 	__u8 byte;
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( dev != NULL, return;);
-	ASSERT( dev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(dev != NULL, return;);
+	ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;);
 	
 	self = (struct irtty_cb *) dev->priv;
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRTTY_MAGIC, return;);
 	
-	if ( !self->tty)
+	if (!self->tty)
 		return;
 
 	tty = self->tty;
@@ -123,26 +130,27 @@
 	cflag &= ~CBAUD;
 
 	switch (baud) {
-	case 9600:
 	default:
+		/* FALLTHROUGH */
+	case 9600:
 		cflag |= B9600;
-		byte = 4;
+		byte = TEKRAM_PW|TEKRAM_9600;
 		break;
 	case 19200:
 		cflag |= B19200;
-		byte = 3;
+		byte = TEKRAM_PW|TEKRAM_19200;
 		break;
 	case 34800:
 		cflag |= B38400;
-		byte = 2;
+		byte = TEKRAM_PW|TEKRAM_38400;
 		break;
 	case 57600:
 		cflag |= B57600;
-		byte = 1;
+		byte = TEKRAM_PW|TEKRAM_57600;
 		break;
 	case 115200:
 		cflag |= B115200;
-		byte = 0;
+		byte = TEKRAM_PW|TEKRAM_115200;
 		break;
 	}
 
@@ -150,22 +158,22 @@
 	irtty_set_dtr_rts(tty, TRUE, FALSE);
 	
 	/* Wait at least 7us */
-	udelay( 7);
+	udelay(7);
 
 	/* Write control byte */
-	if ( tty->driver.write)
-		tty->driver.write( self->tty, 0, &byte, 1);
+	if (tty->driver.write)
+		tty->driver.write(self->tty, 0, &byte, 1);
 	
 	/* Wait at least 100 ms */
 	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout( 10);
+	schedule_timeout(MSECS_TO_JIFFIES(100));
         
 	/* Set DTR, Set RTS */
 	irtty_set_dtr_rts(tty, TRUE, TRUE);
 
 	/* Now change the speed of the serial port */
 	tty->termios->c_cflag = cflag;
-	tty->driver.set_termios( tty, &old_termios);	
+	tty->driver.set_termios(tty, &old_termios);	
 }
 
 /*
@@ -175,30 +183,29 @@
  *      must be called with a process context!! 
  *
  *      Algorithm:
- *    	  0. set RTS and DTR, and wait 50 ms 
- *           ( power off the IR-210 )
+ *    	  0. Clear RTS and DTR, and wait 50 ms (power off the IR-210 )
  *        1. clear RTS 
  *        2. set DTR, and wait at least 1 ms 
  *        3. clear DTR to SPACE state, wait at least 50 us for further 
  *         operation
  */
-void tekram_reset( struct irda_device *dev, int unused)
+void tekram_reset(struct irda_device *dev, int unused)
 {
 	struct irtty_cb *self;
 	struct tty_struct *tty;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( dev != NULL, return;);
-	ASSERT( dev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(dev != NULL, return;);
+	ASSERT(dev->magic == IRDA_DEVICE_MAGIC, return;);
 	
 	self = (struct irtty_cb *) dev->priv;
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRTTY_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IRTTY_MAGIC, return;);
 
 	tty = self->tty;
-	if ( !tty)
+	if (!tty)
 		return;
 
 	/* Power off dongle */
@@ -206,18 +213,20 @@
 
 	/* Sleep 50 ms */
 	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(5);
+	schedule_timeout(MSECS_TO_JIFFIES(50));
 
 	/* Clear DTR, Set RTS */
 	irtty_set_dtr_rts(tty, FALSE, TRUE); 
 
 	/* Should sleep 1 ms, but 10-20 should not do any harm */
 	current->state = TASK_INTERRUPTIBLE;
-	schedule_timeout(2);
+	schedule_timeout(MSECS_TO_JIFFIES(20));
 
 	/* Set DTR, Set RTS */
 	irtty_set_dtr_rts(tty, TRUE, TRUE);
 	
+	udelay(50);
+
 	/* Finished! */
 }
 
@@ -227,10 +236,11 @@
  *    Initialize QoS capabilities
  *
  */
-static void tekram_init_qos( struct irda_device *idev, struct qos_info *qos)
+static void tekram_init_qos(struct irda_device *idev, struct qos_info *qos)
 {
 	qos->baud_rate.bits &= IR_9600|IR_19200|IR_38400|IR_57600|IR_115200;
-	qos->min_turn_time.bits &= 0xfe; /* All except 0 ms */
+	qos->min_turn_time.bits &= 0x01; /* Needs at least 10 ms */
+	irda_qos_bits_to_value(qos);
 }
 
 #ifdef MODULE
@@ -246,8 +256,7 @@
  */
 int init_module(void)
 {
-	tekram_init();
-	return(0);
+	return tekram_init();
 }
 
 /*
diff -urN linux-2.2.7-pre3/drivers/net/irda/uircc.c linux-2.2.7-pre4/drivers/net/irda/uircc.c
--- linux-2.2.7-pre3/drivers/net/irda/uircc.c	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/drivers/net/irda/uircc.c	2003-08-15 15:05:52.000000000 -0700
@@ -7,7 +7,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Dec 26 10:59:03 1998
- * Modified at:   Sat Apr  3 15:54:41 1999
+ * Modified at:   Tue Apr 20 11:15:52 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -190,7 +190,7 @@
 	
 	/* The only value we must override it the baudrate */
 	idev->qos.baud_rate.bits = IR_9600|IR_19200|IR_38400|IR_57600|
-		IR_115200|/*IR_576000|IR_1152000| */(IR_4000000 << 8);
+		IR_115200/*IR_576000|IR_1152000 |(IR_4000000 << 8)*/;
 
 	idev->qos.min_turn_time.bits = 0x0f;
 	irda_qos_bits_to_value(&idev->qos);
@@ -372,7 +372,7 @@
 		DEBUG(0, __FUNCTION__ "(), handling baud of 4000000\n");
 
 		/* Set self pole address */
-		outb(0x10, iobase+UIRCC_CR8);
+		//outb(0xfe, iobase+UIRCC_CR8);
 
 	 	/* outb(0x10, iobase+UIRCC_CR11); */
 		break;
@@ -443,8 +443,7 @@
 		skb->len++;
 
 	idev->tx_buff.len = skb->len;
-	idev->tx_buff.head = idev->tx_buff.data;
-	idev->tx_buff.offset = 0;
+	idev->tx_buff.data = idev->tx_buff.head;
 	
 	mtt = irda_get_mtt(skb);
 	
@@ -586,11 +585,15 @@
 	outb(self->cr3, iobase+UIRCC_CR3);
 
 	/* Transmit reset (just in case) */
-	outb(UIRCC_CR0_XMIT_RST, iobase+UIRCC_CR0);
+	outb(UIRCC_CR0_XMIT_RST|0x17, iobase+UIRCC_CR0);
 
 	/* Set modem */
 	outb(0x08, iobase+UIRCC_CR10);
 
+	/* Enable receiving with CRC */
+	self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN);
+	outb(self->cr3, iobase+UIRCC_CR3);
+
 	/* Make sure Rx DMA is set */
  	outb(UIRCC_CR1_RX_DMA|UIRCC_CR1_MUST_SET, iobase+UIRCC_CR1);
 
@@ -602,13 +605,13 @@
 	
 	/* driver->media_busy = FALSE; */
 	idev->io.direction = IO_RECV;
-	idev->rx_buff.head = idev->rx_buff.data;
-	idev->rx_buff.offset = 0;
+	idev->rx_buff.data = idev->rx_buff.head;
 
+#if 0
 	/* Enable receiving with CRC */
 	self->cr3 = (UIRCC_CR3_RECV_EN|UIRCC_CR3_RX_CRC_EN);
 	outb(self->cr3, iobase+UIRCC_CR3);
-
+#endif
 	DEBUG(4, __FUNCTION__ "(), cr3=%#x\n", self->cr3);
 	
 	/* Address check? */
@@ -673,7 +676,7 @@
 /* 	} */
 
 	skb_put(skb, len);
-	memcpy(skb->data, idev->rx_buff.head, len);
+	memcpy(skb->data, idev->rx_buff.data, len);
 	idev->stats.rx_packets++;
 
 	skb->dev = &idev->netdev;
@@ -737,7 +740,7 @@
 		uircc_dma_xmit_complete(idev, FALSE);
 		uircc_dma_receive(idev);
 
-		/* outb(0, iobase+UIRCC_CR2);  */
+		outb(0x0d, iobase+UIRCC_CR2);
 		break;
 	case UIRCC_SR3_TMR_OUT:
 		/* Disable timer */
diff -urN linux-2.2.7-pre3/drivers/net/irda/w83977af_ir.c linux-2.2.7-pre4/drivers/net/irda/w83977af_ir.c
--- linux-2.2.7-pre3/drivers/net/irda/w83977af_ir.c	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/drivers/net/irda/w83977af_ir.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Paul VanderSpek
  * Created at:    Wed Nov  4 11:46:16 1998
- * Modified at:   Wed Apr  7 17:35:59 1999
+ * Modified at:   Tue Apr 20 11:15:00 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Corel Computer Corp.
@@ -482,8 +482,7 @@
 	if (idev->io.baudrate > 115200) {
 		memcpy(idev->tx_buff.data, skb->data, skb->len);
 		idev->tx_buff.len = skb->len;
-		idev->tx_buff.head = idev->tx_buff.data;
-		idev->tx_buff.offset = 0;
+		idev->tx_buff.data = idev->tx_buff.head;
 		
 		mtt = irda_get_mtt(skb);
 	        if (mtt > 50) {
@@ -512,20 +511,18 @@
 	     		w83977af_dma_write(idev, iobase);
 		}
 	} else {
+		idev->tx_buff.data = idev->tx_buff.head;
 		idev->tx_buff.len = async_wrap_skb(skb, idev->tx_buff.data, 
 						   idev->tx_buff.truesize);
 		
-		idev->tx_buff.offset = 0;
-		idev->tx_buff.head = idev->tx_buff.data;
-		
 		/* Add interrupt on tx low level (will fire immediately) */
-		switch_bank( iobase, SET0);
+		switch_bank(iobase, SET0);
 		outb(ICR_ETXTHI, iobase+ICR);
 	}
 	dev_kfree_skb(skb);
 
 	/* Restore set register */
-	outb( set, iobase+SSR);
+	outb(set, iobase+SSR);
 
 	return 0;
 }
@@ -594,9 +591,9 @@
 	}
 
 	/* Fill FIFO with current frame */
-	while (( fifo_size-- > 0) && (actual < len)) {
+	while ((fifo_size-- > 0) && (actual < len)) {
 		/* Transmit next byte */
-		outb( buf[actual++], iobase+TBR);
+		outb(buf[actual++], iobase+TBR);
 	}
         
 	DEBUG(4, __FUNCTION__ "(), fifo_size %d ; %d sent of %d\n", 
@@ -702,8 +699,7 @@
 #endif
 	/* driver->media_busy = FALSE; */
 	idev->io.direction = IO_RECV;
-	idev->rx_buff.head = idev->rx_buff.data;
-	idev->rx_buff.offset = 0;
+	idev->rx_buff.data = idev->rx_buff.head;
 
 	/* 
 	 * Reset Rx FIFO. This will also flush the ST_FIFO, it's very 
@@ -751,30 +747,30 @@
 	__u8 set;
 	__u8 status;
 
-	DEBUG( 0, __FUNCTION__ "\n");
+	DEBUG(0, __FUNCTION__ "\n");
 
 	iobase = idev->io.iobase;
 
 	/* Save current set */
-	set = inb( iobase+SSR);
+	set = inb(iobase+SSR);
 	
 	iobase = idev->io.iobase;
 
 	switch_bank(iobase, SET5);
-	if ( prev.status & FS_FO_FSFDR) {
+	if (prev.status & FS_FO_FSFDR) {
 		status = prev.status;
 		len = prev.len;
-
+		
 		prev.status = 0;
 	} else {
-		status = inb( iobase+FS_FO);
-		len = inb( iobase+RFLFL);
-		len |= inb( iobase+RFLFH) << 8;
+		status = inb(iobase+FS_FO);
+		len = inb(iobase+RFLFL);
+		len |= inb(iobase+RFLFH) << 8;
 	}
 
-	while ( status & FS_FO_FSFDR) {
+	while (status & FS_FO_FSFDR) {
 		/* Check for errors */
-		if ( status & FS_FO_ERR_MSK) {
+		if (status & FS_FO_ERR_MSK) {
 			if ( status & FS_FO_LST_FR) {
 				/* Add number of lost frames to stats */
 				idev->stats.rx_errors += len;	
@@ -782,29 +778,28 @@
 				/* Skip frame */
 				idev->stats.rx_errors++;
 				
-				idev->rx_buff.offset += len;
-				idev->rx_buff.head   += len;
+				idev->rx_buff.data += len;
 				
-				if ( status & FS_FO_MX_LEX)
+				if (status & FS_FO_MX_LEX)
 					idev->stats.rx_length_errors++;
 				
-				if ( status & FS_FO_PHY_ERR) 
+				if (status & FS_FO_PHY_ERR) 
 					idev->stats.rx_frame_errors++;
 				
-				if ( status & FS_FO_CRC_ERR) 
+				if (status & FS_FO_CRC_ERR) 
 					idev->stats.rx_crc_errors++;
 			}
 			/* The errors below can be reported in both cases */
-			if ( status & FS_FO_RX_OV)
+			if (status & FS_FO_RX_OV)
 				idev->stats.rx_fifo_errors++;
 			
-			if ( status & FS_FO_FSF_OV)
+			if (status & FS_FO_FSF_OV)
 				idev->stats.rx_fifo_errors++;
 			
 		} else {
 			/* Check if we have transfered all data to memory */
 			switch_bank(iobase, SET0);
-			if ( inb( iobase+USR) & USR_RDR) {
+			if (inb(iobase+USR) & USR_RDR) {
 				/* Put this entry back in fifo */
 				prev.status = status;
 				prev.len = len;
@@ -815,31 +810,30 @@
 				return FALSE; 	/* I'll be back! */
 			}
 						
-			skb = dev_alloc_skb( len+1);
+			skb = dev_alloc_skb(len+1);
 			if (skb == NULL)  {
-				printk( KERN_INFO __FUNCTION__ 
-					"(), memory squeeze, dropping frame.\n");
+				printk(KERN_INFO __FUNCTION__ 
+				       "(), memory squeeze, dropping frame.\n");
 				/* Restore set register */
-				outb( set, iobase+SSR);
+				outb(set, iobase+SSR);
 
 				return FALSE;
 			}
 			
 			/*  Align to 20 bytes */
-			skb_reserve( skb, 1); 
+			skb_reserve(skb, 1); 
 			
 			/* Copy frame without CRC */
 			if ( idev->io.baudrate < 4000000) {
 				skb_put( skb, len-2);
-				memcpy( skb->data, idev->rx_buff.head, len-2);
+				memcpy( skb->data, idev->rx_buff.data, len-2);
 			} else {
 				skb_put( skb, len-4);
-				memcpy( skb->data, idev->rx_buff.head, len-4);
+				memcpy( skb->data, idev->rx_buff.data, len-4);
 			}
 
 			/* Move to next frame */
-			idev->rx_buff.offset += len;
-			idev->rx_buff.head += len;
+			idev->rx_buff.data += len;
 			
 			skb->dev = &idev->netdev;
 			skb->mac.raw  = skb->data;
@@ -854,7 +848,7 @@
 		len |= inb( iobase+RFLFH) << 8;
 	}
 	/* Restore set register */
-	outb( set, iobase+SSR);
+	outb(set, iobase+SSR);
 
 	return TRUE;
 }
@@ -865,28 +859,24 @@
  *    Receive all data in receiver FIFO
  *
  */
-static void w83977af_pio_receive( struct irda_device *idev) 
+static void w83977af_pio_receive(struct irda_device *idev) 
 {
 	__u8 byte = 0x00;
 	int iobase;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( idev != NULL, return;);
-	ASSERT( idev->magic == IRDA_DEVICE_MAGIC, return;);
+	ASSERT(idev != NULL, return;);
+	ASSERT(idev->magic == IRDA_DEVICE_MAGIC, return;);
 	
 	iobase = idev->io.iobase;
 	
-	if ( idev->rx_buff.len == 0) {
-		idev->rx_buff.head = idev->rx_buff.data;
-	}
-
 	/*  Receive all characters in Rx FIFO */
 	do {
-		byte = inb( iobase+RBR);
-		async_unwrap_char( idev, byte);
+		byte = inb(iobase+RBR);
+		async_unwrap_char(idev, byte);
 
-	} while ( inb( iobase+USR) & USR_RDR); /* Data available */	
+	} while (inb(iobase+USR) & USR_RDR); /* Data available */	
 }
 
 /*
@@ -897,7 +887,6 @@
  */
 static __u8 w83977af_sir_interrupt(struct irda_device *idev, int isr)
 {
-	int len;
 	int actual;
 	__u8 new_icr = 0;
 
@@ -906,19 +895,19 @@
 	/* Transmit FIFO low on data */
 	if (isr & ISR_TXTH_I) {
 		/* Write data left in transmit buffer */
-		len = idev->tx_buff.len - idev->tx_buff.offset;
-
-		ASSERT(len > 0, return 0;);
 		actual = w83977af_pio_write(idev->io.iobase, 
-					    idev->tx_buff.head, 
-					    len, idev->io.fifo_size);
-		idev->tx_buff.offset += actual;
-		idev->tx_buff.head += actual;
+					    idev->tx_buff.data, 
+					    idev->tx_buff.len, 
+					    idev->io.fifo_size);
+		idev->tx_buff.data += actual;
+		idev->tx_buff.len  -= actual;
 		
 		idev->io.direction = IO_XMIT;
-		ASSERT( actual <= len, return 0;);
+
 		/* Check if finished */
-		if ( actual == len) { 
+		if (idev->tx_buff.len > 0)
+			new_icr |= ICR_ETXTHI;
+		else { 
 			DEBUG( 4, __FUNCTION__ "(), finished with frame!\n");
 			idev->netdev.tbusy = 0; /* Unlock */
 			idev->stats.tx_packets++;
@@ -927,8 +916,8 @@
 		        mark_bh(NET_BH);	
 
 			new_icr |= ICR_ETBREI;
-		} else
-			new_icr |= ICR_ETXTHI;
+		}
+		
 	}
 	/* Check if transmission has completed */
 	if (isr & ISR_TXEMP_I) {
diff -urN linux-2.2.7-pre3/drivers/net/net_init.c linux-2.2.7-pre4/drivers/net/net_init.c
--- linux-2.2.7-pre3/drivers/net/net_init.c	1998-12-18 09:40:15.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/net_init.c	2003-08-15 15:05:52.000000000 -0700
@@ -252,6 +252,22 @@
 	return dev;
 }
 
+
+void unregister_hipdev(struct device *dev)
+{
+	int i;
+	rtnl_lock();
+	unregister_netdevice(dev);
+	for (i = 0; i < MAX_HIP_CARDS; ++i) {
+		if (hipdev_index[i] == dev) {
+			hipdev_index[i] = NULL;
+			break;
+		}
+	}
+	rtnl_unlock();
+}
+
+
 static int hippi_neigh_setup_dev(struct device *dev, struct neigh_parms *p)
 {
 	/* Never send broadcast/multicast ARP messages */
diff -urN linux-2.2.7-pre3/drivers/net/pcnet32.c linux-2.2.7-pre4/drivers/net/pcnet32.c
--- linux-2.2.7-pre3/drivers/net/pcnet32.c	1999-01-17 18:28:06.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/pcnet32.c	2003-08-15 15:05:52.000000000 -0700
@@ -13,7 +13,7 @@
  * 	This driver is for PCnet32 and PCnetPCI based ethercards
  */
 
-static const char *version = "pcnet32.c:v1.11 17.1.99 tsbogend@alpha.franken.de\n";
+static const char *version = "pcnet32.c:v1.21 31.3.99 tsbogend@alpha.franken.de\n";
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -58,9 +58,36 @@
 
 #define PORT_PORTSEL  0x03
 #define PORT_ASEL     0x04
+#define PORT_100      0x40
 #define PORT_FD       0x80
 
-static int options = PORT_ASEL;  /* port selection */
+
+/*
+ * table to translate option values from tulip
+ * to internal options
+ */
+static unsigned char options_mapping[] = {
+    PORT_ASEL,			   /*  0 Auto-select      */
+    PORT_AUI,			   /*  1 BNC/AUI          */
+    PORT_AUI,			   /*  2 AUI/BNC          */ 
+    PORT_ASEL,			   /*  3 not supported    */
+    PORT_10BT | PORT_FD,	   /*  4 10baseT-FD       */
+    PORT_ASEL,			   /*  5 not supported    */
+    PORT_ASEL,			   /*  6 not supported    */
+    PORT_ASEL,			   /*  7 not supported    */
+    PORT_ASEL,			   /*  8 not supported    */
+    PORT_MII,		           /*  9 MII 10baseT      */
+    PORT_MII | PORT_FD,            /* 10 MII 10baseT-FD   */
+    PORT_MII,			   /* 11 MII (autosel)    */
+    PORT_10BT,			   /* 12 10BaseT	  */
+    PORT_MII | PORT_100,	   /* 13 MII 100BaseTx    */
+    PORT_MII | PORT_100 | PORT_FD, /* 14 MII 100BaseTx-FD */
+    PORT_ASEL			   /* 15 not supported    */
+};
+
+#define MAX_UNITS 8
+static int options[MAX_UNITS] = {0, };
+static int full_duplex[MAX_UNITS] = {0, };
 
 /*
  * 				Theory of Operation
@@ -116,6 +143,12 @@
  *         added port selection for modules
  *         detect special T1/E1 WAN card and setup port selection
  * v1.11:  fixed wrong checking of Tx errors
+ * v1.20:  added check of return value kmalloc (cpeterso@cs.washington.edu)
+ *         added save original kmalloc addr for freeing (mcr@solidum.com)
+ *         added support for PCnetHome chip (joe@MIT.EDU)
+ *         rewritten PCI card detection
+ *         added dwio mode to get driver working on some PPC machines
+ * v1.21:  added mii selection and mii ioctl
  */
 
 
@@ -140,202 +173,402 @@
 #define PKT_BUF_SZ		1544
 
 /* Offsets from base I/O address. */
-#define PCNET32_DATA 0x10
-#define PCNET32_ADDR 0x12
-#define PCNET32_RESET 0x14
-#define PCNET32_BUS_IF 0x16
-#define PCNET32_TOTAL_SIZE 0x18
+#define PCNET32_WIO_RDP		0x10
+#define PCNET32_WIO_RAP		0x12
+#define PCNET32_WIO_RESET	0x14
+#define PCNET32_WIO_BDP		0x16
+
+#define PCNET32_DWIO_RDP	0x10
+#define PCNET32_DWIO_RAP	0x14
+#define PCNET32_DWIO_RESET	0x18
+#define PCNET32_DWIO_BDP	0x1C
+
+#define PCNET32_TOTAL_SIZE 0x20
 
 #define CRC_POLYNOMIAL_LE 0xedb88320UL  /* Ethernet CRC, little endian */
 
 /* The PCNET32 Rx and Tx ring descriptors. */
 struct pcnet32_rx_head {
-	u32 base;
-	s16 buf_length;
-        s16 status;    
-	u32 msg_length;
-	u32 reserved;
+    u32 base;
+    s16 buf_length;
+    s16 status;    
+    u32 msg_length;
+    u32 reserved;
 };
 	
 struct pcnet32_tx_head {
-	u32 base;
-	s16 length;
-        s16 status;
-	u32 misc;
-	u32 reserved;
+    u32 base;
+    s16 length;
+    s16 status;
+    u32 misc;
+    u32 reserved;
 };
 
-
 /* The PCNET32 32-Bit initialization block, described in databook. */
 struct pcnet32_init_block {
-	u16 mode;
-	u16 tlen_rlen;
-	u8  phys_addr[6];
-	u16 reserved;
-	u32 filter[2];
-	/* Receive and transmit ring base, along with extra bits. */    
-	u32 rx_ring;
-	u32 tx_ring;
+    u16 mode;
+    u16 tlen_rlen;
+    u8  phys_addr[6];
+    u16 reserved;
+    u32 filter[2];
+    /* Receive and transmit ring base, along with extra bits. */    
+    u32 rx_ring;
+    u32 tx_ring;
+};
+
+/* PCnet32 access functions */
+struct pcnet32_access {
+    u16 (*read_csr)(unsigned long, int);
+    void (*write_csr)(unsigned long, int, u16);
+    u16 (*read_bcr)(unsigned long, int);
+    void (*write_bcr)(unsigned long, int, u16);
+    u16 (*read_rap)(unsigned long);
+    void (*write_rap)(unsigned long, u16);
+    void (*reset)(unsigned long);
 };
 
 struct pcnet32_private {
-	/* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
-	struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
-	struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
-	struct pcnet32_init_block	init_block;
-	const char *name;
-	/* The saved address of a sent-in-place packet/buffer, for skfree(). */
-	struct sk_buff *tx_skbuff[TX_RING_SIZE];
-        struct sk_buff *rx_skbuff[RX_RING_SIZE];
-	int cur_rx, cur_tx;			/* The next free ring entry */
-	int dirty_rx, dirty_tx;		        /* The ring entries to be free()ed. */
-	struct net_device_stats stats;
-	char tx_full;
-        int  options;
-        int  shared_irq:1,                      /* shared irq possible */
-             full_duplex:1;                     /* full duplex possible */
+    /* The Tx and Rx ring entries must be aligned on 16-byte boundaries in 32bit mode. */
+    struct pcnet32_rx_head   rx_ring[RX_RING_SIZE];
+    struct pcnet32_tx_head   tx_ring[TX_RING_SIZE];
+    struct pcnet32_init_block	init_block;
+    const char *name;
+    /* The saved address of a sent-in-place packet/buffer, for skfree(). */
+    struct sk_buff *tx_skbuff[TX_RING_SIZE];
+    struct sk_buff *rx_skbuff[RX_RING_SIZE];
+    struct pcnet32_access a;
+    void *origmem;
+    int cur_rx, cur_tx;			/* The next free ring entry */
+    int dirty_rx, dirty_tx;		        /* The ring entries to be free()ed. */
+    struct net_device_stats stats;
+    char tx_full;
+    int  options;
+    int  shared_irq:1,                      /* shared irq possible */
+         full_duplex:1,                     /* full duplex possible */
+         mii:1;                             /* mii port available */
 #ifdef MODULE
-        struct device *next;
+    struct device *next;
 #endif    
 };
 
-int  pcnet32_probe(struct device *dev);
-static int  pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared);
-static int  pcnet32_open(struct device *dev);
-static int  pcnet32_init_ring(struct device *dev);
-static int  pcnet32_start_xmit(struct sk_buff *skb, struct device *dev);
-static int  pcnet32_rx(struct device *dev);
-static void pcnet32_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int  pcnet32_close(struct device *dev);
-static struct net_device_stats *pcnet32_get_stats(struct device *dev);
-static void pcnet32_set_multicast_list(struct device *dev);
+int  pcnet32_probe(struct device *);
+static int  pcnet32_probe1(struct device *, unsigned long, unsigned char, int, int);
+static int  pcnet32_open(struct device *);
+static int  pcnet32_init_ring(struct device *);
+static int  pcnet32_start_xmit(struct sk_buff *, struct device *);
+static int  pcnet32_rx(struct device *);
+static void pcnet32_interrupt(int, void *, struct pt_regs *);
+static int  pcnet32_close(struct device *);
+static struct net_device_stats *pcnet32_get_stats(struct device *);
+static void pcnet32_set_multicast_list(struct device *);
+#ifdef HAVE_PRIVATE_IOCTL
+static int  pcnet32_mii_ioctl(struct device *, struct ifreq *, int);
+#endif
+
+enum pci_flags_bit {
+    PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
+    PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
+};
+
+struct pcnet32_pci_id_info {
+    const char *name;
+    u16 vendor_id, device_id, device_id_mask, flags;
+    int io_size;
+    int (*probe1) (struct device *, unsigned long, unsigned char, int, int);
+};
+
+static struct pcnet32_pci_id_info pcnet32_tbl[] = {
+    { "AMD PCnetPCI series",
+	0x1022, 0x2000, 0xfffe, PCI_USES_IO|PCI_USES_MASTER, PCNET32_TOTAL_SIZE,
+	pcnet32_probe1},
+    {0,}
+};
+
+static u16 pcnet32_wio_read_csr (unsigned long addr, int index)
+{
+    outw (index, addr+PCNET32_WIO_RAP);
+    return inw (addr+PCNET32_WIO_RDP);
+}
+
+static void pcnet32_wio_write_csr (unsigned long addr, int index, u16 val)
+{
+    outw (index, addr+PCNET32_WIO_RAP);
+    outw (val, addr+PCNET32_WIO_RDP);
+}
+
+static u16 pcnet32_wio_read_bcr (unsigned long addr, int index)
+{
+    outw (index, addr+PCNET32_WIO_RAP);
+    return inw (addr+PCNET32_WIO_BDP);
+}
+
+static void pcnet32_wio_write_bcr (unsigned long addr, int index, u16 val)
+{
+    outw (index, addr+PCNET32_WIO_RAP);
+    outw (val, addr+PCNET32_WIO_BDP);
+}
+
+static u16 pcnet32_wio_read_rap (unsigned long addr)
+{
+    return inw (addr+PCNET32_WIO_RAP);
+}
+
+static void pcnet32_wio_write_rap (unsigned long addr, u16 val)
+{
+    outw (val, addr+PCNET32_WIO_RAP);
+}
+
+static void pcnet32_wio_reset (unsigned long addr)
+{
+    inw (addr+PCNET32_WIO_RESET);
+}
+
+static int pcnet32_wio_check (unsigned long addr)
+{
+    outw (88, addr+PCNET32_WIO_RAP);
+    return (inw (addr+PCNET32_WIO_RAP) == 88);
+}
+
+static struct pcnet32_access pcnet32_wio = {
+    pcnet32_wio_read_csr,
+    pcnet32_wio_write_csr,
+    pcnet32_wio_read_bcr,
+    pcnet32_wio_write_bcr,
+    pcnet32_wio_read_rap,
+    pcnet32_wio_write_rap,
+    pcnet32_wio_reset
+};
+
+static u16 pcnet32_dwio_read_csr (unsigned long addr, int index)
+{
+    outl (index, addr+PCNET32_DWIO_RAP);
+    return (inl (addr+PCNET32_DWIO_RDP) & 0xffff);
+}
+
+static void pcnet32_dwio_write_csr (unsigned long addr, int index, u16 val)
+{
+    outl (index, addr+PCNET32_DWIO_RAP);
+    outl (val, addr+PCNET32_DWIO_RDP);
+}
+
+static u16 pcnet32_dwio_read_bcr (unsigned long addr, int index)
+{
+    outl (index, addr+PCNET32_DWIO_RAP);
+    return (inl (addr+PCNET32_DWIO_BDP) & 0xffff);
+}
+
+static void pcnet32_dwio_write_bcr (unsigned long addr, int index, u16 val)
+{
+    outl (index, addr+PCNET32_DWIO_RAP);
+    outl (val, addr+PCNET32_DWIO_BDP);
+}
+
+static u16 pcnet32_dwio_read_rap (unsigned long addr)
+{
+    return (inl (addr+PCNET32_DWIO_RAP) & 0xffff);
+}
+
+static void pcnet32_dwio_write_rap (unsigned long addr, u16 val)
+{
+    outl (val, addr+PCNET32_DWIO_RAP);
+}
+
+static void pcnet32_dwio_reset (unsigned long addr)
+{
+    inl (addr+PCNET32_DWIO_RESET);
+}
+
+static int pcnet32_dwio_check (unsigned long addr)
+{
+    outl (88, addr+PCNET32_DWIO_RAP);
+    return (inl (addr+PCNET32_DWIO_RAP) == 88);
+}
+
+static struct pcnet32_access pcnet32_dwio = {
+    pcnet32_dwio_read_csr,
+    pcnet32_dwio_write_csr,
+    pcnet32_dwio_read_bcr,
+    pcnet32_dwio_write_bcr,
+    pcnet32_dwio_read_rap,
+    pcnet32_dwio_write_rap,
+    pcnet32_dwio_reset
+
+};
 
 
 
-__initfunc(int pcnet32_probe (struct device *dev))
+int __init pcnet32_probe (struct device *dev)
 {
-    unsigned int  ioaddr = dev ? dev->base_addr: 0;
+    unsigned long ioaddr = dev ? dev->base_addr: 0;
     unsigned int  irq_line = dev ? dev->irq : 0;
     int *port;
+    int cards_found = 0;
     
-    if (ioaddr > 0x1ff)
-      return pcnet32_probe1(dev, ioaddr, irq_line, 0);
-    else if(ioaddr != 0)
-      return ENXIO;
+    
+#ifndef __powerpc__
+    if (ioaddr > 0x1ff) {
+	if (check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0)
+	    return pcnet32_probe1(dev, ioaddr, irq_line, 0, 0);
+	else
+	    return ENODEV;
+    } else
+#endif
+	if(ioaddr != 0)
+	    return ENXIO;
     
 #if defined(CONFIG_PCI)
     if (pci_present()) {
-	struct pci_dev *pdev = NULL;
+	struct pci_dev *pdev;
+	unsigned char pci_bus, pci_device_fn;
+	int pci_index;
 	
 	printk("pcnet32.c: PCI bios is present, checking for devices...\n");
-	while ((pdev = pci_find_device(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, pdev))) {
-	    unsigned short pci_command;
+	for (pci_index = 0; pci_index < 0xff; pci_index++) {
+	    u16 vendor, device, pci_command;
+	    int chip_idx;
 
-	    irq_line = pdev->irq;
+	    if (pcibios_find_class (PCI_CLASS_NETWORK_ETHERNET << 8,
+				    pci_index, &pci_bus, &pci_device_fn) != PCIBIOS_SUCCESSFUL)
+		break;
+	    
+	    pcibios_read_config_word(pci_bus, pci_device_fn, PCI_VENDOR_ID, &vendor);
+	    pcibios_read_config_word(pci_bus, pci_device_fn, PCI_DEVICE_ID, &device);
+
+	    for (chip_idx = 0; pcnet32_tbl[chip_idx].vendor_id; chip_idx++)
+		if (vendor == pcnet32_tbl[chip_idx].vendor_id &&
+		    (device & pcnet32_tbl[chip_idx].device_id_mask) == pcnet32_tbl[chip_idx].device_id)
+		    break;
+	    if (pcnet32_tbl[chip_idx].vendor_id == 0)
+		continue;
+	    
+	    pdev = pci_find_slot(pci_bus, pci_device_fn);
 	    ioaddr = pdev->base_address[0] & PCI_BASE_ADDRESS_IO_MASK;
+#if defined(ADDR_64BITS) && defined(__alpha__)
+	    ioaddr |= ((long)pdev->base_address[1]) << 32;
+#endif
+	    irq_line = pdev->irq;
+	    
+	    /* Avoid already found cards from previous pcnet32_probe() calls */
+	    if ((pcnet32_tbl[chip_idx].flags & PCI_USES_IO) &&
+		check_region(ioaddr, pcnet32_tbl[chip_idx].io_size))
+		continue;
+
 	    /* PCI Spec 2.1 states that it is either the driver or PCI card's
 	     * responsibility to set the PCI Master Enable Bit if needed.
 	     *	(From Mark Stockton <marks@schooner.sys.hou.compaq.com>)
 	     */
 	    pci_read_config_word(pdev, PCI_COMMAND, &pci_command);
-	    
-	    /* Avoid already found cards from previous pcnet32_probe() calls */
-	    if (check_region(ioaddr, PCNET32_TOTAL_SIZE))
-	      continue;
-
 	    if ( ! (pci_command & PCI_COMMAND_MASTER)) {
 		printk("PCI Master Bit has not been set. Setting...\n");
 		pci_command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
 		pci_write_config_word(pdev, PCI_COMMAND, pci_command);
 	    }
+	    printk("Found PCnet/PCI at %#lx, irq %d.\n", ioaddr, irq_line);
 	    
-	    printk("Found PCnet/PCI at %#x, irq %d.\n",
-		   ioaddr, irq_line);
-	    
-	    if (pcnet32_probe1(dev, ioaddr, irq_line, 1) != 0) {	/* Shouldn't happen. */
-		printk(KERN_ERR "pcnet32.c: Probe of PCI card at %#x failed.\n", ioaddr);
-		break;
+	    if (pcnet32_tbl[chip_idx].probe1(dev, ioaddr, irq_line, 1, cards_found) == 0) {
+		cards_found++;
+		dev = NULL;
 	    }
-	    return 0;
 	}
     } else 
 #endif  /* defined(CONFIG_PCI) */
     
     /* now look for PCnet32 VLB cards */
     for (port = pcnet32_portlist; *port; port++) {
-	unsigned int ioaddr = *port;
+	unsigned long ioaddr = *port;
 	
 	if ( check_region(ioaddr, PCNET32_TOTAL_SIZE) == 0) {
     	    /* check if there is really a pcnet chip on that ioaddr */
     	    if ((inb(ioaddr + 14) == 0x57) &&
 		(inb(ioaddr + 15) == 0x57) &&
-	        (pcnet32_probe1(dev, ioaddr, 0, 0) == 0))
-	      return 0;
+	        (pcnet32_probe1(dev, ioaddr, 0, 0, 0) == 0))
+		cards_found++;
 	}
     }
-    return ENODEV;
+    return cards_found ? 0: ENODEV;
 }
 
 
 /* pcnet32_probe1 */
-__initfunc(static int pcnet32_probe1(struct device *dev, unsigned int ioaddr, unsigned char irq_line, int shared))
+static int __init
+pcnet32_probe1(struct device *dev, unsigned long ioaddr, unsigned char irq_line, int shared, int card_idx)
 {
     struct pcnet32_private *lp;
-    int i,full_duplex = 0;
+    int i,media,fdx = 0, mii = 0;
+    int chip_version;
     char *chipname;
+    char *priv;
+    struct pcnet32_access *a;
 
-    inw(ioaddr+PCNET32_RESET); /* Reset the PCNET32 */
+    /* reset the chip */
+    pcnet32_dwio_reset(ioaddr);
+    pcnet32_wio_reset(ioaddr);
+
+    if (pcnet32_wio_read_csr (ioaddr, 0) == 4 && pcnet32_wio_check (ioaddr)) {
+	a = &pcnet32_wio;
+    } else {
+	if (pcnet32_dwio_read_csr (ioaddr, 0) == 4 && pcnet32_dwio_check(ioaddr)) {
+	    a = &pcnet32_dwio;
+	} else
+	    return ENODEV;
+    }
 
-    outw(0x0000, ioaddr+PCNET32_ADDR); /* Switch to window 0 */
-    if (inw(ioaddr+PCNET32_DATA) != 0x0004)
-      return ENODEV;
-
-    /* Get the version of the chip. */
-    outw(88, ioaddr+PCNET32_ADDR);
-    if (inw(ioaddr+PCNET32_ADDR) != 88) {
-	/* should never happen */
+    chip_version = a->read_csr (ioaddr, 88) | (a->read_csr (ioaddr,89) << 16);
+    if (pcnet32_debug > 2)
+	printk("  PCnet chip version is %#x.\n", chip_version);
+    if ((chip_version & 0xfff) != 0x003)
 	return ENODEV;
-    } else {			/* Good, it's a newer chip. */
-	int chip_version = inw(ioaddr+PCNET32_DATA);
-	outw(89, ioaddr+PCNET32_ADDR);
-	chip_version |= inw(ioaddr+PCNET32_DATA) << 16;
+    chip_version = (chip_version >> 12) & 0xffff;
+    switch (chip_version) {
+     case 0x2420:
+	chipname = "PCnet/PCI 79C970";
+	break;
+     case 0x2430:
+	if (shared)
+	    chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */
+	else
+	    chipname = "PCnet/32 79C965";
+	break;
+     case 0x2621:
+	chipname = "PCnet/PCI II 79C970A";
+	fdx = 1;
+	break;
+     case 0x2623:
+	chipname = "PCnet/FAST 79C971";
+	fdx = 1; mii = 1;
+	break;
+     case 0x2624:
+	chipname = "PCnet/FAST+ 79C972";
+	fdx = 1; mii = 1;
+	break;
+     case 0x2626:
+	chipname = "PCnet/Home 79C978";
+	fdx = 1;
+	/* 
+	 * This is based on specs published at www.amd.com.  This section
+	 * assumes that a card with a 79C978 wants to go into 1Mb HomePNA
+	 * mode.  The 79C978 can also go into standard ethernet, and there
+	 * probably should be some sort of module option to select the
+	 * mode by which the card should operate
+	 */
+	/* switch to home wiring mode */
+	media = a->read_bcr (ioaddr, 49);
 	if (pcnet32_debug > 2)
-	  printk("  PCnet chip version is %#x.\n", chip_version);
-	if ((chip_version & 0xfff) != 0x003)
-	  return ENODEV;
-	chip_version = (chip_version >> 12) & 0xffff;
-	switch (chip_version) {
-	 case 0x2420:
-	    chipname = "PCnet/PCI 79C970";
-	    break;
-	 case 0x2430:
-	    if (shared)
-		chipname = "PCnet/PCI 79C970"; /* 970 gives the wrong chip id back */
-	    else
-		chipname = "PCnet/32 79C965";
-	    break;
-	 case 0x2621:
-	    chipname = "PCnet/PCI II 79C970A";
-	    full_duplex = 1;
-	    break;
-	 case 0x2623:
-	    chipname = "PCnet/FAST 79C971";
-	    full_duplex = 1;
-	    break;
-	 case 0x2624:
-	    chipname = "PCnet/FAST+ 79C972";
-	    full_duplex = 1;
-	    break;
-	 default:
-	    printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
-	    return ENODEV;
-	}
+	    printk("pcnet32: pcnet32 media value %#x.\n",  media);
+	media &= ~3;
+	media |= 1;
+	if (pcnet32_debug > 2)
+	    printk("pcnet32: pcnet32 media reset to %#x.\n",  media);
+	a->write_bcr (ioaddr, 49, media);
+	break;
+     default:
+	printk("pcnet32: PCnet version %#x, no PCnet32 chip.\n",chip_version);
+	return ENODEV;
     }
     
-    if (dev == NULL)
-	dev = init_etherdev(0, 0);
+    dev = init_etherdev(dev, 0);
 
-    printk("%s: %s at %#3x,", dev->name, chipname, ioaddr);
+    printk(KERN_INFO "%s: %s at %#3lx,", dev->name, chipname, ioaddr);
 
     /* There is a 16 byte station address PROM at the base address.
      The first six bytes are the station address. */
@@ -345,15 +578,31 @@
     dev->base_addr = ioaddr;
     request_region(ioaddr, PCNET32_TOTAL_SIZE, chipname);
     
-    /* Make certain the data structures used by the PCnet32 are 16byte aligned and DMAble. */
-    lp = (struct pcnet32_private *) (((unsigned long)kmalloc(sizeof(*lp)+15, GFP_DMA | GFP_KERNEL)+15) & ~15);
+    if ((priv = kmalloc(sizeof(*lp)+15,GFP_KERNEL)) == NULL)
+	return ENOMEM;
+
+    /*
+     * Make certain the data structures used by
+     * the PCnet32 are 16byte aligned
+      */
+    lp = (struct pcnet32_private *)(((unsigned long)priv+15) & ~15);
       
     memset(lp, 0, sizeof(*lp));
     dev->priv = lp;
     lp->name = chipname;
     lp->shared_irq = shared;
-    lp->full_duplex = full_duplex;
-    lp->options = options;
+    lp->full_duplex = fdx;
+    lp->mii = mii;
+    if (options[card_idx] > sizeof (options_mapping))
+	lp->options = PORT_ASEL;
+    else
+	lp->options = options_mapping[options[card_idx]];
+    
+    if (fdx && !(lp->options & PORT_ASEL) && full_duplex[card_idx])
+	lp->options |= PORT_FD;
+    
+    lp->origmem = priv;
+    lp->a = *a;
     
     /* detect special T1/E1 WAN card by checking for MAC address */
     if (dev->dev_addr[0] == 0x00 && dev->dev_addr[1] == 0xe0 && dev->dev_addr[2] == 0x75)
@@ -369,24 +618,17 @@
     lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
     
     /* switch pcnet32 to 32bit mode */
-    outw(0x0014, ioaddr+PCNET32_ADDR);
-    outw(0x0002, ioaddr+PCNET32_BUS_IF);
+    a->write_bcr (ioaddr, 20, 2);
 
-    outw(0x0001, ioaddr+PCNET32_ADDR);
-    inw(ioaddr+PCNET32_ADDR);
-    outw(virt_to_bus(&lp->init_block) & 0xffff, ioaddr+PCNET32_DATA);
-    outw(0x0002, ioaddr+PCNET32_ADDR);
-    inw(ioaddr+PCNET32_ADDR);
-    outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA);
-    outw(0x0000, ioaddr+PCNET32_ADDR);
-    inw(ioaddr+PCNET32_ADDR);
+    a->write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) & 0xffff);
+    a->write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16);
     
     if (irq_line) {
 	dev->irq = irq_line;
     }
     
     if (dev->irq >= 2)
-      printk(" assigned IRQ %d.\n", dev->irq);
+	printk(" assigned IRQ %d.\n", dev->irq);
     else {
 	unsigned long irq_mask = probe_irq_on();
 	
@@ -396,7 +638,7 @@
 	 * boards will work.
 	 */
 	/* Trigger an initialization just for the interrupt. */
-	outw(0x0041, ioaddr+PCNET32_DATA);
+	a->write_csr (ioaddr, 0, 0x41);
 	mdelay (1);
 	
 	dev->irq = probe_irq_off (irq_mask);
@@ -409,7 +651,7 @@
     }
 
     if (pcnet32_debug > 0)
-      printk(version);
+	printk(version);
     
     /* The PCNET32-specific entries in the device structure. */
     dev->open = &pcnet32_open;
@@ -417,6 +659,10 @@
     dev->stop = &pcnet32_close;
     dev->get_stats = &pcnet32_get_stats;
     dev->set_multicast_list = &pcnet32_set_multicast_list;
+#ifdef HAVE_PRIVATE_IOCTL
+    dev->do_ioctl = &pcnet32_mii_ioctl;
+#endif
+
     
 #ifdef MODULE
     lp->next = pcnet32_dev;
@@ -432,95 +678,96 @@
 static int
 pcnet32_open(struct device *dev)
 {
-	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-	unsigned int ioaddr = dev->base_addr;
-        unsigned short val;
-	int i;
-
-	if (dev->irq == 0 ||
-		request_irq(dev->irq, &pcnet32_interrupt,
-			    lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) {
-		return -EAGAIN;
-	}
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    u16 val;
+    int i;
+
+    if (dev->irq == 0 ||
+	request_irq(dev->irq, &pcnet32_interrupt,
+		    lp->shared_irq ? SA_SHIRQ : 0, lp->name, (void *)dev)) {
+	return -EAGAIN;
+    }
 
-	/* Reset the PCNET32 */
-	inw(ioaddr+PCNET32_RESET);
+    /* Reset the PCNET32 */
+    lp->a.reset (ioaddr);
 
-	/* switch pcnet32 to 32bit mode */
-	outw(0x0014, ioaddr+PCNET32_ADDR);
-	outw(0x0002, ioaddr+PCNET32_BUS_IF);
-
-	if (pcnet32_debug > 1)
-		printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
-			   dev->name, dev->irq,
-		           (u32) virt_to_bus(lp->tx_ring),
-		           (u32) virt_to_bus(lp->rx_ring),
-			   (u32) virt_to_bus(&lp->init_block));
-    
-        /* set/reset autoselect bit */
-    	outw(0x0002, ioaddr+PCNET32_ADDR);
-        val = inw(ioaddr+PCNET32_BUS_IF) & ~2;
-        if (lp->options & PORT_ASEL)
-	        val |= 2;
-        outw(val, ioaddr+PCNET32_BUS_IF);
-
-        /* handle full duplex setting */
-        if (lp->full_duplex) {
-	    outw (0x0009, ioaddr+PCNET32_ADDR);
-	    val = inw(ioaddr+PCNET32_BUS_IF) & ~3;
-	    if (lp->options & PORT_FD) {
-		val |= 1;
-		if (lp->options == (PORT_FD | PORT_AUI))
-		    val |= 2;
-	    }
-	    outw(val, ioaddr+PCNET32_BUS_IF);
+    /* switch pcnet32 to 32bit mode */
+    lp->a.write_csr (ioaddr, 20, 2);
+
+    if (pcnet32_debug > 1)
+	printk("%s: pcnet32_open() irq %d tx/rx rings %#x/%#x init %#x.\n",
+	       dev->name, dev->irq,
+	       (u32) virt_to_bus(lp->tx_ring),
+	       (u32) virt_to_bus(lp->rx_ring),
+	       (u32) virt_to_bus(&lp->init_block));
+    
+    /* set/reset autoselect bit */
+    val = lp->a.read_bcr (ioaddr, 2) & ~2;
+    if (lp->options & PORT_ASEL)
+	val |= 2;
+    lp->a.write_bcr (ioaddr, 2, val);
+    
+    /* handle full duplex setting */
+    if (lp->full_duplex) {
+	val = lp->a.read_bcr (ioaddr, 9) & ~3;
+	if (lp->options & PORT_FD) {
+	    val |= 1;
+	    if (lp->options == (PORT_FD | PORT_AUI))
+		val |= 2;
 	}
+	lp->a.write_bcr (ioaddr, 9, val);
+    }
     
-        /* set/reset GPSI bit in test register */
-        outw (0x007c, ioaddr+PCNET32_ADDR);
-        val = inw(ioaddr+PCNET32_DATA) & ~0x10;
-        if ((lp->options & PORT_PORTSEL) == PORT_GPSI)
-	        val |= 0x10;
-    	outw(val, ioaddr+PCNET32_DATA);
-	    
-	lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
-	lp->init_block.filter[0] = 0x00000000;
-	lp->init_block.filter[1] = 0x00000000;
-	if (pcnet32_init_ring(dev))
-		return -ENOMEM;
-    
-	/* Re-initialize the PCNET32, and start it when done. */
-	outw(0x0001, ioaddr+PCNET32_ADDR);
-	outw(virt_to_bus(&lp->init_block) &0xffff, ioaddr+PCNET32_DATA);
-	outw(0x0002, ioaddr+PCNET32_ADDR);
-	outw(virt_to_bus(&lp->init_block) >> 16, ioaddr+PCNET32_DATA);
-
-	outw(0x0004, ioaddr+PCNET32_ADDR);
-	outw(0x0915, ioaddr+PCNET32_DATA);
-
-	outw(0x0000, ioaddr+PCNET32_ADDR);
-	outw(0x0001, ioaddr+PCNET32_DATA);
-
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
-	i = 0;
-	while (i++ < 100)
-		if (inw(ioaddr+PCNET32_DATA) & 0x0100)
-			break;
-	/* 
-	 * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
-	 * reports that doing so triggers a bug in the '974.
-	 */
- 	outw(0x0042, ioaddr+PCNET32_DATA);
-
-	if (pcnet32_debug > 2)
-		printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
-			   dev->name, i, (u32) virt_to_bus(&lp->init_block), inw(ioaddr+PCNET32_DATA));
+    /* set/reset GPSI bit in test register */
+    val = lp->a.read_csr (ioaddr, 124) & ~0x10;
+    if ((lp->options & PORT_PORTSEL) == PORT_GPSI)
+	val |= 0x10;
+    lp->a.write_csr (ioaddr, 124, val);
+    
+    if (lp->mii & (lp->options & PORT_ASEL)) {
+	val = lp->a.read_bcr (ioaddr, 32) & ~0x38; /* disable Auto Negotiation, set 10Mpbs, HD */
+	if (lp->options & PORT_FD)
+	    val |= 0x10;
+	if (lp->options & PORT_100)
+	    val |= 0x08;
+	lp->a.write_bcr (ioaddr, 32, val);
+    }
+    
+    lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
+    lp->init_block.filter[0] = 0x00000000;
+    lp->init_block.filter[1] = 0x00000000;
+    if (pcnet32_init_ring(dev))
+	return -ENOMEM;
+    
+    /* Re-initialize the PCNET32, and start it when done. */
+    lp->a.write_csr (ioaddr, 1, virt_to_bus(&lp->init_block) &0xffff);
+    lp->a.write_csr (ioaddr, 2, virt_to_bus(&lp->init_block) >> 16);
+
+    lp->a.write_csr (ioaddr, 4, 0x0915);
+    lp->a.write_csr (ioaddr, 0, 0x0001);
+
+    dev->tbusy = 0;
+    dev->interrupt = 0;
+    dev->start = 1;
+    i = 0;
+    while (i++ < 100)
+	if (lp->a.read_csr (ioaddr, 0) & 0x0100)
+	    break;
+    /* 
+     * We used to clear the InitDone bit, 0x0100, here but Mark Stockton
+     * reports that doing so triggers a bug in the '974.
+     */
+    lp->a.write_csr (ioaddr, 0, 0x0042);
+
+    if (pcnet32_debug > 2)
+	printk("%s: PCNET32 open after %d ticks, init block %#x csr0 %4.4x.\n",
+	       dev->name, i, (u32) virt_to_bus(&lp->init_block),
+	       lp->a.read_csr (ioaddr, 0));
 
-        MOD_INC_USE_COUNT;
+    MOD_INC_USE_COUNT;
     
-	return 0;					/* Always succeed */
+    return 0;	/* Always succeed */
 }
 
 /*
@@ -539,15 +786,15 @@
 static void 
 pcnet32_purge_tx_ring(struct device *dev)
 {
-	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-	int i;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    int i;
 
-	for (i = 0; i < TX_RING_SIZE; i++) {
-		if (lp->tx_skbuff[i]) {
-			dev_kfree_skb(lp->tx_skbuff[i]);
-			lp->tx_skbuff[i] = NULL;
-		}
+    for (i = 0; i < TX_RING_SIZE; i++) {
+	if (lp->tx_skbuff[i]) {
+	    dev_kfree_skb(lp->tx_skbuff[i]);
+	    lp->tx_skbuff[i] = NULL;
 	}
+    }
 }
 
 
@@ -555,445 +802,437 @@
 static int
 pcnet32_init_ring(struct device *dev)
 {
-	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-	int i;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    int i;
 
-	lp->tx_full = 0;
-	lp->cur_rx = lp->cur_tx = 0;
-	lp->dirty_rx = lp->dirty_tx = 0;
-
-	for (i = 0; i < RX_RING_SIZE; i++) {
-	    if (lp->rx_skbuff[i] == NULL) {
-		if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
-		    /* there is not much, we can do at this point */
-		    printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
-		    return -1;
-		}
-		skb_reserve (lp->rx_skbuff[i], 2);
+    lp->tx_full = 0;
+    lp->cur_rx = lp->cur_tx = 0;
+    lp->dirty_rx = lp->dirty_tx = 0;
+
+    for (i = 0; i < RX_RING_SIZE; i++) {
+	if (lp->rx_skbuff[i] == NULL) {
+	    if (!(lp->rx_skbuff[i] = dev_alloc_skb (PKT_BUF_SZ))) {
+		/* there is not much, we can do at this point */
+		printk ("%s: pcnet32_init_ring dev_alloc_skb failed.\n",dev->name);
+		return -1;
 	    }
-	    lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail));
-	    lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
-	    lp->rx_ring[i].status = le16_to_cpu(0x8000);
-	}
-	/* The Tx buffer address is filled in as needed, but we do need to clear
-	   the upper ownership bit. */
-	for (i = 0; i < TX_RING_SIZE; i++) {
-	        lp->tx_ring[i].base = 0;
-	        lp->tx_ring[i].status = 0;
+	    skb_reserve (lp->rx_skbuff[i], 2);
 	}
+	lp->rx_ring[i].base = (u32)le32_to_cpu(virt_to_bus(lp->rx_skbuff[i]->tail));
+	lp->rx_ring[i].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+	lp->rx_ring[i].status = le16_to_cpu(0x8000);
+    }
+    /* The Tx buffer address is filled in as needed, but we do need to clear
+     the upper ownership bit. */
+    for (i = 0; i < TX_RING_SIZE; i++) {
+	lp->tx_ring[i].base = 0;
+	lp->tx_ring[i].status = 0;
+    }
 
-        lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
-	for (i = 0; i < 6; i++)
-		lp->init_block.phys_addr[i] = dev->dev_addr[i];
-	lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
-	lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
-	return 0;
+    lp->init_block.tlen_rlen = TX_RING_LEN_BITS | RX_RING_LEN_BITS;
+    for (i = 0; i < 6; i++)
+	lp->init_block.phys_addr[i] = dev->dev_addr[i];
+    lp->init_block.rx_ring = (u32)le32_to_cpu(virt_to_bus(lp->rx_ring));
+    lp->init_block.tx_ring = (u32)le32_to_cpu(virt_to_bus(lp->tx_ring));
+    return 0;
 }
 
 static void
 pcnet32_restart(struct device *dev, unsigned int csr0_bits)
 {
-        int i;
-	unsigned int ioaddr = dev->base_addr;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    int i;
     
-	pcnet32_purge_tx_ring(dev);
-	if (pcnet32_init_ring(dev))
-		return;
-    
-	outw(0x0000, ioaddr + PCNET32_ADDR);
-        /* ReInit Ring */
-        outw(0x0001, ioaddr + PCNET32_DATA);
-	i = 0;
-	while (i++ < 100)
-		if (inw(ioaddr+PCNET32_DATA) & 0x0100)
-			break;
+    pcnet32_purge_tx_ring(dev);
+    if (pcnet32_init_ring(dev))
+	return;
+    
+    /* ReInit Ring */
+    lp->a.write_csr (ioaddr, 0, 1);
+    i = 0;
+    while (i++ < 100)
+	if (lp->a.read_csr (ioaddr, 0) & 0x0100)
+	    break;
 
-	outw(csr0_bits, ioaddr + PCNET32_DATA);
+    lp->a.write_csr (ioaddr, 0, csr0_bits);
 }
 
 static int
 pcnet32_start_xmit(struct sk_buff *skb, struct device *dev)
 {
-	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-	unsigned int ioaddr = dev->base_addr;
-	int entry;
-	unsigned long flags;
-
-	/* Transmitter timeout, serious problems. */
-	if (dev->tbusy) {
-		int tickssofar = jiffies - dev->trans_start;
-		if (tickssofar < HZ/2)
-			return 1;
-		outw(0, ioaddr+PCNET32_ADDR);
-		printk("%s: transmit timed out, status %4.4x, resetting.\n",
-			   dev->name, inw(ioaddr+PCNET32_DATA));
-		outw(0x0004, ioaddr+PCNET32_DATA);
-		lp->stats.tx_errors++;
-		if (pcnet32_debug > 2) {
-			int i;
-			printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
-				   lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
-				   lp->cur_rx);
-			for (i = 0 ; i < RX_RING_SIZE; i++)
-				printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-					   lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
-					   lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
-			for (i = 0 ; i < TX_RING_SIZE; i++)
-				printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
-					   lp->tx_ring[i].base, -lp->tx_ring[i].length,
-					   lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
-			printk("\n");
-		}
-		pcnet32_restart(dev, 0x0042);
-
-		dev->tbusy = 0;
-		dev->trans_start = jiffies;
-		dev_kfree_skb(skb);
-		return 0;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    unsigned int ioaddr = dev->base_addr;
+    int entry;
+    unsigned long flags;
+
+    /* Transmitter timeout, serious problems. */
+    if (dev->tbusy) {
+	int tickssofar = jiffies - dev->trans_start;
+	if (tickssofar < HZ/2)
+	    return 1;
+	printk("%s: transmit timed out, status %4.4x, resetting.\n",
+	       dev->name, lp->a.read_csr (ioaddr, 0));
+	lp->a.write_csr (ioaddr, 0, 0x0004);
+	lp->stats.tx_errors++;
+	if (pcnet32_debug > 2) {
+	    int i;
+	    printk(" Ring data dump: dirty_tx %d cur_tx %d%s cur_rx %d.",
+		   lp->dirty_tx, lp->cur_tx, lp->tx_full ? " (full)" : "",
+		   lp->cur_rx);
+	    for (i = 0 ; i < RX_RING_SIZE; i++)
+		printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+		       lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,
+		       lp->rx_ring[i].msg_length, (unsigned)lp->rx_ring[i].status);
+	    for (i = 0 ; i < TX_RING_SIZE; i++)
+		printk("%s %08x %04x %08x %04x", i & 1 ? "" : "\n ",
+		       lp->tx_ring[i].base, -lp->tx_ring[i].length,
+		       lp->tx_ring[i].misc, (unsigned)lp->tx_ring[i].status);
+	    printk("\n");
 	}
+	pcnet32_restart(dev, 0x0042);
 
-	if (pcnet32_debug > 3) {
-		outw(0x0000, ioaddr+PCNET32_ADDR);
-		printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n", dev->name,
-			   inw(ioaddr+PCNET32_DATA));
-	}
+	dev->tbusy = 0;
+	dev->trans_start = jiffies;
+	dev_kfree_skb(skb);
+	return 0;
+    }
 
-	/* Block a timer-based transmit from overlapping.  This could better be
-	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
-	if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
-		printk("%s: Transmitter access conflict.\n", dev->name);
-		return 1;
-	}
+    if (pcnet32_debug > 3) {
+	printk("%s: pcnet32_start_xmit() called, csr0 %4.4x.\n",
+	       dev->name, lp->a.read_csr (ioaddr, 0));
+    }
 
-	save_flags (flags);
-	cli ();
+    /* Block a timer-based transmit from overlapping.  This could better be
+       done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+    if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
+	printk("%s: Transmitter access conflict.\n", dev->name);
+	return 1;
+    }
 
-	/* Fill in a Tx ring entry */
+    save_flags (flags);
+    cli ();
 
-	/* Mask to ring buffer boundary. */
-	entry = lp->cur_tx & TX_RING_MOD_MASK;
+    /* Fill in a Tx ring entry */
 
-	/* Caution: the write order is important here, set the base address
-	   with the "ownership" bits last. */
+    /* Mask to ring buffer boundary. */
+    entry = lp->cur_tx & TX_RING_MOD_MASK;
 
-	lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
+    /* Caution: the write order is important here, set the base address
+       with the "ownership" bits last. */
 
-	lp->tx_ring[entry].misc = 0x00000000;
+    lp->tx_ring[entry].length = le16_to_cpu(-skb->len);
 
-	lp->tx_skbuff[entry] = skb;
-	lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
-        lp->tx_ring[entry].status = le16_to_cpu(0x8300);
+    lp->tx_ring[entry].misc = 0x00000000;
 
-	lp->cur_tx++;
-        lp->stats.tx_bytes += skb->len;
+    lp->tx_skbuff[entry] = skb;
+    lp->tx_ring[entry].base = (u32)le32_to_cpu(virt_to_bus(skb->data));
+    lp->tx_ring[entry].status = le16_to_cpu(0x8300);
 
-	/* Trigger an immediate send poll. */
-	outw(0x0000, ioaddr+PCNET32_ADDR);
-	outw(0x0048, ioaddr+PCNET32_DATA);
+    lp->cur_tx++;
+    lp->stats.tx_bytes += skb->len;
 
-	dev->trans_start = jiffies;
+    /* Trigger an immediate send poll. */
+    lp->a.write_csr (ioaddr, 0, 0x0048);
 
-	if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
-		clear_bit (0, (void *)&dev->tbusy);
-	else
-		lp->tx_full = 1;
-	restore_flags(flags);
-	return 0;
+    dev->trans_start = jiffies;
+
+    if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)
+	clear_bit (0, (void *)&dev->tbusy);
+    else
+	lp->tx_full = 1;
+    restore_flags(flags);
+    return 0;
 }
 
 /* The PCNET32 interrupt handler. */
 static void
 pcnet32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
-	struct device *dev = (struct device *)dev_id;
-	struct pcnet32_private *lp;
-	unsigned int csr0, ioaddr;
-	int boguscnt =  max_interrupt_work;
-	int must_restart;
-
-	if (dev == NULL) {
-		printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
-		return;
-	}
+    struct device *dev = (struct device *)dev_id;
+    struct pcnet32_private *lp;
+    unsigned long ioaddr;
+    u16 csr0;
+    int boguscnt =  max_interrupt_work;
+    int must_restart;
 
-	ioaddr = dev->base_addr;
-	lp = (struct pcnet32_private *)dev->priv;
-	if (dev->interrupt)
-		printk("%s: Re-entering the interrupt handler.\n", dev->name);
+    if (dev == NULL) {
+	printk ("pcnet32_interrupt(): irq %d for unknown device.\n", irq);
+	return;
+    }
 
-	dev->interrupt = 1;
+    ioaddr = dev->base_addr;
+    lp = (struct pcnet32_private *)dev->priv;
+    if (dev->interrupt)
+	printk("%s: Re-entering the interrupt handler.\n", dev->name);
 
-	outw(0x00, dev->base_addr + PCNET32_ADDR);
-	while ((csr0 = inw(dev->base_addr + PCNET32_DATA)) & 0x8600 && --boguscnt >= 0) {
-		/* Acknowledge all of the current interrupt sources ASAP. */
-		outw(csr0 & ~0x004f, dev->base_addr + PCNET32_DATA);
+    dev->interrupt = 1;
 
-		must_restart = 0;
+    while ((csr0 = lp->a.read_csr (ioaddr, 0)) & 0x8600 && --boguscnt >= 0) {
+	/* Acknowledge all of the current interrupt sources ASAP. */
+	lp->a.write_csr (ioaddr, 0, csr0 & ~0x004f);
 
-		if (pcnet32_debug > 5)
-			printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
-				   dev->name, csr0, inw(dev->base_addr + PCNET32_DATA));
+	must_restart = 0;
 
-		if (csr0 & 0x0400)			/* Rx interrupt */
-			pcnet32_rx(dev);
+	if (pcnet32_debug > 5)
+	    printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",
+		   dev->name, csr0, lp->a.read_csr (ioaddr, 0));
 
-		if (csr0 & 0x0200) {		/* Tx-done interrupt */
-			int dirty_tx = lp->dirty_tx;
+	if (csr0 & 0x0400)		/* Rx interrupt */
+	    pcnet32_rx(dev);
 
-			while (dirty_tx < lp->cur_tx) {
-				int entry = dirty_tx & TX_RING_MOD_MASK;
-				int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
+	if (csr0 & 0x0200) {		/* Tx-done interrupt */
+	    int dirty_tx = lp->dirty_tx;
+
+	    while (dirty_tx < lp->cur_tx) {
+		int entry = dirty_tx & TX_RING_MOD_MASK;
+		int status = (short)le16_to_cpu(lp->tx_ring[entry].status);
 			
-				if (status < 0)
-					break;			/* It still hasn't been Txed */
+		if (status < 0)
+		    break;		/* It still hasn't been Txed */
 
-				lp->tx_ring[entry].base = 0;
+		lp->tx_ring[entry].base = 0;
 
-				if (status & 0x4000) {
-					/* There was an major error, log it. */
-					int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
-					lp->stats.tx_errors++;
-					if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
-					if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
-					if (err_status & 0x10000000) lp->stats.tx_window_errors++;
-					if (err_status & 0x40000000) {
-						/* Ackk!  On FIFO errors the Tx unit is turned off! */
-						lp->stats.tx_fifo_errors++;
-						/* Remove this verbosity later! */
-						printk("%s: Tx FIFO error! Status %4.4x.\n",
-							   dev->name, csr0);
-						must_restart = 1;
+		if (status & 0x4000) {
+		    /* There was an major error, log it. */
+		    int err_status = le32_to_cpu(lp->tx_ring[entry].misc);
+		    lp->stats.tx_errors++;
+		    if (err_status & 0x04000000) lp->stats.tx_aborted_errors++;
+		    if (err_status & 0x08000000) lp->stats.tx_carrier_errors++;
+		    if (err_status & 0x10000000) lp->stats.tx_window_errors++;
+		    if (err_status & 0x40000000) {
+			/* Ackk!  On FIFO errors the Tx unit is turned off! */
+			lp->stats.tx_fifo_errors++;
+			/* Remove this verbosity later! */
+			printk("%s: Tx FIFO error! Status %4.4x.\n",
+			       dev->name, csr0);
+			must_restart = 1;
 					}
-				} else {
-					if (status & 0x1800)
-						lp->stats.collisions++;
-					lp->stats.tx_packets++;
-				}
-
-				/* We must free the original skb */
-				if (lp->tx_skbuff[entry]) {
-					dev_kfree_skb(lp->tx_skbuff[entry]);
-					lp->tx_skbuff[entry] = 0;
-				}
-				dirty_tx++;
-			}
+		} else {
+		    if (status & 0x1800)
+			lp->stats.collisions++;
+		    lp->stats.tx_packets++;
+		}
+
+		/* We must free the original skb */
+		if (lp->tx_skbuff[entry]) {
+		    dev_kfree_skb(lp->tx_skbuff[entry]);
+		    lp->tx_skbuff[entry] = 0;
+		}
+		dirty_tx++;
+	    }
 
 #ifndef final_version
-			if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
-				printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
-					   dirty_tx, lp->cur_tx, lp->tx_full);
-				dirty_tx += TX_RING_SIZE;
-			}
+	    if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {
+		printk("out-of-sync dirty pointer, %d vs. %d, full=%d.\n",
+		       dirty_tx, lp->cur_tx, lp->tx_full);
+		dirty_tx += TX_RING_SIZE;
+	    }
 #endif
+	    if (lp->tx_full && dev->tbusy
+		&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
+		/* The ring is no longer full, clear tbusy. */
+		lp->tx_full = 0;
+		clear_bit(0, (void *)&dev->tbusy);
+		mark_bh(NET_BH);
+	    }
+	    lp->dirty_tx = dirty_tx;
+	}
 
-			if (lp->tx_full && dev->tbusy
-				&& dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {
-				/* The ring is no longer full, clear tbusy. */
-				lp->tx_full = 0;
-				clear_bit(0, (void *)&dev->tbusy);
-				mark_bh(NET_BH);
-			}
-			lp->dirty_tx = dirty_tx;
-		}
-
-		/* Log misc errors. */
-		if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
-		if (csr0 & 0x1000) {
-		    /*
-		     * this happens when our receive ring is full. This shouldn't
-		     * be a problem as we will see normal rx interrupts for the frames
-		     * in the receive ring. But there are some PCI chipsets (I can reproduce
-		     * this on SP3G with Intel saturn chipset) which have sometimes problems
-		     * and will fill up the receive ring with error descriptors. In this
-		     * situation we don't get a rx interrupt, but a missed frame interrupt sooner
-		     * or later. So we try to clean up our receive ring here.
-		     */
-		    pcnet32_rx(dev);
-		    lp->stats.rx_errors++; /* Missed a Rx frame. */
-		}
-		if (csr0 & 0x0800) {
-			printk("%s: Bus master arbitration failure, status %4.4x.\n",
-				   dev->name, csr0);
-		        /* unlike for the lance, there is no restart needed */
-		}
+	/* Log misc errors. */
+	if (csr0 & 0x4000) lp->stats.tx_errors++; /* Tx babble. */
+	if (csr0 & 0x1000) {
+	    /*
+	     * this happens when our receive ring is full. This shouldn't
+	     * be a problem as we will see normal rx interrupts for the frames
+	     * in the receive ring. But there are some PCI chipsets (I can reproduce
+	     * this on SP3G with Intel saturn chipset) which have sometimes problems
+	     * and will fill up the receive ring with error descriptors. In this
+	     * situation we don't get a rx interrupt, but a missed frame interrupt sooner
+	     * or later. So we try to clean up our receive ring here.
+	     */
+	    pcnet32_rx(dev);
+	    lp->stats.rx_errors++; /* Missed a Rx frame. */
+	}
+	if (csr0 & 0x0800) {
+	    printk("%s: Bus master arbitration failure, status %4.4x.\n",
+		   dev->name, csr0);
+	    /* unlike for the lance, there is no restart needed */
+	}
 
-		if (must_restart) {
-			/* stop the chip to clear the error condition, then restart */
-		        outw(0x0000, dev->base_addr + PCNET32_ADDR);
-		        outw(0x0004, dev->base_addr + PCNET32_DATA);
-		        pcnet32_restart(dev, 0x0002);
-		}
+	if (must_restart) {
+	    /* stop the chip to clear the error condition, then restart */
+	    lp->a.write_csr (ioaddr, 0, 0x0004);
+	    pcnet32_restart(dev, 0x0002);
 	}
+    }
 
     /* Clear any other interrupt, and set interrupt enable. */
-    outw(0x0000, dev->base_addr + PCNET32_ADDR);
-    outw(0x7940, dev->base_addr + PCNET32_DATA);
+    lp->a.write_csr (ioaddr, 0, 0x7940);
 
-	if (pcnet32_debug > 4)
-		printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
-			   dev->name, inw(ioaddr + PCNET32_ADDR),
-			   inw(dev->base_addr + PCNET32_DATA));
+    if (pcnet32_debug > 4)
+	printk("%s: exiting interrupt, csr0=%#4.4x.\n",
+	       dev->name, lp->a.read_csr (ioaddr, 0));
 
-	dev->interrupt = 0;
-	return;
+    dev->interrupt = 0;
+    return;
 }
 
 static int
 pcnet32_rx(struct device *dev)
 {
-	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-	int entry = lp->cur_rx & RX_RING_MOD_MASK;
-	int i;
-
-	/* If we own the next entry, it's a new packet. Send it up. */
-	while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
-		int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
-
-		if (status != 0x03) {			/* There was an error. */
-			/* There is a tricky error noted by John Murphy,
-			   <murf@perftech.com> to Russ Nelson: Even with full-sized
-			   buffers it's possible for a jabber packet to use two
-			   buffers, with only the last correctly noting the error. */
-			if (status & 0x01)	/* Only count a general error at the */
-				lp->stats.rx_errors++; /* end of a packet.*/
-			if (status & 0x20) lp->stats.rx_frame_errors++;
-			if (status & 0x10) lp->stats.rx_over_errors++;
-			if (status & 0x08) lp->stats.rx_crc_errors++;
-			if (status & 0x04) lp->stats.rx_fifo_errors++;
-			lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
-		}
-		else 
-		{
-			/* Malloc up new buffer, compatible with net-2e. */
-			short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
-			struct sk_buff *skb;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    int entry = lp->cur_rx & RX_RING_MOD_MASK;
+    int i;
+
+    /* If we own the next entry, it's a new packet. Send it up. */
+    while ((short)le16_to_cpu(lp->rx_ring[entry].status) >= 0) {
+	int status = (short)le16_to_cpu(lp->rx_ring[entry].status) >> 8;
+
+	if (status != 0x03) {			/* There was an error. */
+	    /* 
+	     * There is a tricky error noted by John Murphy,
+	     * <murf@perftech.com> to Russ Nelson: Even with full-sized
+	     * buffers it's possible for a jabber packet to use two
+	     * buffers, with only the last correctly noting the error.
+	     */
+	    if (status & 0x01)	/* Only count a general error at the */
+		lp->stats.rx_errors++; /* end of a packet.*/
+	    if (status & 0x20) lp->stats.rx_frame_errors++;
+	    if (status & 0x10) lp->stats.rx_over_errors++;
+	    if (status & 0x08) lp->stats.rx_crc_errors++;
+	    if (status & 0x04) lp->stats.rx_fifo_errors++;
+	    lp->rx_ring[entry].status &= le16_to_cpu(0x03ff);
+	} else {
+	    /* Malloc up new buffer, compatible with net-2e. */
+	    short pkt_len = (le32_to_cpu(lp->rx_ring[entry].msg_length) & 0xfff)-4;
+	    struct sk_buff *skb;
 			
-			if(pkt_len < 60) {
-				printk("%s: Runt packet!\n",dev->name);
-				lp->stats.rx_errors++;
-			} else {
-			    int rx_in_place = 0;
+	    if(pkt_len < 60) {
+		printk("%s: Runt packet!\n",dev->name);
+		lp->stats.rx_errors++;
+	    } else {
+		int rx_in_place = 0;
 			    
-			    if (pkt_len > rx_copybreak) {
-				struct sk_buff *newskb;
+		if (pkt_len > rx_copybreak) {
+		    struct sk_buff *newskb;
 				
-				if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
-				    skb_reserve (newskb, 2);
-				    skb = lp->rx_skbuff[entry];
-				    skb_put (skb, pkt_len);
-				    lp->rx_skbuff[entry] = newskb;
-				    newskb->dev = dev;
-				    lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail));
-				    rx_in_place = 1;
-				} else
-				    skb = NULL;
-			    } else
-				skb = dev_alloc_skb(pkt_len+2);
+		    if ((newskb = dev_alloc_skb (PKT_BUF_SZ))) {
+			skb_reserve (newskb, 2);
+			skb = lp->rx_skbuff[entry];
+			skb_put (skb, pkt_len);
+			lp->rx_skbuff[entry] = newskb;
+			newskb->dev = dev;
+			lp->rx_ring[entry].base = le32_to_cpu(virt_to_bus(newskb->tail));
+			rx_in_place = 1;
+		    } else
+			skb = NULL;
+		} else
+		    skb = dev_alloc_skb(pkt_len+2);
 			    
-			    if (skb == NULL) {
-				printk("%s: Memory squeeze, deferring packet.\n", dev->name);
-				for (i=0; i < RX_RING_SIZE; i++)
-				    if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
-					break;
-
-				if (i > RX_RING_SIZE -2) {
-				    lp->stats.rx_dropped++;
-				    lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
-				    lp->cur_rx++;
-				}
-				break;
-			    }
-			    skb->dev = dev;
-			    if (!rx_in_place) {
-				skb_reserve(skb,2);	/* 16 byte align */
-				skb_put(skb,pkt_len);	/* Make room */
-				eth_copy_and_sum(skb,
-					(unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
-					pkt_len,0);
-			    }
-			    lp->stats.rx_bytes += skb->len;
-			    skb->protocol=eth_type_trans(skb,dev);
-			    netif_rx(skb);
-			    lp->stats.rx_packets++;
-			}
+		if (skb == NULL) {
+		    printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+		    for (i=0; i < RX_RING_SIZE; i++)
+			if ((short)le16_to_cpu(lp->rx_ring[(entry+i) & RX_RING_MOD_MASK].status) < 0)
+			    break;
+
+		    if (i > RX_RING_SIZE -2) {
+			lp->stats.rx_dropped++;
+			lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+			lp->cur_rx++;
+		    }
+		    break;
 		}
-		/* The docs say that the buffer length isn't touched, but Andrew Boyd
-		   of QNX reports that some revs of the 79C965 clear it. */
-		lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);
-		lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
-		entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+		skb->dev = dev;
+		if (!rx_in_place) {
+		    skb_reserve(skb,2);	/* 16 byte align */
+		    skb_put(skb,pkt_len);	/* Make room */
+		    eth_copy_and_sum(skb,
+				     (unsigned char *)bus_to_virt(le32_to_cpu(lp->rx_ring[entry].base)),
+				     pkt_len,0);
+		}
+		lp->stats.rx_bytes += skb->len;
+		skb->protocol=eth_type_trans(skb,dev);
+		netif_rx(skb);
+		lp->stats.rx_packets++;
+	    }
 	}
+	/*
+	 * The docs say that the buffer length isn't touched, but Andrew Boyd
+	 * of QNX reports that some revs of the 79C965 clear it.
+	 */
+	lp->rx_ring[entry].buf_length = le16_to_cpu(-PKT_BUF_SZ);
+	lp->rx_ring[entry].status |= le16_to_cpu(0x8000);
+	entry = (++lp->cur_rx) & RX_RING_MOD_MASK;
+    }
 
-	/* We should check that at least two ring entries are free.	 If not,
-	   we should free one and mark stats->rx_dropped++. */
-
-	return 0;
+    return 0;
 }
 
 static int
 pcnet32_close(struct device *dev)
 {
-	unsigned int ioaddr = dev->base_addr;
-	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-        int i;
-
-	dev->start = 0;
-	set_bit (0, (void *)&dev->tbusy);
-
-	outw(112, ioaddr+PCNET32_ADDR);
-	lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
-
-	outw(0, ioaddr+PCNET32_ADDR);
-
-	if (pcnet32_debug > 1)
-		printk("%s: Shutting down ethercard, status was %2.2x.\n",
-			   dev->name, inw(ioaddr+PCNET32_DATA));
-
-	/* We stop the PCNET32 here -- it occasionally polls
-	   memory if we don't. */
-	outw(0x0004, ioaddr+PCNET32_DATA);
-
-	free_irq(dev->irq, dev);
-    
-        /* free all allocated skbuffs */
-        for (i = 0; i < RX_RING_SIZE; i++) {
-	    lp->rx_ring[i].status = 0;	    	    	    
-	    if (lp->rx_skbuff[i])
-		dev_kfree_skb(lp->rx_skbuff[i]);
-	    lp->rx_skbuff[i] = NULL;
-	}
+    unsigned long ioaddr = dev->base_addr;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    int i;
+
+    dev->start = 0;
+    set_bit (0, (void *)&dev->tbusy);
+
+    lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
+
+    if (pcnet32_debug > 1)
+	printk("%s: Shutting down ethercard, status was %2.2x.\n",
+	       dev->name, lp->a.read_csr (ioaddr, 0));
+
+    /* We stop the PCNET32 here -- it occasionally polls memory if we don't. */
+    lp->a.write_csr (ioaddr, 0, 0x0004);
+
+    /*
+     * Switch back to 16bit mode to avoid problems with dumb 
+     * DOS packet driver after a warm reboot
+     */
+    lp->a.write_bcr (ioaddr, 20, 4);
+
+    free_irq(dev->irq, dev);
+    
+    /* free all allocated skbuffs */
+    for (i = 0; i < RX_RING_SIZE; i++) {
+	lp->rx_ring[i].status = 0;	    	    	    
+	if (lp->rx_skbuff[i])
+	    dev_kfree_skb(lp->rx_skbuff[i]);
+	lp->rx_skbuff[i] = NULL;
+    }
     
-        for (i = 0; i < TX_RING_SIZE; i++) {
-	    if (lp->tx_skbuff[i])
-		dev_kfree_skb(lp->tx_skbuff[i]);
-	    lp->rx_skbuff[i] = NULL;
-	}
+    for (i = 0; i < TX_RING_SIZE; i++) {
+	if (lp->tx_skbuff[i])
+	    dev_kfree_skb(lp->tx_skbuff[i]);
+	lp->rx_skbuff[i] = NULL;
+    }
     
-        MOD_DEC_USE_COUNT;
+    MOD_DEC_USE_COUNT;
 
-	return 0;
+    return 0;
 }
 
 static struct net_device_stats *
 pcnet32_get_stats(struct device *dev)
 {
-	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
-	unsigned int ioaddr = dev->base_addr;
-	unsigned short saved_addr;
-	unsigned long flags;
-
-	save_flags(flags);
-	cli();
-	saved_addr = inw(ioaddr+PCNET32_ADDR);
-	outw(112, ioaddr+PCNET32_ADDR);
-	lp->stats.rx_missed_errors = inw(ioaddr+PCNET32_DATA);
-	outw(saved_addr, ioaddr+PCNET32_ADDR);
-	restore_flags(flags);
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;
+    unsigned long ioaddr = dev->base_addr;
+    u16 saved_addr;
+    unsigned long flags;
+
+    save_flags(flags);
+    cli();
+    saved_addr = lp->a.read_rap(ioaddr);
+    lp->stats.rx_missed_errors = lp->a.read_csr (ioaddr, 112);
+    lp->a.write_rap(ioaddr, saved_addr);
+    restore_flags(flags);
 
-	return &lp->stats;
+    return &lp->stats;
 }
 
-
 /* taken from the sunlance driver, which it took from the depca driver */
 static void pcnet32_load_multicast (struct device *dev)
 {
@@ -1044,34 +1283,68 @@
 }
 
 
-/* Set or clear the multicast filter for this adaptor.
+/*
+ * Set or clear the multicast filter for this adaptor.
  */
-
 static void pcnet32_set_multicast_list(struct device *dev)
 {
-	unsigned int ioaddr = dev->base_addr;
-	struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+    unsigned long ioaddr = dev->base_addr;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
 
-	if (dev->flags&IFF_PROMISC) {
-		/* Log any net taps. */
-		printk("%s: Promiscuous mode enabled.\n", dev->name);
-	        lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7);
-	} else {
-	    	lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
-	        pcnet32_load_multicast (dev);
-	}
+    if (dev->flags&IFF_PROMISC) {
+	/* Log any net taps. */
+	printk("%s: Promiscuous mode enabled.\n", dev->name);
+	lp->init_block.mode = le16_to_cpu(0x8000 | (lp->options & PORT_PORTSEL) << 7);
+    } else {
+	lp->init_block.mode = le16_to_cpu((lp->options & PORT_PORTSEL) << 7);
+	pcnet32_load_multicast (dev);
+    }
     
-	outw(0, ioaddr+PCNET32_ADDR);
-	outw(0x0004, ioaddr+PCNET32_DATA); /* Temporarily stop the lance.	 */
+    lp->a.write_csr (ioaddr, 0, 0x0004); /* Temporarily stop the lance. */
 
-	pcnet32_restart(dev, 0x0042); /*  Resume normal operation */
+    pcnet32_restart(dev, 0x0042); /*  Resume normal operation */
 }
 
+#ifdef HAVE_PRIVATE_IOCTL
+static int pcnet32_mii_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+    unsigned long ioaddr = dev->base_addr;
+    struct pcnet32_private *lp = (struct pcnet32_private *)dev->priv;    
+    u16 *data = (u16 *)&rq->ifr_data;
+    int phyaddr = lp->a.read_bcr (ioaddr, 33);
+
+    if (lp->mii) {
+	switch(cmd) {
+	 case SIOCDEVPRIVATE:            /* Get the address of the PHY in use. */
+	    data[0] = (phyaddr >> 5) & 0x1f;
+	    /* Fall Through */
+	 case SIOCDEVPRIVATE+1:          /* Read the specified MII register. */
+	    lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));
+	    data[3] = lp->a.read_bcr (ioaddr, 34);
+	    lp->a.write_bcr (ioaddr, 33, phyaddr);
+	    return 0;
+	 case SIOCDEVPRIVATE+2:          /* Write the specified MII register */
+	    if (!suser())
+		return -EPERM;
+	    lp->a.write_bcr (ioaddr, 33, ((data[0] & 0x1f) << 5) | (data[1] & 0x1f));
+	    lp->a.write_bcr (ioaddr, 34, data[2]);
+	    lp->a.write_bcr (ioaddr, 33, phyaddr);
+	    return 0;
+	 default:
+	    return -EOPNOTSUPP;
+	}
+    }
+    return -EOPNOTSUPP;
+}
+#endif  /* HAVE_PRIVATE_IOCTL */
+					    
 #ifdef MODULE
 MODULE_PARM(debug, "i");
-MODULE_PARM(options, "i");
 MODULE_PARM(max_interrupt_work, "i");
 MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
+					     
 
 /* An additional parameter that may be passed in... */
 static int debug = -1;
@@ -1079,27 +1352,27 @@
 int
 init_module(void)
 {
-        if (debug > 0)
-	        pcnet32_debug = debug;
+    if (debug > 0)
+	pcnet32_debug = debug;
     
-	pcnet32_dev = NULL;
-	return pcnet32_probe(NULL);
+    pcnet32_dev = NULL;
+    return pcnet32_probe(NULL);
 }
 
 void
 cleanup_module(void)
 {
-	struct device *next_dev;
+    struct device *next_dev;
 
-	/* No need to check MOD_IN_USE, as sys_delete_module() checks. */
-	while (pcnet32_dev) {
-		next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next;
-		unregister_netdev(pcnet32_dev);
-		release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
-	        kfree(pcnet32_dev->priv);
-		kfree(pcnet32_dev);
-		pcnet32_dev = next_dev;
-	}
+    /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
+    while (pcnet32_dev) {
+	next_dev = ((struct pcnet32_private *) pcnet32_dev->priv)->next;
+	unregister_netdev(pcnet32_dev);
+	release_region(pcnet32_dev->base_addr, PCNET32_TOTAL_SIZE);
+	kfree(((struct pcnet32_private *)pcnet32_dev->priv)->origmem);
+	kfree(pcnet32_dev);
+	pcnet32_dev = next_dev;
+    }
 }
 #endif /* MODULE */
 
diff -urN linux-2.2.7-pre3/drivers/net/rrunner.c linux-2.2.7-pre4/drivers/net/rrunner.c
--- linux-2.2.7-pre3/drivers/net/rrunner.c	1998-12-17 09:04:49.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/rrunner.c	2003-08-15 15:05:52.000000000 -0700
@@ -59,15 +59,7 @@
  * stack will need to know about I/O vectors or something similar.
  */
 
-static const char *version = "rrunner.c: v0.09 12/14/98  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
-
-static unsigned int read_eeprom(struct rr_private *rrpriv,
-				unsigned long offset,
-				unsigned char *buf,
-				unsigned long length);
-static u32 read_eeprom_word(struct rr_private *rrpriv,
-			    void * offset);
-static int rr_load_firmware(struct device *dev);
+static const char __initdata *version = "rrunner.c: v0.17 03/09/99  Jes Sorensen (Jes.Sorensen@cern.ch)\n";
 
 
 /*
@@ -78,44 +70,32 @@
 extern __u32 sysctl_wmem_max;
 extern __u32 sysctl_rmem_max;
 
+static int probed __initdata = 0;
+
 __initfunc(int rr_hippi_probe (struct device *dev))
 {
-	static int i = 0;
 	int boards_found = 0;
 	int version_disp;	/* was version info already displayed? */
-	u8 pci_bus;		/* PCI bus number (0-255) */
-	u8 pci_dev_fun;		/* PCI device and function numbers (0-255) */
+	struct pci_dev *pdev = NULL;
+	struct pci_dev *opdev = NULL;
 	u8 pci_latency;
-	u16 command;		/* PCI Configuration space Command register */
-	unsigned int tmp;
-	u8 irq;
 	struct rr_private *rrpriv;
 
+	if (probed)
+		return -ENODEV;
+	probed++;
+
 	if (!pci_present())		/* is PCI BIOS even present? */
 		return -ENODEV;
 
 	version_disp = 0;
 
-	for (; i < 255; i++)
+	while((pdev = pci_find_device(PCI_VENDOR_ID_ESSENTIAL,
+				      PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
+				      pdev)))
 	{
-		if (pcibios_find_device(PCI_VENDOR_ID_ESSENTIAL,
-					PCI_DEVICE_ID_ESSENTIAL_ROADRUNNER,
-					i, &pci_bus, &pci_dev_fun) != 0)
-			break;
-
-		pcibios_read_config_word(pci_bus, pci_dev_fun,
-					 PCI_COMMAND, &command);
-
-		/* Enable mastering */
-
-		command |= PCI_COMMAND_MASTER;
-		pcibios_write_config_word(pci_bus, pci_dev_fun,
-					  PCI_COMMAND, command);
-
-		if (!(command & PCI_COMMAND_MEMORY)){
-			printk("shared mem not enabled - unable to configure RoadRunner\n");
-			break;
-		}
+		if (pdev == opdev)
+			return 0;
 
 		/*
 		 * So we found our HIPPI ... time to tell the system.
@@ -123,31 +103,24 @@
 
 		dev = init_hippi_dev(dev, sizeof(struct rr_private));
 
-		if (dev == NULL)
+		if (!dev)
 			break;
 
 		if (!dev->priv)
 			dev->priv = kmalloc(sizeof(*rrpriv), GFP_KERNEL);
 
-		rrpriv = (struct rr_private *)dev->priv;
-
-		/* Read register base address from
-		   PCI Configuration Space */
-
-		pcibios_read_config_dword(pci_bus, pci_dev_fun,
-					  PCI_BASE_ADDRESS_0, &tmp);
+		if (!dev->priv)
+			return -ENOMEM;
 
-		pcibios_read_config_byte(pci_bus, pci_dev_fun,
-					 PCI_INTERRUPT_LINE, &irq);
+		rrpriv = (struct rr_private *)dev->priv;
+		memset(rrpriv, 0, sizeof(*rrpriv));
 
-		dev->irq = irq;
-		rrpriv->pci_bus = pci_bus;
-		rrpriv->pci_dev_fun = pci_dev_fun;
-		sprintf(rrpriv->name, "RoadRunner serial HIPPI");
 #ifdef __SMP__
 		spin_lock_init(&rrpriv->lock);
 #endif
+		sprintf(rrpriv->name, "RoadRunner serial HIPPI");
 
+		dev->irq = pdev->irq;
 		dev->open = &rr_open;
 		dev->hard_start_xmit = &rr_start_xmit;
 		dev->stop = &rr_close;
@@ -168,29 +141,30 @@
 			printk(version);
 		}
 
-		printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI at 0x%08x, irq %i\n",
-		       dev->name, tmp, dev->irq);
-
-		pcibios_read_config_byte(pci_bus, pci_dev_fun,
-					 PCI_LATENCY_TIMER, &pci_latency);
-#if 0
-		if (pci_latency <= 48){
-			printk("  PCI latency counter too low (%i), setting to 48 clocks\n", pci_latency);
-			pcibios_write_config_byte(pci_bus, pci_dev_fun,
-						  PCI_LATENCY_TIMER, 48);
+		pci_read_config_byte(pdev, PCI_LATENCY_TIMER, &pci_latency);
+		if (pci_latency <= 0x58){
+			pci_latency = 0x58;
+			pci_write_config_byte(pdev, PCI_LATENCY_TIMER,
+					      pci_latency);
 		}
-#else
-		if (pci_latency <= 0x58)
-			pcibios_write_config_byte(pci_bus, pci_dev_fun,
-						  PCI_LATENCY_TIMER, 0x58);
-#endif
+
+		pci_set_master(pdev);
+
+		printk(KERN_INFO "%s: Essential RoadRunner serial HIPPI "
+		       "at 0x%08lx, irq %i, PCI latency %i\n", dev->name,
+		       pdev->base_address[0], dev->irq, pci_latency);
+
 		/*
 		 * Remap the regs into kernel space.
 		 */
 
-		rrpriv->regs = (struct rr_regs *)ioremap(tmp, 0x1000);
+		rrpriv->regs = (struct rr_regs *)
+			ioremap(pdev->base_address[0], 0x1000);
+
 		if (!rrpriv->regs){
-			printk(KERN_ERR "%s:  Unable to map I/O register, RoadRunner %i will be disabled.\n", dev->name, i);
+			printk(KERN_ERR "%s:  Unable to map I/O register, "
+			       "RoadRunner %i will be disabled.\n",
+			       dev->name, boards_found);
 			break;
 		}
 
@@ -198,7 +172,7 @@
 		 * Don't access any registes before this point!
 		 */
 #ifdef __BIG_ENDIAN
-		regs->HostCtrl |= NO_SWAP;
+		writel(readl(&regs->HostCtrl) | NO_SWAP, &regs->HostCtrl);
 #endif
 		/*
 		 * Need to add a case for little-endian 64-bit hosts here.
@@ -209,6 +183,7 @@
 		boards_found++;
 		dev->base_addr = 0;
 		dev = NULL;
+		opdev = pdev;
 	}
 
 	/*
@@ -217,12 +192,59 @@
 	 * 1 or more boards. Otherwise, return failure (-ENODEV).
 	 */
 
+#ifdef MODULE
+	return boards_found;
+#else
 	if (boards_found > 0)
 		return 0;
 	else
 		return -ENODEV;
+#endif
+}
+
+static struct device *root_dev = NULL;
+
+#ifdef MODULE
+#if LINUX_VERSION_CODE > 0x20118
+MODULE_AUTHOR("Jes Sorensen <Jes.Sorensen@cern.ch>");
+MODULE_DESCRIPTION("Essential RoadRunner HIPPI driver");
+#endif
+
+
+int init_module(void)
+{
+	int cards;
+
+	root_dev = NULL;
+
+	cards = rr_hippi_probe(NULL);
+	return cards ? 0 : -ENODEV;
 }
 
+void cleanup_module(void)
+{
+	struct rr_private *rr;
+	struct device *next;
+
+	while (root_dev) {
+		next = ((struct rr_private *)root_dev->priv)->next;
+		rr = (struct rr_private *)root_dev->priv;
+
+		if (!(readl(&rr->regs->HostCtrl) & NIC_HALTED)){
+			printk(KERN_ERR "%s: trying to unload running NIC\n",
+			       root_dev->name);
+			writel(HALT_NIC, &rr->regs->HostCtrl);
+		}
+
+		iounmap(rr->regs);
+		unregister_hipdev(root_dev);
+		kfree(root_dev);
+
+		root_dev = next;
+	}
+}
+#endif
+
 
 /*
  * Commands are considered to be slow, thus there is no reason to
@@ -238,21 +260,25 @@
 	 * This is temporary - it will go away in the final version.
 	 * We probably also want to make this function inline.
 	 */
-	if (regs->HostCtrl & NIC_HALTED){
-		printk("issuing command for halted NIC, code 0x%x, HostCtrl %08x\n", cmd->code, regs->HostCtrl);
-		if (regs->Mode & FATAL_ERR)
-			printk("error code %02x\n", regs->Fail1);
+	if (readl(&regs->HostCtrl) & NIC_HALTED){
+		printk("issuing command for halted NIC, code 0x%x, "
+		       "HostCtrl %08x\n", cmd->code, readl(&regs->HostCtrl));
+		if (readl(&regs->Mode) & FATAL_ERR)
+			printk("error codes Fail1 %02x, Fail2 %02x\n",
+			       readl(&regs->Fail1), readl(&regs->Fail2));
 	}
 
 	idx = rrpriv->info->cmd_ctrl.pi;
 
-	regs->CmdRing[idx] = *(u32*)(cmd);
+	writel(*(u32*)(cmd), &regs->CmdRing[idx]);
+	mb();
 
 	idx = (idx - 1) % CMD_RING_ENTRIES;
 	rrpriv->info->cmd_ctrl.pi = idx;
+	mb();
 
-	if (regs->Mode & FATAL_ERR)
-		printk("error code %02x\n", regs->Fail1);
+	if (readl(&regs->Mode) & FATAL_ERR)
+		printk("error code %02x\n", readl(&regs->Fail1));
 }
 
 
@@ -273,85 +299,97 @@
 
 	rr_load_firmware(dev);
 
-	regs->TX_state = 0x01000000;
-	regs->RX_state = 0xff800000;
-	regs->AssistState = 0;
-	regs->LocalCtrl = CLEAR_INTA;
-	regs->BrkPt = 0x01;
-	regs->Timer = 0;
-	regs->TimerRef = 0;
-	regs->DmaReadState = RESET_DMA;
-	regs->DmaWriteState = RESET_DMA;
-	regs->DmaWriteHostHi = 0;
-	regs->DmaWriteHostLo = 0;
-	regs->DmaReadHostHi = 0;
-	regs->DmaReadHostLo = 0;
-	regs->DmaReadLen = 0;
-	regs->DmaWriteLen = 0;
-	regs->DmaWriteLcl = 0;
-	regs->DmaWriteIPchecksum = 0;
-	regs->DmaReadLcl = 0;
-	regs->DmaReadIPchecksum = 0;
-	regs->PciState = 0; /* 0x90 for GE? */
-	regs->Mode = SWAP_DATA;
+	writel(0x01000000, &regs->TX_state);
+	writel(0xff800000, &regs->RX_state);
+	writel(0, &regs->AssistState);
+	writel(CLEAR_INTA, &regs->LocalCtrl);
+	writel(0x01, &regs->BrkPt);
+	writel(0, &regs->Timer);
+	writel(0, &regs->TimerRef);
+	writel(RESET_DMA, &regs->DmaReadState);
+	writel(RESET_DMA, &regs->DmaWriteState);
+	writel(0, &regs->DmaWriteHostHi);
+	writel(0, &regs->DmaWriteHostLo);
+	writel(0, &regs->DmaReadHostHi);
+	writel(0, &regs->DmaReadHostLo);
+	writel(0, &regs->DmaReadLen);
+	writel(0, &regs->DmaWriteLen);
+	writel(0, &regs->DmaWriteLcl);
+	writel(0, &regs->DmaWriteIPchecksum);
+	writel(0, &regs->DmaReadLcl);
+	writel(0, &regs->DmaReadIPchecksum);
+	writel(0, &regs->PciState);
+#if (BITS_PER_LONG == 64) && defined __LITTLE_ENDIAN
+	writel(SWAP_DATA | PTR64BIT | PTR_WD_SWAP, &regs->Mode);
+#elif (BITS_PER_LONG == 64)
+	writel(SWAP_DATA | PTR64BIT | PTR_WD_NOSWAP, &regs->Mode);
+#else
+	writel(SWAP_DATA | PTR32BIT | PTR_WD_NOSWAP, &regs->Mode);
+#endif
 
 #if 0
 	/*
 	 * Don't worry, this is just black magic.
 	 */
-	regs->RxBase = 0xdf000;
-	regs->RxPrd = 0xdf000;
-	regs->RxCon = 0xdf000;
-	regs->TxBase = 0xce000;
-	regs->TxPrd = 0xce000;
-	regs->TxCon = 0xce000;
-	regs->RxIndPro = 0;
-	regs->RxIndCon = 0;
-	regs->RxIndRef = 0;
-	regs->TxIndPro = 0;
-	regs->TxIndCon = 0;
-	regs->TxIndRef = 0;
-	regs->pad10[0] = 0xcc000;
-	regs->DrCmndPro = 0;
-	regs->DrCmndCon = 0;
-	regs->DwCmndPro = 0;
-	regs->DwCmndCon = 0;
-	regs->DwCmndRef = 0;
-	regs->DrDataPro = 0;
-	regs->DrDataCon = 0;
-	regs->DrDataRef = 0;
-	regs->DwDataPro = 0;
-	regs->DwDataCon = 0;
-	regs->DwDataRef = 0;
+	writel(0xdf000, &regs->RxBase);
+	writel(0xdf000, &regs->RxPrd);
+	writel(0xdf000, &regs->RxCon);
+	writel(0xce000, &regs->TxBase);
+	writel(0xce000, &regs->TxPrd);
+	writel(0xce000, &regs->TxCon);
+	writel(0, &regs->RxIndPro);
+	writel(0, &regs->RxIndCon);
+	writel(0, &regs->RxIndRef);
+	writel(0, &regs->TxIndPro);
+	writel(0, &regs->TxIndCon);
+	writel(0, &regs->TxIndRef);
+	writel(0xcc000, &regs->pad10[0]);
+	writel(0, &regs->DrCmndPro);
+	writel(0, &regs->DrCmndCon);
+	writel(0, &regs->DwCmndPro);
+	writel(0, &regs->DwCmndCon);
+	writel(0, &regs->DwCmndRef);
+	writel(0, &regs->DrDataPro);
+	writel(0, &regs->DrDataCon);
+	writel(0, &regs->DrDataRef);
+	writel(0, &regs->DwDataPro);
+	writel(0, &regs->DwDataCon);
+	writel(0, &regs->DwDataRef);
 #endif
 
-	regs->MbEvent = 0xffffffff;
-	regs->Event = 0;
+	writel(0xffffffff, &regs->MbEvent);
+	writel(0, &regs->Event);
 
-	regs->TxPi = 0;
-	regs->IpRxPi = 0;
+	writel(0, &regs->TxPi);
+	writel(0, &regs->IpRxPi);
 
-	regs->EvtCon = 0;
-	regs->EvtPrd = 0;
+	writel(0, &regs->EvtCon);
+	writel(0, &regs->EvtPrd);
 
 	rrpriv->info->evt_ctrl.pi = 0;
 
 	for (i = 0; i < CMD_RING_ENTRIES; i++)
-		regs->CmdRing[i] = 0;
+		writel(0, &regs->CmdRing[i]);
 
-	regs->PciState = 0;
+/*
+ * Why 32 ? is this not cache line size dependant?
+ */
+	writel(WBURST_32, &regs->PciState);
+	mb();
 
-	start_pc = read_eeprom_word(rrpriv, &hw->rncd_info.FwStart);
+	start_pc = rr_read_eeprom_word(rrpriv, &hw->rncd_info.FwStart);
 
 #if (DEBUG > 1)
 	printk("%s: Executing firmware at address 0x%06x\n",
 	       dev->name, start_pc);
 #endif
 
-	regs->Pc = start_pc + 0x800;
+	writel(start_pc + 0x800, &regs->Pc);
+	mb();
 	udelay(5);
 
-	regs->Pc = start_pc;
+	writel(start_pc, &regs->Pc);
+	mb();
 
 	return 0;
 }
@@ -360,7 +398,7 @@
 /*
  * Read a string from the EEPROM.
  */
-static unsigned int read_eeprom(struct rr_private *rrpriv,
+static unsigned int rr_read_eeprom(struct rr_private *rrpriv,
 				unsigned long offset,
 				unsigned char *buf,
 				unsigned long length)
@@ -368,22 +406,25 @@
 	struct rr_regs *regs = rrpriv->regs;
 	u32 misc, io, host, i;
 
-	io = regs->ExtIo;
-	regs->ExtIo = 0;
-	misc = regs->LocalCtrl;
-	regs->LocalCtrl = 0;
-	host = regs->HostCtrl;
-	regs->HostCtrl |= HALT_NIC;
+	io = readl(&regs->ExtIo);
+	writel(0, &regs->ExtIo);
+	misc = readl(&regs->LocalCtrl);
+	writel(0, &regs->LocalCtrl);
+	host = readl(&regs->HostCtrl);
+	writel(host | HALT_NIC, &regs->HostCtrl);
+	mb();
 
 	for (i = 0; i < length; i++){
-		regs->WinBase = (EEPROM_BASE + ((offset+i) << 3));
-		buf[i] = (regs->WinData >> 24) & 0xff;
+		writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);
+		mb();
+		buf[i] = (readl(&regs->WinData) >> 24) & 0xff;
+		mb();
 	}
 
-	regs->HostCtrl = host;
-	regs->LocalCtrl = misc;
-	regs->ExtIo = io;
-
+	writel(host, &regs->HostCtrl);
+	writel(misc, &regs->LocalCtrl);
+	writel(io, &regs->ExtIo);
+	mb();
 	return i;
 }
 
@@ -392,13 +433,13 @@
  * Shortcut to read one word (4 bytes) out of the EEPROM and convert
  * it to our CPU byte-order.
  */
-static u32 read_eeprom_word(struct rr_private *rrpriv,
+static u32 rr_read_eeprom_word(struct rr_private *rrpriv,
 			    void * offset)
 {
 	u32 word;
 
-	if ((read_eeprom(rrpriv, (unsigned long)offset,
-			 (char *)&word, 4) == 4))
+	if ((rr_read_eeprom(rrpriv, (unsigned long)offset,
+			    (char *)&word, 4) == 4))
 		return be32_to_cpu(word);
 	return 0;
 }
@@ -410,38 +451,42 @@
  * This is only called when the firmware is not running.
  */
 static unsigned int write_eeprom(struct rr_private *rrpriv,
-				unsigned long offset,
-				unsigned char *buf,
-				unsigned long length)
+				 unsigned long offset,
+				 unsigned char *buf,
+				 unsigned long length)
 {
 	struct rr_regs *regs = rrpriv->regs;
 	u32 misc, io, data, i, j, ready, error = 0;
 
-	io = regs->ExtIo;
-	regs->ExtIo = 0;
-	misc = regs->LocalCtrl;
-	regs->LocalCtrl = ENABLE_EEPROM_WRITE;
+	io = readl(&regs->ExtIo);
+	writel(0, &regs->ExtIo);
+	misc = readl(&regs->LocalCtrl);
+	writel(ENABLE_EEPROM_WRITE, &regs->LocalCtrl);
+	mb();
 
 	for (i = 0; i < length; i++){
-		regs->WinBase = (EEPROM_BASE + ((offset+i) << 3));
+		writel((EEPROM_BASE + ((offset+i) << 3)), &regs->WinBase);
+		mb();
 		data = buf[i] << 24;
 		/*
 		 * Only try to write the data if it is not the same
 		 * value already.
 		 */
-		if ((regs->WinData & 0xff000000) != data){
-			regs->WinData = data;
+		if ((readl(&regs->WinData) & 0xff000000) != data){
+			writel(data, &regs->WinData);
 			ready = 0;
 			j = 0;
 			mb();
 			while(!ready){
-				udelay(1000);
-				if ((regs->WinData & 0xff000000) == data)
+				udelay(20);
+				if ((readl(&regs->WinData) & 0xff000000) ==
+				    data)
 					ready = 1;
+				mb();
 				if (j++ > 5000){
 					printk("data mismatch: %08x, "
 					       "WinData %08x\n", data,
-					       regs->WinData);
+					       readl(&regs->WinData));
 					ready = 1;
 					error = 1;
 				}
@@ -449,8 +494,9 @@
 		}
 	}
 
-	regs->LocalCtrl = misc;
-	regs->ExtIo = io;
+	writel(misc, &regs->LocalCtrl);
+	writel(io, &regs->ExtIo);
+	mb();
 
 	return error;
 }
@@ -465,7 +511,8 @@
 	rrpriv = (struct rr_private *)dev->priv;
 	regs = rrpriv->regs;
 
-	rev = regs->FwRev;
+	rev = readl(&regs->FwRev);
+	rrpriv->fw_rev = rev;
 	if (rev > 0x00020024)
 		printk("  Firmware revision: %i.%i.%i\n", (rev >> 16),
 		       ((rev >> 8) & 0xff), (rev & 0xff));
@@ -477,13 +524,13 @@
 		printk("  Firmware revision too old: %i.%i.%i, please "
 		       "upgrade to 2.0.37 or later.\n",
 		       (rev >> 16), ((rev >> 8) & 0xff), (rev & 0xff));
-		return -EFAULT;
-		
 	}
 
-	printk("  Maximum receive rings %i\n", regs->MaxRxRng);
+#if (DEBUG > 2)
+	printk("  Maximum receive rings %i\n", readl(&regs->MaxRxRng));
+#endif
 
-	sram_size = read_eeprom_word(rrpriv, (void *)8);
+	sram_size = rr_read_eeprom_word(rrpriv, (void *)8);
 	printk("  SRAM size 0x%06x\n", sram_size);
 
 	if (sysctl_rmem_max < 262144){
@@ -498,6 +545,9 @@
 		sysctl_wmem_max = 262144;
 	}
 
+	rrpriv->next = root_dev;
+	root_dev = dev;
+
 	return 0;
 }
 
@@ -507,7 +557,7 @@
 	struct rr_private *rrpriv;
 	struct rr_regs *regs;
 	u32 hostctrl;
-	unsigned long myjif, flags, tmp_ptr;
+	unsigned long myjif, flags;
 	struct cmd cmd;
 	short i;
 
@@ -516,8 +566,9 @@
 
 	spin_lock_irqsave(&rrpriv->lock, flags);
 
-	hostctrl = regs->HostCtrl;
-	regs->HostCtrl |= HALT_NIC;
+	hostctrl = readl(&regs->HostCtrl);
+	writel(hostctrl | HALT_NIC | RR_CLEAR_INT, &regs->HostCtrl);
+	mb();
 
 	if (hostctrl & PARITY_ERR){
 		printk("%s: Parity error halting NIC - this is serious!\n",
@@ -526,31 +577,14 @@
 		return -EFAULT;
 	}
 
-
-	memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl));
-	memset(rrpriv->info, 0, sizeof(struct rr_info));
-
-	tmp_ptr = virt_to_bus((void *)rrpriv->rx_ctrl);
-#if (BITS_PER_LONG == 64)
-	regs->RxRingHi = (tmp_ptr >> 32);
-#else
-	regs->RxRingHi = 0;
-#endif
-	regs->RxRingLo = ((tmp_ptr) & 0xffffffff);
-
-	tmp_ptr = virt_to_bus((void *)rrpriv->info);
-#if (BITS_PER_LONG == 64)
-	regs->InfoPtrHi = (tmp_ptr >> 32);
-#else
-	regs->InfoPtrHi = 0;
-#endif
-	regs->InfoPtrLo = ((tmp_ptr) & 0xffffffff);
+	set_rxaddr(regs, rrpriv->rx_ctrl);
+	set_infoaddr(regs, rrpriv->info);
 
 	rrpriv->info->evt_ctrl.entry_size = sizeof(struct event);
 	rrpriv->info->evt_ctrl.entries = EVT_RING_ENTRIES;
 	rrpriv->info->evt_ctrl.mode = 0;
 	rrpriv->info->evt_ctrl.pi = 0;
-	rrpriv->info->evt_ctrl.rngptr = virt_to_bus(rrpriv->evt_ring);
+	set_rraddr(&rrpriv->info->evt_ctrl.rngptr, rrpriv->evt_ring);
 
 	rrpriv->info->cmd_ctrl.entry_size = sizeof(struct cmd);
 	rrpriv->info->cmd_ctrl.entries = CMD_RING_ENTRIES;
@@ -558,20 +592,19 @@
 	rrpriv->info->cmd_ctrl.pi = 15;
 
 	for (i = 0; i < CMD_RING_ENTRIES; i++) {
-		regs->CmdRing[i] = 0;
+		writel(0, &regs->CmdRing[i]);
 	}
 
 	for (i = 0; i < TX_RING_ENTRIES; i++) {
 		rrpriv->tx_ring[i].size = 0;
-		rrpriv->tx_ring[i].addr = 0;
+		set_rraddr(&rrpriv->tx_ring[i].addr, 0);
 		rrpriv->tx_skbuff[i] = 0;
 	}
-
 	rrpriv->info->tx_ctrl.entry_size = sizeof(struct tx_desc);
 	rrpriv->info->tx_ctrl.entries = TX_RING_ENTRIES;
 	rrpriv->info->tx_ctrl.mode = 0;
 	rrpriv->info->tx_ctrl.pi = 0;
-	rrpriv->info->tx_ctrl.rngptr = virt_to_bus(rrpriv->tx_ring);
+	set_rraddr(&rrpriv->info->tx_ctrl.rngptr, rrpriv->tx_ring);
 
 	/*
 	 * Set dirty_tx before we start receiving interrupts, otherwise
@@ -585,14 +618,20 @@
 
 	rr_reset(dev);
 
-	regs->IntrTmr = 0x60;
-	regs->WriteDmaThresh = 0x80 | 0x1f;
-	regs->ReadDmaThresh = 0x80 | 0x1f;
+	writel(0x60, &regs->IntrTmr);
+	/*
+	 * These seem to have no real effect as the Firmware sets
+	 * it's own default values
+	 */
+	writel(0x10, &regs->WriteDmaThresh);
+	writel(0x20, &regs->ReadDmaThresh);
 
 	rrpriv->fw_running = 0;
+	mb();
 
 	hostctrl &= ~(HALT_NIC | INVALID_INST_B | PARITY_ERR);
-	regs->HostCtrl = hostctrl;
+	writel(hostctrl, &regs->HostCtrl);
+	mb();
 
 	spin_unlock_irqrestore(&rrpriv->lock, flags);
 
@@ -626,10 +665,7 @@
 		if ((((unsigned long)skb->data) & 0xfff) > ~65320)
 			printk("skb alloc error\n");
 
-#if (BITS_PER_LONG == 32)
-		rrpriv->rx_ring[i].zero = 0;
-#endif
-		rrpriv->rx_ring[i].addr = virt_to_bus(skb->data);
+		set_rraddr(&rrpriv->rx_ring[i].addr, skb->data);
 		rrpriv->rx_ring[i].size = dev->mtu + HIPPI_HLEN;
 	}
 
@@ -637,7 +673,8 @@
 	rrpriv->rx_ctrl[4].entries = RX_RING_ENTRIES;
 	rrpriv->rx_ctrl[4].mode = 8;
 	rrpriv->rx_ctrl[4].pi = 0;
-	rrpriv->rx_ctrl[4].rngptr = virt_to_bus(rrpriv->rx_ring);
+	mb();
+	set_rraddr(&rrpriv->rx_ctrl[4].rngptr, rrpriv->rx_ring);
 
 	cmd.code = C_NEW_RNG;
 	cmd.ring = 4;
@@ -647,18 +684,15 @@
 #if 0
 {
 	u32 tmp;
-	tmp = regs->ExtIo;
-	regs->ExtIo = 0x80;
+	tmp = readl(&regs->ExtIo);
+	writel(0x80, &regs->ExtIo);
 	
 	i = jiffies + 1 * HZ;
 	while (jiffies < i);
-	regs->ExtIo = tmp;
+	writel(tmp, &regs->ExtIo);
 }
 #endif
 	dev->tbusy = 0;
-#if 0
-	dev->interrupt = 0;
-#endif
 	dev->start = 1;
 	return 0;
 }
@@ -669,24 +703,24 @@
  * events) and are handled here, outside the main interrupt handler,
  * to reduce the size of the handler.
  */
-static u32 rr_handle_event(struct device *dev, u32 prodidx)
+static u32 rr_handle_event(struct device *dev, u32 prodidx, u32 eidx)
 {
 	struct rr_private *rrpriv;
 	struct rr_regs *regs;
-	u32 tmp, eidx;
+	u32 tmp;
 
 	rrpriv = (struct rr_private *)dev->priv;
 	regs = rrpriv->regs;
-	eidx = rrpriv->info->evt_ctrl.pi;
 
 	while (prodidx != eidx){
 		switch (rrpriv->evt_ring[eidx].code){
 		case E_NIC_UP:
-			tmp = regs->FwRev;
+			tmp = readl(&regs->FwRev);
 			printk("%s: Firmware revision %i.%i.%i up and running\n",
 			       dev->name, (tmp >> 16), ((tmp >> 8) & 0xff),
 			       (tmp & 0xff));
 			rrpriv->fw_running = 1;
+			mb();
 			break;
 		case E_LINK_ON:
 			printk("%s: Optical link ON\n", dev->name);
@@ -729,7 +763,7 @@
 #if (DEBUG > 2)
 			printk("%s: RX ring valid event\n", dev->name);
 #endif
-			regs->IpRxPi = RX_RING_ENTRIES - 1;
+			writel(RX_RING_ENTRIES - 1, &regs->IpRxPi);
 			break;
 		case E_INV_RNG:
 			printk("%s: RX ring invalid event\n", dev->name);
@@ -756,35 +790,24 @@
 	}
 
 	rrpriv->info->evt_ctrl.pi = eidx;
+	mb();
 	return eidx;
 }
 
 
-static int rx_int(struct device *dev, u32 rxlimit)
+static void rx_int(struct device *dev, u32 rxlimit, u32 index)
 {
 	struct rr_private *rrpriv = (struct rr_private *)dev->priv;
-	u32 index, pkt_len;
+	u32 pkt_len;
 	struct rr_regs *regs = rrpriv->regs;
 
-	index = rrpriv->cur_rx;
-
-	while(index != rxlimit){
+	do {
 		pkt_len = rrpriv->rx_ring[index].size;
 #if (DEBUG > 2)
 		printk("index %i, rxlimit %i\n", index, rxlimit);
 		printk("len %x, mode %x\n", pkt_len,
 		       rrpriv->rx_ring[index].mode);
 #endif
-#if 0
-/*
- * I have never seen this occur
- */
-		if(!(rrpriv->rx_skbuff[index])){
-			printk("Trying to receive in empty skbuff\n");
-			goto out;
-		}
-#endif
-
 		if (pkt_len > 0){
 			struct sk_buff *skb;
 
@@ -808,7 +831,7 @@
 					skb = rrpriv->rx_skbuff[index];
 					skb_put(skb, pkt_len);
 					rrpriv->rx_skbuff[index] = newskb;
-					rrpriv->rx_ring[index].addr = virt_to_bus(newskb->data);
+					set_rraddr(&rrpriv->rx_ring[index].addr, newskb->data);
 				}else{
 					printk("%s: Out of memory, deferring "
 					       "packet\n", dev->name);
@@ -829,13 +852,13 @@
 		rrpriv->rx_ring[index].size = dev->mtu + HIPPI_HLEN;
 
 		if ((index & 7) == 7)
-			regs->IpRxPi = index;
+			writel(index, &regs->IpRxPi);
 
 		index = (index + 1) % RX_RING_ENTRIES;
-	}
+	} while(index != rxlimit);
 
 	rrpriv->cur_rx = index;
-	return index;
+	mb();
 }
 
 
@@ -844,25 +867,18 @@
 	struct rr_private *rrpriv;
 	struct rr_regs *regs;
 	struct device *dev = (struct device *)dev_id;
-	u32 prodidx, eidx, txcsmr, rxlimit, txcon;
+	u32 prodidx, rxindex, eidx, txcsmr, rxlimit, txcon;
 	unsigned long flags;
 
 	rrpriv = (struct rr_private *)dev->priv;
 	regs = rrpriv->regs;
 
-	if (!(regs->HostCtrl & RR_INT))
+	if (!(readl(&regs->HostCtrl) & RR_INT))
 		return;
 
-#if 0
-	if (test_and_set_bit(0, (void*)&dev->interrupt) != 0) {
-		printk("%s: Re-entering the interrupt handler.\n", dev->name);
-		return;
-	}
-#endif
-
 	spin_lock_irqsave(&rrpriv->lock, flags);
 
-	prodidx = regs->EvtPrd;
+	prodidx = readl(&regs->EvtPrd);
 	txcsmr = (prodidx >> 8) & 0xff;
 	rxlimit = (prodidx >> 16) & 0xff;
 	prodidx &= 0xff;
@@ -872,6 +888,10 @@
 	       prodidx, rrpriv->info->evt_ctrl.pi);
 #endif
 
+	rxindex = rrpriv->cur_rx;
+	if (rxindex != rxlimit)
+		rx_int(dev, rxlimit, rxindex);
+
 	txcon = rrpriv->dirty_tx;
 	if (txcsmr != txcon) {
 		do {
@@ -881,11 +901,12 @@
 
 			rrpriv->tx_skbuff[txcon] = NULL;
 			rrpriv->tx_ring[txcon].size = 0;
-			rrpriv->tx_ring[txcon].addr = 0;
+			set_rraddr(&rrpriv->tx_ring[txcon].addr, 0);
 			rrpriv->tx_ring[txcon].mode = 0;
 
 			txcon = (txcon + 1) % TX_RING_ENTRIES;
 		} while (txcsmr != txcon);
+		mb();
 
 		rrpriv->dirty_tx = txcon;
 		if (rrpriv->tx_full && dev->tbusy &&
@@ -897,21 +918,15 @@
 		}
 	}
 
-	rx_int(dev, rxlimit);
-
 	eidx = rrpriv->info->evt_ctrl.pi;
-
 	if (prodidx != eidx)
-		eidx = rr_handle_event(dev, prodidx);
+		eidx = rr_handle_event(dev, prodidx, eidx);
 
 	eidx |= ((txcsmr << 8) | (rxlimit << 16));
-	regs->EvtCon = eidx;
+	writel(eidx, &regs->EvtCon);
+	mb();
 
 	spin_unlock_irqrestore(&rrpriv->lock, flags);
-
-#if 0
-	dev->interrupt = 0;
-#endif
 }
 
 
@@ -919,35 +934,64 @@
 {
 	struct rr_private *rrpriv;
 	struct rr_regs *regs;
+	int ecode = 0;
+	unsigned long flags;
 
 	rrpriv = (struct rr_private *)dev->priv;
 	regs = rrpriv->regs;
 
-#if 0
-	regs->HostCtrl |= (HALT_NIC | RR_CLEAR_INT);
-#endif
+	if (rrpriv->fw_rev < 0x00020000) {
+		printk(KERN_WARNING "%s: trying to configure device with "
+		       "obsolete firmware\n", dev->name);
+		ecode = -EBUSY;
+		goto error;
+	}
+
+	rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl),
+				  GFP_KERNEL | GFP_DMA);
+	if (!rrpriv->rx_ctrl) {
+		ecode = -ENOMEM;
+		goto error;
+	}
+
+	rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA);
+	if (!rrpriv->info){
+		kfree(rrpriv->rx_ctrl);
+		ecode = -ENOMEM;
+		goto error;
+	}
+	memset(rrpriv->rx_ctrl, 0, 256 * sizeof(struct ring_ctrl));
+	memset(rrpriv->info, 0, sizeof(struct rr_info));
+	mb();
+
+	spin_lock_irqsave(&rrpriv->lock, flags);
+	writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT, &regs->HostCtrl);
+	spin_unlock_irqrestore(&rrpriv->lock, flags);
 
 	if (request_irq(dev->irq, rr_interrupt, SA_SHIRQ, rrpriv->name, dev))
 	{
 		printk(KERN_WARNING "%s: Requested IRQ %d is busy\n",
 		       dev->name, dev->irq);
-		return -EAGAIN;
+		ecode = -EAGAIN;
+		goto error;
 	}
 
-	rrpriv->rx_ctrl = kmalloc(256*sizeof(struct ring_ctrl),
-				  GFP_KERNEL | GFP_DMA);
-	rrpriv->info = kmalloc(sizeof(struct rr_info), GFP_KERNEL | GFP_DMA);
-
 	rr_init1(dev);
 
 	dev->tbusy = 0;
-#if 0
-	dev->interrupt = 0;
-#endif
 	dev->start = 1;
 
 	MOD_INC_USE_COUNT;
 	return 0;
+
+ error:
+	spin_lock_irqsave(&rrpriv->lock, flags);
+	writel(readl(&regs->HostCtrl)|HALT_NIC|RR_CLEAR_INT, &regs->HostCtrl);
+	spin_unlock_irqrestore(&rrpriv->lock, flags);
+
+	dev->tbusy = 1;
+	dev->start = 0;
+	return -ENOMEM;
 }
 
 
@@ -965,12 +1009,13 @@
 	printk("%s: dumping NIC TX rings\n", dev->name);
 
 	printk("RxPrd %08x, TxPrd %02x, EvtPrd %08x, TxPi %02x, TxCtrlPi %02x\n",
-	       regs->RxPrd, regs->TxPrd, regs->EvtPrd, regs->TxPi,
+	       readl(&regs->RxPrd), readl(&regs->TxPrd),
+	       readl(&regs->EvtPrd), readl(&regs->TxPi),
 	       rrpriv->info->tx_ctrl.pi);
 
-	printk("Error code 0x%x\n", regs->Fail1);
+	printk("Error code 0x%x\n", readl(&regs->Fail1));
 
-	index = (((regs->EvtPrd >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES;
+	index = (((readl(&regs->EvtPrd) >> 8) & 0xff ) - 1) % EVT_RING_ENTRIES;
 	cons = rrpriv->dirty_tx;
 	printk("TX ring index %i, TX consumer %i\n",
 	       index, cons);
@@ -989,12 +1034,12 @@
 	if (rrpriv->tx_skbuff[cons]){
 		len = min(0x80, rrpriv->tx_skbuff[cons]->len);
 		printk("skbuff for cons %i is valid - dumping data (0x%x bytes - skbuff len 0x%x)\n", cons, len, rrpriv->tx_skbuff[cons]->len);
-		printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08x), skbuff-addr %08x, truesize 0x%x\n",
+		printk("mode 0x%x, size 0x%x,\n phys %08x (virt %08lx), skbuff-addr %08lx, truesize 0x%x\n",
 		       rrpriv->tx_ring[cons].mode,
 		       rrpriv->tx_ring[cons].size,
-		       rrpriv->tx_ring[cons].addr,
-		       (unsigned int)bus_to_virt(rrpriv->tx_ring[cons].addr),
-		       (unsigned int)rrpriv->tx_skbuff[cons]->data,
+		       rrpriv->tx_ring[cons].addr.addrlo,
+		       (unsigned long)bus_to_virt(rrpriv->tx_ring[cons].addr.addrlo),
+		       (unsigned long)rrpriv->tx_skbuff[cons]->data,
 		       (unsigned int)rrpriv->tx_skbuff[cons]->truesize);
 		for (i = 0; i < len; i++){
 			if (!(i & 7))
@@ -1009,7 +1054,7 @@
 		printk("mode 0x%x, size 0x%x, phys-addr %08x\n",
 		       rrpriv->tx_ring[i].mode,
 		       rrpriv->tx_ring[i].size,
-		       rrpriv->tx_ring[i].addr);
+		       rrpriv->tx_ring[i].addr.addrlo);
 
 }
 
@@ -1033,24 +1078,26 @@
 	 */
 	spin_lock(&rrpriv->lock);
 
-	tmp = regs->HostCtrl;
+	tmp = readl(&regs->HostCtrl);
 	if (tmp & NIC_HALTED){
 		printk("%s: NIC already halted\n", dev->name);
 		rr_dump(dev);
-	}else
-		tmp |= HALT_NIC;
-	regs->HostCtrl = tmp;
+	}else{
+		tmp |= HALT_NIC | RR_CLEAR_INT;
+		writel(tmp, &regs->HostCtrl);
+		mb();
+	}
 
 	rrpriv->fw_running = 0;
 
-	regs->TxPi = 0;
-	regs->IpRxPi = 0;
+	writel(0, &regs->TxPi);
+	writel(0, &regs->IpRxPi);
 
-	regs->EvtCon = 0;
-	regs->EvtPrd = 0;
+	writel(0, &regs->EvtCon);
+	writel(0, &regs->EvtPrd);
 
 	for (i = 0; i < CMD_RING_ENTRIES; i++)
-		regs->CmdRing[i] = 0;
+		writel(0, &regs->CmdRing[i]);
 
 	rrpriv->info->tx_ctrl.entries = 0;
 	rrpriv->info->cmd_ctrl.pi = 0;
@@ -1060,7 +1107,7 @@
 	for (i = 0; i < TX_RING_ENTRIES; i++) {
 		if (rrpriv->tx_skbuff[i]) {
 			rrpriv->tx_ring[i].size = 0;
-			rrpriv->tx_ring[i].addr = 0;
+			set_rraddr(&rrpriv->tx_ring[i].addr, 0);
 			dev_kfree_skb(rrpriv->tx_skbuff[i]);
 		}
 	}
@@ -1068,7 +1115,7 @@
 	for (i = 0; i < RX_RING_ENTRIES; i++) {
 		if (rrpriv->rx_skbuff[i]) {
 			rrpriv->rx_ring[i].size = 0;
-			rrpriv->rx_ring[i].addr = 0;
+			set_rraddr(&rrpriv->rx_ring[i].addr, 0);
 			dev_kfree_skb(rrpriv->rx_skbuff[i]);
 		}
 	}
@@ -1094,6 +1141,10 @@
 	u32 *ifield;
 	struct sk_buff *new_skb;
 
+	if (readl(&regs->Mode) & FATAL_ERR)
+		printk("error codes Fail1 %02x, Fail2 %02x\n",
+		       readl(&regs->Fail1), readl(&regs->Fail2));
+
 	/*
 	 * We probably need to deal with tbusy here to prevent overruns.
 	 */
@@ -1128,11 +1179,11 @@
 	index = txctrl->pi;
 
 	rrpriv->tx_skbuff[index] = skb;
-	rrpriv->tx_ring[index].addr = virt_to_bus(skb->data);
+	set_rraddr(&rrpriv->tx_ring[index].addr, skb->data);
 	rrpriv->tx_ring[index].size = len + 8; /* include IFIELD */
 	rrpriv->tx_ring[index].mode = PACKET_START | PACKET_END;
 	txctrl->pi = (index + 1) % TX_RING_ENTRIES;
-	regs->TxPi = txctrl->pi;
+	writel(txctrl->pi, &regs->TxPi);
 
 	if (txctrl->pi == rrpriv->dirty_tx){
 		rrpriv->tx_full = 1;
@@ -1167,8 +1218,9 @@
 {
 	struct rr_private *rrpriv;
 	struct rr_regs *regs;
+	unsigned long eptr, segptr;
 	int i, j;
-	u32 localctrl, eptr, sptr, segptr, len, tmp;
+	u32 localctrl, sptr, len, tmp;
 	u32 p2len, p2size, nr_seg, revision, io, sram_size;
 	struct eeprom *hw = NULL;
 
@@ -1178,40 +1230,44 @@
 	if (dev->flags & IFF_UP)
 		return -EBUSY;
 
-	if (!(regs->HostCtrl & NIC_HALTED)){
+	if (!(readl(&regs->HostCtrl) & NIC_HALTED)){
 		printk("%s: Trying to load firmware to a running NIC.\n", 
 		       dev->name);
 		return -EBUSY;
 	}
 
-	localctrl = regs->LocalCtrl;
-	regs->LocalCtrl = 0;
+	localctrl = readl(&regs->LocalCtrl);
+	writel(0, &regs->LocalCtrl);
 
-	regs->EvtPrd = 0;
-	regs->RxPrd = 0;
-	regs->TxPrd = 0;
+	writel(0, &regs->EvtPrd);
+	writel(0, &regs->RxPrd);
+	writel(0, &regs->TxPrd);
 
 	/*
 	 * First wipe the entire SRAM, otherwise we might run into all
 	 * kinds of trouble ... sigh, this took almost all afternoon
 	 * to track down ;-(
 	 */
-	io = regs->ExtIo;
-	regs->ExtIo = 0;
-	sram_size = read_eeprom_word(rrpriv, (void *)8);
+	io = readl(&regs->ExtIo);
+	writel(0, &regs->ExtIo);
+	sram_size = rr_read_eeprom_word(rrpriv, (void *)8);
 
 	for (i = 200; i < sram_size / 4; i++){
-		regs->WinBase = i * 4;
-		regs->WinData = 0;
+		writel(i * 4, &regs->WinBase);
+		mb();
+		writel(0, &regs->WinData);
+		mb();
 	}
-	regs->ExtIo = io;
+	writel(io, &regs->ExtIo);
+	mb();
 
-	eptr = read_eeprom_word(rrpriv, &hw->rncd_info.AddrRunCodeSegs);
+	eptr = (unsigned long)rr_read_eeprom_word(rrpriv,
+					       &hw->rncd_info.AddrRunCodeSegs);
 	eptr = ((eptr & 0x1fffff) >> 3);
 
-	p2len = read_eeprom_word(rrpriv, (void *)(0x83*4));
+	p2len = rr_read_eeprom_word(rrpriv, (void *)(0x83*4));
 	p2len = (p2len << 2);
-	p2size = read_eeprom_word(rrpriv, (void *)(0x84*4));
+	p2size = rr_read_eeprom_word(rrpriv, (void *)(0x84*4));
 	p2size = ((p2size & 0x1fffff) >> 3);
 
 	if ((eptr < p2size) || (eptr > (p2size + p2len))){
@@ -1219,7 +1275,7 @@
 		goto out;
 	}
 
-	revision = read_eeprom_word(rrpriv, &hw->manf.HeaderFmt);
+	revision = rr_read_eeprom_word(rrpriv, &hw->manf.HeaderFmt);
 
 	if (revision != 1){
 		printk("%s: invalid firmware format (%i)\n",
@@ -1227,18 +1283,18 @@
 		goto out;
 	}
 
-	nr_seg = read_eeprom_word(rrpriv, (void *)eptr);
+	nr_seg = rr_read_eeprom_word(rrpriv, (void *)eptr);
 	eptr +=4;
 #if (DEBUG > 1)
 	printk("%s: nr_seg %i\n", dev->name, nr_seg);
 #endif
 
 	for (i = 0; i < nr_seg; i++){
-		sptr = read_eeprom_word(rrpriv, (void *)eptr);
+		sptr = rr_read_eeprom_word(rrpriv, (void *)eptr);
 		eptr += 4;
-		len = read_eeprom_word(rrpriv, (void *)eptr);
+		len = rr_read_eeprom_word(rrpriv, (void *)eptr);
 		eptr += 4;
-		segptr = read_eeprom_word(rrpriv, (void *)eptr);
+		segptr = (unsigned long)rr_read_eeprom_word(rrpriv, (void *)eptr);
 		segptr = ((segptr & 0x1fffff) >> 3);
 		eptr += 4;
 #if (DEBUG > 1)
@@ -1246,16 +1302,19 @@
 		       dev->name, i, sptr, len, segptr);
 #endif
 		for (j = 0; j < len; j++){
-			tmp = read_eeprom_word(rrpriv, (void *)segptr);
-			regs->WinBase = sptr;
-			regs->WinData = tmp;
+			tmp = rr_read_eeprom_word(rrpriv, (void *)segptr);
+			writel(sptr, &regs->WinBase);
+			mb();
+			writel(tmp, &regs->WinData);
+			mb();
 			segptr += 4;
 			sptr += 4;
 		}
 	}
 
 out:
-	regs->LocalCtrl = localctrl;
+	writel(localctrl, &regs->LocalCtrl);
+	mb();
 	return 0;
 }
 
@@ -1291,7 +1350,7 @@
 			error = -ENOMEM;
 			goto out;
 		}
-		i = read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
+		i = rr_read_eeprom(rrpriv, 0, image, EEPROM_BYTES);
 		if (i != EEPROM_BYTES){
 			kfree(image);
 			printk(KERN_ERR "%s: Error reading EEPROM\n",
@@ -1325,7 +1384,7 @@
 		}
 
 		oldimage = kmalloc(EEPROM_WORDS * sizeof(u32), GFP_KERNEL);
-		if (!image){
+		if (!oldimage){
 			printk(KERN_ERR "%s: Unable to allocate memory "
 			       "for old EEPROM image\n", dev->name);
 			error = -ENOMEM;
@@ -1343,7 +1402,7 @@
 			printk(KERN_ERR "%s: Error writing EEPROM\n",
 			       dev->name);
 
-		i = read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES);
+		i = rr_read_eeprom(rrpriv, 0, oldimage, EEPROM_BYTES);
 		if (i != EEPROM_BYTES)
 			printk(KERN_ERR "%s: Error reading back EEPROM "
 			       "image\n", dev->name);
@@ -1354,7 +1413,6 @@
 			       dev->name);
 			error = -EFAULT;
 		}
-
 		kfree(image);
 		kfree(oldimage);
 		break;
@@ -1374,6 +1432,6 @@
 
 /*
  * Local variables:
- * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -c rrunner.c"
+ * compile-command: "gcc -D__SMP__ -D__KERNEL__ -I../../include -Wall -Wstrict-prototypes -O2 -pipe -fomit-frame-pointer -fno-strength-reduce -m486 -malign-loops=2 -malign-jumps=2 -malign-functions=2 -DCPU=686 -DMODULE -DMODVERSIONS -include ../../include/linux/modversions.h -c rrunner.c"
  * End:
  */
diff -urN linux-2.2.7-pre3/drivers/net/rrunner.h linux-2.2.7-pre4/drivers/net/rrunner.h
--- linux-2.2.7-pre3/drivers/net/rrunner.h	1998-12-17 09:04:49.000000000 -0800
+++ linux-2.2.7-pre4/drivers/net/rrunner.h	2003-08-15 15:05:52.000000000 -0700
@@ -278,7 +278,6 @@
 #define TRACE_ON_WHAT_BIT	0x00020000    /* Traces on */
 #define ONEM_BUF_WHAT_BIT	0x00040000    /* 1Meg vs 256K */
 #define CHAR_API_WHAT_BIT	0x00080000    /* Char API vs network only */
-#define MS_DOS_WHAT_BIT		0x00100000    /* MS_DOS */
 #define CMD_EVT_WHAT_BIT	0x00200000    /* Command event */
 #define LONG_TX_WHAT_BIT	0x00400000
 #define LONG_RX_WHAT_BIT	0x00800000
@@ -486,6 +485,63 @@
 #define  SAME_IFIELD		0x80
 
 
+typedef struct {
+#if (BITS_PER_LONG == 64)
+	u64 addrlo;
+#else
+	u32 addrhi;
+	u32 addrlo;
+#endif
+} rraddr;
+
+
+static inline void set_rraddr(rraddr *ra, volatile void *addr)
+{
+	unsigned long baddr = virt_to_bus((void *)addr);
+#if (BITS_PER_LONG == 64)
+	ra->addrlo = baddr;
+#else
+    /* Don't bother setting zero every time */
+	ra->addrlo = baddr;
+#endif
+	mb();
+}
+
+
+static inline void set_rxaddr(struct rr_regs *regs, volatile void *addr)
+{
+	unsigned long baddr = virt_to_bus((void *)addr);
+#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN)
+	writel(baddr & 0xffffffff, &regs->RxRingHi);
+	writel(baddr >> 32, &regs->RxRingLo);
+#elif (BITS_PER_LONG == 64)
+	writel(baddr >> 32, &regs->RxRingHi);
+	writel(baddr & 0xffffffff, &regs->RxRingLo);
+#else
+	writel(0, &regs->RxRingHi);
+	writel(baddr, &regs->RxRingLo);
+#endif
+	mb();
+}
+
+
+static inline void set_infoaddr(struct rr_regs *regs, volatile void *addr)
+{
+	unsigned long baddr = virt_to_bus((void *)addr);
+#if (BITS_PER_LONG == 64) && defined(__LITTLE_ENDIAN)
+	writel(baddr & 0xffffffff, &regs->InfoPtrHi);
+	writel(baddr >> 32, &regs->InfoPtrLo);
+#elif (BITS_PER_LONG == 64)
+	writel(baddr >> 32, &regs->InfoPtrHi);
+	writel(baddr & 0xffffffff, &regs->InfoPtrLo);
+#else
+	writel(0, &regs->InfoPtrHi);
+	writel(baddr, &regs->InfoPtrLo);
+#endif
+	mb();
+}
+
+
 /*
  * TX ring
  */
@@ -498,12 +554,7 @@
 #define TX_RING_SIZE	(TX_RING_ENTRIES * sizeof(struct tx_desc))
 
 struct tx_desc{
-#if (BITS_PER_LONG == 64)
-	u64	addr;
-#else
-        u32	zero;
-	u32	addr;
-#endif
+	rraddr	addr;
 	u32	res;
 #ifdef __LITTLE_ENDIAN
 	u16	size;
@@ -525,12 +576,7 @@
 #define RX_RING_SIZE	(RX_RING_ENTRIES * sizeof(struct rx_desc))
 
 struct rx_desc{
-#if (BITS_PER_LONG == 64)
-	u64	addr;
-#else
-        u32	zero;
-	u32	addr;
-#endif
+	rraddr	addr;
 	u32	res;
 #ifdef __LITTLE_ENDIAN
 	u16	size;
@@ -714,12 +760,7 @@
  * This struct is shared with the NIC firmware.
  */
 struct ring_ctrl {
-#if (BITS_PER_LONG == 64)
-	u64	rngptr;
-#else
-	u32	zero;
-	u32	rngptr;
-#endif
+	rraddr	rngptr;
 #ifdef __LITTLE_ENDIAN
 	u16	entries;
 	u8	pad;
@@ -759,19 +800,19 @@
 	struct rx_desc		rx_ring[RX_RING_ENTRIES];
 	struct tx_desc		tx_ring[TX_RING_ENTRIES];
 	struct event		evt_ring[EVT_RING_ENTRIES];
-	struct sk_buff		*tx_skbuff[TX_RING_ENTRIES];
 	struct sk_buff		*rx_skbuff[RX_RING_ENTRIES];
+	struct sk_buff		*tx_skbuff[TX_RING_ENTRIES];
 	struct rr_regs		*regs;		/* Register base */
 	struct ring_ctrl	*rx_ctrl;	/* Receive ring control */
 	struct rr_info		*info;		/* Shared info page */
+	struct device		*next;
 	spinlock_t		lock;
 	struct timer_list	timer;
 	u32			cur_rx, cur_cmd, cur_evt;
 	u32			dirty_rx, dirty_tx;
 	u32			tx_full;
+	u32			fw_rev;
 	short			fw_running;
-	u8			pci_bus;	/* PCI bus number */
-	u8			pci_dev_fun;	/* PCI device numbers */
 	char			name[24];	/* The assigned name */
 	struct net_device_stats stats;
 };
@@ -789,5 +830,11 @@
 static int rr_close(struct device *dev);
 static struct net_device_stats *rr_get_stats(struct device *dev);
 static int rr_ioctl(struct device *dev, struct ifreq *rq, int cmd);
+static unsigned int rr_read_eeprom(struct rr_private *rrpriv,
+				   unsigned long offset,
+				   unsigned char *buf,
+				   unsigned long length);
+static u32 rr_read_eeprom_word(struct rr_private *rrpriv, void * offset);
+static int rr_load_firmware(struct device *dev);
 
 #endif /* _RRUNNER_H_ */
diff -urN linux-2.2.7-pre3/drivers/net/z85230.c linux-2.2.7-pre4/drivers/net/z85230.c
--- linux-2.2.7-pre3/drivers/net/z85230.c	1999-04-16 13:58:46.000000000 -0700
+++ linux-2.2.7-pre4/drivers/net/z85230.c	2003-08-15 15:05:52.000000000 -0700
@@ -48,6 +48,7 @@
 #include <asm/spinlock.h>
 
 #include "z85230.h"
+#include "syncppp.h"
 
 
 static spinlock_t z8530_buffer_lock = SPIN_LOCK_UNLOCKED;
diff -urN linux-2.2.7-pre3/drivers/sbus/char/pcikbd.c linux-2.2.7-pre4/drivers/sbus/char/pcikbd.c
--- linux-2.2.7-pre3/drivers/sbus/char/pcikbd.c	1999-03-15 16:11:30.000000000 -0800
+++ linux-2.2.7-pre4/drivers/sbus/char/pcikbd.c	2003-08-15 15:05:52.000000000 -0700
@@ -262,29 +262,22 @@
 			return 0;
 		}
 	}
-	if(scancode == 0) {
-		prev_scancode = 0;
-		return 0;
-	}
 	return 1;
 }
 
-int pcikbd_pretranslate(unsigned char scancode, char raw_mode)
+int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
+		     char raw_mode)
 {
-	if(scancode == 0xff) {
-		prev_scancode = 0;
+	static int prev_scancode = 0;
+
+	if (scancode == 0xe0 || scancode == 0xe1) {
+		prev_scancode = scancode;
 		return 0;
 	}
-	if(scancode == 0xe0 || scancode == 0xe1) {
-		prev_scancode = scancode;
+	if (scancode == 0x00 || scancode == 0xff) {
+		prev_scancode = 0;
 		return 0;
 	}
-	return 1;
-}
-
-int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
-		     char raw_mode)
-{
 	if(prev_scancode) {
 		if(prev_scancode != 0xe0) {
 			if(prev_scancode == 0xe1 && scancode == 0x1d) {
@@ -338,7 +331,7 @@
 			break;
 		scancode = pcikbd_inb(pcikbd_iobase + KBD_DATA_REG);
 		if((status & KBD_STAT_OBF) && do_acknowledge(scancode))
-			handle_scancode(scancode);
+			handle_scancode(scancode, !(scancode & 0x80));
 		status = pcikbd_inb(pcikbd_iobase + KBD_STATUS_REG);
 	} while(status & KBD_STAT_OBF);
 	mark_bh(KEYBOARD_BH);
diff -urN linux-2.2.7-pre3/drivers/usb/Config.in linux-2.2.7-pre4/drivers/usb/Config.in
--- linux-2.2.7-pre3/drivers/usb/Config.in	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/Config.in	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,25 @@
+#
+# USB device configuration
+#
+# NOTE NOTE NOTE! This is still considered extremely experimental.
+# Right now hubs, mice and keyboards work - at least with UHCI.
+# But that may be more a lucky coincidence than anything else..
+#
+# This was all developed modularly, but I've been lazy in cleaning
+# it up, so right now they are all bools. 
+#
+mainmenu_option next_comment
+comment 'USB drivers - not for the faint of heart'
+
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+  bool 'Support for USB (EXPERIMENTAL!)' CONFIG_USB
+  if [ "$CONFIG_USB" = "y" ]; then
+    bool 'UHCI (intel PIIX4 and others) support?' CONFIG_USB_UHCI
+    bool 'OHCI (compaq and some others) support?' CONFIG_USB_OHCI
+
+    bool 'USB mouse support' CONFIG_USB_MOUSE
+    bool 'USB keyboard support' CONFIG_USB_KBD
+  fi
+fi
+
+endmenu
diff -urN linux-2.2.7-pre3/drivers/usb/CREDITS linux-2.2.7-pre4/drivers/usb/CREDITS
--- linux-2.2.7-pre3/drivers/usb/CREDITS	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/CREDITS	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,23 @@
+Credits for the Simple Linux USB Driver:
+
+The following people have contributed to this code (in alphabetical
+order by last name).  I'm sure this list should be longer, its
+difficult to maintain.
+
+  Johannes Erdfelt <jerdfelt@sventech.com>
+  ham <ham@unsuave.com>
+  Bradley M Keryan <keryan@andrew.cmu.edu>
+  Vojtech Pavlik <vojtech@twilight.ucw.cz>
+  Gregory P. Smith <greg@electricrain.com>
+  Linus Torvalds <torvalds@transmeta.com>
+  <Kazuki.Yasumatsu@fujixerox.co.jp>
+
+Special thanks to:
+
+  Inaky Perez Gonzalez <inaky@peloncho.fis.ucm.es> for starting the
+  Linux USB driver effort and writing much of the larger uusbd driver.
+  Much has been learned from that effort.
+
+  The NetBSD & FreeBSD USB developers.  For being on the Linux USB list
+  and offering suggestions and sharing implementation experiences.
+
diff -urN linux-2.2.7-pre3/drivers/usb/hub.c linux-2.2.7-pre4/drivers/usb/hub.c
--- linux-2.2.7-pre3/drivers/usb/hub.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/hub.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,409 @@
+/*
+ * USB hub driver.
+ *
+ * This is horrible, it knows about the UHCI driver
+ * internals, but it's just meant as a rough example,
+ * let's do the virtualization later when this works.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ * (C) Copyright 1999 Johannes Erdfelt
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/list.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+
+#include <asm/spinlock.h>
+
+#include "usb.h"
+#include "uhci.h"
+#include "hub.h"
+
+extern struct usb_operations uhci_device_operations;
+
+/* Wakes up khubd */
+static struct wait_queue *usb_hub_wait = NULL;
+static spinlock_t hub_event_lock = SPIN_LOCK_UNLOCKED;
+
+/* List of hubs needing servicing */
+static struct list_head hub_event_list;
+
+/*
+ * A irq handler returns non-zero to indicate to
+ * the low-level driver that it wants to be re-activated,
+ * or zero to say "I'm done".
+ */
+static int hub_irq(int status, void *__buffer, void *dev_id)
+{
+	struct usb_hub *hub = dev_id;
+	unsigned long flags;
+
+	if (waitqueue_active(&usb_hub_wait)) {
+		/* Add the hub to the event queue */
+		spin_lock_irqsave(&hub_event_lock, flags);
+		if (hub->event_list.next == &hub->event_list) {
+			list_add(&hub->event_list, &hub_event_list);
+			/* Wake up khubd */
+			wake_up(&usb_hub_wait);
+		}
+		spin_unlock_irqrestore(&hub_event_lock, flags);
+	}
+
+	return 1;
+}
+
+static void usb_hub_configure(struct usb_hub *hub)
+{
+	struct usb_device *dev = hub->dev;
+	unsigned char hubdescriptor[8], buf[4];
+	int charac, i;
+
+	usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+
+	if (usb_get_hub_descriptor(dev, hubdescriptor, 8))
+		return;
+
+	hub->nports = dev->maxchild = hubdescriptor[2];
+	printk("hub: %d-port%s detected\n", hub->nports,
+		(hub->nports == 1) ? "" : "s");
+
+	charac = (hubdescriptor[4] << 8) + hubdescriptor[3];
+	switch (charac & HUB_CHAR_LPSM) {
+		case 0x00:
+			printk("hub: ganged power switching\n");
+			break;
+		case 0x01:
+			printk("hub: individual port power switching\n");
+			break;
+		case 0x02:
+		case 0x03:
+			printk("hub: unknown reserved power switching mode\n");
+			break;
+	}
+
+	if (charac & HUB_CHAR_COMPOUND)
+		printk("hub: part of a compound device\n");
+	else
+		printk("hub: standalone hub\n");
+
+	switch (charac & HUB_CHAR_OCPM) {
+		case 0x00:
+			printk("hub: global over current protection\n");
+			break;
+		case 0x08:
+			printk("hub: individual port over current protection\n");
+			break;
+		case 0x10:
+		case 0x18:
+			printk("hub: no over current protection\n");
+                        break;
+	}
+
+	printk("hub: power on to power good time: %dms\n",
+		hubdescriptor[5] * 2);
+
+	printk("hub: hub controller current requirement: %dmA\n",
+		hubdescriptor[6]);
+
+	for (i = 0; i < dev->maxchild; i++)
+		printk("hub:  port %d is%s removable\n", i + 1,
+			hubdescriptor[7 + ((i + 1)/8)] & (1 << ((i + 1) % 8))
+			? " not" : "");
+
+	if (usb_get_hub_status(dev, buf))
+		return;
+
+	printk("hub: local power source is %s\n",
+		(buf[0] & 1) ? "lost (inactive)" : "good");
+
+	printk("hub: %sover current condition exists\n",
+		(buf[0] & 2) ? "" : "no ");
+
+#if 0
+	for (i = 0; i < hub->nports; i++) {
+		int portstat, portchange;
+		unsigned char portstatus[4];
+
+		if (usb_get_port_status(dev, i + 1, portstatus))
+			return;
+		portstat = (portstatus[1] << 8) + portstatus[0];
+		portchange = (portstatus[3] << 8) + portstatus[2];
+
+		printk("hub: port %d status\n", i + 1);
+		printk("hub:  %sdevice present\n", (portstat & 1) ? "" : "no ");
+		printk("hub:  %s\n", (portstat & 2) ? "enabled" : "disabled");
+		printk("hub:  %ssuspended\n", (portstat & 4) ? "" : "not ");
+		printk("hub:  %sover current\n", (portstat & 8) ? "" : "not ");
+		printk("hub:  has %spower\n", (portstat & 0x100) ? "" : "no ");
+		printk("hub:  %s speed\n", (portstat & 0x200) ? "low" : "full");
+	}
+#endif
+
+	/* Enable power to the ports */
+	printk("enabling power on all ports\n");
+	for (i = 0; i < hub->nports; i++)
+		usb_set_port_feature(dev, i + 1, USB_PORT_FEAT_POWER);
+}
+
+static int hub_probe(struct usb_device *dev)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct usb_hub *hub;
+
+	/* We don't handle multi-config hubs */
+	if (dev->descriptor.bNumConfigurations != 1)
+		return -1;
+
+	/* We don't handle multi-interface hubs */
+	if (dev->config[0].bNumInterfaces != 1)
+		return -1;
+
+	interface = &dev->config[0].interface[0];
+
+	/* Is it a hub? */
+	if (interface->bInterfaceClass != 9)
+		return -1;
+	if (interface->bInterfaceSubClass != 0)
+		return -1;
+
+	/* Multiple endpoints? What kind of mutant ninja-hub is this? */
+	if (interface->bNumEndpoints != 1)
+		return -1;
+
+	endpoint = &interface->endpoint[0];
+
+	/* Output endpoint? Curiousier and curiousier.. */
+	if (!(endpoint->bEndpointAddress & 0x80))
+		return -1;
+
+	/* If it's not an interrupt endpoint, we'd better punt! */
+	if ((endpoint->bmAttributes & 3) != 3)
+		return -1;
+
+	/* We found a hub */
+	printk("USB hub found\n");
+
+	if ((hub = kmalloc(sizeof(*hub), GFP_KERNEL)) == NULL) {
+		printk("couldn't kmalloc hub struct\n");
+		return -1;
+	}
+
+	memset(hub, 0, sizeof(*hub));
+
+	dev->private = hub;
+
+	INIT_LIST_HEAD(&hub->event_list);
+	hub->dev = dev;
+
+	usb_hub_configure(hub);
+
+	usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), hub_irq, endpoint->bInterval, hub);
+
+	/* Wake up khubd */
+	wake_up(&usb_hub_wait);
+
+	return 0;
+}
+
+static void hub_disconnect(struct usb_device *dev)
+{
+	struct usb_hub *hub = dev->private;
+	unsigned long flags;
+
+	spin_lock_irqsave(&hub_event_lock, flags);
+
+	/* Delete it and then reset it */
+	list_del(&hub->event_list);
+	INIT_LIST_HEAD(&hub->event_list);
+
+	spin_unlock_irqrestore(&hub_event_lock, flags);
+
+	/* Free the memory */
+	kfree(hub);
+}
+
+static void usb_hub_port_connect_change(struct usb_device *hub, int port)
+{
+	struct usb_device *usb;
+	unsigned char buf[4];
+	unsigned short portstatus, portchange;
+
+	usb_disconnect(&hub->children[port]);
+
+	usb_set_port_feature(hub, port + 1, USB_PORT_FEAT_RESET);
+
+	wait_ms(50);	/* FIXME: This is from the *BSD stack, thanks! :) */
+
+	if (usb_get_port_status(hub, port + 1, buf)) {
+		printk("get_port_status failed\n");
+		return;
+	}
+
+	portstatus = *((unsigned short *)buf + 0);
+	portchange = *((unsigned short *)buf + 1);
+
+	if ((!(portstatus & USB_PORT_STAT_CONNECTION)) &&
+		(!(portstatus & USB_PORT_STAT_ENABLE))) {
+		/* We're done now, we already disconnected the device */
+		/* printk("not connected/enabled\n"); */
+		return;
+	}
+
+	usb = hub->bus->op->allocate(hub);
+	if (!usb) {
+		printk("couldn't allocate usb_device\n");
+		return;
+	}
+
+	usb_connect(usb);
+
+	usb->slow = (portstatus & USB_PORT_STAT_LOW_SPEED) ? 1 : 0;
+
+	hub->children[port] = usb;
+
+	usb_new_device(usb);
+}
+
+static void usb_hub_events(void)
+{
+	unsigned long flags;
+	unsigned char buf[4];
+	unsigned short portstatus, portchange;
+	int i;
+	struct list_head *next, *tmp, *head = &hub_event_list;
+	struct usb_device *dev;
+	struct usb_hub *hub;
+
+	spin_lock_irqsave(&hub_event_lock, flags);
+
+	tmp = head->next;
+	while (tmp != head) {
+		hub = list_entry(tmp, struct usb_hub, event_list);
+		dev = hub->dev;
+
+		next = tmp->next;
+
+		list_del(tmp);
+		INIT_LIST_HEAD(tmp);
+
+		for (i = 0; i < hub->nports; i++) {
+			if (usb_get_port_status(dev, i + 1, buf)) {
+				printk("get_port_status failed\n");
+				continue;
+			}
+
+			portstatus = *((unsigned short *)buf + 0);
+			portchange = *((unsigned short *)buf + 1);
+
+			if (portchange & USB_PORT_STAT_C_CONNECTION) {
+				printk("hub: port %d connection change\n", i + 1);
+
+				usb_clear_port_feature(dev, i + 1,
+					USB_PORT_FEAT_C_CONNECTION);
+
+				usb_hub_port_connect_change(dev, i);
+			}
+
+			if (portchange & USB_PORT_STAT_C_ENABLE) {
+				printk("hub: port %d enable change\n", i + 1);
+				usb_clear_port_feature(dev, i + 1,
+					USB_PORT_FEAT_C_ENABLE);
+			}
+
+			if (portchange & USB_PORT_STAT_C_SUSPEND)
+				printk("hub: port %d suspend change\n", i + 1);
+
+			if (portchange & USB_PORT_STAT_C_OVERCURRENT)
+				printk("hub: port %d over-current change\n", i + 1);
+
+			if (portchange & USB_PORT_STAT_C_RESET) {
+				printk("hub: port %d reset change\n", i + 1);
+				usb_clear_port_feature(dev, i + 1,
+					USB_PORT_FEAT_C_RESET);
+			}
+
+#if 0
+			if (!portchange)
+				continue;
+
+			if (usb_get_port_status(dev, i + 1, buf))
+				return;
+
+			portstatus = (buf[1] << 8) + buf[0];
+			portchange = (buf[3] << 8) + buf[2];
+
+			printk("hub: port %d status\n", i + 1);
+			printk("hub:  %sdevice present\n", (portstatus & 1) ? "" : "no ");
+			printk("hub:  %s\n", (portstatus & 2) ? "enabled" : "disabled");
+			printk("hub:  %ssuspended\n", (portstatus & 4) ? "" : "not ");
+			printk("hub:  %sover current\n", (portstatus & 8) ? "" : "not ");
+			printk("hub:  has %spower\n", (portstatus & 0x100) ? "" : "no ");
+			printk("hub:  %s speed\n", (portstatus & 0x200) ? "low" : "full");
+#endif
+		}
+		tmp = next;
+#if 0
+		wait_ms(1000);
+#endif
+        }
+
+	spin_unlock_irqrestore(&hub_event_lock, flags);
+}
+
+static int usb_hub_thread(void *__hub)
+{
+	lock_kernel();
+
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all our resources
+	 */
+	printk("usb_hub_thread at %p\n", &usb_hub_thread);
+	exit_mm(current);
+	exit_files(current);
+	exit_fs(current);
+
+	/* Setup a nice name */
+	strcpy(current->comm, "khubd");
+
+	/* Send me a signal to get me die (for debugging) */
+	do {
+		interruptible_sleep_on(&usb_hub_wait);
+		usb_hub_events();
+	} while (!signal_pending(current));
+
+	printk("usb_hub_thread exiting\n");
+
+	return 0;
+}
+
+static struct usb_driver hub_driver = {
+	"hub",
+	hub_probe,
+	hub_disconnect,
+	{ NULL, NULL }
+};
+
+/*
+ * This should be a separate module.
+ */
+int hub_init(void)
+{
+	int pid;
+
+	INIT_LIST_HEAD(&hub_event_list);
+
+	usb_register(&hub_driver);
+	pid = kernel_thread(usb_hub_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+	if (pid >= 0)
+		return 0;
+
+	/* Fall through if kernel_thread failed */
+	usb_deregister(&hub_driver);
+
+	return 0;
+}
+
diff -urN linux-2.2.7-pre3/drivers/usb/hub.h linux-2.2.7-pre4/drivers/usb/hub.h
--- linux-2.2.7-pre3/drivers/usb/hub.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/hub.h	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,80 @@
+#ifndef __LINUX_HUB_H
+#define __LINUX_HUB_H
+
+#include <linux/list.h>
+
+/*
+ * Hub feature numbers
+ */
+#define C_HUB_LOCAL_POWER	0
+#define C_HUB_OVER_CURRENT	1
+
+/*
+ * Port feature numbers
+ */
+#define USB_PORT_FEAT_ENABLE		1
+#define USB_PORT_FEAT_SUSPEND		2
+#define USB_PORT_FEAT_OVER_CURRENT	3
+#define USB_PORT_FEAT_RESET		4
+#define USB_PORT_FEAT_POWER		8
+#define USB_PORT_FEAT_LOWSPEED		9
+#define USB_PORT_FEAT_C_CONNECTION	16
+#define USB_PORT_FEAT_C_ENABLE		17
+#define USB_PORT_FEAT_C_SUSPEND		18
+#define USB_PORT_FEAT_C_OVER_CURRENT	19
+#define USB_PORT_FEAT_C_RESET		20
+
+/* wPortStatus */
+#define USB_PORT_STAT_CONNECTION	0x0001
+#define USB_PORT_STAT_ENABLE		0x0002
+#define USB_PORT_STAT_SUSPEND		0x0004
+#define USB_PORT_STAT_OVERCURRENT	0x0008
+#define USB_PORT_STAT_RESET		0x0010
+#define USB_PORT_STAT_POWER		0x0100
+#define USB_PORT_STAT_LOW_SPEED		0x0200
+
+/* wPortChange */
+#define USB_PORT_STAT_C_CONNECTION	0x0001
+#define USB_PORT_STAT_C_ENABLE		0x0002
+#define USB_PORT_STAT_C_SUSPEND		0x0004
+#define USB_PORT_STAT_C_OVERCURRENT	0x0008
+#define USB_PORT_STAT_C_RESET		0x0010
+
+/* Characteristics */
+#define HUB_CHAR_LPSM		0x0003
+#define HUB_CHAR_COMPOUND	0x0004
+#define HUB_CHAR_OCPM		0x0018
+
+struct usb_device;
+
+typedef enum {
+	USB_PORT_UNPOWERED = 0,		/* Default state */
+	USB_PORT_POWERED,		/* When we've put power to it */
+	USB_PORT_ENABLED,		/* When it's been enabled */
+	USB_PORT_DISABLED,		/* If it's been disabled */
+	USB_PORT_ADMINDISABLED,		/* Forced down */
+} usb_hub_port_state;
+
+struct usb_hub_port {
+	usb_hub_port_state cstate;	/* Configuration state */
+
+	struct usb_device *child;	/* Device attached to this port */
+
+	struct usb_hub *parent;		/* Parent hub */
+};
+
+struct usb_hub {
+	/* Device structure */
+	struct usb_device *dev;
+
+	/* Temporary event list */
+	struct list_head event_list;
+
+	/* Number of ports on the hub */
+	int nports;
+
+	struct usb_hub_port ports[0];	/* Dynamically allocated */
+};
+
+#endif
+
diff -urN linux-2.2.7-pre3/drivers/usb/inits.h linux-2.2.7-pre4/drivers/usb/inits.h
--- linux-2.2.7-pre3/drivers/usb/inits.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/inits.h	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,3 @@
+int bp_mouse_init(void);
+int usb_kbd_init(void);
+int hub_init(void);
diff -urN linux-2.2.7-pre3/drivers/usb/keyboard.c linux-2.2.7-pre4/drivers/usb/keyboard.c
--- linux-2.2.7-pre3/drivers/usb/keyboard.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/keyboard.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,226 @@
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/string.h>
+#include <linux/timer.h>
+#include <linux/sched.h>
+#include <linux/kbd_ll.h>
+#include "usb.h"
+
+#define PCKBD_PRESSED  0x00
+#define PCKBD_RELEASED 0x80
+#define PCKBD_NEEDS_E0 0x80
+
+#define USBKBD_MODIFIER_BASE  120
+#define USBKBD_KEYCODE_OFFSET 2
+#define USBKBD_KEYCODE_COUNT  6
+
+#define USBKBD_VALID_KEYCODE(key) ((unsigned char)(key) > 3)
+#define USBKBD_FIND_KEYCODE(down, key, count) \
+    ((unsigned char*) memscan((down), (key), (count)) < ((down) + (count)))
+
+#define USBKBD_REPEAT_DELAY (HZ / 4)
+#define USBKBD_REPEAT_RATE (HZ / 20)
+
+struct usb_keyboard
+{
+    struct usb_device *dev;
+    unsigned long down[2];
+    unsigned char repeat_key;
+    struct timer_list repeat_timer;
+    struct list_head list;
+};
+
+extern unsigned char usb_kbd_map[];
+
+static int usb_kbd_probe(struct usb_device *dev);
+static void usb_kbd_disconnect(struct usb_device *dev);
+static void usb_kbd_repeat(unsigned long dummy);
+
+static LIST_HEAD(usb_kbd_list);
+
+static struct usb_driver usb_kbd_driver =
+{
+    "keyboard",
+    usb_kbd_probe,
+    usb_kbd_disconnect,
+    {NULL, NULL}
+};
+
+
+static void
+usb_kbd_handle_key(unsigned char key, int down)
+{
+    int scancode = (int) usb_kbd_map[key];
+    if(scancode)
+    {
+        if(scancode & PCKBD_NEEDS_E0)
+        {
+            handle_scancode(0xe0, 1);
+        }
+        handle_scancode((scancode & ~PCKBD_NEEDS_E0), down);
+    }
+}
+
+static void
+usb_kbd_repeat(unsigned long dev_id)
+{
+    struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
+
+    unsigned long flags;
+    save_flags(flags);
+    cli();
+
+    if(kbd->repeat_key)
+    {
+        usb_kbd_handle_key(kbd->repeat_key, 1);
+
+        /* reset repeat timer */
+        kbd->repeat_timer.function = usb_kbd_repeat;
+        kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_RATE;
+        kbd->repeat_timer.data = (unsigned long) kbd;
+        kbd->repeat_timer.prev = NULL;
+        kbd->repeat_timer.next = NULL;
+        add_timer(&kbd->repeat_timer);
+    }
+
+    restore_flags(flags);
+}
+
+static int
+usb_kbd_irq(int state, void *buffer, void *dev_id)
+{
+    struct usb_keyboard *kbd = (struct usb_keyboard*) dev_id;
+    unsigned long *down = (unsigned long*) buffer;
+
+    if(kbd->down[0] != down[0] || kbd->down[1] != down[1])
+    {
+        unsigned char *olddown, *newdown;
+        unsigned char modsdelta, key;
+        int i;
+
+        /* handle modifier change */
+        modsdelta = (*(unsigned char*) down ^ *(unsigned char*) kbd->down);
+        if(modsdelta)
+        {
+            for(i = 0; i < 8; i++)
+            {
+                if(modsdelta & 0x01)
+                {
+                    int pressed = (*(unsigned char*) down >> i) & 0x01;
+                    usb_kbd_handle_key(
+                        i + USBKBD_MODIFIER_BASE,
+                        pressed);
+                }
+                modsdelta >>= 1;
+            }
+        }
+
+        olddown = (unsigned char*) kbd->down + USBKBD_KEYCODE_OFFSET;
+        newdown = (unsigned char*) down + USBKBD_KEYCODE_OFFSET;
+
+        /* handle released keys */
+        for(i = 0; i < USBKBD_KEYCODE_COUNT; i++)
+        {
+            key = olddown[i];
+            if(USBKBD_VALID_KEYCODE(key)
+               && !USBKBD_FIND_KEYCODE(newdown, key, USBKBD_KEYCODE_COUNT))
+            {
+                usb_kbd_handle_key(key, 0);
+            }
+        }
+
+        /* handle pressed keys */
+        kbd->repeat_key = 0;
+        for(i = 0; i < USBKBD_KEYCODE_COUNT; i++)
+        {
+            key = newdown[i];
+            if(USBKBD_VALID_KEYCODE(key)
+               && !USBKBD_FIND_KEYCODE(olddown, key, USBKBD_KEYCODE_COUNT))
+            {
+                usb_kbd_handle_key(key, 1);
+                kbd->repeat_key = key;
+            }
+        }
+
+        /* set repeat timer if any keys were pressed */
+        if(kbd->repeat_key)
+        {
+            del_timer(&kbd->repeat_timer);
+            kbd->repeat_timer.function = usb_kbd_repeat;
+            kbd->repeat_timer.expires = jiffies + USBKBD_REPEAT_DELAY;
+            kbd->repeat_timer.data = (unsigned long) kbd;
+            kbd->repeat_timer.prev = NULL;
+            kbd->repeat_timer.next = NULL;
+            add_timer(&kbd->repeat_timer);
+        }
+
+        kbd->down[0] = down[0];
+        kbd->down[1] = down[1];
+    }
+
+    return 1;
+}
+
+static int
+usb_kbd_probe(struct usb_device *dev)
+{
+    struct usb_interface_descriptor *interface;
+    struct usb_endpoint_descriptor *endpoint;
+    struct usb_keyboard *kbd;
+
+    interface = &dev->config[0].interface[0];
+    endpoint = &interface->endpoint[0];
+
+    if(interface->bInterfaceClass != 3
+       || interface->bInterfaceSubClass != 1
+       || interface->bInterfaceProtocol != 1)
+    {
+        return -1;
+    }
+
+    printk(KERN_INFO "USB HID boot protocol keyboard detected.\n");
+
+    kbd = kmalloc(sizeof(struct usb_keyboard), GFP_KERNEL);
+    if(kbd)
+    {
+        memset(kbd, 0, sizeof(*kbd));
+        kbd->dev = dev;
+        dev->private = kbd;
+
+        usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+        usb_set_protocol(dev, 0);
+        usb_set_idle(dev, 0, 0);
+        
+        usb_request_irq(dev,
+                        usb_rcvctrlpipe(dev, endpoint->bEndpointAddress),
+                        usb_kbd_irq,
+                        endpoint->bInterval,
+                        kbd);
+
+        list_add(&kbd->list, &usb_kbd_list);
+    }
+
+    return 0;
+}
+
+static void
+usb_kbd_disconnect(struct usb_device *dev)
+{
+    struct usb_keyboard *kbd = (struct usb_keyboard*) dev->private;
+    if(kbd)
+    {
+        dev->private = NULL;
+        list_del(&kbd->list);
+        del_timer(&kbd->repeat_timer);
+        kfree(kbd);
+    }
+
+    printk(KERN_INFO "USB HID boot protocol keyboard removed.\n");
+}
+
+int
+usb_kbd_init(void)
+{
+    usb_register(&usb_kbd_driver);
+    return 0;
+}
diff -urN linux-2.2.7-pre3/drivers/usb/keymap.c linux-2.2.7-pre4/drivers/usb/keymap.c
--- linux-2.2.7-pre3/drivers/usb/keymap.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/keymap.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,50 @@
+unsigned char usb_kbd_map[256] = 
+{
+    0x00,  0x00,  0x00,  0x00,  0x1e,  0x30,  0x2e,  0x20,
+    0x12,  0x21,  0x22,  0x23,  0x17,  0x24,  0x25,  0x26,
+
+    0x32,  0x31,  0x18,  0x19,  0x10,  0x13,  0x1f,  0x14,
+    0x16,  0x2f,  0x11,  0x2d,  0x15,  0x2c,  0x02,  0x03,
+
+    0x04,  0x05,  0x06,  0x07,  0x08,  0x09,  0x0a,  0x0b,
+    0x1c,  0x01,  0xd3,  0x0f,  0x39,  0x0c,  0x0d,  0x1a,
+
+    0x1b,  0x2b,  0x00,  0x27,  0x28,  0x29,  0x33,  0x34,
+    0x35,  0x3a,  0x3b,  0x3c,  0x3d,  0x3e,  0x3f,  0x40,
+
+    0x41,  0x42,  0x43,  0x44,  0x57,  0x58,  0xb7,  0x46,
+    0x00,  0xd2,  0xc7,  0xc9,  0x63,  0xcf,  0xd1,  0xcd,
+
+    0xcb,  0xd0,  0xc8,  0x45,  0xb5,  0x37,  0x4a,  0x4e,
+    0x9c,  0x4f,  0x50,  0x51,  0x4b,  0x4c,  0x4d,  0x47,
+
+    0x48,  0x49,  0x52,  0x53,  0x00,  0x6d,  0x00,  0x00,
+    0xbd,  0xbe,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x1d,  0x2a,  0x38,  0xdb,  0x9d,  0x36,  0xb8,  0xdc,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+    0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,  0x00,
+};
diff -urN linux-2.2.7-pre3/drivers/usb/Makefile linux-2.2.7-pre4/drivers/usb/Makefile
--- linux-2.2.7-pre3/drivers/usb/Makefile	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/Makefile	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,59 @@
+#
+# Makefile for the kernel usb device drivers.
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+# This isn't actually supported yet. Don't try to use it.
+
+SUB_DIRS     :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := usb.a
+M_OBJS   :=
+L_OBJS   := usb.o hub.o usb-debug.o
+LX_OBJS  :=
+
+ifeq ($(CONFIG_USB_UHCI),y)
+  L_OBJS += uhci.o uhci-debug.o
+else
+  ifeq ($(CONFIG_USB_UHCI),m)
+    MX_OBJS += usb-uhci.o uhci-debug.o
+  endif
+endif
+
+ifeq ($(CONFIG_USB_OHCI),y)
+  L_OBJS += ohci.o ohci-debug.o
+else
+  ifeq ($(CONFIG_USB_UHCI),m)
+    MX_OBJS += ohci.o ohci-debug.o
+  endif
+endif
+
+ifeq ($(CONFIG_USB_MOUSE),y)
+  L_OBJS += mouse.o
+else
+  ifeq ($(CONFIG_USB_UHCI),m)
+    MX_OBJS += mouse.o
+  endif
+endif
+
+ifeq ($(CONFIG_USB_KBD),y)
+  L_OBJS += keyboard.o keymap.o
+else
+  ifeq ($(CONFIG_USB_UHCI),m)
+    MX_OBJS += keyboard.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
+
+keymap.o: keymap.c
+
+keymap.c: maps/serial.map maps/usb.map maps/fixup.map
+	./mkmap > $@
diff -urN linux-2.2.7-pre3/drivers/usb/maps/fixup.map linux-2.2.7-pre4/drivers/usb/maps/fixup.map
--- linux-2.2.7-pre3/drivers/usb/maps/fixup.map	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/maps/fixup.map	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,31 @@
+# misc fixes
+keycode   0 = Pause
+keycode  29 = Control
+keycode  99 = Remove
+keycode  42 = Shift
+keycode  54 = Shift_R
+keycode 109 = Application
+
+# E0 keys (or'ed with 0x80)
+keycode 156 = KP_Enter
+keycode 157 = Control_R
+keycode 181 = KP_Divide
+keycode 183 = Print_Screen
+keycode 184 = Alt_R
+keycode 189 = F13
+keycode 190 = F14
+keycode 193 = F17
+keycode 198 = Break
+keycode 199 = Home
+keycode 200 = Up
+keycode 201 = Prior
+keycode 203 = Left
+keycode 205 = Right
+keycode 207 = End
+keycode 208 = Down
+keycode 209 = Next
+keycode 210 = Insert
+keycode 211 = Delete
+keycode 219 = Window
+keycode 220 = Window_R
+keycode 221 = Menu
diff -urN linux-2.2.7-pre3/drivers/usb/maps/serial.map linux-2.2.7-pre4/drivers/usb/maps/serial.map
--- linux-2.2.7-pre3/drivers/usb/maps/serial.map	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/maps/serial.map	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,370 @@
+keymaps 0-2,4-6,8-9,12
+keycode   1 = Escape          
+	alt	keycode   1 = Meta_Escape     
+	shift	alt	keycode   1 = Meta_Escape     
+	control	alt	keycode   1 = Meta_Escape     
+keycode   2 = one              exclam          
+	alt	keycode   2 = Meta_one        
+	shift	alt	keycode   2 = Meta_exclam     
+keycode   3 = two              at               at               nul              nul             
+	alt	keycode   3 = Meta_two        
+	shift	alt	keycode   3 = Meta_at         
+	control	alt	keycode   3 = Meta_nul        
+keycode   4 = three            numbersign      
+	control	keycode   4 = Escape          
+	alt	keycode   4 = Meta_three      
+	shift	alt	keycode   4 = Meta_numbersign 
+keycode   5 = four             dollar           dollar           Control_backslash
+	alt	keycode   5 = Meta_four       
+	shift	alt	keycode   5 = Meta_dollar     
+	control	alt	keycode   5 = Meta_Control_backslash
+keycode   6 = five             percent         
+	control	keycode   6 = Control_bracketright
+	alt	keycode   6 = Meta_five       
+	shift	alt	keycode   6 = Meta_percent    
+keycode   7 = six              asciicircum     
+	control	keycode   7 = Control_asciicircum
+	alt	keycode   7 = Meta_six        
+	shift	alt	keycode   7 = Meta_asciicircum
+keycode   8 = seven            ampersand        braceleft        Control_underscore
+	alt	keycode   8 = Meta_seven      
+	shift	alt	keycode   8 = Meta_ampersand  
+	control	alt	keycode   8 = Meta_Control_underscore
+keycode   9 = eight            asterisk         bracketleft      Delete          
+	alt	keycode   9 = Meta_eight      
+	shift	alt	keycode   9 = Meta_asterisk   
+	control	alt	keycode   9 = Meta_Delete     
+keycode  10 = nine             parenleft        bracketright    
+	alt	keycode  10 = Meta_nine       
+	shift	alt	keycode  10 = Meta_parenleft  
+keycode  11 = zero             parenright       braceright      
+	alt	keycode  11 = Meta_zero       
+	shift	alt	keycode  11 = Meta_parenright 
+keycode  12 = minus            underscore       backslash        Control_underscore Control_underscore
+	alt	keycode  12 = Meta_minus      
+	shift	alt	keycode  12 = Meta_underscore 
+	control	alt	keycode  12 = Meta_Control_underscore
+keycode  13 = equal            plus            
+	alt	keycode  13 = Meta_equal      
+	shift	alt	keycode  13 = Meta_plus       
+keycode  14 = Delete          
+	alt	keycode  14 = Meta_Delete     
+	shift	alt	keycode  14 = Meta_Delete     
+	control	alt	keycode  14 = Meta_Delete     
+keycode  15 = Tab             
+	alt	keycode  15 = Meta_Tab        
+	shift	alt	keycode  15 = Meta_Tab        
+	control	alt	keycode  15 = Meta_Tab        
+keycode  16 = q               
+keycode  17 = w               
+keycode  18 = e               
+keycode  19 = r               
+keycode  20 = t               
+keycode  21 = y               
+keycode  22 = u               
+keycode  23 = i               
+keycode  24 = o               
+keycode  25 = p               
+keycode  26 = bracketleft      braceleft       
+	control	keycode  26 = Escape          
+	alt	keycode  26 = Meta_bracketleft
+	shift	alt	keycode  26 = Meta_braceleft  
+keycode  27 = bracketright     braceright       asciitilde       Control_bracketright
+	alt	keycode  27 = Meta_bracketright
+	shift	alt	keycode  27 = Meta_braceright 
+	control	alt	keycode  27 = Meta_Control_bracketright
+keycode  28 = Return          
+	alt	keycode  28 = Meta_Control_m  
+keycode  29 = Control         
+keycode  30 = a               
+keycode  31 = s               
+keycode  32 = d               
+keycode  33 = f               
+keycode  34 = g               
+keycode  35 = h               
+keycode  36 = j               
+keycode  37 = k               
+keycode  38 = l               
+keycode  39 = semicolon        colon           
+	alt	keycode  39 = Meta_semicolon  
+	shift	alt	keycode  39 = Meta_colon      
+keycode  40 = apostrophe       quotedbl        
+	control	keycode  40 = Control_g       
+	alt	keycode  40 = Meta_apostrophe 
+	shift	alt	keycode  40 = Meta_quotedbl   
+keycode  41 = grave            asciitilde      
+	control	keycode  41 = nul             
+	alt	keycode  41 = Meta_grave      
+	shift	alt	keycode  41 = Meta_asciitilde 
+keycode  42 = Shift           
+keycode  43 = backslash        bar             
+	control	keycode  43 = Control_backslash
+	alt	keycode  43 = Meta_backslash  
+	shift	alt	keycode  43 = Meta_bar        
+keycode  44 = z               
+keycode  45 = x               
+keycode  46 = c               
+keycode  47 = v               
+keycode  48 = b               
+keycode  49 = n               
+keycode  50 = m               
+keycode  51 = comma            less            
+	alt	keycode  51 = Meta_comma      
+	shift	alt	keycode  51 = Meta_less       
+keycode  52 = period           greater         
+	alt	keycode  52 = Meta_period     
+	shift	alt	keycode  52 = Meta_greater    
+keycode  53 = slash            question        
+	control	keycode  53 = Delete          
+	alt	keycode  53 = Meta_slash      
+	shift	alt	keycode  53 = Meta_question   
+keycode  54 = Shift           
+keycode  55 = KP_Multiply     
+	altgr	keycode  55 = Hex_C           
+keycode  56 = Alt             
+keycode  57 = space           
+	control	keycode  57 = nul             
+	alt	keycode  57 = Meta_space      
+	shift	alt	keycode  57 = Meta_space      
+	control	alt	keycode  57 = Meta_nul        
+keycode  58 = Caps_Lock       
+keycode  59 = F1               F13              Console_13       F25             
+	alt	keycode  59 = Console_1       
+	control	alt	keycode  59 = Console_1       
+keycode  60 = F2               F14              Console_14       F26             
+	alt	keycode  60 = Console_2       
+	control	alt	keycode  60 = Console_2       
+keycode  61 = F3               F15              Console_15       F27             
+	alt	keycode  61 = Console_3       
+	control	alt	keycode  61 = Console_3       
+keycode  62 = F4               F16              Console_16       F28             
+	alt	keycode  62 = Console_4       
+	control	alt	keycode  62 = Console_4       
+keycode  63 = F5               F17              Console_17       F29             
+	alt	keycode  63 = Console_5       
+	control	alt	keycode  63 = Console_5       
+keycode  64 = F6               F18              Console_18       F30             
+	alt	keycode  64 = Console_6       
+	control	alt	keycode  64 = Console_6       
+keycode  65 = F7               F19              Console_19       F31             
+	alt	keycode  65 = Console_7       
+	control	alt	keycode  65 = Console_7       
+keycode  66 = F8               F20              Console_20       F32             
+	alt	keycode  66 = Console_8       
+	control	alt	keycode  66 = Console_8       
+keycode  67 = F9               F21              Console_21       F33             
+	alt	keycode  67 = Console_9       
+	control	alt	keycode  67 = Console_9       
+keycode  68 = F10              F22              Console_22       F34             
+	alt	keycode  68 = Console_10      
+	control	alt	keycode  68 = Console_10      
+keycode  69 = Num_Lock        
+	altgr	keycode  69 = Hex_E           
+keycode  70 = Scroll_Lock      Show_Memory      Show_Registers   Show_State      
+	alt	keycode  70 = Scroll_Lock     
+keycode  71 = KP_7            
+	altgr	keycode  71 = Hex_7           
+	alt	keycode  71 = Ascii_7         
+keycode  72 = KP_8            
+	altgr	keycode  72 = Hex_8           
+	alt	keycode  72 = Ascii_8         
+keycode  73 = KP_9            
+	altgr	keycode  73 = Hex_9           
+	alt	keycode  73 = Ascii_9         
+keycode  74 = KP_Subtract     
+keycode  75 = KP_4            
+	altgr	keycode  75 = Hex_4           
+	alt	keycode  75 = Ascii_4         
+keycode  76 = KP_5            
+	altgr	keycode  76 = Hex_5           
+	alt	keycode  76 = Ascii_5         
+keycode  77 = KP_6            
+	altgr	keycode  77 = Hex_6           
+	alt	keycode  77 = Ascii_6         
+keycode  78 = KP_Add          
+keycode  79 = KP_1            
+	altgr	keycode  79 = Hex_1           
+	alt	keycode  79 = Ascii_1         
+keycode  80 = KP_2            
+	altgr	keycode  80 = Hex_2           
+	alt	keycode  80 = Ascii_2         
+keycode  81 = KP_3            
+	altgr	keycode  81 = Hex_3           
+	alt	keycode  81 = Ascii_3         
+keycode  82 = KP_0            
+	altgr	keycode  82 = Hex_0           
+	alt	keycode  82 = Ascii_0         
+keycode  83 = KP_Period       
+	altgr	control	keycode  83 = Boot            
+	control	alt	keycode  83 = Boot            
+keycode  84 = Last_Console    
+keycode  85 =
+keycode  86 = less             greater          bar             
+	alt	keycode  86 = Meta_less       
+	shift	alt	keycode  86 = Meta_greater    
+keycode  87 = F11              F23              Console_23       F35             
+	alt	keycode  87 = Console_11      
+	control	alt	keycode  87 = Console_11      
+keycode  88 = F12              F24              Console_24       F36             
+	alt	keycode  88 = Console_12      
+	control	alt	keycode  88 = Console_12      
+keycode  89 =
+keycode  90 =
+keycode  91 =
+keycode  92 =
+keycode  93 =
+keycode  94 =
+keycode  95 =
+keycode  96 = KP_Enter        
+keycode  97 = Control         
+keycode  98 = KP_Divide       
+	altgr	keycode  98 = Hex_B           
+keycode  99 = Control_backslash
+	alt	keycode  99 = Meta_Control_backslash
+	shift	alt	keycode  99 = Meta_Control_backslash
+	control	alt	keycode  99 = Meta_Control_backslash
+keycode 100 = AltGr           
+keycode 101 = Break           
+keycode 102 = Find            
+keycode 103 = Up              
+	alt	keycode 103 = KeyboardSignal  
+keycode 104 = Prior           
+	shift	keycode 104 = Scroll_Backward 
+keycode 105 = Left            
+	alt	keycode 105 = Decr_Console    
+keycode 106 = Right           
+	alt	keycode 106 = Incr_Console    
+keycode 107 = Select          
+keycode 108 = Down            
+keycode 109 = Next            
+	shift	keycode 109 = Scroll_Forward  
+keycode 110 = Insert          
+keycode 111 = Remove          
+	altgr	control	keycode 111 = Boot            
+	control	alt	keycode 111 = Boot            
+keycode 112 = Macro           
+	altgr	control	keycode 112 = VoidSymbol      
+	shift	alt	keycode 112 = VoidSymbol      
+keycode 113 = F13             
+	altgr	control	keycode 113 = VoidSymbol      
+	shift	alt	keycode 113 = VoidSymbol      
+keycode 114 = F14             
+	altgr	control	keycode 114 = VoidSymbol      
+	shift	alt	keycode 114 = VoidSymbol      
+keycode 115 = Help            
+	altgr	control	keycode 115 = VoidSymbol      
+	shift	alt	keycode 115 = VoidSymbol      
+keycode 116 = Do              
+	altgr	control	keycode 116 = VoidSymbol      
+	shift	alt	keycode 116 = VoidSymbol      
+keycode 117 = F17             
+	altgr	control	keycode 117 = VoidSymbol      
+	shift	alt	keycode 117 = VoidSymbol      
+keycode 118 = KP_MinPlus      
+	altgr	control	keycode 118 = VoidSymbol      
+	shift	alt	keycode 118 = VoidSymbol      
+keycode 119 = Pause           
+keycode 120 =
+keycode 121 =
+keycode 122 =
+keycode 123 =
+keycode 124 =
+keycode 125 =
+keycode 126 =
+keycode 127 =
+string F1 = "\033[[A"
+string F2 = "\033[[B"
+string F3 = "\033[[C"
+string F4 = "\033[[D"
+string F5 = "\033[[E"
+string F6 = "\033[17~"
+string F7 = "\033[18~"
+string F8 = "\033[19~"
+string F9 = "\033[20~"
+string F10 = "\033[21~"
+string F11 = "\033[23~"
+string F12 = "\033[24~"
+string F13 = "\033[25~"
+string F14 = "\033[26~"
+string F15 = "\033[28~"
+string F16 = "\033[29~"
+string F17 = "\033[31~"
+string F18 = "\033[32~"
+string F19 = "\033[33~"
+string F20 = "\033[34~"
+string Find = "\033[1~"
+string Insert = "\033[2~"
+string Remove = "\033[3~"
+string Select = "\033[4~"
+string Prior = "\033[5~"
+string Next = "\033[6~"
+string Macro = "\033[M"
+string Pause = "\033[P"
+compose '`' 'A' to 'À'
+compose '`' 'a' to 'à'
+compose '\'' 'A' to 'Á'
+compose '\'' 'a' to 'á'
+compose '^' 'A' to 'Â'
+compose '^' 'a' to 'â'
+compose '~' 'A' to 'Ã'
+compose '~' 'a' to 'ã'
+compose '"' 'A' to 'Ä'
+compose '"' 'a' to 'ä'
+compose 'O' 'A' to 'Å'
+compose 'o' 'a' to 'å'
+compose '0' 'A' to 'Å'
+compose '0' 'a' to 'å'
+compose 'A' 'A' to 'Å'
+compose 'a' 'a' to 'å'
+compose 'A' 'E' to 'Æ'
+compose 'a' 'e' to 'æ'
+compose ',' 'C' to 'Ç'
+compose ',' 'c' to 'ç'
+compose '`' 'E' to 'È'
+compose '`' 'e' to 'è'
+compose '\'' 'E' to 'É'
+compose '\'' 'e' to 'é'
+compose '^' 'E' to 'Ê'
+compose '^' 'e' to 'ê'
+compose '"' 'E' to 'Ë'
+compose '"' 'e' to 'ë'
+compose '`' 'I' to 'Ì'
+compose '`' 'i' to 'ì'
+compose '\'' 'I' to 'Í'
+compose '\'' 'i' to 'í'
+compose '^' 'I' to 'Î'
+compose '^' 'i' to 'î'
+compose '"' 'I' to 'Ï'
+compose '"' 'i' to 'ï'
+compose '-' 'D' to 'Ð'
+compose '-' 'd' to 'ð'
+compose '~' 'N' to 'Ñ'
+compose '~' 'n' to 'ñ'
+compose '`' 'O' to 'Ò'
+compose '`' 'o' to 'ò'
+compose '\'' 'O' to 'Ó'
+compose '\'' 'o' to 'ó'
+compose '^' 'O' to 'Ô'
+compose '^' 'o' to 'ô'
+compose '~' 'O' to 'Õ'
+compose '~' 'o' to 'õ'
+compose '"' 'O' to 'Ö'
+compose '"' 'o' to 'ö'
+compose '/' 'O' to 'Ø'
+compose '/' 'o' to 'ø'
+compose '`' 'U' to 'Ù'
+compose '`' 'u' to 'ù'
+compose '\'' 'U' to 'Ú'
+compose '\'' 'u' to 'ú'
+compose '^' 'U' to 'Û'
+compose '^' 'u' to 'û'
+compose '"' 'U' to 'Ü'
+compose '"' 'u' to 'ü'
+compose '\'' 'Y' to 'Ý'
+compose '\'' 'y' to 'ý'
+compose 'T' 'H' to 'Þ'
+compose 't' 'h' to 'þ'
+compose 's' 's' to 'ß'
+compose '"' 'y' to 'ÿ'
+compose 's' 'z' to 'ß'
+compose 'i' 'j' to 'ÿ'
diff -urN linux-2.2.7-pre3/drivers/usb/maps/usb.map linux-2.2.7-pre4/drivers/usb/maps/usb.map
--- linux-2.2.7-pre3/drivers/usb/maps/usb.map	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/maps/usb.map	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,233 @@
+# USB kernel keymap.
+keymaps 0-2,4-5,8,12
+
+keycode   4 = a
+	altgr   keycode  30 = Hex_A
+keycode   5 = b
+	altgr   keycode  48 = Hex_B
+keycode   6 = c
+	altgr   keycode  46 = Hex_C   
+keycode   7 = d
+	altgr   keycode  32 = Hex_D   
+keycode   8 = e
+	altgr   keycode  18 = Hex_E   
+keycode   9 = f
+	altgr   keycode  33 = Hex_F               
+keycode  10 = g               
+keycode  11 = h               
+keycode  12 = i               
+keycode  13 = j               
+keycode  14 = k               
+keycode  15 = l               
+keycode  16 = m               
+keycode  17 = n               
+keycode  18 = o               
+keycode  19 = p               
+keycode  20 = q               
+keycode  21 = r               
+keycode  22 = s               
+keycode  23 = t               
+keycode  24 = u               
+keycode  25 = v               
+keycode  26 = w               
+keycode  27 = x               
+keycode  28 = y               
+keycode  29 = z               
+keycode  30 = one              exclam          
+	alt     keycode   2 = Meta_one        
+keycode  31 = two              at
+	control	keycode   3 = nul             
+	shift	control	keycode   3 = nul             
+	alt	keycode   3 = Meta_two        
+keycode  32 = three            numbersign      
+	control keycode   4 = Escape          
+	alt     keycode   4 = Meta_three      
+keycode  33 = four             dollar
+	control keycode   5 = Control_backslash
+	alt     keycode   5 = Meta_four       
+keycode  34 = five             percent         
+	control keycode   6 = Control_bracketright
+	alt     keycode   6 = Meta_five       
+keycode  35 = six              asciicircum     
+	control keycode   7 = Control_asciicircum
+	alt     keycode   7 = Meta_six        
+keycode  36 = seven            ampersand
+	control keycode   8 = Control_underscore
+	alt     keycode   8 = Meta_seven      
+keycode  37 = eight            asterisk
+	control keycode   9 = Delete          
+	alt     keycode   9 = Meta_eight      
+keycode  38 = nine             parenleft
+	alt     keycode  10 = Meta_nine       
+keycode  39 = zero             parenright
+	alt     keycode  11 = Meta_zero       
+keycode  40 = Return          
+	alt     keycode  28 = Meta_Control_m  
+keycode  41 = Escape           Escape          
+	alt     keycode   1 = Meta_Escape     
+keycode  42 = Delete           Delete          
+	control keycode  14 = BackSpace
+	alt     keycode  14 = Meta_Delete     
+keycode  43 = Tab              Tab             
+	alt     keycode  15 = Meta_Tab        
+keycode  44 = space            space           
+	control keycode  57 = nul             
+	alt     keycode  57 = Meta_space      
+keycode  45 = minus            underscore       backslash       
+	control	keycode  12 = Control_underscore
+	shift	control	keycode  12 = Control_underscore
+	alt	keycode  12 = Meta_minus      
+keycode  46 = equal            plus            
+	alt     keycode  13 = Meta_equal      
+keycode  47 = bracketleft      braceleft       
+	control keycode  26 = Escape          
+	alt     keycode  26 = Meta_bracketleft
+keycode  48 = bracketright     braceright       asciitilde      
+	control keycode  27 = Control_bracketright
+	alt     keycode  27 = Meta_bracketright
+keycode  49 = backslash        bar             
+	control keycode  43 = Control_backslash
+	alt     keycode  43 = Meta_backslash  
+keycode 50 =
+keycode  51 = semicolon        colon           
+	alt     keycode  39 = Meta_semicolon  
+keycode  52 = apostrophe       quotedbl        
+	control keycode  40 = Control_g       
+	alt     keycode  40 = Meta_apostrophe 
+keycode  53 = grave            asciitilde      
+	control keycode  41 = nul             
+	alt     keycode  41 = Meta_grave      
+keycode  54 = comma            less            
+	alt     keycode  51 = Meta_comma      
+keycode  55 = period           greater         
+	control keycode  52 = Compose         
+	alt     keycode  52 = Meta_period     
+keycode  56 = slash            question        
+	control keycode  53 = Delete          
+	alt     keycode  53 = Meta_slash      
+keycode  57 = Caps_Lock       
+keycode  58 = F1               F11              Console_13      
+	control keycode  59 = F1              
+	alt     keycode  59 = Console_1       
+	control alt     keycode  59 = Console_1       
+keycode  59 = F2               F12              Console_14      
+	control keycode  60 = F2              
+	alt     keycode  60 = Console_2       
+	control alt     keycode  60 = Console_2       
+keycode  60 = F3               F13              Console_15      
+	control keycode  61 = F3              
+	alt     keycode  61 = Console_3       
+	control alt     keycode  61 = Console_3       
+keycode  61 = F4               F14              Console_16      
+	control keycode  62 = F4              
+	alt     keycode  62 = Console_4       
+	control alt     keycode  62 = Console_4       
+keycode  62 = F5               F15              Console_17      
+	control keycode  63 = F5              
+	alt     keycode  63 = Console_5       
+	control alt     keycode  63 = Console_5       
+keycode  63 = F6               F16              Console_18      
+	control keycode  64 = F6              
+	alt     keycode  64 = Console_6       
+	control alt     keycode  64 = Console_6       
+keycode  64 = F7               F17              Console_19      
+	control keycode  65 = F7              
+	alt     keycode  65 = Console_7       
+	control alt     keycode  65 = Console_7       
+keycode  65 = F8               F18              Console_20      
+	control keycode  66 = F8              
+	alt     keycode  66 = Console_8       
+	control alt     keycode  66 = Console_8       
+keycode  66 = F9               F19              Console_21      
+	control keycode  67 = F9              
+	alt     keycode  67 = Console_9       
+	control alt     keycode  67 = Console_9       
+keycode  67 = F10              F20              Console_22      
+	control keycode  68 = F10             
+	alt     keycode  68 = Console_10      
+	control alt     keycode  68 = Console_10      
+keycode  68 = F11              F11              Console_23      
+	control keycode  87 = F11             
+	alt     keycode  87 = Console_11      
+	control alt     keycode  87 = Console_11      
+keycode  69 = F12              F12              Console_24      
+	control keycode  88 = F12             
+	alt     keycode  88 = Console_12      
+	control alt     keycode  88 = Console_12      
+keycode  70 = Print_Screen
+keycode  71 = Scroll_Lock      Show_Memory      Show_Registers  
+	control keycode  70 = Show_State      
+	alt     keycode  70 = Scroll_Lock     
+keycode  72 = Pause           
+keycode  73 = Insert          
+keycode  74 = Home
+keycode  75 = Prior           
+	shift   keycode 104 = Scroll_Backward 
+keycode  76 = Remove          
+#	altgr   control keycode 111 = Boot            
+	control alt     keycode 111 = Boot            
+keycode  77 = End
+keycode  78 = Next            
+	shift   keycode 109 = Scroll_Forward  
+keycode  79 = Right           
+	alt     keycode 106 = Incr_Console
+keycode  80 = Left            
+	alt     keycode 105 = Decr_Console
+keycode  81 = Down            
+keycode  82 = Up              
+keycode  83 = Num_Lock
+	shift   keycode  69 = Bare_Num_Lock
+keycode  84 = KP_Divide       
+keycode  85 = KP_Multiply     
+keycode  86 = KP_Subtract     
+keycode  87 = KP_Add          
+keycode  88 = KP_Enter        
+keycode  89 = KP_1            
+	alt     keycode  79 = Ascii_1         
+	altgr   keycode  79 = Hex_1         
+keycode  90 = KP_2            
+	alt     keycode  80 = Ascii_2         
+	altgr   keycode  80 = Hex_2         
+keycode  91 = KP_3            
+	alt     keycode  81 = Ascii_3         
+	altgr   keycode  81 = Hex_3         
+keycode  92 = KP_4            
+	alt     keycode  75 = Ascii_4         
+	altgr   keycode  75 = Hex_4         
+keycode  93 = KP_5            
+	alt     keycode  76 = Ascii_5         
+	altgr   keycode  76 = Hex_5         
+keycode  94 = KP_6            
+	alt     keycode  77 = Ascii_6         
+	altgr   keycode  77 = Hex_6         
+keycode  95 = KP_7            
+	alt     keycode  71 = Ascii_7         
+	altgr   keycode  71 = Hex_7         
+keycode  96 = KP_8            
+	alt     keycode  72 = Ascii_8         
+	altgr   keycode  72 = Hex_8         
+keycode  97 = KP_9            
+	alt     keycode  73 = Ascii_9         
+	altgr   keycode  73 = Hex_9         
+keycode  98 = KP_0            
+	alt     keycode  82 = Ascii_0         
+	altgr   keycode  82 = Hex_0         
+keycode  99 = KP_Period       
+#	altgr   control keycode  83 = Boot            
+	control alt     keycode  83 = Boot            
+keycode 100 =
+keycode 101 = Application
+keycode 102 =
+keycode 103 =
+keycode 104 = F13             
+keycode 105 = F14             
+
+# modifiers
+keycode 120 = Control
+keycode 121 = Shift
+keycode 122 = Alt
+keycode 123 = Window
+keycode 124 = Control_R
+keycode 125 = Shift_R
+keycode 126 = Alt_R
+keycode 127 = Window_R
diff -urN linux-2.2.7-pre3/drivers/usb/mkmap linux-2.2.7-pre4/drivers/usb/mkmap
--- linux-2.2.7-pre3/drivers/usb/mkmap	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/mkmap	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,83 @@
+#!/usr/bin/perl
+
+($ME = $0) =~ s|.*/||;
+
+$file = "maps/serial.map";
+$line = 1;
+open(PC, $file) || die("$!");
+while(<PC>)
+{
+    if(/^\s*keycode\s+(\d+)\s*=\s*(\S+)/)
+    {
+	my($idx) = int($1);
+	my($sym) = $2;
+	if(defined($map{uc($sym)}))
+	{
+	    # print STDERR "$file:$line: warning: `$sym' redefined\n";
+	}
+	$map{uc($sym)} = $idx;
+    }
+    $line++;
+}
+close(PC);
+
+$file = "maps/fixup.map";
+$line = 1;
+open(FIXUP, $file) || die("$!");
+while(<FIXUP>)
+{
+    if(/^\s*keycode\s+(\d+)\s*=\s*/)
+    {
+	my($idx) = int($1);
+	for $sym (split(/\s+/, $'))
+        {
+	    $map{uc($sym)} = $idx;
+	}
+    }
+    $line++;
+}
+close(FIXUP);
+
+$file = "maps/usb.map";
+$line = 1;
+open(USB, $file) || die("$!");
+while(<USB>)
+{
+    if(/^\s*keycode\s+(\d+)\s*=\s*/)
+    {
+	my($idx) = int($1);
+	for $sym (split(/\s+/, $'))
+        {
+	    my($val) = $map{uc($sym)};
+	    $map[$idx] = $val;
+	    if(!defined($val))
+	    {
+		print STDERR "$file:$line: warning: `$sym' undefined\n";
+	    }
+	    else
+	    {
+		last;
+	    }
+	}
+    }
+    $line++;
+}
+close(USB);
+
+print "unsigned char usb_kbd_map[256] = \n{\n";
+for($x = 0; $x < 32; $x++)
+{
+    if($x && !($x % 2))
+    {
+	print "\n";
+    }
+    print "  ";
+    for($y = 0; $y < 8; $y++)
+    {
+	my($idx) = $x * 8 + $y;
+	print sprintf("  0x%02x,",
+		      int(defined($map[$idx]) ? $map[$idx]:0));
+    }
+    print "\n";
+}
+print "};\n";
diff -urN linux-2.2.7-pre3/drivers/usb/mouse.c linux-2.2.7-pre4/drivers/usb/mouse.c
--- linux-2.2.7-pre3/drivers/usb/mouse.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/mouse.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,299 @@
+/*
+ * USB HID boot protocol mouse support based on MS BusMouse driver, psaux 
+ * driver, and Linus's skeleton USB mouse driver
+ *
+ * Brad Keryan 4/3/1999
+ *
+ * version 0.02: Hmm, the mouse seems drunk because I'm queueing the events.
+ * This is wrong: when an application (like X or gpm) reads the mouse device,
+ * it wants to find out the mouse's current position, not its recent history.
+ * The button thing turned out to be UHCI not flipping data toggle, so half the
+ * packets were thrown out.
+ *
+ * version 0.01: Switched over to busmouse protocol, and changed the minor
+ * number to 32 (same as uusbd's hidbp driver). Buttons work more sanely now, 
+ * but it still doesn't generate button events unless you move the mouse.
+ *
+ * version 0.0: Driver emulates a PS/2 mouse, stealing /dev/psaux (sorry, I 
+ * know that's not very nice). Moving in the X and Y axes works. Buttons don't
+ * work right yet: X sees a lot of MotionNotify/ButtonPress/ButtonRelease 
+ * combos when you hold down a button and drag the mouse around. Probably has 
+ * some additional bugs on an SMP machine.
+ */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/miscdevice.h>
+#include <linux/random.h>
+#include <linux/poll.h>
+#include <linux/init.h>
+#include <linux/malloc.h>
+
+#include <asm/spinlock.h>
+
+#include "usb.h"
+
+#define USB_MOUSE_MINOR 32
+
+struct mouse_state {
+	unsigned char buttons; /* current button state */
+	long dx; /* dx, dy, dz are change since last read */
+	long dy; 
+	long dz;
+	int present; /* this mouse is plugged in */
+	int active; /* someone is has this mouse's device open */
+	int ready; /* the mouse has changed state since the last read */
+	struct wait_queue *wait; /* for polling */
+	struct fasync_struct *fasync;
+	/* later, add a list here to support multiple mice */
+	/* but we will also need a list of file pointers to identify it */
+};
+
+static struct mouse_state static_mouse_state;
+
+spinlock_t usb_mouse_lock = SPIN_LOCK_UNLOCKED;
+
+static int mouse_irq(int state, void *__buffer, void *dev_id)
+{
+	signed char *data = __buffer;
+	/* finding the mouse is easy when there's only one */
+	struct mouse_state *mouse = &static_mouse_state; 
+
+	/* if a mouse moves with no one listening, do we care? no */
+	if(!mouse->active)
+		return 1;
+
+	/* if the USB mouse sends an interrupt, then something noteworthy
+	   must have happened */
+	mouse->buttons = data[0] & 0x07;
+	mouse->dx += data[1]; /* data[] is signed, so this works */
+	mouse->dy -= data[2]; /* y-axis is reversed */
+	mouse->dz += data[3];
+	mouse->ready = 1;
+
+	add_mouse_randomness((mouse->buttons << 24) + (mouse->dz << 16 ) + 
+				     (mouse->dy << 8) + mouse->dx);
+
+	wake_up_interruptible(&mouse->wait);
+	if (mouse->fasync)
+		kill_fasync(mouse->fasync, SIGIO);
+
+	return 1;
+}
+
+static int fasync_mouse(int fd, struct file *filp, int on)
+{
+	int retval;
+	struct mouse_state *mouse = &static_mouse_state;
+
+	retval = fasync_helper(fd, filp, on, &mouse->fasync);
+	if (retval < 0)
+		return retval;
+	return 0;
+}
+
+static int release_mouse(struct inode * inode, struct file * file)
+{
+	struct mouse_state *mouse = &static_mouse_state;
+
+	fasync_mouse(-1, file, 0);
+	if (--mouse->active)
+		return 0;
+	return 0;
+}
+
+static int open_mouse(struct inode * inode, struct file * file)
+{
+	struct mouse_state *mouse = &static_mouse_state;
+
+	if (!mouse->present)
+		return -EINVAL;
+	if (mouse->active++)
+		return 0;
+	/* flush state */
+	mouse->buttons = mouse->dx = mouse->dy = mouse->dz = 0;
+	return 0;
+}
+
+static ssize_t write_mouse(struct file * file,
+       const char * buffer, size_t count, loff_t *ppos)
+{
+	return -EINVAL;
+}
+
+/*
+ * Look like a PS/2 mouse, please..
+ *
+ * The PS/2 protocol is fairly strange, but
+ * oh, well, it's at least common..
+ */
+static ssize_t read_mouse(struct file * file, char * buffer, size_t count, loff_t *ppos)
+{
+	int retval = 0;
+	static int state = 0;
+	struct mouse_state *mouse = &static_mouse_state;
+
+	if (count) {
+		mouse->ready = 0;
+		switch (state) {
+		case 0: { /* buttons and sign */
+			int buttons = mouse->buttons;
+			mouse->buttons = 0;
+			if (mouse->dx < 0)
+				buttons |= 0x10;
+			if (mouse->dy < 0)
+				buttons |= 0x20;
+			put_user(buttons, buffer);
+			buffer++;
+			retval++;
+			state = 1;
+			if (!--count)
+				break;
+		}
+		case 1: { /* dx */
+			int dx = mouse->dx;
+			mouse->dx = 0;
+			put_user(dx, buffer);
+			buffer++;
+			retval++;
+			state = 2;
+			if (!--count)
+				break;
+		}
+		case 2:	{ /* dy */
+			int dy = mouse->dy;
+			mouse->dy = 0;
+			put_user(dy, buffer);
+			buffer++;
+			retval++;
+			state = 0;
+		}
+		break;
+		}
+	}
+	return retval;
+}
+
+static unsigned int mouse_poll(struct file *file, poll_table * wait)
+{
+	struct mouse_state *mouse = &static_mouse_state;
+
+	poll_wait(file, &mouse->wait, wait);
+	if (mouse->ready)
+		return POLLIN | POLLRDNORM;
+	return 0;
+}
+
+struct file_operations usb_mouse_fops = {
+	NULL,		/* mouse_seek */
+	read_mouse,
+	write_mouse,
+	NULL, 		/* mouse_readdir */
+	mouse_poll, 	/* mouse_poll */
+	NULL, 		/* mouse_ioctl */
+	NULL,		/* mouse_mmap */
+	open_mouse,
+	NULL,		/* flush */
+	release_mouse,
+	NULL,
+	fasync_mouse,
+};
+
+static struct miscdevice usb_mouse = {
+	USB_MOUSE_MINOR, "USB mouse", &usb_mouse_fops
+};
+
+static int mouse_probe(struct usb_device *dev)
+{
+	struct usb_interface_descriptor *interface;
+	struct usb_endpoint_descriptor *endpoint;
+	struct mouse_state *mouse = &static_mouse_state;
+
+	/* We don't handle multi-config mice */
+	if (dev->descriptor.bNumConfigurations != 1)
+		return -1;
+
+	/* We don't handle multi-interface mice */
+	if (dev->config[0].bNumInterfaces != 1)
+		return -1;
+
+	/* Is it a mouse interface? */
+	interface = &dev->config[0].interface[0];
+	if (interface->bInterfaceClass != 3)
+		return -1;
+	if (interface->bInterfaceSubClass != 1)
+		return -1;
+	if (interface->bInterfaceProtocol != 2)
+		return -1;
+
+	/* Multiple endpoints? What kind of mutant ninja-mouse is this? */
+	if (interface->bNumEndpoints != 1)
+		return -1;
+
+	endpoint = &interface->endpoint[0];
+
+	/* Output endpoint? Curiousier and curiousier.. */
+	if (!(endpoint->bEndpointAddress & 0x80))
+		return -1;
+
+	/* If it's not an interrupt endpoint, we'd better punt! */
+	if ((endpoint->bmAttributes & 3) != 3)
+		return -1;
+
+	printk("USB mouse found\n");
+
+	usb_set_configuration(dev, dev->config[0].bConfigurationValue);
+
+	usb_request_irq(dev, usb_rcvctrlpipe(dev, endpoint->bEndpointAddress), mouse_irq, endpoint->bInterval, NULL);
+
+	mouse->present = 1;
+	return 0;
+}
+
+static void mouse_disconnect(struct usb_device *dev)
+{
+	struct mouse_state *mouse = &static_mouse_state;
+
+	/* this might need work */
+	mouse->present = 0;
+}
+
+static struct usb_driver mouse_driver = {
+	"mouse",
+	mouse_probe,
+	mouse_disconnect,
+	{ NULL, NULL }
+};
+
+int usb_mouse_init(void)
+{
+	struct mouse_state *mouse = &static_mouse_state;
+
+	misc_register(&usb_mouse);
+
+	mouse->present = mouse->active = 0;
+	mouse->wait = NULL;
+	mouse->fasync = NULL;
+
+	usb_register(&mouse_driver);
+	printk(KERN_INFO "USB HID boot protocol mouse registered.\n");
+	return 0;
+}
+
+#if 0
+
+int init_module(void)
+{
+	return usb_mouse_init();
+}
+
+void cleanup_module(void)
+{
+	/* this, too, probably needs work */
+	usb_deregister(&mouse_driver);
+	misc_deregister(&usb_mouse);
+}
+
+#endif
diff -urN linux-2.2.7-pre3/drivers/usb/ohci.c linux-2.2.7-pre4/drivers/usb/ohci.c
--- linux-2.2.7-pre3/drivers/usb/ohci.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/ohci.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,1040 @@
+/*
+ * Open Host Controller Interface driver for USB.
+ *
+ * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
+ *
+ * This is the "other" host controller interface for USB.  You will
+ * find this on many non-Intel based motherboards, and of course the
+ * Mac.  As Linus hacked his UHCI driver together first, I modeled
+ * this after his.. (it should be obvious)
+ *
+ * From the programming standpoint the OHCI interface seems a little
+ * prettier and potentially less CPU intensive.  This remains to be
+ * proven.  In reality, I don't believe it'll make one darn bit of
+ * difference.  USB v1.1 is a slow bus by today's standards.
+ *
+ * OHCI hardware takes care of most of the scheduling of different
+ * transfer types with the correct prioritization for us.
+ *
+ * To get started in USB, I used the "Universal Serial Bus System
+ * Architecture" book by Mindshare, Inc.  It was a reasonable introduction
+ * and overview of USB and the two dominant host controller interfaces
+ * however you're better off just reading the real specs available
+ * from www.usb.org as you'll need them to get enough detailt to
+ * actually implement a HCD.  The book has many typos and omissions
+ * Beware, the specs are the victim of a committee.
+ *
+ * This code was written with Guinness on the brain, xsnow on the desktop
+ * and Orbital, Orb, Enya & Massive Attack on the CD player.  What a life!  ;) 
+ *
+ * No filesystems were harmed in the development of this code.
+ *
+ * $Id: ohci.c,v 1.11 1999/04/25 00:18:52 greg Exp $
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "ohci.h"
+#include "inits.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+static int apm_resume = 0;
+#endif
+
+static struct wait_queue *ohci_configure = NULL;
+
+
+static int ohci_td_result(struct ohci_device *dev, struct ohci_td *td)
+{
+	unsigned int status;
+
+	status = td->info & OHCI_TD_CC;
+
+	/* TODO Debugging code for TD failures goes here */
+
+	return status;
+}
+
+
+static spinlock_t ohci_edtd_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Add a TD to the end of the TD list on a given ED.  td->next_td is
+ * assumed to be set correctly for the situation of no TDs already
+ * being on the list (ie: pointing to NULL).
+ */
+static void ohci_add_td_to_ed(struct ohci_td *td, struct ohci_ed *ed)
+{
+	struct ohci_td *tail = bus_to_virt(ed->tail_td);
+	struct ohci_td *head = bus_to_virt(ed->head_td);
+	unsigned long flags;
+
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+	if (tail == head) {	/* empty list, put it on the head */
+		head = (struct ohci_td *) virt_to_bus(td);
+		tail = 0;
+	} else {
+		if (!tail) {	/* no tail, single element list */
+			td->next_td = head->next_td;
+			head->next_td = virt_to_bus(td);
+			tail = (struct ohci_td *) virt_to_bus(td);
+		} else {	/* append to the list */
+			td->next_td = tail->next_td;
+			tail->next_td = virt_to_bus(td);
+			tail = (struct ohci_td *) virt_to_bus(td);
+		}
+	}
+	/* save the reverse link */
+	td->ed_bus = virt_to_bus(ed);
+
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_add_td_to_ed() */
+
+
+/*
+ *  Remove a TD from the given EDs TD list
+ */
+static void ohci_remove_td_from_ed(struct ohci_td *td, struct ohci_ed *ed)
+{
+	struct ohci_td *head = bus_to_virt(ed->head_td);
+	struct ohci_td *tmp_td;
+	unsigned long flags;
+
+	spin_lock_irqsave(&ohci_edtd_lock, flags);
+
+	/* set the "skip me bit" in this ED */
+	writel_set(OHCI_ED_SKIP, ed->status);
+
+	/* XXX Assuming this list will never be circular */
+
+	if (td == head) {
+		/* unlink this TD; it was at the beginning */
+		ed->head_td = head->next_td;
+	}
+
+	tmp_td = head;
+	head = (struct ohci_td *) ed->head_td;
+	
+	while (head != NULL) {
+
+		if (td == head) {
+			/* unlink this TD from the middle or end */
+			tmp_td->next_td = head->next_td;
+		}
+
+		tmp_td = head;
+		head = bus_to_virt(head->next_td);
+	}
+
+	td->next_td = virt_to_bus(NULL);  /* remove links to ED list */
+
+	/* XXX mark this TD for possible cleanup? */
+
+	/* unset the "skip me bit" in this ED */
+	writel_mask(~(__u32)OHCI_ED_SKIP, ed->status);
+
+	spin_unlock_irqrestore(&ohci_edtd_lock, flags);
+} /* ohci_remove_td_from_ed() */
+
+
+/*
+ * Get a pointer (virtual) to an available TD from the given device's
+ * pool.
+ *
+ * Return NULL if none are left.
+ */
+static struct ohci_td *ohci_get_free_td(struct ohci_device *dev)
+{
+	int idx;
+
+	for (idx=0; idx < NUM_TDS; idx++) {
+		if (td_done(dev->td[idx].info)) {
+			/* XXX should this also zero out the structure? */
+			/* mark all new TDs as unaccessed */
+			dev->td[idx].info = OHCI_TD_CC_NEW;
+			return &dev->td[idx];
+		}
+	}
+
+	return NULL;
+} /* ohci_get_free_td() */
+
+
+/**********************************
+ * OHCI interrupt list operations *
+ **********************************/
+static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED;
+
+static void ohci_add_irq_list(struct ohci *ohci, struct ohci_td *td, usb_device_irq completed, void *dev_id)
+{
+	unsigned long flags;
+
+	/* save the irq in our private portion of the TD */
+	td->completed = completed;
+	td->dev_id = dev_id;
+
+	spin_lock_irqsave(&irqlist_lock, flags);
+	list_add(&td->irq_list, &ohci->interrupt_list);
+	spin_unlock_irqrestore(&irqlist_lock, flags);
+} /* ohci_add_irq_list() */
+
+static void ohci_remove_irq_list(struct ohci_td *td)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irqlist_lock, flags);
+	list_del(&td->irq_list);
+	spin_unlock_irqrestore(&irqlist_lock, flags);
+} /* ohci_remove_irq_list() */
+
+/*
+ * Request an interrupt handler for one "pipe" of a USB device.
+ * (this function is pretty minimal right now)
+ *
+ * At the moment this is only good for input interrupts. (ie: for a
+ * mouse)
+ *
+ * period is desired polling interval in ms.  The closest, shorter
+ * match will be used.  Powers of two from 1-32 are supported by OHCI.
+ */
+static int ohci_request_irq(struct usb_device *usb, unsigned int pipe,
+	usb_device_irq handler, int period, void *dev_id)
+{
+	struct ohci_device *dev = usb_to_ohci(usb);
+	struct ohci_td *td = dev->td;	/* */
+	struct ohci_ed *interrupt_ed;	/* endpoint descriptor for this irq */
+
+	/*
+	 * Pick a good frequency endpoint based on the requested period
+	 */
+	interrupt_ed = &dev->ohci->root_hub->ed[ms_to_ed_int(period)];
+
+	/*
+	 * Set the max packet size, device speed, endpoint number, usb
+	 * device number (function address), and type of TD.
+	 *
+	 * FIXME: Isochronous transfers need a pool of special 32 byte
+	 * TDs (32 byte aligned) in order to be supported.
+	 */
+	interrupt_ed->status = \
+		ed_set_maxpacket(usb_maxpacket(pipe)) |
+		ed_set_speed(usb_pipeslow(pipe)) |
+		usb_pipe_endpdev(pipe) |
+		OHCI_ED_F_NORM;
+
+	/*
+	 * Set the not accessed condition code, allow odd sized data,
+	 * and set the data transfer direction.
+	 */
+	td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
+		td_set_dir_out(usb_pipeout(pipe));
+
+	/* point it to our data buffer */
+	td->cur_buf = virt_to_bus(dev->data);
+
+	/* FIXME: we're only using 1 TD right now! */
+	td->next_td = virt_to_bus(&td);
+
+	/*
+	 * FIXME: be aware that OHCI won't advance out of the 4kb
+	 * page cur_buf started in.  It'll wrap around to the start
+	 * of the page...  annoying or useful? you decide.
+	 *
+	 * A pointer to the last *byte* in the buffer (ergh.. we get
+	 * to work around C's pointer arithmatic here with a typecast)
+	 */
+	td->buf_end = virt_to_bus(((u8*)(dev->data + DATA_BUF_LEN)) - 1);
+
+	/* does this make sense for ohci?.. time to think.. */
+	ohci_add_irq_list(dev->ohci, td, handler, dev_id);
+	wmb();     /* found in asm/system.h; scary concept... */
+	ohci_add_td_to_ed(td, interrupt_ed);
+
+	return 0;
+} /* ohci_request_irq() */
+
+/*
+ * Control thread operations:
+ */
+static struct wait_queue *control_wakeup;
+
+static int ohci_control_completed(int stats, void *buffer, void *dev_id)
+{
+	wake_up(&control_wakeup);
+	return 0;
+} /* ohci_control_completed() */
+
+
+/*
+ * Run a control transaction from the root hub's control endpoint.
+ * The passed in TD is the control transfer's Status TD.
+ */
+static int ohci_run_control(struct ohci_device *dev, struct ohci_td *status_td)
+{
+	struct wait_queue wait = { current, NULL };
+	struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
+
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue(&control_wakeup, &wait);
+
+	ohci_add_irq_list(dev->ohci, status_td, ohci_control_completed, NULL);
+	ohci_add_td_to_ed(status_td, control_ed);
+
+	/* FIXME? isn't this a little gross */
+	schedule_timeout(HZ/10);
+
+	ohci_remove_irq_list(status_td);
+	ohci_remove_td_from_ed(status_td, control_ed);
+
+	return ohci_td_result(dev, status_td);
+} /* ohci_run_control() */
+
+/*
+ * Send or receive a control message on a "pipe"
+ *
+ * A control message contains:
+ *   - The command itself
+ *   - An optional data phase
+ *   - Status complete phase
+ *
+ * The data phase can be an arbitrary number of TD's.  Currently since
+ * we use statically allocated TDs if too many come in we'll just
+ * start tossing them and printk() some warning goo...  Most control
+ * messages won't have much data anyways.
+ */
+static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, void *cmd, void *data, int len)
+{
+	struct ohci_device *dev = usb_to_ohci(usb);
+	/*
+	 * ideally dev->ed should be linked into the root hub's
+	 * control_ed list and used instead of just using it directly.
+	 * This could present a problem as is with more than one
+	 * device.  (but who wants to use a keyboard AND a mouse
+	 * anyways? ;)
+	 */
+	struct ohci_ed *control_ed = &dev->ohci->root_hub->ed[ED_CONTROL];
+	struct ohci_td *control_td;
+	struct ohci_td *data_td;
+	struct ohci_td *last_td;
+	__u32 data_td_info;
+
+	/*
+	 * Set the max packet size, device speed, endpoint number, usb
+	 * device number (function address), and type of TD.
+	 *
+	 */
+	control_ed->status = \
+		ed_set_maxpacket(usb_maxpacket(pipe)) |
+		ed_set_speed(usb_pipeslow(pipe)) |
+		usb_pipe_endpdev(pipe) |
+		OHCI_ED_F_NORM;
+
+	/*
+	 * Build the control TD
+	 */
+
+	/* get a TD to send this control message with */
+	control_td = ohci_get_free_td(dev);
+	/* TODO check for NULL */
+
+	/*
+	 * Set the not accessed condition code, allow odd sized data,
+	 * and set the data transfer type to SETUP.  Setup DATA always
+	 * uses a DATA0 packet.
+	 */
+	control_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND |
+		OHCI_TD_D_SETUP | OHCI_TD_IOC_OFF | td_force_toggle(0);
+
+	/* point it to the command */
+	control_td->cur_buf = virt_to_bus(cmd);
+
+	/* link to a free TD for the control data input */
+	data_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+	control_td->next_td = virt_to_bus(data_td);
+
+	/*
+	 * Build the DATA TDs
+	 */
+
+	data_td_info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | OHCI_TD_IOC_OFF |
+		td_set_dir_out(usb_pipeout(pipe));
+
+	while (len > 0) {
+		int pktsize = len;
+		struct ohci_td *tmp_td;
+
+		if (pktsize > usb_maxpacket(pipe))
+			pktsize = usb_maxpacket(pipe);
+
+		/* set the data transaction type */
+		data_td->info = data_td_info;
+		/* point to the current spot in the data buffer */
+		data_td->cur_buf = virt_to_bus(data);
+		/* point to the end of this data */
+		data_td->buf_end = virt_to_bus(data+pktsize-1);
+
+		/* allocate the next TD */
+		tmp_td = ohci_get_free_td(dev);  /* TODO check for NULL */
+		data_td->next_td = virt_to_bus(tmp_td);
+		data_td = tmp_td;
+
+		/* move on.. */
+		data += pktsize;
+		len -= pktsize;
+	}
+
+	/* point it at the newly allocated TD from above */
+	last_td = data_td;
+
+	/* The control status packet always uses a DATA1 */
+	last_td->info = OHCI_TD_CC_NEW | OHCI_TD_ROUND | td_force_toggle(1);
+	last_td->next_td = 0; /* end of TDs */
+	last_td->cur_buf = 0; /* no data in this packet */
+	last_td->buf_end = 0;
+
+	/*
+	 * Start the control transaction.. give it the last TD so the
+	 * result can be returned.
+	 */
+	return ohci_run_control(dev, last_td);
+} /* ohci_control_msg() */
+
+
+static struct usb_device *ohci_usb_allocate(struct usb_device *parent)
+{
+	struct usb_device *usb_dev;
+	struct ohci_device *dev;
+
+	usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
+	if (!usb_dev)
+		return NULL;
+
+	memset(usb_dev, 0, sizeof(*usb_dev));
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		kfree(usb_dev);
+		return NULL;
+	}
+
+	/* Initialize "dev" */
+	memset(dev, 0, sizeof(*dev));
+
+	usb_dev->hcpriv = dev;
+	dev->usb = usb_dev;
+
+	usb_dev->parent = parent;
+
+	if (parent) {
+		usb_dev->bus = parent->bus;
+		dev->ohci = usb_to_ohci(parent)->ohci;
+	}
+
+	return usb_dev;
+}
+
+static int ohci_usb_deallocate(struct usb_device *usb_dev)
+{
+	kfree(usb_to_ohci(usb_dev));
+	kfree(usb_dev);
+	return 0;
+}
+
+/*
+ * functions for the generic USB driver
+ */
+struct usb_operations ohci_device_operations = {
+	ohci_usb_allocate,
+	ohci_usb_deallocate,
+	ohci_control_msg,
+	ohci_request_irq,
+};
+
+/*
+ * Reset an OHCI controller
+ */
+static void reset_hc(struct ohci *ohci)
+{
+	writel((1<<31), &ohci->regs->intrdisable); /* Disable HC interrupts */
+	writel(1,  &ohci->regs->cmdstatus);	   /* HC Reset */
+	writel_mask(0x3f, &ohci->regs->control);   /* move to UsbReset state */
+} /* reset_hc() */
+
+
+/*
+ * Reset and start an OHCI controller
+ */
+static void start_hc(struct ohci *ohci)
+{
+	int timeout = 1000;	/* used to prevent an infinite loop. */
+
+	reset_hc(ohci);
+
+	while ((readl(&ohci->regs->control) & 0xc0) == 0) {
+		if (!--timeout) {
+			printk("USB HC Reset timed out!\n");
+			break;
+		}
+	}
+
+	/* Choose the interrupts we care about */
+	writel( OHCI_INTR_MIE | OHCI_INTR_RHSC | OHCI_INTR_SF |
+		OHCI_INTR_WDH | OHCI_INTR_SO | OHCI_INTR_UE |
+		OHCI_INTR_FNO,
+		&ohci->regs->intrenable);
+
+	/* Enter the USB Operational state & start the frames a flowing.. */
+	writel_set(OHCI_USB_OPER, &ohci->regs->control);
+
+} /* start_hc() */
+
+
+/*
+ * Reset a root hub port
+ */
+static void ohci_reset_port(struct ohci *ohci, unsigned int port)
+{
+	short ms;
+	int status;
+
+	/* Don't allow overflows. */
+	if (port >= MAX_ROOT_PORTS) {
+		printk("Bad port # passed to ohci_reset_port\n");
+		port = MAX_ROOT_PORTS-1;
+	}
+
+	writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);  /* Reset */
+
+	/*
+	 * Get the time required for a root hub port to reset and wait
+	 * it out (adding 1ms for good measure).
+	 */
+	ms = (readl(&ohci->regs->roothub.a) >> 24) * 2 + 1;
+	wait_ms(ms);
+
+	/* check port status to see that the reset completed */
+	status = readl(&ohci->regs->roothub.portstatus[port]);
+	if (status & PORT_PRS) {
+		/* reset failed, try harder? */
+		printk("usb-ohci: port %d reset failed, retrying\n", port);
+		writel(PORT_PRS, &ohci->regs->roothub.portstatus[port]);
+		wait_ms(50);
+	}
+
+	/* TODO we might need to re-enable the port here or is that
+	 * done elsewhere? */
+
+} /* ohci_reset_port */
+
+
+/*
+ * This gets called if the connect status on the root hub changes.
+ */
+static void ohci_connect_change(struct ohci * ohci, int port)
+{
+	struct usb_device *usb_dev;
+	struct ohci_device *dev;
+	/* memory I/O address of the port status register */
+	void *portaddr = &ohci->regs->roothub.portstatus[port];
+	int portstatus;	
+
+	/*
+	 * Because of the status change we have to forget
+	 * everything we think we know about the device
+	 * on this root hub port.  It may have changed.
+	 */
+	usb_disconnect(ohci->root_hub->usb->children + port);
+
+	portstatus = readl(portaddr);
+
+	/* disable the port if nothing is connected */
+	if (!(portstatus & PORT_CCS)) {
+		writel(PORT_CCS, portaddr);
+		return;
+	}
+
+	/*
+	 * Allocate a device for the new thingy that's been attached
+	 */
+	usb_dev = ohci_usb_allocate(ohci->root_hub->usb);
+	dev = usb_dev->hcpriv;
+
+	dev->ohci = ohci;
+
+	usb_connect(dev->usb);
+
+	/* link it into the bus's device tree */
+	ohci->root_hub->usb->children[port] = usb_dev;
+
+	wait_ms(200); /* wait for powerup; XXX is this needed? */
+	ohci_reset_port(ohci, port);
+
+	/* Get information on speed by using LSD */
+	usb_dev->slow = readl(portaddr) & PORT_LSDA ? 1 : 0;
+
+	/*
+	 * Do generic USB device tree processing on the new device.
+	 */
+	usb_new_device(usb_dev);
+} /* ohci_connect_change() */
+
+
+/*
+ * This gets called when the root hub configuration
+ * has changed.  Just go through each port, seeing if
+ * there is something interesting happening.
+ */
+static void ohci_check_configuration(struct ohci *ohci)
+{
+	int num = 0;
+	int maxport = readl(&ohci->regs->roothub) & 0xff;
+
+	do {
+		if (readl(ohci->regs->roothub.portstatus[num]) & PORT_CSC)
+			ohci_connect_change(ohci, num);
+	} while (++num < maxport);
+} /* ohci_check_configuration() */
+
+
+/*
+ * Get annoyed at the controller for bothering us.
+ */
+static void ohci_interrupt(int irq, void *__ohci, struct pt_regs *r)
+{
+	struct ohci *ohci = __ohci;
+	struct ohci_regs *regs = ohci->regs;
+	struct ohci_hcca *hcca = ohci->root_hub->hcca;
+	__u32 donehead = hcca->donehead;
+
+	/*
+	 * Check the interrupt status register if needed
+	 */
+	if (!donehead || (donehead & 1)) {
+		__u32 intrstatus = readl(&regs->intrstatus);
+
+		/*
+		 * XXX eek! printk's in an interrupt handler.  shoot me!
+		 */
+		if (intrstatus & OHCI_INTR_SO) {
+			printk(KERN_DEBUG "usb-ohci: scheduling overrun\n");
+		}
+		if (intrstatus & OHCI_INTR_RD) {
+			printk(KERN_DEBUG "usb-ohci: resume detected\n");
+		}
+		if (intrstatus & OHCI_INTR_UE) {
+			printk(KERN_DEBUG "usb-ohci: unrecoverable error\n");
+		}
+		if (intrstatus & OHCI_INTR_OC) {
+			printk(KERN_DEBUG "usb-ohci: ownership change?\n");
+		}
+
+		if (intrstatus & OHCI_INTR_RHSC) {
+			/* TODO Process events on the root hub */
+		}
+	}
+
+	/*
+	 * Process the done list
+	 */
+	if (donehead &= ~0x1) {
+		/*
+		 * TODO See which TD's completed..
+		 */
+	}
+
+	/* Re-enable done queue interrupts and reset the donehead */
+	hcca->donehead = 0;
+	writel(OHCI_INTR_WDH, &regs->intrenable);
+	
+} /* ohci_interrupt() */
+
+
+/*
+ * Allocate the resources required for running an OHCI controller.
+ * Host controller interrupts must not be running while calling this
+ * function or the penguins will get angry.
+ *
+ * The mem_base parameter must be the usable -virtual- address of the
+ * host controller's memory mapped I/O registers.
+ */
+static struct ohci *alloc_ohci(void* mem_base)
+{
+	int i;
+	struct ohci *ohci;
+	struct usb_bus *bus;
+	struct ohci_device *dev;
+	struct usb_device *usb;
+
+	ohci = kmalloc(sizeof(*ohci), GFP_KERNEL);
+	if (!ohci)
+		return NULL;
+
+	memset(ohci, 0, sizeof(*ohci));
+
+	ohci->irq = -1;
+	ohci->regs = mem_base;
+	INIT_LIST_HEAD(&ohci->interrupt_list);
+
+	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+
+	memset(bus, 0, sizeof(*bus));
+
+	ohci->bus = bus;
+	bus->hcpriv = ohci;
+	bus->op = &ohci_device_operations;
+
+	/*
+	 * Here we allocate our own root hub and TDs as well as the
+	 * OHCI host controller communications area.  The HCCA is just
+	 * a nice pool of memory with pointers to endpoint descriptors
+	 * for the different interrupts.
+	 */
+	usb = ohci_usb_allocate(NULL);
+	if (!usb)
+		return NULL;
+
+	dev = ohci->root_hub = usb_to_ohci(usb);
+
+	usb->bus = bus;
+
+	/* Initialize the root hub */
+	memset(dev, 0, sizeof(*dev));
+	dev->ohci = ohci;    /* link back to the controller */
+
+	/*
+	 * Allocate the Host Controller Communications Area
+	 */
+	dev->hcca = (struct ohci_hcca *) kmalloc(sizeof(*dev->hcca), GFP_KERNEL);
+
+	/* Tell the controller where the HCCA is */
+	writel(virt_to_bus(dev->hcca), &ohci->regs->hcca);
+
+	/* Get the number of ports on the root hub */
+	usb->maxchild = readl(&ohci->regs->roothub.a) & 0xff;
+	if (usb->maxchild > MAX_ROOT_PORTS) {
+		printk("usb-ohci: Limited to %d ports\n", MAX_ROOT_PORTS);
+		usb->maxchild = MAX_ROOT_PORTS;
+	}
+	if (usb->maxchild < 1) {
+		printk("usb-ohci: Less than one root hub port? Impossible!\n");
+		usb->maxchild = 1;
+	}
+	printk("usb-ohci: %d root hub ports found\n", usb->maxchild);
+
+	printk("alloc_ohci() controller\n");
+	show_ohci_status(ohci);
+	printk("alloc_ohci() root_hub device\n");
+	show_ohci_device(dev);
+
+	/*
+	 * Initialize the ED polling "tree" (for simplicity's sake in
+	 * this driver many nodes in the tree will be identical)
+	 */
+	dev->ed[ED_INT_32].next_ed = virt_to_bus(&dev->ed[ED_INT_16]);
+	dev->ed[ED_INT_16].next_ed = virt_to_bus(&dev->ed[ED_INT_8]);
+	dev->ed[ED_INT_8].next_ed = virt_to_bus(&dev->ed[ED_INT_4]);
+	dev->ed[ED_INT_4].next_ed = virt_to_bus(&dev->ed[ED_INT_2]);
+	dev->ed[ED_INT_2].next_ed = virt_to_bus(&dev->ed[ED_INT_1]);
+
+	/*
+	 * Initialize the polling table to call interrupts at the
+	 * intended intervals.
+	 */
+	for (i = 0; i < NUM_INTS; i++) {
+		if (i == 0)
+			dev->hcca->int_table[i] =
+				virt_to_bus(&dev->ed[ED_INT_32]);
+		else if (i & 1)
+			dev->hcca->int_table[i] =
+				virt_to_bus(&dev->ed[ED_INT_16]);
+		else if (i & 2)
+			dev->hcca->int_table[i] =
+				virt_to_bus(&dev->ed[ED_INT_8]);
+		else if (i & 4)
+			dev->hcca->int_table[i] =
+				virt_to_bus(&dev->ed[ED_INT_4]);
+		else if (i & 8)
+			dev->hcca->int_table[i] =
+				virt_to_bus(&dev->ed[ED_INT_2]);
+		else if (i & 16)
+			dev->hcca->int_table[i] =
+				virt_to_bus(&dev->ed[ED_INT_1]);
+	}
+
+	/*
+	 * Tell the controller where the control and bulk lists are
+	 */
+	writel(virt_to_bus(&dev->ed[ED_CONTROL]), &ohci->regs->ed_controlhead);
+	writel(virt_to_bus(&dev->ed[ED_BULK]), &ohci->regs->ed_bulkhead);
+
+	return ohci;
+} /* alloc_ohci() */
+
+
+/*
+ * De-allocate all resoueces..
+ */
+static void release_ohci(struct ohci *ohci)
+{
+	if (ohci->irq >= 0) {
+		free_irq(ohci->irq, ohci);
+		ohci->irq = -1;
+	}
+
+	if (ohci->root_hub) {
+		/* ensure that HC is stopped before releasing the HCCA */
+		writel(OHCI_USB_SUSPEND, &ohci->regs->control);
+		free_pages((unsigned int) ohci->root_hub->hcca, 1);
+		free_pages((unsigned int) ohci->root_hub, 1);
+		ohci->root_hub->hcca = NULL;
+		ohci->root_hub = NULL;
+	}
+
+	/* unmap the IO address space */
+	iounmap(ohci->regs);
+
+	/* If the ohci itself were dynamic we'd free it here */
+
+} /* release_ohci() */
+
+/*
+ * USB OHCI control thread
+ */
+static int ohci_control_thread(void * __ohci)
+{
+	struct ohci *ohci = (struct ohci *)__ohci;
+	
+	/*
+	 * I'm unfamiliar with the SMP kernel locking.. where should
+	 * this be released?  -greg
+	 */
+	lock_kernel();
+
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all of our resources..
+	 */
+	printk("ohci_control_thread at %p\n", &ohci_control_thread);
+	exit_mm(current);
+	exit_files(current);
+	exit_fs(current);
+
+	strcpy(current->comm, "ohci-control");
+
+	/*
+	 * Damn the torpedoes, full speed ahead
+	 */
+	start_hc(ohci);
+	do {
+		interruptible_sleep_on(&ohci_configure);
+#ifdef CONFIG_APM
+		if (apm_resume) {
+			apm_resume = 0;
+			start_hc(ohci);
+			continue;
+		}
+#endif
+		ohci_check_configuration(ohci);
+	} while (!signal_pending(current));
+
+	reset_hc(ohci);
+
+	release_ohci(ohci);
+	MOD_DEC_USE_COUNT;
+	return 0;
+} /* ohci_control_thread() */
+
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+	static int down = 0;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (down) {
+			printk(KERN_DEBUG "usb-ohci: received extra suspend event\n");
+			break;
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (!down) {
+			printk(KERN_DEBUG "usb-ohci: received bogus resume event\n");
+			break;
+		}
+		down = 0;
+		if (waitqueue_active(&ohci_configure)) {
+			apm_resume = 1;
+			wake_up(&ohci_configure);
+		}
+		break;
+	}
+	return 0;
+}
+#endif
+
+/* ... */
+
+/*
+ * Increment the module usage count, start the control thread and
+ * return success if the controller is good.
+ */
+static int found_ohci(int irq, void* mem_base)
+{
+	int retval;
+	struct ohci *ohci;
+
+	/* Allocate the running OHCI structures */
+	ohci = alloc_ohci(mem_base);
+	if (!ohci)
+		return -ENOMEM;
+
+	printk("usb-ohci: alloc_ohci() = %p\n", ohci);
+
+	reset_hc(ohci);
+
+	retval = -EBUSY;
+	if (request_irq(irq, ohci_interrupt, SA_SHIRQ, "usb-ohci", ohci) == 0) {
+		int pid;
+
+		MOD_INC_USE_COUNT;
+		ohci->irq = irq;
+
+		/* fork off the handler */
+		pid = kernel_thread(ohci_control_thread, ohci,
+				CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+		if (pid >= 0)
+			return 0;
+
+		MOD_DEC_USE_COUNT;
+		retval = pid;
+	}
+	release_ohci(ohci);
+	return retval;
+} /* found_ohci() */
+
+
+/*
+ * If this controller is for real, map the IO memory and proceed
+ */
+static int init_ohci(struct pci_dev *dev)
+{
+	unsigned int mem_base = dev->base_address[0];
+	
+	printk("usb-ohci: mem_base is %p\n", (void*)mem_base);
+
+	/* If its OHCI, its memory */
+	if (mem_base & PCI_BASE_ADDRESS_SPACE_IO)
+		return -ENODEV;
+
+	/* Get the memory address and map it for IO */
+	mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+	/* 
+	 * FIXME ioremap_nocache isn't implemented on all CPUs (such
+	 * as the Alpha) [?]  What should I use instead...
+	 *
+	 * The iounmap() is done on in release_ohci.
+	 */
+	mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
+
+	if (!mem_base) {
+		printk("Error mapping OHCI memory\n");
+		return -EFAULT;
+	}
+
+	return found_ohci(dev->irq, (void *) mem_base);
+} /* init_ohci() */
+
+
+#ifdef MODULE
+
+/*
+ *  Clean up when unloading the module
+ */
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+	apm_unregister_callback(&handle_apm_event);
+#endif
+}
+
+#define ohci_init init_module
+
+#endif
+
+
+/* TODO this should be named following Linux convention and go in pci.h */
+#define PCI_CLASS_SERIAL_USB_OHCI ((PCI_CLASS_SERIAL_USB << 8) | 0x0010)
+
+/*
+ * Search the PCI bus for an OHCI USB controller and set it up
+ *
+ * If anyone wants multiple controllers this will need to be
+ * updated..  Right now, it just picks the first one it finds.
+ */
+int ohci_init(void)
+{
+	int retval;
+	struct pci_dev *dev = NULL;
+	/*u8 type;*/
+
+	if (sizeof(struct ohci_device) > 4096) {
+		printk("usb-ohci: struct ohci_device to large\n");
+		return -ENODEV;
+	}
+
+	retval = -ENODEV;
+	for (;;) {
+		/* Find an OHCI USB controller */
+		dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev);
+		if (!dev)
+			break;
+
+		/* Verify that its OpenHCI by checking for MMIO */
+		/* pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
+		if (!type)
+			continue; */
+
+		/* Ok, set it up */
+		retval = init_ohci(dev);
+		if (retval < 0)
+			continue;
+
+		/* TODO check module params here to determine what to load */
+
+/*		usb_mouse_init(); */
+/*		usb_kbd_init();
+		hub_init();	*/
+#ifdef CONFIG_APM
+		apm_register_callback(&handle_apm_event);
+#endif
+
+		return 0; /* no error */
+	}
+	return retval;
+} /* init_module() */
+
+/* vim:sw=8
+ */
diff -urN linux-2.2.7-pre3/drivers/usb/ohci-debug.c linux-2.2.7-pre4/drivers/usb/ohci-debug.c
--- linux-2.2.7-pre3/drivers/usb/ohci-debug.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/ohci-debug.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,139 @@
+/*
+ * OHCI debugging code.  It's gross.
+ *
+ * (C) Copyright 1999 Gregory P. Smith
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include "ohci.h"
+
+void show_ohci_status(struct ohci *ohci)
+{
+	struct ohci_regs regs;
+	int i;
+
+	regs.revision = readl(ohci->regs->revision);
+	regs.control = readl(ohci->regs->control);
+	regs.cmdstatus = readl(ohci->regs->cmdstatus);
+	regs.intrstatus = readl(ohci->regs->intrstatus);
+	regs.intrenable = readl(ohci->regs->intrenable);
+	regs.intrdisable = readl(ohci->regs->intrdisable);
+	regs.hcca = readl(ohci->regs->hcca);
+	regs.ed_periodcurrent = readl(ohci->regs->ed_periodcurrent);
+	regs.ed_controlhead = readl(ohci->regs->ed_controlhead);
+	regs.ed_bulkhead = readl(ohci->regs->ed_bulkhead);
+	regs.ed_bulkcurrent = readl(ohci->regs->ed_bulkcurrent);
+	regs.current_donehead = readl(ohci->regs->current_donehead);
+	regs.fminterval = readl(ohci->regs->fminterval);
+	regs.fmremaining = readl(ohci->regs->fmremaining);
+	regs.fmnumber = readl(ohci->regs->fmnumber);
+	regs.periodicstart = readl(ohci->regs->periodicstart);
+	regs.lsthresh = readl(ohci->regs->lsthresh);
+	regs.roothub.a = readl(ohci->regs->roothub.a);
+	regs.roothub.b = readl(ohci->regs->roothub.b);
+	regs.roothub.status = readl(ohci->regs->roothub.status);
+	for (i=0; i<MAX_ROOT_PORTS; ++i)
+		regs.roothub.portstatus[i] = readl(ohci->regs->roothub.portstatus[i]);
+
+	printk("  ohci revision    =  0x%x\n", regs.revision);
+	printk("  ohci control     =  0x%x\n", regs.control);
+	printk("  ohci cmdstatus   =  0x%x\n", regs.cmdstatus);
+	printk("  ohci intrstatus  =  0x%x\n", regs.intrstatus);
+	printk("  ohci roothub.a   =  0x%x\n", regs.roothub.a);
+	printk("  ohci roothub.b   =  0x%x\n", regs.roothub.b);
+	printk("  ohci root status =  0x%x\n", regs.roothub.status);
+} /* show_ohci_status() */
+
+
+static void show_ohci_ed(struct ohci_ed *ed)
+{
+	int stat = ed->status;
+	int skip = (stat & OHCI_ED_SKIP);
+	int mps = (stat & OHCI_ED_MPS) >> 16;
+	int isoc = (stat & OHCI_ED_F_ISOC);
+	int low_speed = (stat & OHCI_ED_S_LOW);
+	int dir = (stat & OHCI_ED_D);
+	int endnum = (stat & OHCI_ED_EN) >> 7;
+	int funcaddr = (stat & OHCI_ED_FA);
+	int halted = (ed->head_td & 1);
+	int toggle = (ed->head_td & 2) >> 1;
+
+	printk("   ohci ED:\n");
+	printk("     status     =  0x%x\n", stat);
+	printk("       %sMPS %d%s%s%s%s tc%d e%d fa%d\n",
+			skip ? "Skip " : "",
+			mps,
+			isoc ? "Isoc. " : "",
+			low_speed ? "LowSpd " : "",
+			(dir == OHCI_ED_D_IN) ? "Input " :
+			(dir == OHCI_ED_D_OUT) ? "Output " : "",
+			halted ? "Halted " : "",
+			toggle,
+			endnum,
+			funcaddr);
+	printk("     tail_td    =  0x%x\n", ed->tail_td);
+	printk("     head_td    =  0x%x\n", ed->head_td);
+	printk("     next_ed    =  0x%x\n", ed->next_ed);
+} /* show_ohci_ed() */
+
+
+static void show_ohci_td(struct ohci_td *td)
+{
+	int td_round = td->info & OHCI_TD_ROUND;
+	int td_dir = td->info & OHCI_TD_D;
+	int td_int_delay = td->info & OHCI_TD_IOC_DELAY;
+	int td_toggle = td->info & OHCI_TD_DT;
+	int td_errcnt = td_errorcount(td->info);
+	int td_cc = td->info & OHCI_TD_CC;
+
+	printk("   ohci TD hardware fields:\n");
+	printk("      info     =  0x%x\n", td->info);
+	printk("        %s%s%s%d%s%s%d%s%d\n",
+		td_round ? "Rounding " : "",
+		(td_dir == OHCI_TD_D_IN) ? "Input " :
+		(td_dir == OHCI_TD_D_OUT) ? "Output " :
+		(td_dir == OHCI_TD_D_SETUP) ? "Setup " : "",
+		"IntDelay ", td_int_delay >> 21,
+		td_toggle ? "Data1 " : "Data0 ",
+		"ErrorCnt ", td_errcnt,
+		"ComplCode ", td_cc);
+	printk("       %sAccessed, %sActive\n",
+			td_cc_accessed(td->info) ? "" : "Not ",
+			td_active(td->info) ? "" : "Not ");
+
+	printk("      cur_buf  =  0x%x\n", td->cur_buf);
+	printk("      next_td  =  0x%x\n", td->next_td);
+	printk("      buf_end  =  0x%x\n", td->buf_end);
+	printk("   ohci TD driver fields:\n");
+	printk("      data     =  %p\n", td->data);
+	printk("      dev_id   =  %p\n", td->dev_id);
+	printk("      ed_bus   =  %x\n", td->ed_bus);
+} /* show_ohci_td() */
+
+
+void show_ohci_device(struct ohci_device *dev)
+{
+	int idx;
+	printk("  ohci_device usb       =  %p\n", dev->usb);
+	printk("  ohci_device ohci      =  %p\n", dev->ohci);
+	printk("  ohci_device ohci_hcca =  %p\n", dev->hcca);
+	for (idx=0; idx<8 /*NUM_EDS*/; ++idx) {
+		printk("   [ed num %d] ", idx);
+		show_ohci_ed(&dev->ed[idx]);
+	}
+	for (idx=0; idx<8 /*NUM_TDS*/; ++idx) {
+		printk("   [td num %d] ", idx);
+		show_ohci_td(&dev->td[idx]);
+	}
+	printk("  ohci_device data\n    ");
+	for (idx=0; idx<4; ++idx) {
+		printk(" %08lx", dev->data[idx]);
+	}
+	printk("\n");
+} /* show_ohci_device() */
+
+
+/* vim:sw=8
+ */
diff -urN linux-2.2.7-pre3/drivers/usb/ohci.h linux-2.2.7-pre4/drivers/usb/ohci.h
--- linux-2.2.7-pre3/drivers/usb/ohci.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/ohci.h	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,301 @@
+#ifndef __LINUX_OHCI_H
+#define __LINUX_OHCI_H
+
+/*
+ * Open Host Controller Interface data structures and defines.
+ *
+ * (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com>
+ *
+ * $Id: ohci.h,v 1.6 1999/04/24 22:50:06 greg Exp $
+ */
+
+#include <linux/list.h>
+#include <asm/io.h>
+
+#include "usb.h"
+
+/*
+ * Each TD must be aligned on a 16-byte boundary.  From the OHCI v1.0 spec
+ * it does not state that TDs must be contiguious in memory (due to the
+ * use of the next_td field).  This gives us extra room at the end of a
+ * TD for our own driver specific data.
+ *
+ * This structure's size must be a multiple of 16 bytes.
+ */
+struct ohci_td {
+    	/* OHCI Hardware fields */
+    	__u32 info;
+	__u32 cur_buf;		/* Current Buffer Pointer */
+	__u32 next_td;		/* Next TD Pointer */
+	__u32 buf_end;		/* Memory Buffer End Pointer */
+
+	/* Driver specific fields */
+	struct list_head irq_list;	/* Active interrupt list */
+	usb_device_irq completed;	/* Completion handler routine */
+	void *data;	/* XXX ? */
+	void *dev_id;	/* XXX ? */
+	__u32 ed_bus;			/* bus address of original ED */
+} __attribute((aligned(32)));
+
+#define OHCI_TD_ROUND	(1 << 18)	/* buffer rounding bit */
+#define OHCI_TD_D	(3 << 11)	/* direction of xfer: */
+#define OHCI_TD_D_IN	(2 << 11)
+#define OHCI_TD_D_OUT	(1 << 11)
+#define OHCI_TD_D_SETUP (0)
+#define td_set_dir_in(d)	((d) ? OHCI_TD_D_IN : OHCI_TD_D_OUT )
+#define td_set_dir_out(d)	((d) ? OHCI_TD_D_OUT : OHCI_TD_D_IN )
+#define OHCI_TD_IOC_DELAY (7 << 21)	/* frame delay allowed before int. */
+#define OHCI_TD_IOC_OFF	(OHCI_TD_IOC_DELAY)	/* no interrupt on complete */
+#define OHCI_TD_DT	(3 << 24)	/* data toggle bits */
+#define td_force_toggle(b)	(((b) | 2) << 24)
+#define OHCI_TD_ERRCNT	(3 << 26)	/* error count */
+#define td_errorcount(td)	(((td) >> 26) & 3)
+#define OHCI_TD_CC	(0xf << 28)	/* condition code */
+#define OHCI_TD_CC_NEW	(OHCI_TD_CC)	/* set this on all unaccessed TDs! */
+#define td_cc_notaccessed(td)	((td >> 29) == 7)
+#define td_cc_accessed(td)	((td >> 29) != 7)
+#define td_cc_noerror(td)	(((td) & OHCI_TD_CC) == 0)
+#define td_active(td)	(!td_cc_noerror((td)) && (td_errorcount((td)) < 3))
+#define td_done(td)	(td_cc_noerror((td)) || (td_errorcount((td)) == 3))
+
+/*
+ * The endpoint descriptors also requires 16-byte alignment
+ */
+struct ohci_ed {
+	/* OHCI hardware fields */
+	__u32 status;
+	__u32 tail_td;	/* TD Queue tail pointer */
+	__u32 head_td;	/* TD Queue head pointer */
+	__u32 next_ed;	/* Next ED */
+} __attribute((aligned(16)));
+
+#define OHCI_ED_SKIP	(1 << 14)
+#define OHCI_ED_MPS	(0x7ff << 16)
+/* FIXME: should cap at the USB max packet size [0x4ff] */
+#define ed_set_maxpacket(s)	(((s) << 16) & OHCI_ED_MPS)
+#define OHCI_ED_F_NORM	(0)
+#define OHCI_ED_F_ISOC	(1 << 15)
+#define ed_set_type_isoc(i)	((i) ? OHCI_ED_F_ISOC : OHCI_ED_F_NORM)
+#define OHCI_ED_S_LOW	(1 << 13)
+#define OHCI_ED_S_HIGH	(0)
+#define ed_set_speed(s)		((s) ? OHCI_ED_S_LOW : OHCI_ED_S_HIGH)
+#define OHCI_ED_D	(3 << 11)
+#define OHCI_ED_D_IN	(2 << 11)
+#define OHCI_ED_D_OUT	(1 << 11)
+#define ed_set_dir_in(d)	((d) ? OHCI_ED_D_IN : OHCI_ED_D_OUT)
+#define ed_set_dir_out(d)	((d) ? OHCI_ED_D_OUT : OHCI_ED_D_IN)
+#define OHCI_ED_EN	(0xf << 7)
+#define OHCI_ED_FA	(0x7f)
+
+
+/* NOTE: bits 27-31 of the status dword are reserved for the driver */
+/*
+ * We'll use this status flag for the non-predefined EDs to mark if
+ * they're in use or not.
+ *
+ * FIXME: unimplemented (needed?)
+ */
+#define ED_USED	(1 << 31)
+
+/*
+ * The HCCA (Host Controller Communications Area) is a 256 byte
+ * structure defined in the OHCI spec. that the host controller is
+ * told the base address of.  It must be 256-byte aligned.
+ */
+#define NUM_INTS 32	/* part of the OHCI standard */
+struct ohci_hcca {
+    	__u32	int_table[NUM_INTS];	/* Interrupt ED table */
+	__u16	frame_no;		/* current frame number */
+	__u16	pad1;			/* set to 0 on each frame_no change */
+	__u32	donehead;		/* info returned for an interrupt */
+	u8	reserved_for_hc[116];
+} __attribute((aligned(256)));
+
+/*
+ * The TD entries here are pre-allocated as Linus did with his simple
+ * UHCI implementation.  With the current state of this driver that
+ * shouldn't be a problem.  However if someone ever connects 127
+ * supported devices to this driver and tries to use them all at once:
+ * 	a)  They're insane!
+ * 	b)  They should code in dynamic allocation
+ */
+struct ohci;
+
+/*
+ *  Warning: These constants must not be so large as to cause the
+ *  ohci_device structure to exceed one 4096 byte page.  Or "weird
+ *  things will happen" as the alloc_ohci() function assumes that
+ *  its less than one page.  (FIXME)
+ */
+#define NUM_TDS	32		/* num of preallocated transfer descriptors */
+#define DATA_BUF_LEN 16		/* num of unsigned long's for the data buf */
+
+/*
+ * For this "simple" driver we only support a single ED for each
+ * polling rate.
+ *
+ * Later on this driver should be extended to use a full tree of EDs
+ * so that there can be 32 different 32ms polling frames, etc.
+ * Individual devices shouldn't need as many as the root hub in that
+ * case; complicating how things are done at the moment.
+ *
+ * Bulk and Control transfers hang off of their own ED lists.
+ */
+#define NUM_EDS 16		/* num of preallocated endpoint descriptors */
+
+#define ohci_to_usb(ohci)	((ohci)->usb)
+#define usb_to_ohci(usb)	((struct ohci_device *)(usb)->hcpriv)
+
+/* The usb_device must be first! */
+struct ohci_device {
+    	struct usb_device	*usb;
+
+	struct ohci		*ohci;
+	struct ohci_hcca 	*hcca;		/* OHCI mem. mapped IO area */
+
+	struct ohci_ed		ed[NUM_EDS];	/* Endpoint Descriptors */
+	struct ohci_td		td[NUM_TDS];	/* Transfer Descriptors */
+
+	unsigned long		data[DATA_BUF_LEN];
+};
+
+/* .... */
+
+#define ED_INT_1	0
+#define ED_INT_2	1
+#define ED_INT_4	2
+#define ED_INT_8	3
+#define ED_INT_16	4
+#define ED_INT_32	5
+#define ED_CONTROL	6
+#define ED_BULK		7
+#define ED_ISO		ED_INT_1	/* same as 1ms interrupt queue */
+#define ED_FIRST_AVAIL  8		/* first non-reserved ED */
+
+/*
+ * Given a period p in ms, convert it to the closest endpoint
+ * interrupt frequency; rounding down.  I'm sure many feel that this
+ * is a gross macro.  Feel free to toss it for actual code.
+ */
+#define ms_to_ed_int(p) \
+	((p >= 32) ? ED_INT_32 : \
+	 ((p & 16) ? ED_INT_16 : \
+	  ((p & 8) ? ED_INT_8 : \
+	   ((p & 4) ? ED_INT_4 : \
+	    ((p & 2) ? ED_INT_2 : \
+	     ED_INT_1)))))  /* hmm.. scheme or lisp anyone? */
+
+/*
+ * This is the maximum number of root hub ports.  I don't think we'll
+ * ever see more than two as that's the space available on an ATX
+ * motherboard's case, but it could happen.  The OHCI spec allows for
+ * up to 15... (which is insane!)
+ * 
+ * Although I suppose several "ports" could be connected directly to
+ * internal laptop devices such as a keyboard, mouse, camera and
+ * serial/parallel ports.  hmm...  That'd be neat.
+ */
+#define MAX_ROOT_PORTS	15	/* maximum OHCI root hub ports */
+
+/*
+ * This is the structure of the OHCI controller's memory mapped I/O
+ * region.  This is Memory Mapped I/O.  You must use the readl() and
+ * writel() macros defined in asm/io.h to access these!!
+ */
+struct ohci_regs {
+	/* control and status registers */
+	__u32	revision;
+	__u32	control;
+	__u32	cmdstatus;
+	__u32	intrstatus;
+	__u32	intrenable;
+	__u32	intrdisable;
+	/* memory pointers */
+	__u32	hcca;
+	__u32	ed_periodcurrent;
+	__u32	ed_controlhead;
+	__u32	ed_controlcurrent;
+	__u32	ed_bulkhead;
+	__u32	ed_bulkcurrent;
+	__u32	current_donehead; /* The driver should get this from the HCCA */
+	/* frame counters */
+	__u32	fminterval;
+	__u32	fmremaining;
+	__u32	fmnumber;
+	__u32	periodicstart;
+	__u32	lsthresh;
+	/* Root hub ports */
+	struct	ohci_roothub_regs {
+		__u32	a;
+		__u32	b;
+		__u32	status;
+		__u32	portstatus[MAX_ROOT_PORTS];
+	} roothub;
+} __attribute((aligned(32)));
+
+/* 
+ * Read a MMIO register and re-write it after ANDing with (m)
+ */
+#define writel_mask(m, a) writel( (readl((__u32)(a))) & (__u32)(m), (__u32)(a) )
+
+/*
+ * Read a MMIO register and re-write it after ORing with (b)
+ */
+#define writel_set(b, a) writel( (readl((__u32)(a))) | (__u32)(b), (__u32)(a) )
+
+
+#define PORT_CCS	(1)		/* port current connect status */
+#define PORT_PES	(1 << 1)	/* port enable status */
+#define PORT_PSS	(1 << 2)	/* port suspend status */
+#define PORT_POCI	(1 << 3)	/* port overcurrent indicator */
+#define PORT_PRS	(1 << 4)	/* port reset status */
+#define PORT_PPS	(1 << 8)	/* port power status */
+#define PORT_LSDA	(1 << 9)	/* port low speed dev. attached */
+#define PORT_CSC	(1 << 16)	/* port connect status change */
+#define PORT_PESC	(1 << 17)	/* port enable status change */
+#define PORT_PSSC	(1 << 18)	/* port suspend status change */
+#define PORT_OCIC	(1 << 19)	/* port over current indicator chg */
+#define PORT_PRSC	(1 << 20)	/* port reset status change */
+
+
+/*
+ * Interrupt register masks
+ */
+#define OHCI_INTR_SO	(1)
+#define OHCI_INTR_WDH	(1 << 1)
+#define OHCI_INTR_SF	(1 << 2)
+#define OHCI_INTR_RD	(1 << 3)
+#define OHCI_INTR_UE	(1 << 4)
+#define OHCI_INTR_FNO	(1 << 5)
+#define OHCI_INTR_RHSC	(1 << 6)
+#define OHCI_INTR_OC	(1 << 30)
+#define OHCI_INTR_MIE	(1 << 31)
+
+/*
+ * Control register masks
+ */
+#define OHCI_USB_OPER		(2 << 6)
+#define OHCI_USB_SUSPEND	(3 << 6)
+
+/*
+ * This is the full ohci controller description
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs. (Linus)
+ */
+struct ohci {
+    	int irq;
+	struct ohci_regs *regs;			/* OHCI controller's memory */
+	struct usb_bus *bus;
+	struct ohci_device *root_hub;		/* Root hub & controller */
+	struct list_head interrupt_list;	/* List of interrupt active TDs for this OHCI */
+};
+
+/* Debugging code */
+void show_ed(struct ohci_ed *ed);
+void show_td(struct ohci_td *td);
+void show_status(struct ohci *ohci);
+
+#endif
+/* vim:sw=8
+ */
diff -urN linux-2.2.7-pre3/drivers/usb/README.kbd linux-2.2.7-pre4/drivers/usb/README.kbd
--- linux-2.2.7-pre3/drivers/usb/README.kbd	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/README.kbd	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,65 @@
+This is a simple USB keyboard driver written from Linus'
+USB driver (started with Greg's usb-0.03b.tar.gz source
+tree)
+
+It works fine with my BTC keyboard but I'm still investigating
+trouble with my MS keyboard (trouble starts with an inability
+to set into boot protocol mode, though, this very well could
+be all due to crappy hardware).
+
+Anyway, I would appreciate you taking a look if you have
+any USB keyboards lying around.  Oh also, I'm doing this on
+UHCI so sorry if it breaks with OHCI.
+
+-ham
+
+
+
+Keyboard patch
+--------------
+
+Instead of using the multiple keyboard patch and then running into all
+of the kernel version problems that the current Linux-USB project has
+had, I'm just mapping the USB keycodes to the standard AT-101 keycodes
+and sending them directly to "handle_scancode".
+
+This may or may not be considered a hack.  Anyway it is effective, and
+I think safe, and allows USB keyboards to coexist with a serial
+keyboard (oh yeah, one side effect is that you can for example hold
+down the control key on the serial keyboard and press "a" on the USB
+keyboard and you get Control-a like with Windows USB) and works
+fine for console and X.
+
+You do need to make a *tiny* patch the kernel source tree so that the
+function "handle_scancode" is exported from keyboard.c though.
+
+  $ cd /usr/src/linux
+  $ patch -p0 < kbd.patch
+
+And, of course, then, you need to rebuild and install the kernel.
+
+** [Vojtech]: Alternately, just 'insmod kbd-stub', if you don't want
+to use the keyboard and are too lazy to patch the kernel.
+
+Keyboard map
+------------
+
+I'm including a stupid utility "mkmap" which generates the USB->serial
+keymap.  It takes in maps/serial.map (the current serial keymap,
+generated by "dumpkeys"), maps/usb.map (the USB keymap), and
+maps/fixup.map (fixes for e0 keys and misc.) and spits out keymap.c
+Anyway, it is not beautiful but should serve its purpose for the
+moment.
+
+Other changes
+-------------
+uhci.c:
+  * added a context value to the irq callback function
+    (this is exactly like the "dev_id" field to request_irq)
+  * played with uhci_reset_port to get better hot-plug results
+    (eg. do a wait_ms(200) before calling uhci_reset_port)
+usb.c:
+  * disconnect all devices after uhci-control thread is killed
+  * skip over the HID descriptor
+  * disconnect the high-level driver in usb_disconnect
+
diff -urN linux-2.2.7-pre3/drivers/usb/README.ohci linux-2.2.7-pre4/drivers/usb/README.ohci
--- linux-2.2.7-pre3/drivers/usb/README.ohci	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/README.ohci	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,8 @@
+April 24, 1999 04:37:42 PST
+
+Okay, I've written a lot more of the OHCI code and actually got it back to
+a compiling state now with all of the recent improvements to the way stuff
+is structured.  It is completely untested.
+
+- greg@electricrain.com
+
diff -urN linux-2.2.7-pre3/drivers/usb/restart linux-2.2.7-pre4/drivers/usb/restart
--- linux-2.2.7-pre3/drivers/usb/restart	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/restart	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,35 @@
+#!/bin/sh
+
+ME=`basename $0`
+
+#UMOD=`lsmod | grep '^bp-mouse' | grep -v grep`
+#if test "$UMOD"; then
+#  echo "$ME: removing bp-mouse.o"
+#  if ! rmmod bp-mouse; then
+#    echo "$ME: cannot remove bp-mouse.o"
+#    exit 1
+#  fi
+#fi
+
+UPID=`ps aux | grep uhci-control | grep -v grep | awk '{print $2}'`
+if test "$UPID"; then
+  echo "$ME: killing $UPID"
+  kill $UPID
+fi
+
+UMOD=`lsmod | grep '^usb-uhci' | grep -v grep`
+if test "$UMOD"; then
+  echo "$ME: removing usb-uhci.o"
+  sleep 1
+  if ! rmmod usb-uhci; then
+    echo "$ME: cannot remove usb-uhci.o"
+    exit 1
+  fi
+fi
+
+dmesg -c > /dev/null
+
+echo "$ME: starting usb-uhci.o"
+insmod -m usb-uhci.o > usb-uhci.map
+#echo "$ME: starting bp-mouse.o"
+#insmod -m bp-mouse.o > bp-mouse.map
diff -urN linux-2.2.7-pre3/drivers/usb/stopusb linux-2.2.7-pre4/drivers/usb/stopusb
--- linux-2.2.7-pre3/drivers/usb/stopusb	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/stopusb	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,8 @@
+#!/bin/sh
+
+killall uhci-control
+killall khubd
+
+sleep 1
+
+rmmod usb-uhci
diff -urN linux-2.2.7-pre3/drivers/usb/uhci.c linux-2.2.7-pre4/drivers/usb/uhci.c
--- linux-2.2.7-pre3/drivers/usb/uhci.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/uhci.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,1195 @@
+/*
+ * Universal Host Controller Interface driver for USB.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ *
+ * Intel documents this fairly well, and as far as I know there
+ * are no royalties or anything like that, but even so there are
+ * people who decided that they want to do the same thing in a
+ * completely different way.
+ *
+ * Oh, well. The intel version is the more common by far. As such,
+ * that's the one I care about right now.
+ *
+ * WARNING! The USB documentation is downright evil. Most of it
+ * is just crap, written by a committee. You're better off ignoring
+ * most of it, the important stuff is:
+ *  - the low-level protocol (fairly simple but lots of small details)
+ *  - working around the horridness of the rest
+ */
+
+/* 4/4/1999 added data toggle for interrupt pipes -keryan */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/ioport.h>
+#include <linux/sched.h>
+#include <linux/malloc.h>
+#include <linux/smp_lock.h>
+#include <linux/errno.h>
+
+#include <asm/spinlock.h>
+#include <asm/io.h>
+#include <asm/irq.h>
+#include <asm/system.h>
+
+#include "uhci.h"
+#include "inits.h"
+
+#ifdef CONFIG_APM
+#include <linux/apm_bios.h>
+static int handle_apm_event(apm_event_t event);
+static int apm_resume = 0;
+#endif
+
+#define compile_assert(x) do { switch (0) { case 1: case !(x): } } while (0)
+
+int usb_mouse_init(void);
+int hub_init(void);
+
+static struct wait_queue *uhci_configure = NULL;
+
+/*
+ * Return the result of a TD..
+ */
+static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td)
+{
+	unsigned int status;
+
+	status = (td->status >> 16) & 0xff;
+
+	/* Some debugging code */
+	if (status) {
+		int i = 10;
+		struct uhci_td *tmp = dev->control_td;
+		printk("uhci_td_result() failed with status %d\n", status);
+		show_status(dev->uhci);
+		do {
+			show_td(tmp);
+			tmp++;
+			if (!--i)
+				break;
+		} while (tmp <= td);
+	}
+	return status;		
+}
+
+/*
+ * Inserts a td into qh list at the top.
+ *
+ * Careful about atomicity: even on UP this
+ * requires a locked access due to the concurrent
+ * DMA engine.
+ *
+ * NOTE! This assumes that first->last is a valid
+ * list of TD's with the proper backpointers set
+ * up and all..
+ */
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *first, struct uhci_td *last)
+{
+	unsigned int link = qh->element;
+	unsigned int new = 4 | virt_to_bus(first);
+
+	for (;;) {
+		unsigned char success;
+
+		last->link = link;
+		first->backptr = &qh->element;
+		asm volatile("lock ; cmpxchg %4,%2 ; sete %0"
+			:"=q" (success), "=a" (link)
+			:"m" (qh->element), "1" (link), "r" (new)
+			:"memory");
+		if (success) {
+			/* Was there a successor entry? Fix it's backpointer.. */
+			if ((link & 1) == 0) {
+				struct uhci_td *next = bus_to_virt(link & ~15);
+				next->backptr = &last->link;
+			}
+			break;
+		}
+	}
+}
+
+static inline void uhci_insert_td_in_qh(struct uhci_qh *qh, struct uhci_td *td)
+{
+	uhci_insert_tds_in_qh(qh, td, td);
+}
+
+static void uhci_insert_qh(struct uhci_qh *qh, struct uhci_qh *newqh)
+{
+	newqh->link = qh->link;
+	qh->link = virt_to_bus(newqh) | 2;
+}
+
+static void uhci_remove_qh(struct uhci_qh *qh, struct uhci_qh *remqh)
+{
+	unsigned int remphys = virt_to_bus(remqh);
+	struct uhci_qh *lqh = qh;
+
+	while ((lqh->link & ~0xF) != remphys) {
+		if (lqh->link & 1)
+			break;
+
+		lqh = bus_to_virt(lqh->link & ~0xF);
+	}
+
+	if (lqh->link & 1) {
+		printk("couldn't find qh in chain!\n");
+		return;
+	}
+
+	lqh->link = remqh->link;
+}
+
+/*
+ * Removes td from qh if present.
+ *
+ * NOTE! We keep track of both forward and back-pointers,
+ * so this should be trivial, right?
+ *
+ * Wrong. While all TD insert/remove operations are synchronous
+ * on the CPU, the UHCI controller can (and does) play with the
+ * very first forward pointer. So we need to validate the backptr
+ * before we change it, so that we don't by mistake reset the QH
+ * head to something old.
+ */
+static void uhci_remove_td(struct uhci_td *td)
+{
+	unsigned int *backptr = td->backptr;
+	unsigned int link = td->link;
+	unsigned int me;
+
+	if (!backptr)
+		return;
+
+	td->backptr = NULL;
+
+	/*
+	 * This is the easy case: the UHCI will never change "td->link",
+	 * so we can always just look at that and fix up the backpointer
+	 * of any next element..
+	 */
+	if (!(link & 1)) {
+		struct uhci_td *next = bus_to_virt(link & ~15);
+		next->backptr = backptr;
+	}
+
+	/*
+	 * The nasty case is "backptr->next", which we need to
+	 * update to "link" _only_ if "backptr" still points
+	 * to us (it may not: maybe backptr is a QH->element
+	 * pointer and the UHCI has changed the value).
+	 */
+	me = virt_to_bus(td) | (0xe & *backptr);
+	asm volatile("lock ; cmpxchg %0,%1"
+		:
+		:"r" (link), "m" (*backptr), "a" (me)
+		:"memory");
+}
+
+static struct uhci_qh *uhci_qh_allocate(struct uhci_device *dev)
+{
+	struct uhci_qh *qh;
+	int inuse;
+
+	qh = dev->qh;
+	for (; (inuse = test_and_set_bit(0, &qh->inuse)) != 0 && qh < &dev->qh[UHCI_MAXQH]; qh++)
+		;
+
+	if (!inuse)
+		return(qh);
+
+	printk("ran out of qh's for dev %p\n", dev);
+	return(NULL);
+}
+
+static void uhci_qh_deallocate(struct uhci_qh *qh)
+{
+	if (qh->element != 1)
+		printk("qh %p leaving dangling entries? (%X)\n", qh, qh->element);
+
+	qh->element = 1;
+	qh->link = 1;
+
+	clear_bit(0, &qh->inuse);
+}
+
+static struct uhci_td *uhci_td_allocate(struct uhci_device *dev)
+{
+	struct uhci_td *td;
+	int inuse;
+
+	td = dev->td;
+	for (; (inuse = test_and_set_bit(0, &td->inuse)) != 0 && td < &dev->td[UHCI_MAXTD]; td++)
+		;
+
+	if (!inuse)
+		return(td);
+
+	printk("ran out of td's for dev %p\n", dev);
+	return(NULL);
+}
+
+/*
+ * This MUST only be called when it has been removed from a QH already (or
+ * the QH has been removed from the skeleton
+ */
+static void uhci_td_deallocate(struct uhci_td *td)
+{
+	td->link = 1;
+
+	clear_bit(0, &td->inuse);
+}
+
+/*
+ * UHCI interrupt list operations..
+ */
+static spinlock_t irqlist_lock = SPIN_LOCK_UNLOCKED;
+
+static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td, usb_device_irq completed, void *dev_id)
+{
+	unsigned long flags;
+
+	td->completed = completed;
+	td->dev_id = dev_id;
+
+	spin_lock_irqsave(&irqlist_lock, flags);
+	list_add(&td->irq_list, &uhci->interrupt_list);
+	spin_unlock_irqrestore(&irqlist_lock, flags);
+}
+
+static void uhci_remove_irq_list(struct uhci_td *td)
+{
+	unsigned long flags;
+
+	spin_lock_irqsave(&irqlist_lock, flags);
+	list_del(&td->irq_list);
+	spin_unlock_irqrestore(&irqlist_lock, flags);
+}
+
+/*
+ * Request a interrupt handler..
+ */
+static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+{
+	struct uhci_device *dev = usb_to_uhci(usb_dev);
+	struct uhci_td *td = uhci_td_allocate(dev);
+	struct uhci_qh *interrupt_qh = uhci_qh_allocate(dev);
+
+	unsigned int destination, status;
+
+	/* Destination: pipe destination with INPUT */
+	destination = (pipe & 0x0007ff00)  |  0x69;
+
+	/* Status:    slow/fast,      Interrupt,   Active,    Short Packet Detect     Infinite Errors */
+	status = (pipe & (1 << 26)) | (1 << 24) | (1 << 23)   |   (1 << 29)       |    (0 << 27);
+
+	if(interrupt_qh->element != 1)
+		printk("interrupt_qh->element = 0x%x\n", 
+		       interrupt_qh->element);
+
+	td->link = 1;
+	td->status = status;			/* In */
+	td->info = destination | (7 << 21);	/* 8 bytes of data */
+	td->buffer = virt_to_bus(dev->data);
+	td->qh = interrupt_qh;
+	interrupt_qh->skel = &dev->uhci->root_hub->skel_int8_qh;
+
+	uhci_add_irq_list(dev->uhci, td, handler, dev_id);
+
+	uhci_insert_td_in_qh(interrupt_qh, td);
+
+	/* Add it into the skeleton */
+	uhci_insert_qh(&dev->uhci->root_hub->skel_int8_qh, interrupt_qh);
+	return 0;
+}
+
+/*
+ * Control thread operations: we just mark the last TD
+ * in a control thread as an interrupt TD, and wake up
+ * the front-end on completion.
+ *
+ * We need to remove the TD from the lists (both interrupt
+ * list and TD lists) by hand if something bad happens!
+ */
+static struct wait_queue *control_wakeup;
+
+static int uhci_control_completed(int status, void *buffer, void *dev_id)
+{
+	wake_up(&control_wakeup);
+	return 0;			/* Don't re-instate */
+}
+
+/* td points to the last td in the list, which interrupts on completion */
+static int uhci_run_control(struct uhci_device *dev, struct uhci_td *first, struct uhci_td *last)
+{
+	struct wait_queue wait = { current, NULL };
+	struct uhci_qh *ctrl_qh = uhci_qh_allocate(dev);
+	struct uhci_td *curtd;
+
+	current->state = TASK_UNINTERRUPTIBLE;
+	add_wait_queue(&control_wakeup, &wait);
+
+	uhci_add_irq_list(dev->uhci, last, uhci_control_completed, NULL);
+	
+	/* FIXME: This is kinda kludged */
+	/* Walk the TD list and update the QH pointer */
+	{
+	int maxcount = 100;
+
+	curtd = first;
+	do {
+		curtd->qh = ctrl_qh;
+		if (curtd->link & 1)
+			break;
+
+		curtd = bus_to_virt(curtd->link & ~0xF);
+		if (!--maxcount) {
+			printk("runaway tds!\n");
+			break;
+		}
+	} while (1);
+	}
+
+	uhci_insert_tds_in_qh(ctrl_qh, first, last);
+
+	/* Add it into the skeleton */
+	uhci_insert_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh);
+
+	schedule_timeout(HZ/10);
+
+	remove_wait_queue(&control_wakeup, &wait);
+
+	/* Clean up in case it failed.. */
+	uhci_remove_irq_list(last);
+
+#if 0
+	printk("Looking for tds [%p, %p]\n", dev->control_td, td);
+#endif
+
+	/* Remove it from the skeleton */
+	uhci_remove_qh(&dev->uhci->root_hub->skel_control_qh, ctrl_qh);
+
+	uhci_qh_deallocate(ctrl_qh);
+
+	return uhci_td_result(dev, last);
+}
+
+/*
+ * Send or receive a control message on a pipe.
+ *
+ * Note that the "pipe" structure is set up to map
+ * easily to the uhci destination fields.
+ *
+ * A control message is built up from three parts:
+ *  - The command itself
+ *  - [ optional ] data phase
+ *  - Status complete phase
+ *
+ * The data phase can be an arbitrary number of TD's
+ * although we currently had better not have more than
+ * 29 TD's here (we have 31 TD's allocated for control
+ * operations, and two of them are used for command and
+ * status).
+ *
+ * 29 TD's is a minimum of 232 bytes worth of control
+ * information, that's just ridiculously high. Most
+ * control messages have just a few bytes of data.
+ */
+static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, void *cmd, void *data, int len)
+{
+	struct uhci_device *dev = usb_to_uhci(usb_dev);
+	struct uhci_td *first, *td, *prevtd;
+	unsigned long destination, status;
+	int ret;
+
+	if (len > usb_maxpacket(usb_dev->maxpacketsize) * 29)
+		printk("Warning, too much data for a control packet, crashing\n");
+
+	first = td = uhci_td_allocate(dev);
+
+	/* The "pipe" thing contains the destination in bits 8--18, 0x2D is SETUP */
+	destination = (pipe & 0x0007ff00) | 0x2D;
+
+	/* Status:    slow/fast,       Active,    Short Packet Detect     Three Errors */
+	status = (pipe & (1 << 26)) | (1 << 23)   |   (1 << 29)       |    (3 << 27);
+
+	/*
+	 * Build the TD for the control request
+	 */
+	td->status = status;				/* Try forever */
+	td->info = destination | (7 << 21);		/* 8 bytes of data */
+	td->buffer = virt_to_bus(cmd);
+
+	/*
+	 * If direction is "send", change the frame from SETUP (0x2D)
+	 * to OUT (0xE1). Else change it from SETUP to IN (0x69)
+	 */
+	destination ^= (0x2D ^ 0x69);			/* SETUP -> IN */
+	if (usb_pipeout(pipe))
+		destination ^= (0xE1 ^ 0x69);		/* IN -> OUT */
+
+	prevtd = td;
+	td = uhci_td_allocate(dev);
+	prevtd->link = 4 | virt_to_bus(td);
+
+	/*
+	 * Build the DATA TD's
+	 */
+	while (len > 0) {
+		/* Build the TD for control status */
+		int pktsze = len;
+		int maxsze = usb_maxpacket(pipe);
+
+		if (pktsze > maxsze)
+			pktsze = maxsze;
+
+		/* Alternate Data0/1 (start with Data1) */
+		destination ^= 1 << 19;
+	
+		td->status = status;					/* Status */
+		td->info = destination | ((pktsze-1) << 21);		/* pktsze bytes of data */
+		td->buffer = virt_to_bus(data);
+		td->backptr = &prevtd->link;
+
+		prevtd = td;
+		td = uhci_td_allocate(dev);
+		prevtd->link = 4 | virt_to_bus(td);			/* Update previous TD */
+
+		data += maxsze;
+		len -= maxsze;
+	}
+
+	/*
+	 * Build the final TD for control status
+	 */
+	destination ^= (0xE1 ^ 0x69);			/* OUT -> IN */
+	destination |= 1 << 19;				/* End in Data1 */
+
+	td->link = 1;					/* Terminate */
+	td->status = status | (1 << 24);		/* IOC */
+	td->info = destination | (0x7ff << 21);		/* 0 bytes of data */
+	td->buffer = 0;
+	td->backptr = &prevtd->link;
+
+	/* Start it up.. */
+	ret = uhci_run_control(dev, first, td);
+
+	{
+		int maxcount = 100;
+		struct uhci_td *curtd = first;
+		unsigned int nextlink;
+
+		do {
+			nextlink = curtd->link;
+			uhci_remove_td(curtd);
+			uhci_td_deallocate(curtd);
+			if (nextlink & 1)	/* Tail? */
+				break;
+
+			curtd = bus_to_virt(nextlink & ~0xF);
+			if (!--maxcount) {
+				printk("runaway td's!?\n");
+				break;
+			}
+		} while (1);
+	}
+
+	return ret;
+}
+
+static struct usb_device *uhci_usb_allocate(struct usb_device *parent)
+{
+	struct usb_device *usb_dev;
+	struct uhci_device *dev;
+	int i;
+
+	usb_dev = kmalloc(sizeof(*usb_dev), GFP_KERNEL);
+	if (!usb_dev)
+		return NULL;
+
+	memset(usb_dev, 0, sizeof(*usb_dev));
+
+	dev = kmalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev) {
+		kfree(usb_dev);
+		return NULL;
+	}
+
+	/* Initialize "dev" */
+	memset(dev, 0, sizeof(*dev));
+
+	usb_dev->hcpriv = dev;
+	dev->usb = usb_dev;
+
+	usb_dev->parent = parent;
+
+	if (parent) {
+		usb_dev->bus = parent->bus;
+		dev->uhci = usb_to_uhci(parent)->uhci;
+	}
+
+	/* Reset the QH's and TD's */
+	for (i = 0; i < UHCI_MAXQH; i++) {
+		dev->qh[i].link = 1;
+		dev->qh[i].element = 1;
+		dev->qh[i].inuse = 0;
+	}
+
+	for (i = 0; i < UHCI_MAXTD; i++) {
+		dev->td[i].link = 1;
+		dev->td[i].inuse = 0;
+	}
+
+	return usb_dev;
+}
+
+static int uhci_usb_deallocate(struct usb_device *usb_dev)
+{
+	struct uhci_device *dev = usb_to_uhci(usb_dev);
+	int i;
+
+	/* There are UHCI_MAXTD preallocated tds */
+	for (i = 0; i < UHCI_MAXTD; ++i) {
+		struct uhci_td *td = dev->td + i;
+
+		/* And remove it from the irq list, if it's active */
+		if (td->status & (1 << 23))
+			uhci_remove_irq_list(td);
+
+		if (td->inuse)
+			uhci_remove_td(td);
+	}
+
+	/* Remove the td from any queues */
+	for (i = 0; i < UHCI_MAXQH; ++i) {
+		struct uhci_qh *qh = dev->qh + i;
+
+		if (qh->inuse)
+			uhci_remove_qh(qh->skel, qh);
+	}
+
+	kfree(dev);
+	kfree(usb_dev);
+
+	return 0;
+}
+
+struct usb_operations uhci_device_operations = {
+	uhci_usb_allocate,
+	uhci_usb_deallocate,
+	uhci_control_msg,
+	uhci_request_irq,
+};
+
+/*
+ * This is just incredibly fragile. The timings must be just
+ * right, and they aren't really documented very well.
+ *
+ * Note the short delay between disabling reset and enabling
+ * the port..
+ */
+static void uhci_reset_port(unsigned int port)
+{
+	unsigned short status;
+
+	status = inw(port);
+	outw(status | USBPORTSC_PR, port);		/* reset port */
+	wait_ms(10);
+	outw(status & ~USBPORTSC_PR, port);
+	udelay(5);
+
+	status = inw(port);
+	outw(status | USBPORTSC_PE, port);		/* enable port */
+	wait_ms(10);
+
+	status = inw(port);
+	if(!(status & USBPORTSC_PE)) {
+		outw(status | USBPORTSC_PE, port);	/* one more try at enabling port */
+		wait_ms(50);
+	}
+
+}
+
+
+/*
+ * This gets called if the connect status on the root
+ * hub (and the root hub only) changes.
+ */
+static void uhci_connect_change(struct uhci *uhci, unsigned int port, unsigned int nr)
+{
+	struct usb_device *usb_dev;
+	struct uhci_device *dev;
+	unsigned short status;
+
+	printk("uhci_connect_change: called for %d\n", nr);
+
+	/*
+	 * Even if the status says we're connected,
+	 * the fact that the status bits changed may
+	 * that we got disconnected and then reconnected.
+	 *
+	 * So start off by getting rid of any old devices..
+	 */
+	usb_disconnect(&uhci->root_hub->usb->children[nr]);
+
+	status = inw(port);
+
+	/* If we have nothing connected, then clear change status and disable the port */
+	status = (status & ~USBPORTSC_PE) | USBPORTSC_PEC;
+	if (!(status & USBPORTSC_CCS)) {
+		outw(status, port);
+		return;
+	}
+
+	/*
+	 * Ok, we got a new connection. Allocate a device to it,
+	 * and find out what it wants to do..
+	 */
+	usb_dev = uhci_usb_allocate(uhci->root_hub->usb);
+	dev = usb_dev->hcpriv;
+
+	dev->uhci = uhci;
+
+	usb_connect(usb_dev);
+
+	uhci->root_hub->usb->children[nr] = usb_dev;
+
+	wait_ms(200); /* wait for powerup */
+	uhci_reset_port(port);
+
+	/* Get speed information */
+	usb_dev->slow = (inw(port) & USBPORTSC_LSDA) ? 1 : 0;
+
+	/*
+	 * Ok, all the stuff specific to the root hub has been done.
+	 * The rest is generic for any new USB attach, regardless of
+	 * hub type.
+	 */
+	usb_new_device(usb_dev);
+}
+
+/*
+ * This gets called when the root hub configuration
+ * has changed. Just go through each port, seeing if
+ * there is something interesting happening.
+ */
+static void uhci_check_configuration(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr + USBPORTSC1;
+	int maxchild = uhci->root_hub->usb->maxchild;
+	int nr = 0;
+
+	do {
+		unsigned short status = inw(io_addr);
+
+		if (status & USBPORTSC_CSC)
+			uhci_connect_change(uhci, io_addr, nr);
+
+		nr++; io_addr += 2;
+	} while (nr < maxchild);
+}
+
+static void uhci_interrupt_notify(struct uhci *uhci)
+{
+	struct list_head *head = &uhci->interrupt_list;
+	struct list_head *tmp;
+
+	spin_lock(&irqlist_lock);
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
+		struct list_head *next;
+
+		next = tmp->next;
+
+		if (!(td->status & (1 << 23))) {	/* No longer active? */
+			/* remove from IRQ list */
+			__list_del(tmp->prev, next);
+			INIT_LIST_HEAD(tmp);
+			if (td->completed(td->status, bus_to_virt(td->buffer), td->dev_id)) {
+				struct uhci_qh *interrupt_qh = td->qh;
+
+				list_add(&td->irq_list, &uhci->interrupt_list);
+				td->info ^= 1 << 19; /* toggle between data0 and data1 */
+				td->status = (td->status & 0x2f000000) | (1 << 23) | (1 << 24);	/* active */
+
+				/* Remove then readd? Is that necessary */
+				uhci_remove_td(td);
+				uhci_insert_td_in_qh(interrupt_qh, td);
+			}
+			/* If completed wants to not reactivate, then it's */
+			/* responsible for free'ing the TD's and QH's */
+			/* or another function (such as run_control) */
+		}
+		tmp = next;
+	}
+	spin_unlock(&irqlist_lock);
+}
+
+/*
+ * Check port status - Connect Status Change - for
+ * each of the attached ports (defaults to two ports,
+ * but at least in theory there can be more of them).
+ *
+ * Wake up the configurator if something happened, we
+ * can't really do much at interrupt time.
+ */
+static void uhci_root_hub_events(struct uhci *uhci, unsigned int io_addr)
+{
+	if (waitqueue_active(&uhci_configure)) {
+		int ports = uhci->root_hub->usb->maxchild;
+		io_addr += USBPORTSC1;
+		do {
+			if (inw(io_addr) & USBPORTSC_CSC) {
+				wake_up(&uhci_configure);
+				return;
+			}
+			io_addr += 2;
+		} while (--ports > 0);
+	}
+}
+
+static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
+{
+	struct uhci *uhci = __uhci;
+	unsigned int io_addr = uhci->io_addr;
+	unsigned short status;
+
+	/*
+	 * Read the interrupt status, and write it back to clear the interrupt cause
+	 */
+	status = inw(io_addr + USBSTS);
+	outw(status, io_addr + USBSTS);
+
+	/* Walk the list of pending TD's to see which ones completed.. */
+	uhci_interrupt_notify(uhci);
+
+	/* Check if there are any events on the root hub.. */
+	uhci_root_hub_events(uhci, io_addr);
+}
+
+/*
+ * We init one packet, and mark it just IOC and _not_
+ * active. Which will result in no actual USB traffic,
+ * but _will_ result in an interrupt every second.
+ *
+ * Which is exactly what we want.
+ */
+static void uhci_init_ticktd(struct uhci *uhci)
+{
+	struct uhci_device *dev = uhci->root_hub;
+	struct uhci_td *td = uhci_td_allocate(dev);
+
+	td->link = 1;
+	td->status = (1 << 24);					/* interrupt on completion */
+	td->info = (15 << 21) | 0x7f69;				/* (ignored) input packet, 16 bytes, device 127 */
+	td->buffer = 0;
+	td->qh = NULL;
+
+	uhci->fl->frame[0] = virt_to_bus(td);
+}
+
+static void reset_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+
+	/* Global reset for 50ms */
+	outw(USBCMD_GRESET, io_addr+USBCMD);
+	wait_ms(50);
+	outw(0, io_addr+USBCMD);
+	wait_ms(10);
+}
+
+static void start_hc(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	int timeout = 1000;
+
+	uhci_init_ticktd(uhci);
+
+	/*
+	 * Reset the HC - this will force us to get a
+	 * new notification of any already connected
+	 * ports due to the virtual disconnect that it
+	 * implies.
+	 */
+	outw(USBCMD_HCRESET, io_addr + USBCMD);
+	while (inw(io_addr + USBCMD) & USBCMD_HCRESET) {
+		if (!--timeout) {
+			printk("USBCMD_HCRESET timed out!\n");
+			break;
+		}
+	}
+
+	outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP, io_addr + USBINTR);
+	outw(0, io_addr + USBFRNUM);
+	outl(virt_to_bus(uhci->fl), io_addr + USBFLBASEADD);
+
+	/* Run and mark it configured with a 64-byte max packet */
+	outw(USBCMD_RS | USBCMD_CF, io_addr + USBCMD);
+}
+
+/*
+ * Allocate a frame list, and four regular queues.
+ *
+ * The hardware doesn't really know any difference
+ * in the queues, but the order does matter for the
+ * protocols higher up. The order is:
+ *
+ *  - any isochronous events handled before any
+ *    of the queues. We don't do that here, because
+ *    we'll create the actual TD entries on demand.
+ *  - The first queue is the "interrupt queue".
+ *  - The second queue is the "control queue".
+ *  - The third queue is "bulk data".
+ *
+ * We could certainly have multiple queues of the same
+ * type, and maybe we should. We could have per-device
+ * queues, for example. We begin small.
+ */
+static struct uhci *alloc_uhci(unsigned int io_addr)
+{
+	int i;
+	struct uhci *uhci;
+	struct usb_bus *bus;
+	struct uhci_device *dev;
+	struct usb_device *usb;
+
+	uhci = kmalloc(sizeof(*uhci), GFP_KERNEL);
+	if (!uhci)
+		return NULL;
+
+	memset(uhci, 0, sizeof(*uhci));
+
+	uhci->irq = -1;
+	uhci->io_addr = io_addr;
+	INIT_LIST_HEAD(&uhci->interrupt_list);
+
+	/* We need exactly one page (per UHCI specs), how convenient */
+	uhci->fl = (void *)__get_free_page(GFP_KERNEL);
+
+	bus = kmalloc(sizeof(*bus), GFP_KERNEL);
+	if (!bus)
+		return NULL;
+
+	memset(bus, 0, sizeof(*bus));
+
+	uhci->bus = bus;
+	bus->hcpriv = uhci;
+	bus->op = &uhci_device_operations;
+
+	/*
+	 * We allocate a 8kB area for the UHCI hub. The area
+	 * is described by the uhci_device structure, and basically
+	 * contains everything needed for normal operation.
+	 *
+	 * The first page is the actual device descriptor for the
+	 * hub.
+	 *
+	 * The second page is used for the frame list.
+	 */
+	usb = uhci_usb_allocate(NULL);
+	if (!usb)
+		return NULL;
+
+	dev = uhci->root_hub = usb_to_uhci(usb);
+
+	usb->bus = bus;
+
+	/* Initialize the root hub */
+	/* UHCI specs says devices must have 2 ports, but goes on to say */
+	/* they may have more but give no way to determine how many they */
+	/* have, so default to 2 */
+	usb->maxchild = 2;
+	usb_init_root_hub(usb);
+
+	/*
+	 * Initialize the queues. They all start out empty,
+	 * linked to each other in the proper order.
+	 */
+	for (i = 1 ; i < 9; i++) {
+		dev->qh[i].link = 2 | virt_to_bus(&dev->skel_control_qh);
+		dev->qh[i].element = 1;
+	}
+	
+	dev->skel_control_qh.link = 2 | virt_to_bus(&dev->skel_bulk0_qh);
+	dev->skel_control_qh.element = 1;
+
+	dev->skel_bulk0_qh.link = 2 | virt_to_bus(&dev->skel_bulk1_qh);
+	dev->skel_bulk0_qh.element = 1;
+
+	dev->skel_bulk1_qh.link = 2 | virt_to_bus(&dev->skel_bulk2_qh);
+	dev->skel_bulk1_qh.element = 1;
+
+	dev->skel_bulk2_qh.link = 2 | virt_to_bus(&dev->skel_bulk3_qh);
+	dev->skel_bulk2_qh.element = 1;
+
+	dev->skel_bulk3_qh.link = 1;
+	dev->skel_bulk3_qh.element = 1;
+
+	/*
+	 * Fill the frame list: make all entries point to
+	 * the proper interrupt queue.
+	 *
+	 * This is probably silly, but it's a simple way to
+	 * scatter the interrupt queues in a way that gives
+	 * us a reasonable dynamic range for irq latencies.
+	 */
+	for (i = 0; i < 1024; i++) {
+		struct uhci_qh * irq = &dev->skel_int2_qh;
+		if (i & 1) {
+			irq++;
+			if (i & 2) {
+				irq++;
+				if (i & 4) { 
+					irq++;
+					if (i & 8) { 
+						irq++;
+						if (i & 16) {
+							irq++;
+							if (i & 32) {
+								irq++;
+								if (i & 64) {
+									irq++;
+								}
+							}
+						}
+					}
+				}
+			}
+		}
+		uhci->fl->frame[i] =  2 | virt_to_bus(irq);
+	}
+
+	return uhci;
+}
+
+
+/*
+ * De-allocate all resources..
+ */
+static void release_uhci(struct uhci *uhci)
+{
+	if (uhci->irq >= 0) {
+		free_irq(uhci->irq, uhci);
+		uhci->irq = -1;
+	}
+
+#if 0
+	if (uhci->root_hub) {
+		uhci_usb_deallocate(uhci_to_usb(uhci->root_hub));
+		uhci->root_hub = NULL;
+	}
+#endif
+
+	if (uhci->fl) {
+		free_page((unsigned long)uhci->fl);
+		uhci->fl = NULL;
+	}
+
+	kfree(uhci->bus);
+	kfree(uhci);
+}
+
+static int uhci_control_thread(void * __uhci)
+{
+	struct uhci *uhci = (struct uhci *)__uhci;
+
+	lock_kernel();
+	request_region(uhci->io_addr, 32, "usb-uhci");
+
+	/*
+	 * This thread doesn't need any user-level access,
+	 * so get rid of all our resources..
+	 */
+	printk("uhci_control_thread at %p\n", &uhci_control_thread);
+	exit_mm(current);
+	exit_files(current);
+	exit_fs(current);
+
+	strcpy(current->comm, "uhci-control");
+
+	/*
+	 * Ok, all systems are go..
+	 */
+	start_hc(uhci);
+	for(;;) {
+		siginfo_t info;
+		int unsigned long signr;
+
+		interruptible_sleep_on(&uhci_configure);
+#ifdef CONFIG_APM
+		if (apm_resume) {
+			apm_resume = 0;
+			start_hc(uhci);
+			continue;
+		}
+#endif
+		uhci_check_configuration(uhci);
+
+		if(signal_pending(current)) {
+			/* sending SIGUSR1 makes us print out some info */
+			spin_lock_irq(&current->sigmask_lock);
+			signr = dequeue_signal(&current->blocked, &info);
+			spin_unlock_irq(&current->sigmask_lock);
+
+			if(signr == SIGUSR1) {
+				printk("UHCI queue dump:\n");
+				show_queues(uhci);
+			} else {
+				break;
+			}
+		}
+	}
+
+#if 0
+	if(uhci->root_hub)
+		for(i = 0; i < uhci->root_hub->usb->maxchild; i++)
+			usb_disconnect(uhci->root_hub->usb->children + i);
+#endif
+
+	reset_hc(uhci);
+	release_region(uhci->io_addr, 32);
+
+	release_uhci(uhci);
+	MOD_DEC_USE_COUNT;
+
+	printk("uhci_control_thread exiting\n");
+
+	return 0;
+}	
+
+/*
+ * If we've successfully found a UHCI, now is the time to increment the
+ * module usage count, start the control thread, and return success..
+ */
+static int found_uhci(int irq, unsigned int io_addr)
+{
+	int retval;
+	struct uhci *uhci;
+
+	uhci = alloc_uhci(io_addr);
+	if (!uhci)
+		return -ENOMEM;
+
+	reset_hc(uhci);
+
+	retval = -EBUSY;
+	if (request_irq(irq, uhci_interrupt, SA_SHIRQ, "usb", uhci) == 0) {
+		int pid;
+
+		MOD_INC_USE_COUNT;
+		uhci->irq = irq;
+		pid = kernel_thread(uhci_control_thread, uhci, CLONE_FS | CLONE_FILES | CLONE_SIGHAND);
+		if (pid >= 0)
+			return 0;
+
+		MOD_DEC_USE_COUNT;
+		retval = pid;
+	}
+	release_uhci(uhci);
+	return retval;
+}
+
+static int start_uhci(struct pci_dev *dev)
+{
+	int i;
+
+	/* Search for the IO base address.. */
+	for (i = 0; i < 6; i++) {
+		unsigned int io_addr = dev->base_address[i];
+
+		/* IO address? */
+		if (!(io_addr & 1))
+			continue;
+
+		io_addr &= PCI_BASE_ADDRESS_IO_MASK;
+
+		/* Is it already in use? */
+		if (check_region(io_addr, 32))
+			break;
+
+		return found_uhci(dev->irq, io_addr);
+	}
+	return -1;
+}
+
+#ifdef CONFIG_APM
+static int handle_apm_event(apm_event_t event)
+{
+	static int down = 0;
+
+	switch (event) {
+	case APM_SYS_SUSPEND:
+	case APM_USER_SUSPEND:
+		if (down) {
+			printk(KERN_DEBUG "uhci: received extra suspend event\n");
+			break;
+		}
+		down = 1;
+		break;
+	case APM_NORMAL_RESUME:
+	case APM_CRITICAL_RESUME:
+		if (!down) {
+			printk(KERN_DEBUG "uhci: received bogus resume event\n");
+			break;
+		}
+		down = 0;
+		if (waitqueue_active(&uhci_configure)) {
+			apm_resume = 1;
+			wake_up(&uhci_configure);
+		}
+		break;
+	}
+	return 0;
+}
+#endif
+
+#ifdef MODULE
+
+void cleanup_module(void)
+{
+#ifdef CONFIG_APM
+	apm_unregister_callback(&handle_apm_event);
+#endif
+}
+
+#define uhci_init init_module
+
+#endif
+
+int uhci_init(void)
+{
+	int retval;
+	struct pci_dev *dev = NULL;
+	u8 type;
+
+	retval = -ENODEV;
+	for (;;) {
+		dev = pci_find_class(PCI_CLASS_SERIAL_USB<<8, dev);
+		if (!dev)
+			break;
+		/* Is it UHCI */
+		pci_read_config_byte(dev, PCI_CLASS_PROG, &type);
+		if(type != 0)
+			continue;
+		/* Ok set it up */
+		retval = start_uhci(dev);
+		if (retval < 0)
+			continue;
+
+		usb_mouse_init();
+		usb_kbd_init();
+		hub_init();
+#ifdef CONFIG_APM
+		apm_register_callback(&handle_apm_event);
+#endif
+
+		return 0;
+	}
+	return retval;
+}
diff -urN linux-2.2.7-pre3/drivers/usb/uhci-debug.c linux-2.2.7-pre4/drivers/usb/uhci-debug.c
--- linux-2.2.7-pre3/drivers/usb/uhci-debug.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/uhci-debug.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,168 @@
+/*
+ * UHCI-specific debugging code. Invaluable when something
+ * goes wrong, but don't get in my face.
+ *
+ * (C) Copyright 1999 Linus Torvalds
+ */
+
+#include <linux/kernel.h>
+#include <asm/io.h>
+
+#include "uhci.h"
+
+void show_td(struct uhci_td * td)
+{
+	printk("%08x ", td->link);
+	printk("%se%d %s%s%s%s%s%s%s%s%s%sLength=%x ",
+		((td->status >> 29) & 1) ? "SPD " : "",
+		((td->status >> 27) & 3),
+		((td->status >> 26) & 1) ? "LS " : "",
+		((td->status >> 25) & 1) ? "IOS " : "",
+		((td->status >> 24) & 1) ? "IOC " : "",
+		((td->status >> 23) & 1) ? "Active " : "",
+		((td->status >> 22) & 1) ? "Stalled " : "",
+		((td->status >> 21) & 1) ? "DataBufErr " : "",
+		((td->status >> 20) & 1) ? "Babble " : "",
+		((td->status >> 19) & 1) ? "NAK " : "",
+		((td->status >> 18) & 1) ? "CRC/Timeo " : "",
+		((td->status >> 17) & 1) ? "BitStuff " : "",
+		td->status & 0x7ff);
+	printk("MaxLen=%x %sEndPt=%x Dev=%x, PID=%x ",
+		td->info >> 21,
+		 ((td->info >> 19) & 1) ? "DT " : "",
+		 (td->info >> 15) & 15,
+		 (td->info >> 8) & 127,
+		 td->info & 0xff);
+	printk("(buf=%08x)\n", td->buffer);
+}
+
+static void show_sc(int port, unsigned short status)
+{
+	printk("  stat%d     =     %04x   %s%s%s%s%s%s%s%s\n",
+		port,
+		status,
+		(status & (1 << 12)) ? " PortSuspend" : "",
+		(status & (1 << 9)) ? " PortReset" : "",
+		(status & (1 << 8)) ? " LowSpeed" : "",
+		(status & 0x40) ? " ResumeDetect" : "",
+		(status & 0x08) ? " EnableChange" : "",
+		(status & 0x04) ? " PortEnabled" : "",
+		(status & 0x02) ? " ConnectChange" : "",
+		(status & 0x01) ? " PortConnected" : "");
+}
+
+void show_status(struct uhci *uhci)
+{
+	unsigned int io_addr = uhci->io_addr;
+	unsigned short usbcmd, usbstat, usbint, usbfrnum;
+	unsigned int flbaseadd;
+	unsigned char sof;
+	unsigned short portsc1, portsc2;
+
+	usbcmd    = inw(io_addr + 0);
+	usbstat   = inw(io_addr + 2);
+	usbint    = inw(io_addr + 4);
+	usbfrnum  = inw(io_addr + 6);
+	flbaseadd = inl(io_addr + 8);
+	sof       = inb(io_addr + 12);
+	portsc1   = inw(io_addr + 16);
+	portsc2   = inw(io_addr + 18);
+
+	printk("  usbcmd    =     %04x   %s%s%s%s%s%s%s%s\n",
+		usbcmd,
+		(usbcmd & 0x80) ? " Maxp64" : " Maxp32",
+		(usbcmd & 0x40) ? " CF" : "",
+		(usbcmd & 0x20) ? " SWDBG" : "",
+		(usbcmd & 0x10) ? " FGR" : "",
+		(usbcmd & 0x08) ? " EGSM" : "",
+		(usbcmd & 0x04) ? " GRESET" : "",
+		(usbcmd & 0x02) ? " HCRESET" : "",
+		(usbcmd & 0x01) ? " RS" : "");
+
+	printk("  usbstat   =     %04x   %s%s%s%s%s%s\n",
+		usbstat,
+		(usbstat & 0x20) ? " HCHalted" : "",
+		(usbstat & 0x10) ? " HostControllerProcessError" : "",
+		(usbstat & 0x08) ? " HostSystemError" : "",
+		(usbstat & 0x04) ? " ResumeDetect" : "",
+		(usbstat & 0x02) ? " USBError" : "",
+		(usbstat & 0x01) ? " USBINT" : "");
+
+	printk("  usbint    =     %04x\n", usbint);
+	printk("  usbfrnum  =   (%d)%03x\n", (usbfrnum >> 10) & 1, 0xfff & (4*(unsigned int)usbfrnum));
+	printk("  flbaseadd = %08x\n", flbaseadd);
+	printk("  sof       =       %02x\n", sof);
+	show_sc(1, portsc1);
+	show_sc(2, portsc2);
+}
+
+#define uhci_link_to_qh(x) ((struct uhci_qh *) uhci_link_to_td(x))
+
+struct uhci_td * uhci_link_to_td(unsigned int link)
+{
+	if (link & 1)
+		return NULL;
+
+	return bus_to_virt(link & ~15);
+}
+
+void show_queue(struct uhci_qh *qh)
+{
+	struct uhci_td *td;
+	int i = 0;
+
+#if 0
+	printk("    link = %p, element = %p\n", qh->link, qh->element);
+#endif
+	if(!qh->element) {
+		printk("    td 0 = NULL\n");
+		return;
+	}
+
+	for(td = uhci_link_to_td(qh->element); td; 
+	    td = uhci_link_to_td(td->link)) {
+		printk("    td %d = %p\n", i++, td);
+		printk("    ");
+		show_td(td);
+	}
+}
+
+int is_skeleton_qh(struct uhci *uhci, struct uhci_qh *qh)
+{
+	int j;
+
+	for (j = 0; j < UHCI_MAXQH; j++)
+		if (qh == uhci->root_hub->qh + j)
+			return 1;
+
+	return 0;
+}
+
+static const char *qh_names[] = {"isochronous", "interrupt2", "interrupt4",
+				 "interrupt8", "interrupt16", "interrupt32",
+				 "interrupt64", "interrupt128", "interrupt256",
+				 "control", "bulk0", "bulk1", "bulk2", "bulk3",
+				 "unused", "unused"};
+
+void show_queues(struct uhci *uhci)
+{
+	int i;
+	struct uhci_qh *qh;
+
+	for (i = 0; i < UHCI_MAXQH; ++i) {
+		printk("  %s:\n", qh_names[i]);
+#if 0
+		printk("  qh #%d, %p\n", i, virt_to_bus(uhci->root_hub->qh + i));
+		show_queue(uhci->root_hub->qh + i);
+#endif
+
+		qh = uhci_link_to_qh(uhci->root_hub->qh[i].link);
+		for (; qh; qh = uhci_link_to_qh(qh->link)) {
+			if (is_skeleton_qh(uhci, qh))
+				break;
+
+			show_queue(qh);
+		}
+	}
+}
+
diff -urN linux-2.2.7-pre3/drivers/usb/uhci.h linux-2.2.7-pre4/drivers/usb/uhci.h
--- linux-2.2.7-pre3/drivers/usb/uhci.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/uhci.h	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,229 @@
+#ifndef __LINUX_UHCI_H
+#define __LINUX_UHCI_H
+
+#include <linux/list.h>
+
+#include "usb.h"
+
+/*
+ * Universal Host Controller Interface data structures and defines
+ */
+
+/* Command register */
+#define USBCMD		0
+#define   USBCMD_RS		0x0001	/* Run/Stop */
+#define   USBCMD_HCRESET	0x0002	/* Host reset */
+#define   USBCMD_GRESET		0x0004	/* Global reset */
+#define   USBCMD_EGSM		0x0008	/* Global Suspend Mode */
+#define   USBCMD_FGR		0x0010	/* Force Global Resume */
+#define   USBCMD_SWDBG		0x0020	/* SW Debug mode */
+#define   USBCMD_CF		0x0040	/* Config Flag (sw only) */
+#define   USBCMD_MAXP		0x0080	/* Max Packet (0 = 32, 1 = 64) */
+
+/* Status register */
+#define USBSTS		2
+#define   USBSTS_USBINT		0x0001	/* Interrupt due to IOC */
+#define   USBSTS_ERROR		0x0002	/* Interrupt due to error */
+#define   USBSTS_RD		0x0004	/* Resume Detect */
+#define   USBSTS_HSE		0x0008	/* Host System Error - basically PCI problems */
+#define   USBSTS_HCPE		0x0010	/* Host Controller Process Error - the scripts were buggy */
+#define   USBSTS_HCH		0x0020	/* HC Halted */
+
+/* Interrupt enable register */
+#define USBINTR		4
+#define   USBINTR_TIMEOUT	0x0001	/* Timeout/CRC error enable */
+#define   USBINTR_RESUME	0x0002	/* Resume interrupt enable */
+#define   USBINTR_IOC		0x0004	/* Interrupt On Complete enable */
+#define   USBINTR_SP		0x0008	/* Short packet interrupt enable */
+
+#define USBFRNUM	6
+#define USBFLBASEADD	8
+#define USBSOF		12
+
+/* USB port status and control registers */
+#define USBPORTSC1	16
+#define USBPORTSC2	18
+#define   USBPORTSC_CCS		0x0001	/* Current Connect Status ("device present") */
+#define   USBPORTSC_CSC		0x0002	/* Connect Status Change */
+#define   USBPORTSC_PE		0x0004	/* Port Enable */
+#define   USBPORTSC_PEC		0x0008	/* Port Enable Change */
+#define   USBPORTSC_LS		0x0030	/* Line Status */
+#define   USBPORTSC_RD		0x0040	/* Resume Detect */
+#define   USBPORTSC_LSDA	0x0100	/* Low Speed Device Attached */
+#define   USBPORTSC_PR		0x0200	/* Port Reset */
+#define   USBPORTSC_SUSP	0x1000	/* Suspend */
+
+struct uhci_qh {
+	unsigned int link;	/* Next queue */
+	unsigned int element;	/* Queue element pointer */
+	int inuse;		/* Inuse? */
+	struct uhci_qh *skel;	/* Skeleton head */
+} __attribute__((aligned(16)));
+
+struct uhci_framelist {
+	unsigned int frame[1024];
+} __attribute__((aligned(4096)));
+
+/*
+ * The documentation says "4 words for hardware, 4 words for software".
+ *
+ * That's silly, the hardware doesn't care. The hardware only cares that
+ * the hardware words are 16-byte aligned, and we can have any amount of
+ * sw space after the TD entry as far as I can tell.
+ *
+ * But let's just go with the documentation, at least for 32-bit machines.
+ * On 64-bit machines we probably want to take advantage of the fact that
+ * hw doesn't really care about the size of the sw-only area.
+ *
+ * Alas, not anymore, we have more than 4 words of software, woops
+ */
+struct uhci_td {
+	/* Hardware fields */
+	__u32 link;
+	__u32 status;
+	__u32 info;
+	__u32 buffer;
+
+	/* Software fields */
+	struct list_head irq_list;	/* Active interrupt list.. */
+	usb_device_irq completed;	/* Completion handler routine */
+	unsigned int *backptr;		/* Where to remove this from.. */
+	void *dev_id;
+	int inuse;			/* Inuse? */
+	struct uhci_qh *qh;
+} __attribute__((aligned(32)));
+
+/*
+ * Note the alignment requirements of the entries
+ *
+ * Each UHCI device has pre-allocated QH and TD entries.
+ * You can use more than the pre-allocated ones, but I
+ * don't see you usually needing to.
+ */
+struct uhci;
+
+#define UHCI_MAXTD 32
+
+#define UHCI_MAXQH	16
+
+/* The usb device part must be first! */
+struct uhci_device {
+	struct usb_device	*usb;
+
+	struct uhci		*uhci;
+	struct uhci_qh		qh[UHCI_MAXQH];		/* These are the "common" qh's for each device */
+	struct uhci_td		td[UHCI_MAXTD];
+
+	unsigned long		data[16];
+};
+
+#define uhci_to_usb(uhci)	((uhci)->usb)
+#define usb_to_uhci(usb)	((struct uhci_device *)(usb)->hcpriv)
+
+/*
+ * The root hub pre-allocated QH's and TD's have
+ * some special global uses..
+ */
+#define control_td	td		/* Td's 0-30 */
+/* This is only for the root hub's TD list */
+#define tick_td		td[31]
+
+/*
+ * There are various standard queues. We set up several different
+ * queues for each of the three basic queue types: interrupt,
+ * control, and bulk.
+ *
+ *  - There are various different interrupt latencies: ranging from
+ *    every other USB frame (2 ms apart) to every 256 USB frames (ie
+ *    256 ms apart). Make your choice according to how obnoxious you
+ *    want to be on the wire, vs how critical latency is for you.
+ *  - The control list is done every frame.
+ *  - There are 4 bulk lists, so that up to four devices can have a
+ *    bulk list of their own and when run concurrently all four lists
+ *    will be be serviced.
+ *
+ * This is a bit misleading, there are various interrupt latencies, but they
+ * vary a bit, interrupt2 isn't exactly 2ms, it can vary up to 4ms since the
+ * other queues can "override" it. interrupt4 can vary up to 8ms, etc. Minor
+ * problem
+ *
+ * In the case of the root hub, these QH's are just head's of qh's. Don't
+ * be scared, it kinda makes sense. Look at this wonderful picture care of
+ * Linus:
+ *
+ *  generic-iso-QH  ->  dev1-iso-QH  ->  generic-irq-QH  ->  dev1-irq-QH  -> ...
+ *       |                       |                  |                   |
+ *      End          dev1-iso-TD1          End            dev1-irq-TD1
+ *                       |
+ *                   dev1-iso-TD2
+ *                       |
+ *                      ....
+ *
+ * This may vary a bit (the UHCI docs don't explicitly say you can put iso
+ * transfers in QH's and all of their pictures don't have that either) but
+ * other than that, that is what we're doing now
+ *
+ * To keep with Linus' nomenclature, this is called the qh skeleton. These
+ * labels (below) are only signficant to the root hub's qh's
+ */
+#define skel_iso_qh		qh[0]
+
+#define skel_int2_qh		qh[1]
+#define skel_int4_qh		qh[2]
+#define skel_int8_qh		qh[3]
+#define skel_int16_qh		qh[4]
+#define skel_int32_qh		qh[5]
+#define skel_int64_qh		qh[6]
+#define skel_int128_qh		qh[7]
+#define skel_int256_qh		qh[8]
+
+#define skel_control_qh		qh[9]
+
+#define skel_bulk0_qh		qh[10]
+#define skel_bulk1_qh		qh[11]
+#define skel_bulk2_qh		qh[12]
+#define skel_bulk3_qh		qh[13]
+
+/*
+ * These are significant to the devices allocation of QH's
+ */
+#if 0
+#define iso_qh			qh[0]
+#define int_qh			qh[1]	/* We have 2 "common" interrupt QH's */
+#define control_qh		qh[3]
+#define bulk_qh			qh[4]	/* We have 4 "common" bulk QH's */
+#define extra_qh		qh[8]	/* The rest, anything goes */
+#endif
+
+/*
+ * This describes the full uhci information.
+ *
+ * Note how the "proper" USB information is just
+ * a subset of what the full implementation needs.
+ */
+struct uhci {
+	int irq;
+	unsigned int io_addr;
+
+	struct usb_bus *bus;
+
+#if 0
+	/* These are "standard" QH's for the entire bus */
+	struct uhci_qh qh[UHCI_MAXQH];
+#endif
+	struct uhci_device *root_hub;		/* Root hub device descriptor.. */
+
+	struct uhci_framelist *fl;		/* Frame list */
+	struct list_head interrupt_list;	/* List of interrupt-active TD's for this uhci */
+};
+
+/* needed for the debugging code */
+struct uhci_td *uhci_link_to_td(unsigned int element);
+
+/* Debugging code */
+void show_td(struct uhci_td * td);
+void show_status(struct uhci *uhci);
+void show_queues(struct uhci *uhci);
+
+#endif
+
diff -urN linux-2.2.7-pre3/drivers/usb/usb.c linux-2.2.7-pre4/drivers/usb/usb.c
--- linux-2.2.7-pre3/drivers/usb/usb.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/usb.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,546 @@
+/*
+ * driver/usb/usb.c
+ *
+ * (C) Copyright Linus Torvalds 1999
+ *
+ * NOTE! This is not actually a driver at all, rather this is
+ * just a collection of helper routines that implement the
+ * generic USB things that the real drivers can use..
+ *
+ * Think of this as a "USB library" rather than anything else.
+ * It should be considered a slave, with no callbacks. Callbacks
+ * are evil.
+ */
+
+/*
+ * Table 9-2
+ *
+ * Offset	Field		Size	Value		Desc
+ * 0		bmRequestType	1	Bitmap		D7:	Direction
+ *							0 = Host-to-device
+ *							1 = Device-to-host
+ *							D6..5:	Type
+ *							0 = Standard
+ *							1 = Class
+ *							2 = Vendor
+ *							3 = Reserved
+ *							D4..0:	Recipient
+ *							0 = Device
+ *							1 = Interface
+ *							2 = Endpoint
+ *							3 = Other
+ *							4..31 = Reserved
+ * 1		bRequest	1	Value		Specific request (9-3)
+ * 2		wValue		2	Value		Varies
+ * 4		wIndex		2	Index/Offset	Varies
+ * 6		wLength		2	Count		Bytes for data
+ */
+
+#include <linux/string.h>
+#include <linux/bitops.h>
+#include <linux/malloc.h>
+
+#include "usb.h"
+
+/*
+ * We have a per-interface "registered driver" list.
+ */
+static LIST_HEAD(usb_driver_list);
+
+int usb_register(struct usb_driver *new_driver)
+{
+	/* Add it to the list of known drivers */
+	list_add(&new_driver->driver_list, &usb_driver_list);
+
+	/*
+	 * We should go through all existing devices, and see if any of
+	 * them would be acceptable to the new driver.. Let's do that
+	 * in version 2.0.
+	 */
+	return 0;
+}
+
+void usb_deregister(struct usb_driver *driver)
+{
+	list_del(&driver->driver_list);
+}
+
+/*
+ * This entrypoint gets called for each new device.
+ *
+ * We now walk the list of registered USB drivers,
+ * looking for one that will accept this device as
+ * his..
+ */
+void usb_device_descriptor(struct usb_device *dev)
+{
+	struct list_head *tmp = usb_driver_list.next;
+
+	while (tmp != &usb_driver_list) {
+		struct usb_driver *driver = list_entry(tmp, struct usb_driver, driver_list);
+		tmp = tmp->next;
+		if (driver->probe(dev))
+			continue;
+		dev->driver = driver;
+		return;
+	}
+
+	/*
+	 * Ok, no driver accepted the device, so show the info
+	 * for debugging..
+	 */
+	printk("Unknown new USB device:\n");
+	usb_show_device(dev);
+}
+
+/*
+ * Parse the fairly incomprehensible output of
+ * the USB configuration data, and build up the
+ * USB device database.
+ */
+static int usb_expect_descriptor(unsigned char *ptr, int len, unsigned char desctype, unsigned char descindex)
+{
+	int parsed = 0;
+
+	for (;;) {
+		unsigned short n_desc;
+		int n_len, i;
+
+		if (len < descindex)
+			return -1;
+		n_desc = *(unsigned short *)ptr;
+		if (n_desc == ((desctype << 8) + descindex))
+			return parsed;
+		printk(
+		"Expected descriptor %02X/%02X, got %02X/%02X - skipping\n",
+			desctype, descindex,
+			(n_desc >> 8) & 0xFF, n_desc & 0xFF);
+		n_len = n_desc & 0xff;
+		if (n_len < 2 || n_len > len)
+			return -1;
+		for (i = 0 ; i < n_len; i++)
+			printk("   %d %02x\n", i, ptr[i]);
+		len -= n_len;
+		ptr += n_len;
+		parsed += n_len;
+	}
+}
+
+static int usb_parse_endpoint(struct usb_endpoint_descriptor *endpoint, unsigned char *ptr, int len)
+{
+	int parsed = usb_expect_descriptor(ptr, len, USB_DT_ENDPOINT, 7);
+
+	if (parsed < 0)
+		return parsed;
+
+	memcpy(endpoint, ptr + parsed, 7);
+	return parsed + 7;
+}
+
+static int usb_parse_interface(struct usb_interface_descriptor *interface, unsigned char *ptr, int len)
+{
+	int i;
+	int parsed = usb_expect_descriptor(ptr, len, USB_DT_INTERFACE, 9);
+	int retval;
+
+	if (parsed < 0)
+		return parsed;
+
+	memcpy(interface, ptr + parsed, 9);
+	len -= 9;
+	parsed += 9;
+
+	if (interface->bNumEndpoints > USB_MAXENDPOINTS)
+		return -1;
+
+	for (i = 0; i < interface->bNumEndpoints; i++) {
+		if(((USB_DT_HID << 8) | 9) == *(unsigned short*)(ptr + parsed)) {
+			parsed += 9;	/* skip over the HID descriptor for now */
+			len -= 9;
+		}
+		retval = usb_parse_endpoint(interface->endpoint + i, ptr + parsed, len);
+		if (retval < 0) return retval;
+		parsed += retval;
+		len -= retval;
+	}
+	return parsed;
+}
+
+static int usb_parse_config(struct usb_config_descriptor *config, unsigned char *ptr, int len)
+{
+	int i;
+	int parsed = usb_expect_descriptor(ptr, len, USB_DT_CONFIG, 9);
+
+	if (parsed < 0)
+		return parsed;
+
+	memcpy(config, ptr + parsed, 9);
+	len -= 9;
+	parsed += 9;
+
+	if (config->bNumInterfaces > USB_MAXINTERFACES)
+		return -1;
+
+	for (i = 0; i < config->bNumInterfaces; i++) {
+		int retval = usb_parse_interface(config->interface + i, ptr + parsed, len);
+		if (retval < 0)
+			return retval;
+		parsed += retval;
+		len -= retval;
+	}
+	return parsed;
+}
+
+int usb_parse_configuration(struct usb_device *dev, void *__buf, int bytes)
+{
+	int i;
+	unsigned char *ptr = __buf;
+
+	if (dev->descriptor.bNumConfigurations > USB_MAXCONFIG)
+		return -1;
+
+	for (i = 0; i < dev->descriptor.bNumConfigurations; i++) {
+		int retval = usb_parse_config(dev->config + i, ptr, bytes);
+		if (retval < 0)
+			return retval;
+		ptr += retval;
+		bytes += retval;
+	}
+	return 0;
+}
+
+void usb_init_root_hub(struct usb_device *dev)
+{
+	dev->devnum = -1;
+	dev->slow = 0;
+}
+
+/*
+ * Something got disconnected. Get rid of it, and all of its children.
+ */
+void usb_disconnect(struct usb_device **pdev)
+{
+	struct usb_device * dev = *pdev;
+
+	if (dev) {
+		int i;
+
+		*pdev = NULL;
+
+		printk("USB disconnect on device %d\n", dev->devnum);
+
+		if(dev->driver) dev->driver->disconnect(dev);
+
+		/* Free up all the children.. */
+		for (i = 0; i < USB_MAXCHILDREN; i++) {
+			struct usb_device **child = dev->children + i;
+			usb_disconnect(child);
+		}
+
+		/* Free up the device itself, including its device number */
+		if (dev->devnum > 0)
+			clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
+		dev->bus->op->deallocate(dev);
+	}
+}
+
+
+/*
+ * Connect a new USB device. This basically just initializes
+ * the USB device information and sets up the topology - it's
+ * up to the low-level driver to reset the port and actually
+ * do the setup (the upper levels don't know how to do that).
+ */
+void usb_connect(struct usb_device *dev)
+{
+	int devnum;
+
+	dev->descriptor.bMaxPacketSize0 = 8;  /* XXX fixed 8 bytes for now */
+
+	devnum = find_next_zero_bit(dev->bus->devmap.devicemap, 128, 1);
+	if (devnum < 128) {
+		set_bit(devnum, dev->bus->devmap.devicemap);
+		dev->devnum = devnum;
+	}
+}
+
+/*
+ * These are the actual routines to send
+ * and receive control messages.
+ */
+int usb_set_address(struct usb_device *dev)
+{
+	devrequest dr;
+
+	dr.requesttype = 0;
+	dr.request = USB_REQ_SET_ADDRESS;
+	dr.value = dev->devnum;
+	dr.index = 0;
+	dr.length = 0;
+
+	return dev->bus->op->control_msg(dev, usb_snddefctrl(dev), &dr, NULL, 0);
+}
+
+int usb_get_descriptor(struct usb_device *dev, unsigned char type, unsigned char index, void *buf, int size)
+{
+	devrequest dr;
+
+	dr.requesttype = 0x80;
+	dr.request = USB_REQ_GET_DESCRIPTOR;
+	dr.value = (type << 8) + index;
+	dr.index = 0;
+	dr.length = size;
+
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, buf, size);
+}
+
+int usb_get_device_descriptor(struct usb_device *dev)
+{
+	return usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, sizeof(dev->descriptor));
+}
+
+int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_HUB | 0x80;
+	dr.request = USB_REQ_GET_DESCRIPTOR;
+	dr.value = (USB_DT_HUB << 8);
+	dr.index = 0;
+	dr.length = size;
+
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, size);
+}
+
+int usb_clear_port_feature(struct usb_device *dev, int port, int feature)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_PORT;
+	dr.request = USB_REQ_CLEAR_FEATURE;
+	dr.value = feature;
+	dr.index = port;
+	dr.length = 0;
+
+	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_set_port_feature(struct usb_device *dev, int port, int feature)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_PORT;
+	dr.request = USB_REQ_SET_FEATURE;
+	dr.value = feature;
+	dr.index = port;
+	dr.length = 0;
+
+	return dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev,0), &dr, NULL, 0);
+}
+
+int usb_get_hub_status(struct usb_device *dev, void *data)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_HUB | 0x80;
+	dr.request = USB_REQ_GET_STATUS;
+	dr.value = 0;
+	dr.index = 0;
+	dr.length = 4;
+
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
+}
+
+int usb_get_port_status(struct usb_device *dev, int port, void *data)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_PORT | 0x80;
+	dr.request = USB_REQ_GET_STATUS;
+	dr.value = 0;
+	dr.index = port;
+	dr.length = 4;
+
+	return dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev,0), &dr, data, 4);
+}
+
+int usb_get_protocol(struct usb_device *dev)
+{
+	unsigned char buf[8];
+	devrequest dr;
+
+	dr.requesttype = USB_RT_HIDD | 0x80;
+	dr.request = USB_REQ_GET_PROTOCOL;
+	dr.value = 0;
+	dr.index = 1;
+	dr.length = 1;
+
+	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 1))
+		return -1;
+
+	return buf[0];
+}
+
+int usb_set_protocol(struct usb_device *dev, int protocol)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_HIDD;
+	dr.request = USB_REQ_SET_PROTOCOL;
+	dr.value = protocol;
+	dr.index = 1;
+	dr.length = 0;
+
+	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+		return -1;
+
+	return 0;
+}
+
+/* keyboards want a nonzero duration according to HID spec, but
+   mice should use infinity (0) -keryan */
+int usb_set_idle(struct usb_device *dev,  int duration, int report_id)
+{
+	devrequest dr;
+
+	dr.requesttype = USB_RT_HIDD;
+	dr.request = USB_REQ_SET_IDLE;
+	dr.value = (duration << 8) | report_id;
+	dr.index = 1;
+	dr.length = 0;
+
+	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+		return -1;
+
+	return 0;
+}
+
+int usb_set_configuration(struct usb_device *dev, int configuration)
+{
+	devrequest dr;
+
+	dr.requesttype = 0;
+	dr.request = USB_REQ_SET_CONFIGURATION;
+	dr.value = configuration;
+	dr.index = 0;
+	dr.length = 0;
+
+	if (dev->bus->op->control_msg(dev, usb_sndctrlpipe(dev, 0), &dr, NULL, 0))
+		return -1;
+
+	return 0;
+}
+
+int usb_get_report(struct usb_device *dev)
+{
+	unsigned char buf[8];
+	devrequest dr;
+
+	dr.requesttype = USB_RT_HIDD | 0x80;
+	dr.request = USB_REQ_GET_REPORT;
+	dr.value = 0x100;
+	dr.index = 1;
+	dr.length = 3;
+
+	if (dev->bus->op->control_msg(dev, usb_rcvctrlpipe(dev, 0), &dr, buf, 3))
+		return -1;
+
+	return buf[0];
+}
+
+int usb_get_configuration(struct usb_device *dev)
+{
+	unsigned int size;
+	unsigned char buffer[128];
+
+	/* Get the first 8 bytes - guaranteed */
+	if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, 8))
+		return -1;
+
+	/* Get the full buffer */
+	size = *(unsigned short *)(buffer+2);
+	if (size > sizeof(buffer))
+		size = sizeof(buffer);
+
+	if (usb_get_descriptor(dev, USB_DT_CONFIG, 0, buffer, size))
+		return -1;
+
+	return usb_parse_configuration(dev, buffer, size);
+}
+
+/*
+ * By the time we get here, the device has gotten a new device ID
+ * and is in the default state. We need to identify the thing and
+ * get the ball rolling..
+ */
+void usb_new_device(struct usb_device *dev)
+{
+	int addr, i;
+
+	printk("USB new device connect, assigned device number %d\n",
+		dev->devnum);
+
+	dev->maxpacketsize = 0;		/* Default to 8 byte max packet size */
+
+	addr = dev->devnum;
+	dev->devnum = 0;
+
+	/* Slow devices */
+	for (i = 0; i < 5; i++) {
+		if (!usb_get_descriptor(dev, USB_DT_DEVICE, 0, &dev->descriptor, 8))
+			break;
+
+		printk("get_descriptor failed, waiting\n");
+		wait_ms(200);
+	}
+	if (i == 5) {
+		printk("giving up\n");
+		return;
+	}
+
+#if 0
+	printk("maxpacketsize: %d\n", dev->descriptor.bMaxPacketSize0);
+#endif
+	switch (dev->descriptor.bMaxPacketSize0) {
+		case 8: dev->maxpacketsize = 0; break;
+		case 16: dev->maxpacketsize = 1; break;
+		case 32: dev->maxpacketsize = 2; break;
+		case 64: dev->maxpacketsize = 3; break;
+	}
+#if 0
+	printk("dev->mps: %d\n", dev->maxpacketsize);
+#endif
+
+	dev->devnum = addr;
+
+	if (usb_set_address(dev)) {
+		printk("Unable to set address\n");
+		/* FIXME: We should disable the port */
+		return;
+	}
+
+	wait_ms(10);	/* Let the SET_ADDRESS settle */
+
+	if (usb_get_device_descriptor(dev)) {
+		printk("Unable to get device descriptor\n");
+		return;
+	}
+
+	if (usb_get_configuration(dev)) {
+		printk("Unable to get configuration\n");
+		return;
+	}
+
+#if 0
+	printk("Vendor: %X\n", dev->descriptor.idVendor);
+	printk("Product: %X\n", dev->descriptor.idProduct);
+#endif
+
+	usb_device_descriptor(dev);
+}
+
+int usb_request_irq(struct usb_device *dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id)
+{
+	return dev->bus->op->request_irq(dev, pipe, handler, period, dev_id);
+}
+
diff -urN linux-2.2.7-pre3/drivers/usb/usb-debug.c linux-2.2.7-pre4/drivers/usb/usb-debug.c
--- linux-2.2.7-pre3/drivers/usb/usb-debug.c	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/usb-debug.c	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,127 @@
+/*
+ * debug.c - USB debug helper routines.
+ *
+ * I just want these out of the way where they aren't in your
+ * face, but so that you can still use them..
+ */
+#include <linux/kernel.h>
+
+#include "usb.h"
+
+static void usb_show_endpoint(struct usb_endpoint_descriptor *endpoint)
+{
+	usb_show_endpoint_descriptor(endpoint);
+}
+
+static void usb_show_interface(struct usb_interface_descriptor *interface)
+{
+	int i;
+
+	usb_show_interface_descriptor(interface);
+	for (i = 0 ; i < interface->bNumEndpoints; i++)
+		usb_show_endpoint(interface->endpoint + i);
+}
+
+static void usb_show_config(struct usb_config_descriptor *config)
+{
+	int i;
+
+	usb_show_config_descriptor(config);
+	for (i = 0 ; i < config->bNumInterfaces; i++)
+		usb_show_interface(config->interface + i);
+}
+
+void usb_show_device(struct usb_device *dev)
+{
+	int i;
+
+	usb_show_device_descriptor(&dev->descriptor);
+	for (i = 0; i < dev->descriptor.bNumConfigurations; i++)
+		usb_show_config(dev->config + i);
+}
+
+
+/*
+ * Parse and show the different USB descriptors.
+ */
+void usb_show_device_descriptor(struct usb_device_descriptor *desc)
+{
+	printk("  USB version %x.%02x\n", desc->bcdUSB >> 8, desc->bcdUSB & 0xff);
+	printk("  Vendor:  %04x\n", desc->idVendor);
+	printk("  Product: %04x\n", desc->idProduct);
+	printk("  Configurations: %d\n", desc->bNumConfigurations);
+
+	printk("  Device Class: %d\n", desc->bDeviceClass);
+	switch (desc->bDeviceClass) {
+	case 0:
+		printk("    Per-interface classes\n");
+		break;
+	case 9:
+		printk("    Hub device class\n");
+		break;
+	case 0xff:
+		printk("    Vendor class\n");
+		break;
+	default:
+		printk("    Unknown class\n");
+	}
+}
+
+void usb_show_config_descriptor(struct usb_config_descriptor * desc)
+{
+	printk("Configuration:\n");
+	printk("  bLength             = %4d%s\n", desc->bLength,
+		desc->bLength == 9 ? "" : " (!!!)");
+	printk("  bDescriptorType     =   %02x\n", desc->bDescriptorType);
+	printk("  wTotalLength        = %04x\n", desc->wTotalLength);
+	printk("  bNumInterfaces      =   %02x\n", desc->bNumInterfaces);
+	printk("  bConfigurationValue =   %02x\n", desc->bConfigurationValue);
+	printk("  iConfiguration      =   %02x\n", desc->iConfiguration);
+	printk("  bmAttributes        =   %02x\n", desc->bmAttributes);
+	printk("  MaxPower            = %4dmA\n", desc->MaxPower * 2);
+}
+
+void usb_show_interface_descriptor(struct usb_interface_descriptor * desc)
+{
+	printk("  Interface:\n");
+	printk("    bLength             = %4d%s\n", desc->bLength,
+		desc->bLength == 9 ? "" : " (!!!)");
+	printk("    bDescriptorType     =   %02x\n", desc->bDescriptorType);
+	printk("    bInterfaceNumber    =   %02x\n", desc->bInterfaceNumber);
+	printk("    bAlternateSetting   =   %02x\n", desc->bAlternateSetting);
+	printk("    bNumEndpoints       =   %02x\n", desc->bNumEndpoints);
+	printk("    bInterfaceClass     =   %02x\n", desc->bInterfaceClass);
+	printk("    bInterfaceSubClass  =   %02x\n", desc->bInterfaceSubClass);
+	printk("    bInterfaceProtocol  =   %02x\n", desc->bInterfaceProtocol);
+	printk("    iInterface          =   %02x\n", desc->iInterface);
+}
+
+void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor * desc)
+{
+	char *EndpointType[4] = { "Control", "Isochronous", "Bulk", "Interrupt" };
+	printk("    Endpoint:\n");
+	printk("      bLength             = %4d%s\n", desc->bLength,
+		desc->bLength == 7 ? "" : " (!!!)");
+	printk("      bDescriptorType     =   %02x\n", desc->bDescriptorType);
+	printk("      bEndpointAddress    =   %02x (%s)\n", desc->bEndpointAddress,
+		(desc->bEndpointAddress & 0x80) ? "in" : "out");
+	printk("      bmAttributes        =   %02x (%s)\n", desc->bmAttributes,
+		EndpointType[3 & desc->bmAttributes]);
+	printk("      wMaxPacketSize      = %04x\n", desc->wMaxPacketSize);
+	printk("      bInterval           =   %02x\n", desc->bInterval);
+}
+
+void usb_show_hub_descriptor(struct usb_hub_descriptor * desc)
+{
+	int len = 7;
+	unsigned char *ptr = (unsigned char *) desc;
+
+	printk("Interface:");
+	while (len) {
+		printk(" %02x", *ptr);
+		ptr++; len--;
+	}
+	printk("\n");
+}
+
+
diff -urN linux-2.2.7-pre3/drivers/usb/usb.h linux-2.2.7-pre4/drivers/usb/usb.h
--- linux-2.2.7-pre3/drivers/usb/usb.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/drivers/usb/usb.h	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,359 @@
+#ifndef __LINUX_USB_H
+#define __LINUX_USB_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/sched.h>
+
+static __inline__ void wait_ms(unsigned int ms)
+{
+        current->state = TASK_UNINTERRUPTIBLE;
+        schedule_timeout(1 + ms / 10);
+}
+
+
+typedef struct {
+  unsigned char requesttype;
+  unsigned char request;
+  unsigned short value;
+  unsigned short index;
+  unsigned short length;
+} devrequest;
+
+/*
+ * Class codes
+ */
+#define USB_CLASS_HUB			9
+
+/*
+ * Descriptor types
+ */
+#define USB_DT_DEVICE			0x01
+#define USB_DT_CONFIG			0x02
+#define USB_DT_STRING			0x03
+#define USB_DT_INTERFACE		0x04
+#define USB_DT_ENDPOINT			0x05
+
+#define USB_DT_HUB			0x29
+#define USB_DT_HID			0x21
+
+/*
+ * Standard requests
+ */
+#define USB_REQ_GET_STATUS		0x00
+#define USB_REQ_CLEAR_FEATURE		0x01
+/* 0x02 is reserved */
+#define USB_REQ_SET_FEATURE		0x03
+/* 0x04 is reserved */
+#define USB_REQ_SET_ADDRESS		0x05
+#define USB_REQ_GET_DESCRIPTOR		0x06
+#define USB_REQ_SET_DESCRIPTOR		0x07
+#define USB_REQ_GET_CONFIGURATION	0x08
+#define USB_REQ_SET_CONFIGURATION	0x09
+#define USB_REQ_GET_INTERFACE		0x0A
+#define USB_REQ_SET_INTERFACE		0x0B
+#define USB_REQ_SYNCH_FRAME		0x0C
+
+/*
+ * HIDD requests
+ */
+#define USB_REQ_GET_REPORT		0x01
+#define USB_REQ_GET_IDLE		0x02
+#define USB_REQ_GET_PROTOCOL		0x03
+#define USB_REQ_SET_REPORT		0x09
+#define USB_REQ_SET_IDLE		0x0A
+#define USB_REQ_SET_PROTOCOL		0x0B
+
+#define USB_TYPE_STANDARD		(0x00 << 5)
+#define USB_TYPE_CLASS			(0x01 << 5)
+#define USB_TYPE_VENDOR			(0x02 << 5)
+#define USB_TYPE_RESERVED		(0x03 << 5)
+
+#define USB_RECIP_DEVICE		0x00
+#define USB_RECIP_INTERFACE		0x01
+#define USB_RECIP_ENDPOINT		0x02
+#define USB_RECIP_OTHER			0x03
+
+/*
+ * Request target types.
+ */
+#define USB_RT_DEVICE			0x00
+#define USB_RT_INTERFACE		0x01
+#define USB_RT_ENDPOINT			0x02
+
+#define USB_RT_HUB			(USB_TYPE_CLASS | USB_RECIP_DEVICE)
+#define USB_RT_PORT			(USB_TYPE_CLASS | USB_RECIP_OTHER)
+
+#define USB_RT_HIDD			(USB_TYPE_CLASS | USB_RECIP_INTERFACE)
+
+/*
+ * USB device number allocation bitmap. There's one bitmap
+ * per USB tree.
+ */
+struct usb_devmap {
+	unsigned long devicemap[128 / (8*sizeof(unsigned long))];
+};
+
+/*
+ * This is a USB device descriptor.
+ *
+ * USB device information
+ *
+ * Make this MUCH dynamic, right now
+ * it contains enough information for
+ * a USB floppy controller, and nothing
+ * else.
+ *
+ * I'm not proud. I just want this dang
+ * thing to start working.
+ */
+#define USB_MAXCONFIG		1
+#define USB_MAXINTERFACES	3
+#define USB_MAXENDPOINTS	3
+
+struct usb_device_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u16 bcdUSB;
+	__u8  bDeviceClass;
+	__u8  bDeviceSubClass;
+	__u8  bDeviceProtocol;
+	__u8  bMaxPacketSize0;
+	__u16 idVendor;
+	__u16 idProduct;
+	__u16 bcdDevice;
+	__u8  iManufacturer;
+	__u8  iProduct;
+	__u8  iSerialNumber;
+	__u8  bNumConfigurations;
+};
+
+/* Endpoint descriptor */
+struct usb_endpoint_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bEndpointAddress;
+	__u8  bmAttributes;
+	__u16 wMaxPacketSize;
+	__u8  bInterval;
+};
+
+/* Interface descriptor */
+struct usb_interface_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bInterfaceNumber;
+	__u8  bAlternateSetting;
+	__u8  bNumEndpoints;
+	__u8  bInterfaceClass;
+	__u8  bInterfaceSubClass;
+	__u8  bInterfaceProtocol;
+	__u8  iInterface;
+
+	struct usb_endpoint_descriptor endpoint[USB_MAXENDPOINTS];
+};
+
+/* Configuration descriptor information.. */
+struct usb_config_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u16 wTotalLength;
+	__u8  bNumInterfaces;
+	__u8  bConfigurationValue;
+	__u8  iConfiguration;
+	__u8  bmAttributes;
+	__u8  MaxPower;
+
+	struct usb_interface_descriptor interface[USB_MAXINTERFACES];
+};
+
+/* String descriptor */
+struct usb_string_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+};
+
+/* Hub descriptor */
+struct usb_hub_descriptor {
+	__u8  bLength;
+	__u8  bDescriptorType;
+	__u8  bNbrPorts;
+	__u16 wHubCharacteristics;
+	__u8  bPwrOn2PwrGood;
+	__u8  bHubContrCurrent;
+	/* DeviceRemovable and PortPwrCtrlMask want to be variable-length 
+	   bitmaps that hold max 256 entries, but for now they're ignored */
+	__u8  filler;
+};
+
+struct usb_device;
+
+struct usb_driver {
+	const char * name;
+	int (*probe)(struct usb_device *);
+	void (*disconnect)(struct usb_device *);
+	struct list_head driver_list;
+};
+
+/*
+ * Pointer to a device endpoint interrupt function -greg
+ */
+typedef int (*usb_device_irq)(int, void *, void *);
+
+struct usb_operations {
+	struct usb_device *(*allocate)(struct usb_device *);
+	int (*deallocate)(struct usb_device *);
+	int (*control_msg)(struct usb_device *, unsigned int, void *, void *, int);
+	int (*request_irq)(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+};
+
+/*
+ * Allocated per bus we have
+ */
+struct usb_bus {
+	struct usb_devmap devmap;       /* Device map */
+	struct usb_operations *op;      /* Operations (specific to the HC) */
+	struct usb_device *root_hub;    /* Root hub */
+	void *hcpriv;                   /* Host Controller private data */
+};
+
+
+#define USB_MAXCHILDREN (8)
+
+struct usb_device {
+	int devnum;						/* Device number on USB bus */
+	int slow;						/* Slow device? */
+	int maxpacketsize;					/* Maximum packet size */
+
+	struct usb_bus *bus;					/* Bus we're apart of */
+	struct usb_driver *driver;				/* Driver */
+	struct usb_device_descriptor descriptor;		/* Descriptor */
+	struct usb_config_descriptor config[USB_MAXCONFIG];	/* All of the configs */
+	struct usb_device *parent;
+  
+	/*
+	 * Child devices - these can be either new devices
+	 * (if this is a hub device), or different instances
+	 * of this same device.
+	 *
+	 * Each instance needs its own set of data structuctures.
+	 */
+
+	int maxchild;			/* Number of ports if hub */
+	struct usb_device *children[USB_MAXCHILDREN];
+
+	void *hcpriv;			/* Host Controller private data */
+	void *private;			/* Upper layer private data */
+};
+
+extern int usb_register(struct usb_driver *);
+extern void usb_deregister(struct usb_driver *);
+
+extern int usb_request_irq(struct usb_device *, unsigned int, usb_device_irq, int, void *);
+
+extern void usb_init_root_hub(struct usb_device *dev);
+extern void usb_connect(struct usb_device *dev);
+extern void usb_disconnect(struct usb_device **);
+extern void usb_device_descriptor(struct usb_device *dev);
+
+extern int  usb_parse_configuration(struct usb_device *dev, void *buf, int len);
+
+/*
+ * Calling this entity a "pipe" is glorifying it. A USB pipe
+ * is something embarrassingly simple: it basically consists
+ * of the following information:
+ *  - device number (7 bits)
+ *  - endpoint number (4 bits)
+ *  - current Data0/1 state (1 bit)
+ *  - direction (1 bit)
+ *  - speed (1 bit)
+ *  - max packet size (2 bits: 8, 16, 32 or 64)
+ *  - pipe type (2 bits: control, interrupt, bulk, isochronous)
+ *
+ * That's 18 bits. Really. Nothing more. And the USB people have
+ * documented these eighteen bits as some kind of glorious
+ * virtual data structure.
+ *
+ * Let's not fall in that trap. We'll just encode it as a simple
+ * unsigned int. The encoding is:
+ *
+ *  - device:		bits 8-14
+ *  - endpoint:		bits 15-18
+ *  - Data0/1:		bit 19
+ *  - direction:	bit 7		(0 = Host-to-Device, 1 = Device-to-Host)
+ *  - speed:		bit 26		(0 = High, 1 = Low Speed)
+ *  - max size:		bits 0-1	(00 = 8, 01 = 16, 10 = 32, 11 = 64)
+ *  - pipe type:	bits 30-31	(00 = isochronous, 01 = interrupt, 10 = control, 11 = bulk)
+ *
+ * Why? Because it's arbitrary, and whatever encoding we select is really
+ * up to us. This one happens to share a lot of bit positions with the UCHI
+ * specification, so that much of the uhci driver can just mask the bits
+ * appropriately.
+ */
+
+#define usb_maxpacket(pipe)	(8 << ((pipe) & 3))
+#define usb_packetid(pipe)	(((pipe) & 0x80) ? 0x69 : 0xE1)
+
+#define usb_pipedevice(pipe)	(((pipe) >> 8) & 0x7f)
+#define usb_pipeendpoint(pipe)	(((pipe) >> 15) & 0xf)
+#define usb_pipedata(pipe)	(((pipe) >> 19) & 1)
+#define usb_pipeout(pipe)	(((pipe) & 0x80) == 0)
+#define usb_pipeslow(pipe)	(((pipe) >> 26) & 1)
+
+#define usb_pipetype(pipe)	(((pipe) >> 30) & 3)
+#define usb_pipeisoc(pipe)	(usb_pipetype((pipe)) == 0)
+#define usb_pipeint(pipe)	(usb_pipetype((pipe)) == 1)
+#define usb_pipecontrol(pipe)	(usb_pipetype((pipe)) == 2)
+#define usb_pipebulk(pipe)	(usb_pipetype((pipe)) == 3)
+
+#define usb_pipe_endpdev(pipe)	(((pipe) >> 8) & 0x7ff)
+
+static inline unsigned int __create_pipe(struct usb_device *dev, unsigned int endpoint)
+{
+	return (dev->devnum << 8) | (endpoint << 15) | (dev->slow << 26) | dev->maxpacketsize;
+}
+
+static inline unsigned int __default_pipe(struct usb_device *dev)
+{
+	return (dev->slow << 26);
+}
+
+/* Create control pipes.. */
+#define usb_sndctrlpipe(dev,endpoint)	((2 << 30) | __create_pipe(dev,endpoint))
+#define usb_rcvctrlpipe(dev,endpoint)	((2 << 30) | __create_pipe(dev,endpoint) | 0x80)
+#define usb_snddefctrl(dev)		((2 << 30) | __default_pipe(dev))
+#define usb_rcvdefctrl(dev)		((2 << 30) | __default_pipe(dev) | 0x80)
+
+/* Create .. */
+
+/*
+ * Send and receive control messages..
+ */
+void usb_new_device(struct usb_device *dev);
+int usb_set_address(struct usb_device *dev);
+int usb_get_descriptor(struct usb_device *dev, unsigned char desctype, unsigned
+char descindex, void *buf, int size);
+int usb_get_device_descriptor(struct usb_device *dev);
+int usb_get_hub_descriptor(struct usb_device *dev, void *data, int size);
+int usb_clear_port_feature(struct usb_device *dev, int port, int feature);
+int usb_set_port_feature(struct usb_device *dev, int port, int feature);
+int usb_get_hub_status(struct usb_device *dev, void *data);
+int usb_get_port_status(struct usb_device *dev, int port, void *data);
+int usb_get_protocol(struct usb_device *dev);
+int usb_set_protocol(struct usb_device *dev, int protocol);
+int usb_set_idle(struct usb_device *dev, int duration, int report_id);
+int usb_set_configuration(struct usb_device *dev, int configuration);
+int usb_get_report(struct usb_device *dev);
+
+/*
+ * Debugging helpers..
+ */
+void usb_show_device_descriptor(struct usb_device_descriptor *);
+void usb_show_config_descriptor(struct usb_config_descriptor *);
+void usb_show_interface_descriptor(struct usb_interface_descriptor *);
+void usb_show_endpoint_descriptor(struct usb_endpoint_descriptor *);
+void usb_show_hub_descriptor(struct usb_hub_descriptor *);
+void usb_show_device(struct usb_device *);
+
+#endif
+
diff -urN linux-2.2.7-pre3/fs/adfs/dir.c linux-2.2.7-pre4/fs/adfs/dir.c
--- linux-2.2.7-pre3/fs/adfs/dir.c	1998-08-24 13:02:44.000000000 -0700
+++ linux-2.2.7-pre4/fs/adfs/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -280,8 +280,6 @@
 	unsigned long parent_object_id, dir_object_id;
 	int buffers, pos;
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
 	sb = inode->i_sb;
 
 	if (filp->f_pos > ADFS_NUM_DIR_ENTRIES + 2)
diff -urN linux-2.2.7-pre3/fs/adfs/namei.c linux-2.2.7-pre4/fs/adfs/namei.c
--- linux-2.2.7-pre3/fs/adfs/namei.c	1998-01-20 16:44:58.000000000 -0800
+++ linux-2.2.7-pre4/fs/adfs/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -98,22 +98,22 @@
 	return 0;
 }
 
-int adfs_lookup (struct inode *dir, struct dentry *dentry)
+struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry)
 {
 	struct inode *inode = NULL;
 	struct adfs_idir_entry de;
 	unsigned long ino;
 
 	if (dentry->d_name.len > ADFS_NAME_LEN)
-		return -ENAMETOOLONG;
+		return ERR_PTR(-ENAMETOOLONG);
 
 	if (adfs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de)) {
 		ino = de.inode_no;
 		inode = iget (dir->i_sb, ino);
 
 		if (!inode)
-			return -EACCES;
+			return ERR_PTR(-EACCES);
 	}
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
diff -urN linux-2.2.7-pre3/fs/affs/dir.c linux-2.2.7-pre4/fs/affs/dir.c
--- linux-2.2.7-pre3/fs/affs/dir.c	1998-08-24 13:02:44.000000000 -0700
+++ linux-2.2.7-pre4/fs/affs/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -90,9 +90,6 @@
 
 	pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
-
 	stored = 0;
 	dir_bh = NULL;
 	fh_bh  = NULL;
diff -urN linux-2.2.7-pre3/fs/affs/namei.c linux-2.2.7-pre4/fs/affs/namei.c
--- linux-2.2.7-pre3/fs/affs/namei.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/affs/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -201,7 +201,7 @@
 	return bh;
 }
 
-int
+struct dentry *
 affs_lookup(struct inode *dir, struct dentry *dentry)
 {
 	unsigned long		 ino;
@@ -218,11 +218,11 @@
 		affs_brelse(bh);
 		inode = iget(dir->i_sb,ino);
 		if (!inode)
-			return -EACCES;
+			return ERR_PTR(-EACCES);
 	}
 	dentry->d_op = &affs_dentry_operations;
 	d_add(dentry,inode);
-	return 0;
+	return NULL;
 }
 
 int
diff -urN linux-2.2.7-pre3/fs/autofs/dir.c linux-2.2.7-pre4/fs/autofs/dir.c
--- linux-2.2.7-pre3/fs/autofs/dir.c	1998-10-27 14:13:53.000000000 -0800
+++ linux-2.2.7-pre4/fs/autofs/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -38,10 +38,10 @@
 /*
  * No entries except for "." and "..", both of which are handled by the VFS layer
  */
-static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *autofs_dir_lookup(struct inode *dir,struct dentry *dentry)
 {
 	d_add(dentry, NULL);
-	return 0;
+	return NULL;
 }
 
 static struct file_operations autofs_dir_operations = {
diff -urN linux-2.2.7-pre3/fs/autofs/root.c linux-2.2.7-pre4/fs/autofs/root.c
--- linux-2.2.7-pre3/fs/autofs/root.c	1999-03-10 15:07:56.000000000 -0800
+++ linux-2.2.7-pre4/fs/autofs/root.c	2003-08-15 15:05:52.000000000 -0700
@@ -16,7 +16,7 @@
 #include "autofs_i.h"
 
 static int autofs_root_readdir(struct file *,void *,filldir_t);
-static int autofs_root_lookup(struct inode *,struct dentry *);
+static struct dentry *autofs_root_lookup(struct inode *,struct dentry *);
 static int autofs_root_symlink(struct inode *,struct dentry *,const char *);
 static int autofs_root_unlink(struct inode *,struct dentry *);
 static int autofs_root_rmdir(struct inode *,struct dentry *);
@@ -209,7 +209,7 @@
 	NULL,			/* d_compare */
 };
 
-static int autofs_root_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *autofs_root_lookup(struct inode *dir, struct dentry *dentry)
 {
 	struct autofs_sb_info *sbi;
 	int oz_mode;
@@ -217,11 +217,8 @@
 	DPRINTK(("autofs_root_lookup: name = "));
 	autofs_say(dentry->d_name.name,dentry->d_name.len);
 
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOTDIR;
-
 	if (dentry->d_name.len > NAME_MAX)
-		return -ENOENT;	/* File name too long to exist */
+		return ERR_PTR(-ENOENT);/* File name too long to exist */
 
 	sbi = autofs_sbi(dir->i_sb);
 
@@ -253,7 +250,7 @@
 	 */
 	if (dentry->d_flags & DCACHE_AUTOFS_PENDING) {
 		if (signal_pending(current))
-			return -ERESTARTNOINTR;
+			return ERR_PTR(-ERESTARTNOINTR);
 	}
 
 	/*
@@ -263,9 +260,9 @@
 	 * be OK for the operations we permit from an autofs.
 	 */
 	if ( dentry->d_inode && list_empty(&dentry->d_hash) )
-		return -ENOENT;
+		return ERR_PTR(-ENOENT);
 
-	return 0;
+	return NULL;
 }
 
 static int autofs_root_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
diff -urN linux-2.2.7-pre3/fs/buffer.c linux-2.2.7-pre4/fs/buffer.c
--- linux-2.2.7-pre3/fs/buffer.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/fs/buffer.c	2003-08-15 15:05:52.000000000 -0700
@@ -804,6 +804,7 @@
 	/* If dirty, mark the time this buffer should be written back. */
 	set_writetime(buf, 0);
 	refile_buffer(buf);
+	touch_buffer(buf);
 
 	if (buf->b_count) {
 		buf->b_count--;
@@ -839,7 +840,6 @@
 	struct buffer_head * bh;
 
 	bh = getblk(dev, block, size);
-	touch_buffer(bh);
 	if (buffer_uptodate(bh))
 		return bh;
 	ll_rw_block(READ, 1, &bh);
@@ -876,7 +876,6 @@
 	bh = getblk(dev, block, bufsize);
 	index = BUFSIZE_INDEX(bh->b_size);
 
-	touch_buffer(bh);
 	if (buffer_uptodate(bh))
 		return(bh);   
 	else ll_rw_block(READ, 1, &bh);
diff -urN linux-2.2.7-pre3/fs/coda/dir.c linux-2.2.7-pre4/fs/coda/dir.c
--- linux-2.2.7-pre3/fs/coda/dir.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/coda/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -29,7 +29,7 @@
 /* dir inode-ops */
 static int coda_create(struct inode *dir, struct dentry *new, int mode);
 static int coda_mknod(struct inode *dir, struct dentry *new, int mode, int rdev);
-static int coda_lookup(struct inode *dir, struct dentry *target);
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *target);
 static int coda_link(struct dentry *old_dentry, struct inode *dir_inode, 
 		     struct dentry *entry);
 static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
@@ -107,7 +107,7 @@
 
 /* inode operations for directories */
 /* acces routines: lookup, readlink, permission */
-static int coda_lookup(struct inode *dir, struct dentry *entry)
+static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry)
 {
         struct coda_inode_info *dircnp;
 	struct inode *res_inode = NULL;
@@ -125,16 +125,9 @@
 	if ( length > CODA_MAXNAMLEN ) {
 	        printk("name too long: lookup, %s (%*s)\n", 
 		       coda_f2s(&dircnp->c_fid), length, name);
-		return -ENAMETOOLONG;
+		return ERR_PTR(-ENAMETOOLONG);
 	}
 
-
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("coda_lookup: inode is NULL or not a directory\n");
-		return -ENOTDIR;
-	}
-
-
         CDEBUG(D_INODE, "name %s, len %d in ino %ld, fid %s\n", 
 	       name, length, dir->i_ino, coda_f2s(&dircnp->c_fid));
 
@@ -160,11 +153,11 @@
 		}
 	    	error = coda_cnode_make(&res_inode, &resfid, dir->i_sb);
 		if (error)
-			return error;
+			return ERR_PTR(error);
 	} else if (error != -ENOENT) {
 	        CDEBUG(D_INODE, "error for %s(%*s)%d\n",
 		       coda_f2s(&dircnp->c_fid), length, name, error);
-		return error;
+		return ERR_PTR(error);
 	}
 	CDEBUG(D_INODE, "lookup: %s is (%s), type %d result %d, dropme %d\n",
 	       name, coda_f2s(&resfid), type, error, dropme);
@@ -178,7 +171,7 @@
 		ITOC(res_inode)->c_flags |= C_VATTR;
 	}
         EXIT;
-        return 0;
+        return NULL;
 }
 
 
@@ -236,11 +229,6 @@
 
 	CDEBUG(D_INODE, "name: %s, length %d, mode %o\n",name, length, mode);
 
-        if (!dir || !S_ISDIR(dir->i_mode)) {
-                printk("coda_create: inode is null or not a directory\n");
-                return -ENOENT;
-        }
-
 	if (coda_isroot(dir) && coda_iscontrol(name, length))
 		return -EPERM;
 
@@ -286,11 +274,6 @@
 
 	CDEBUG(D_INODE, "name: %s, length %d, mode %o, rdev %x\n",name, length, mode, rdev);
 
-        if (!dir || !S_ISDIR(dir->i_mode)) {
-                printk("coda_mknod: inode is null or not a directory\n");
-                return -ENOENT;
-        }
-
 	if (coda_isroot(dir) && coda_iscontrol(name, length))
 		return -EPERM;
 
@@ -332,11 +315,6 @@
 	ENTRY;
 	coda_vfs_stat.mkdir++;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("coda_mkdir: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
-
 	if (coda_isroot(dir) && coda_iscontrol(name, len))
 		return -EPERM;
 
@@ -490,10 +468,6 @@
 	ENTRY;
 	coda_vfs_stat.rmdir++;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk("coda_rmdir: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
         dircnp = ITOC(dir);
 
 	if (!list_empty(&de->d_hash))
@@ -572,11 +546,6 @@
         ENTRY;
 	coda_vfs_stat.readdir++;
 
-        if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
-                printk("coda_readdir: inode is NULL or not a directory\n");
-                return -EBADF;
-        }
-
         cnp = ITOC(inode);
         if ( !cnp->c_ovp ) {
                 CDEBUG(D_FILE, "open inode pointer = NULL.\n");
diff -urN linux-2.2.7-pre3/fs/dcache.c linux-2.2.7-pre4/fs/dcache.c
--- linux-2.2.7-pre3/fs/dcache.c	1999-03-19 08:08:54.000000000 -0800
+++ linux-2.2.7-pre4/fs/dcache.c	2003-08-15 15:05:52.000000000 -0700
@@ -471,8 +471,12 @@
  */
 void shrink_dcache_memory(int priority, unsigned int gfp_mask)
 {
-	if (gfp_mask & __GFP_IO)
-		prune_dcache(0);
+	if (gfp_mask & __GFP_IO) {
+		int count = 0;
+		if (priority)
+			count = dentry_stat.nr_unused / priority;
+		prune_dcache(count);
+	}
 }
 
 #define NAME_ALLOC_LEN(len)	((len+16) & ~15)
diff -urN linux-2.2.7-pre3/fs/devpts/root.c linux-2.2.7-pre4/fs/devpts/root.c
--- linux-2.2.7-pre3/fs/devpts/root.c	1998-09-30 10:46:53.000000000 -0700
+++ linux-2.2.7-pre4/fs/devpts/root.c	2003-08-15 15:05:52.000000000 -0700
@@ -17,7 +17,7 @@
 #include "devpts_i.h"
 
 static int devpts_root_readdir(struct file *,void *,filldir_t);
-static int devpts_root_lookup(struct inode *,struct dentry *);
+static struct dentry *devpts_root_lookup(struct inode *,struct dentry *);
 static int devpts_revalidate(struct dentry *);
 
 static struct file_operations devpts_root_operations = {
@@ -81,9 +81,6 @@
 	off_t nr;
 	char numbuf[16];
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -ENOTDIR;
-
 	nr = filp->f_pos;
 
 	switch(nr)
@@ -131,42 +128,39 @@
 	return ( sbi->inodes[dentry->d_inode->i_ino - 2] == dentry->d_inode );
 }
 
-static int devpts_root_lookup(struct inode * dir, struct dentry * dentry)
+static struct dentry *devpts_root_lookup(struct inode * dir, struct dentry * dentry)
 {
 	struct devpts_sb_info *sbi = SBI(dir->i_sb);
 	unsigned int entry;
 	int i;
 	const char *p;
 
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOTDIR;
-
 	dentry->d_inode = NULL;	/* Assume failure */
 	dentry->d_op    = &devpts_dentry_operations;
 
 	if ( dentry->d_name.len == 1 && dentry->d_name.name[0] == '0' ) {
 		entry = 0;
 	} else if ( dentry->d_name.len < 1 ) {
-		return 0;
+		return NULL;
 	} else {
 		p = dentry->d_name.name;
 		if ( *p < '1' || *p > '9' )
-			return 0;
+			return NULL;
 		entry = *p++ - '0';
 
 		for ( i = dentry->d_name.len-1 ; i ; i-- ) {
 			unsigned int nentry = *p++ - '0';
 			if ( nentry > 9 )
-				return 0;
+				return NULL;
 			nentry += entry * 10;
 			if (nentry < entry)
-				return 0;
+				return NULL;
 			entry = nentry;
 		}
 	}
 
 	if ( entry >= sbi->max_ptys )
-		return 0;
+		return NULL;
 
 	dentry->d_inode = sbi->inodes[entry];
 	if ( dentry->d_inode )
@@ -174,5 +168,5 @@
 	
 	d_add(dentry, dentry->d_inode);
 
-	return 0;
+	return NULL;
 }
diff -urN linux-2.2.7-pre3/fs/ext2/dir.c linux-2.2.7-pre4/fs/ext2/dir.c
--- linux-2.2.7-pre3/fs/ext2/dir.c	1998-11-11 11:49:59.000000000 -0800
+++ linux-2.2.7-pre4/fs/ext2/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -115,8 +115,6 @@
 	int err;
 	struct inode *inode = filp->f_dentry->d_inode;
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
 	sb = inode->i_sb;
 
 	stored = 0;
diff -urN linux-2.2.7-pre3/fs/ext2/namei.c linux-2.2.7-pre4/fs/ext2/namei.c
--- linux-2.2.7-pre3/fs/ext2/namei.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/ext2/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -168,14 +168,14 @@
 	return NULL;
 }
 
-int ext2_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct inode * inode;
 	struct ext2_dir_entry_2 * de;
 	struct buffer_head * bh;
 
 	if (dentry->d_name.len > EXT2_NAME_LEN)
-		return -ENAMETOOLONG;
+		return ERR_PTR(-ENAMETOOLONG);
 
 	bh = ext2_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
 	inode = NULL;
@@ -185,10 +185,10 @@
 		inode = iget(dir->i_sb, ino);
 
 		if (!inode)
-			return -EACCES;
+			return ERR_PTR(-EACCES);
 	}
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
 
 /*
diff -urN linux-2.2.7-pre3/fs/fat/dir.c linux-2.2.7-pre4/fs/fat/dir.c
--- linux-2.2.7-pre3/fs/fat/dir.c	1998-08-24 13:02:44.000000000 -0700
+++ linux-2.2.7-pre4/fs/fat/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -9,6 +9,7 @@
  *
  *  VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
  *  Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
+ *  Plugged buffer overrun in readdir(). AV
  */
 
 #define ASC_LINUX_VERSION(V, P, S)	(((V) * 65536) + ((P) * 256) + (S))
@@ -59,6 +60,7 @@
  * characters are a sort of uuencoded 16 bit Unicode value.  This lets
  * us do a full dump and restore of Unicode filenames.  We could get
  * into some trouble with long Unicode names, but ignore that right now.
+ * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
  */
 static int
 uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
@@ -93,6 +95,11 @@
 				*op++ = '?';
 			}
 		}
+		/* We have some slack there, so it's OK */
+		if (op>ascii+256) {
+			op = ascii + 256;
+			break;
+		}
 	}
 	*op = 0;
 	return (op - ascii);
@@ -138,8 +145,6 @@
 	unsigned char *unicode = NULL;
 	struct nls_table *nls = MSDOS_SB(sb)->nls_io;
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
 /* Fake . and .. for the root directory. */
 	if (inode->i_ino == MSDOS_ROOT_INO) {
 		while (oldpos < 2) {
@@ -186,9 +191,17 @@
 			id = ds->id;
 			if (id & 0x40) {
 				slots = id & ~0x40;
-				long_slots = slots;
-				is_long = 1;
-				alias_checksum = ds->alias_checksum;
+				/*
+				 * Dirty, but not dirtier than the original,
+				 * and plugs the hole.
+				 */
+				if (slots > 20)
+					slots = 0;
+				else {
+					long_slots = slots;
+					is_long = 1;
+					alias_checksum = ds->alias_checksum;
+				}
 			}
 
 			get_new_entry = 1;
diff -urN linux-2.2.7-pre3/fs/fat/inode.c linux-2.2.7-pre4/fs/fat/inode.c
--- linux-2.2.7-pre3/fs/fat/inode.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/fs/fat/inode.c	2003-08-15 15:05:52.000000000 -0700
@@ -332,7 +332,6 @@
 		fat_brelse (sb, bh);
 		goto out_no_bread;
 	}
-	set_blocksize(sb->s_dev, blksize);
 
 /*
  * The DOS3 partition size limit is *not* 32M as many people think.  
@@ -423,6 +422,7 @@
 		    || !b->secs_track || !b->heads;
 	}
 	fat_brelse(sb, bh);
+	set_blocksize(sb->s_dev, blksize);
 	/*
 		This must be done after the brelse because the bh is a dummy
 		allocated by fat_bread (see buffer.c)
diff -urN linux-2.2.7-pre3/fs/hfs/dir_cap.c linux-2.2.7-pre4/fs/hfs/dir_cap.c
--- linux-2.2.7-pre3/fs/hfs/dir_cap.c	1998-11-02 09:35:16.000000000 -0800
+++ linux-2.2.7-pre4/fs/hfs/dir_cap.c	2003-08-15 15:05:52.000000000 -0700
@@ -27,7 +27,7 @@
 
 /*================ Forward declarations ================*/
 
-static int cap_lookup(struct inode *, struct dentry *);
+static struct dentry *cap_lookup(struct inode *, struct dentry *);
 static int cap_readdir(struct file *, void *, filldir_t);
 
 /*================ Global variables ================*/
@@ -147,7 +147,7 @@
  * inode corresponding to an entry in a directory, given the inode for
  * the directory and the name (and its length) of the entry.
  */
-static int cap_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *cap_lookup(struct inode * dir, struct dentry *dentry)
 {
 	ino_t dtype;
 	struct hfs_name cname;
@@ -155,10 +155,6 @@
 	struct hfs_cat_key key;
 	struct inode *inode = NULL;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		return -ENOENT;
-	}
-
 	dentry->d_op = &hfs_dentry_operations;
 	entry = HFS_I(dir)->entry;
 	dtype = HFS_ITYPE(dir->i_ino);
@@ -207,7 +203,7 @@
 
 done:
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
 
 /*
diff -urN linux-2.2.7-pre3/fs/hfs/dir_dbl.c linux-2.2.7-pre4/fs/hfs/dir_dbl.c
--- linux-2.2.7-pre3/fs/hfs/dir_dbl.c	1998-11-02 09:35:16.000000000 -0800
+++ linux-2.2.7-pre4/fs/hfs/dir_dbl.c	2003-08-15 15:05:52.000000000 -0700
@@ -23,7 +23,7 @@
 
 /*================ Forward declarations ================*/
 
-static int dbl_lookup(struct inode *, struct dentry *);
+static struct dentry *dbl_lookup(struct inode *, struct dentry *);
 static int dbl_readdir(struct file *, void *, filldir_t);
 static int dbl_create(struct inode *, struct dentry *, int);
 static int dbl_mkdir(struct inode *, struct dentry *, int);
@@ -130,17 +130,13 @@
  * the inode for the directory and the name (and its length) of the
  * entry.
  */
-static int dbl_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *dbl_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct hfs_name cname;
 	struct hfs_cat_entry *entry;
 	struct hfs_cat_key key;
 	struct inode *inode = NULL;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		return -ENOENT;
-	}
-
 	dentry->d_op = &hfs_dentry_operations;
 	entry = HFS_I(dir)->entry;
 	
@@ -173,7 +169,7 @@
 	
 done:
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
 
 /*
diff -urN linux-2.2.7-pre3/fs/hfs/dir_nat.c linux-2.2.7-pre4/fs/hfs/dir_nat.c
--- linux-2.2.7-pre3/fs/hfs/dir_nat.c	1998-11-02 09:35:16.000000000 -0800
+++ linux-2.2.7-pre4/fs/hfs/dir_nat.c	2003-08-15 15:05:52.000000000 -0700
@@ -29,7 +29,7 @@
 
 /*================ Forward declarations ================*/
 
-static int nat_lookup(struct inode *, struct dentry *);
+static struct dentry *nat_lookup(struct inode *, struct dentry *);
 static int nat_readdir(struct file *, void *, filldir_t);
 static int nat_rmdir(struct inode *, struct dentry *);
 static int nat_hdr_unlink(struct inode *, struct dentry *);
@@ -136,7 +136,7 @@
  * the inode corresponding to an entry in a directory, given the inode
  * for the directory and the name (and its length) of the entry.
  */
-static int nat_lookup(struct inode * dir, struct dentry *dentry)
+static struct dentry *nat_lookup(struct inode * dir, struct dentry *dentry)
 {
 	ino_t dtype;
 	struct hfs_name cname;
@@ -144,10 +144,6 @@
 	struct hfs_cat_key key;
 	struct inode *inode = NULL;
 
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		return -ENOENT;
-	}
-
 	dentry->d_op = &hfs_dentry_operations;
 	entry = HFS_I(dir)->entry;
 	dtype = HFS_ITYPE(dir->i_ino);
@@ -199,7 +195,7 @@
 
 done:
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
 
 /*
diff -urN linux-2.2.7-pre3/fs/hpfs/hpfs_fs.c linux-2.2.7-pre4/fs/hpfs/hpfs_fs.c
--- linux-2.2.7-pre3/fs/hpfs/hpfs_fs.c	1998-10-05 10:04:34.000000000 -0700
+++ linux-2.2.7-pre4/fs/hpfs/hpfs_fs.c	2003-08-15 15:05:52.000000000 -0700
@@ -192,7 +192,7 @@
 			     size_t count, loff_t *ppos);
 static int hpfs_readdir(struct file *filp,
 			void *dirent, filldir_t filldir);
-static int hpfs_lookup(struct inode *, struct dentry *);
+static struct dentry *hpfs_lookup(struct inode *, struct dentry *);
 
 static const struct file_operations hpfs_dir_ops =
 {
@@ -1119,7 +1119,7 @@
  * the boondocks.)
  */
 
-static int hpfs_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry)
 {
 	const char *name = dentry->d_name.name;
 	int len = dentry->d_name.len;
@@ -1129,14 +1129,6 @@
 	int retval;
 	struct quad_buffer_head qbh;
 
-	/* In case of madness */
-
-	retval = -ENOTDIR;
-	if (dir == 0)
-		goto out;
-	if (!S_ISDIR(dir->i_mode))
-		goto out;
-
 	/*
 	 * Read in the directory entry. "." is there under the name ^A^A .
 	 * Always read the dir even for . and .. in case we need the dates.
@@ -1208,7 +1200,7 @@
 	brelse4(&qbh);
 
       out:
-	return retval;
+	return ERR_PTR(retval);
 }
 
 /*
@@ -1374,11 +1366,6 @@
 	long old_pos;
 	struct inode *inode = filp->f_dentry->d_inode;
 
-	if (inode == 0
-	    || inode->i_sb == 0
-	    || !S_ISDIR(inode->i_mode))
-		return -EBADF;
-
 	tempname = (char *) __get_free_page(GFP_KERNEL);
 	if (!tempname)
 		return -ENOMEM;
diff -urN linux-2.2.7-pre3/fs/inode.c linux-2.2.7-pre4/fs/inode.c
--- linux-2.2.7-pre3/fs/inode.c	1999-04-15 05:42:49.000000000 -0700
+++ linux-2.2.7-pre4/fs/inode.c	2003-08-15 15:05:52.000000000 -0700
@@ -359,10 +359,8 @@
 		found = 1;
 	}
 
-	if (found) {
+	if (found)
 		dispose_list(freeable);
-		found = 1;	/* silly compiler */
-	}
 
 	return found;
 }
@@ -750,7 +748,7 @@
  * Initialize the hash tables and default
  * value for max inodes
  */
-#define MAX_INODE (12288)
+#define MAX_INODE (16384)
 
 void __init inode_init(void)
 {
diff -urN linux-2.2.7-pre3/fs/isofs/dir.c linux-2.2.7-pre4/fs/isofs/dir.c
--- linux-2.2.7-pre3/fs/isofs/dir.c	1998-11-12 11:44:09.000000000 -0800
+++ linux-2.2.7-pre4/fs/isofs/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -295,9 +295,6 @@
 	struct iso_directory_record * tmpde;
 	struct inode *inode = filp->f_dentry->d_inode;
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
-
 	tmpname = (char *) __get_free_page(GFP_KERNEL);
 	if (!tmpname)
 		return -ENOMEM;
diff -urN linux-2.2.7-pre3/fs/isofs/namei.c linux-2.2.7-pre4/fs/isofs/namei.c
--- linux-2.2.7-pre3/fs/isofs/namei.c	1999-01-15 14:41:04.000000000 -0800
+++ linux-2.2.7-pre4/fs/isofs/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -228,7 +228,7 @@
 	return retval;
 }
 
-int isofs_lookup(struct inode * dir, struct dentry * dentry)
+struct dentry *isofs_lookup(struct inode * dir, struct dentry * dentry)
 {
 	unsigned long ino;
 	struct buffer_head * bh;
@@ -237,12 +237,6 @@
 #ifdef DEBUG
 	printk("lookup: %x %s\n",dir->i_ino, dentry->d_name.name);
 #endif
-	if (!dir)
-		return -ENOENT;
-
-	if (!S_ISDIR(dir->i_mode))
-		return -ENOENT;
-
 	dentry->d_op = dir->i_sb->s_root->d_op;
 
 	bh = isofs_find_entry(dir, dentry, &ino);
@@ -253,8 +247,8 @@
 
 		inode = iget(dir->i_sb,ino);
 		if (!inode)
-			return -EACCES;
+			return ERR_PTR(-EACCES);
 	}
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
diff -urN linux-2.2.7-pre3/fs/minix/dir.c linux-2.2.7-pre4/fs/minix/dir.c
--- linux-2.2.7-pre3/fs/minix/dir.c	1998-11-11 11:49:59.000000000 -0800
+++ linux-2.2.7-pre4/fs/minix/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -68,8 +68,6 @@
 	struct minix_sb_info * info;
 	struct inode *inode = filp->f_dentry->d_inode;
 
-	if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode))
-		return -EBADF;
 	info = &inode->i_sb->u.minix_sb;
 	if (filp->f_pos & (info->s_dirsize - 1))
 		return -EBADF;
diff -urN linux-2.2.7-pre3/fs/minix/inode.c linux-2.2.7-pre4/fs/minix/inode.c
--- linux-2.2.7-pre3/fs/minix/inode.c	1999-04-13 07:54:02.000000000 -0700
+++ linux-2.2.7-pre4/fs/minix/inode.c	2003-08-15 15:05:52.000000000 -0700
@@ -38,14 +38,13 @@
 	minix_free_inode(inode);
 }
 
-static void minix_commit_super (struct super_block * sb,
-			       struct minix_super_block * ms)
+static void minix_commit_super(struct super_block * sb)
 {
 	mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
 	sb->s_dirt = 0;
 }
 
-static void minix_write_super (struct super_block * sb)
+static void minix_write_super(struct super_block * sb)
 {
 	struct minix_super_block * ms;
 
@@ -54,7 +53,7 @@
 
 		if (ms->s_state & MINIX_VALID_FS)
 			ms->s_state &= ~MINIX_VALID_FS;
-		minix_commit_super (sb, ms);
+		minix_commit_super(sb);
 	}
 	sb->s_dirt = 0;
 }
@@ -106,7 +105,7 @@
 		ms->s_state = sb->u.minix_sb.s_mount_state;
 		mark_buffer_dirty(sb->u.minix_sb.s_sbh, 1);
 		sb->s_dirt = 1;
-		minix_commit_super (sb, ms);
+		minix_commit_super(sb);
 	}
 	else {
 	  	/* Mount a partition which is read-only, read-write. */
diff -urN linux-2.2.7-pre3/fs/minix/namei.c linux-2.2.7-pre4/fs/minix/namei.c
--- linux-2.2.7-pre3/fs/minix/namei.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/minix/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -116,7 +116,7 @@
 	0		/* compare */
 };
 
-int minix_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct inode * inode = NULL;
 	struct minix_dir_entry * de;
@@ -132,10 +132,10 @@
 		inode = iget(dir->i_sb, ino);
  
 		if (!inode)
-			return -EACCES;
+			return ERR_PTR(-EACCES);
 	}
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
 
 /*
@@ -221,8 +221,6 @@
 	struct buffer_head * bh;
 	struct minix_dir_entry * de;
 
-	if (!dir)
-		return -ENOENT;
 	inode = minix_new_inode(dir);
 	if (!inode)
 		return -ENOSPC;
@@ -251,8 +249,6 @@
 	struct buffer_head * bh;
 	struct minix_dir_entry * de;
 
-	if (!dir)
-		return -ENOENT;
 	bh = minix_find_entry(dir, dentry->d_name.name,
 			      dentry->d_name.len, &de);
 	if (bh) {
@@ -298,8 +294,6 @@
 	struct minix_dir_entry * de;
 	struct minix_sb_info * info;
 
-	if (!dir || !dir->i_sb)
-		return -EINVAL;
 	info = &dir->i_sb->u.minix_sb;
 	bh = minix_find_entry(dir, dentry->d_name.name,
 			      dentry->d_name.len, &de);
diff -urN linux-2.2.7-pre3/fs/msdos/namei.c linux-2.2.7-pre4/fs/msdos/namei.c
--- linux-2.2.7-pre3/fs/msdos/namei.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/fs/msdos/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -250,7 +250,7 @@
 
 
 /***** Get inode using directory and name */
-int msdos_lookup(struct inode *dir,struct dentry *dentry)
+struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
 {
 	struct super_block *sb = dir->i_sb;
 	struct inode *inode = NULL;
@@ -292,7 +292,7 @@
 	d_add(dentry, inode);
 	res = 0;
 out:
-	return res;
+	return ERR_PTR(res);
 }
 
 
diff -urN linux-2.2.7-pre3/fs/namei.c linux-2.2.7-pre4/fs/namei.c
--- linux-2.2.7-pre3/fs/namei.c	1999-04-15 06:11:56.000000000 -0700
+++ linux-2.2.7-pre4/fs/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -263,12 +263,11 @@
 		struct dentry * dentry = d_alloc(parent, name);
 		result = ERR_PTR(-ENOMEM);
 		if (dentry) {
-			int error = dir->i_op->lookup(dir, dentry);
-			result = dentry;
-			if (error) {
+			result = dir->i_op->lookup(dir, dentry);
+			if (result)
 				dput(dentry);
-				result = ERR_PTR(error);
-			}
+			else
+				result = dentry;
 		}
 	}
 	up(&dir->i_sem);
diff -urN linux-2.2.7-pre3/fs/ncpfs/dir.c linux-2.2.7-pre4/fs/ncpfs/dir.c
--- linux-2.2.7-pre3/fs/ncpfs/dir.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/fs/ncpfs/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -50,7 +50,7 @@
 static int ncp_readdir(struct file *, void *, filldir_t);
 
 static int ncp_create(struct inode *, struct dentry *, int);
-static int ncp_lookup(struct inode *, struct dentry *);
+static struct dentry *ncp_lookup(struct inode *, struct dentry *);
 static int ncp_unlink(struct inode *, struct dentry *);
 static int ncp_mkdir(struct inode *, struct dentry *, int);
 static int ncp_rmdir(struct inode *, struct dentry *);
@@ -440,11 +440,6 @@
 	DDPRINTK(KERN_DEBUG "ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
 		 inode->i_ino, c_ino);
 
-	result = -EBADF;
-	if (!inode || !S_ISDIR(inode->i_mode)) {
-		printk(KERN_WARNING "ncp_readdir: inode is NULL or not a directory\n");
-		goto out;
-	}
 	result = -EIO;
 	if (!ncp_conn_valid(server))
 		goto out;
@@ -744,7 +739,7 @@
 	return result;
 }
 
-static int ncp_lookup(struct inode *dir, struct dentry *dentry)
+static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry)
 {
 	struct ncp_server *server;
 	struct inode *inode = NULL;
@@ -754,11 +749,6 @@
 	struct ncpfs_inode_info finfo;
 	__u8 __name[dentry->d_name.len + 1];
 
-	error =  -ENOENT;
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk(KERN_WARNING "ncp_lookup: inode is NULL or not a directory.\n");
-		goto finished;
-	}
 	server = NCP_SERVER(dir);
 
 	error = -EIO;
@@ -831,7 +821,7 @@
 	   	if (res != 0) {
 			goto add_entry;
 		} else vol2io(server, finfo.nw_info.i.entryName,
-			      ncp_preserve_entry_case(dir,
+			      !ncp_preserve_entry_case(dir,
 			      finfo.nw_info.i.NSCreator));
 	}
 
@@ -854,7 +844,7 @@
 #ifdef NCPFS_PARANOIA
 printk(KERN_DEBUG "ncp_lookup: result=%d\n", error);
 #endif
-	return error;
+	return ERR_PTR(error);
 }
 
 /*
@@ -897,10 +887,6 @@
 printk(KERN_DEBUG "ncp_create_new: creating %s/%s, mode=%x\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, mode);
 #endif
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk(KERN_WARNING "ncp_create_new: inode is NULL or not a directory\n");
-		return -ENOENT;
-	}
 	error = -EIO;
 	if (!ncp_conn_valid(NCP_SERVER(dir)))
 		goto out;
@@ -940,11 +926,6 @@
 
 	DPRINTK(KERN_DEBUG "ncp_mkdir: making %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
-	error = -ENOTDIR;
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk(KERN_WARNING "ncp_mkdir: inode is NULL or not a directory\n");
-		goto out;
-	}
 	error = -EIO;
 	if (!ncp_conn_valid(NCP_SERVER(dir)))
 		goto out;
@@ -971,13 +952,6 @@
 
 	DPRINTK(KERN_DEBUG "ncp_rmdir: removing %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
-	
-	error = -ENOENT;
-	if (!dir || !S_ISDIR(dir->i_mode))
-	{
-		printk(KERN_WARNING "ncp_rmdir: inode is NULL or not a directory\n");
-		goto out;
-	}
 
 	error = -EIO;
 	if (!ncp_conn_valid(NCP_SERVER(dir)))
@@ -1030,11 +1004,6 @@
 	DPRINTK(KERN_DEBUG "ncp_unlink: unlinking %s/%s\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
 	
-	error = -ENOTDIR;
-	if (!dir || !S_ISDIR(dir->i_mode)) {
-		printk(KERN_WARNING "ncp_unlink: inode is NULL or not a directory\n");
-		goto out;
-	}
 	error = -EIO;
 	if (!ncp_conn_valid(NCP_SERVER(dir)))
 		goto out;
@@ -1102,15 +1071,6 @@
 		old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
 		new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
 
-	error = -ENOTDIR;
-	if (!old_dir || !S_ISDIR(old_dir->i_mode)) {
-		printk(KERN_WARNING "ncp_rename: old inode is NULL or not a directory\n");
-		goto out;
-	}
-	if (!new_dir || !S_ISDIR(new_dir->i_mode)) {
-		printk(KERN_WARNING "ncp_rename: new inode is NULL or not a directory\n");
-		goto out;
-	}
 	error = -EIO;
 	if (!ncp_conn_valid(NCP_SERVER(old_dir)))
 		goto out;
diff -urN linux-2.2.7-pre3/fs/nfs/dir.c linux-2.2.7-pre4/fs/nfs/dir.c
--- linux-2.2.7-pre3/fs/nfs/dir.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/fs/nfs/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -51,10 +51,9 @@
 
 static int nfs_safe_remove(struct dentry *);
 
-static int nfs_dir_open(struct inode *, struct file *);
 static ssize_t nfs_dir_read(struct file *, char *, size_t, loff_t *);
 static int nfs_readdir(struct file *, void *, filldir_t);
-static int nfs_lookup(struct inode *, struct dentry *);
+static struct dentry *nfs_lookup(struct inode *, struct dentry *);
 static int nfs_create(struct inode *, struct dentry *, int);
 static int nfs_mkdir(struct inode *, struct dentry *, int);
 static int nfs_rmdir(struct inode *, struct dentry *);
@@ -73,7 +72,7 @@
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
 	NULL,			/* mmap */
-	nfs_dir_open,		/* open - revalidate */
+	NULL,			/* no special open is needed */
 	NULL,			/* flush */
 	NULL,			/* no special release code */
 	NULL			/* fsync */
@@ -102,16 +101,6 @@
 	nfs_revalidate,		/* revalidate */
 };
 
-static int
-nfs_dir_open(struct inode *dir, struct file *file)
-{
-	struct dentry *dentry = file->f_dentry;
-
-	dfprintk(VFS, "NFS: nfs_dir_open(%s/%s)\n",
-		dentry->d_parent->d_name.name, dentry->d_name.name);
-	return _nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
-}
-
 static ssize_t
 nfs_dir_read(struct file *filp, char *buf, size_t count, loff_t *ppos)
 {
@@ -147,11 +136,6 @@
 
 	dfprintk(VFS, "NFS: nfs_readdir(%s/%s)\n",
 		dentry->d_parent->d_name.name, dentry->d_name.name);
-	result = -EBADF;
-	if (!inode || !S_ISDIR(inode->i_mode)) {
-		printk("nfs_readdir: inode is NULL or not a directory\n");
-		goto out;
-	}
 
 	result = nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
 	if (result < 0)
@@ -397,7 +381,6 @@
 {
 	struct dentry * parent = dentry->d_parent;
 	struct inode * inode = dentry->d_inode;
-	unsigned long time = jiffies - dentry->d_time;
 	int error;
 	struct nfs_fh fhandle;
 	struct nfs_fattr fattr;
@@ -406,31 +389,36 @@
 	 * If we don't have an inode, let's just assume
 	 * a 5-second "live" time for negative dentries.
 	 */
-	if (!inode) {
-		if (time < NFS_REVALIDATE_INTERVAL)
-			goto out_valid;
-		goto out_bad;
-	}
+	if (!inode)
+		goto do_lookup;
 
 	if (is_bad_inode(inode)) {
-#ifdef NFS_PARANOIA
-printk("nfs_lookup_validate: %s/%s has dud inode\n",
-parent->d_name.name, dentry->d_name.name);
-#endif
+		dfprintk(VFS, "nfs_lookup_validate: %s/%s has dud inode\n",
+			parent->d_name.name, dentry->d_name.name);
 		goto out_bad;
 	}
 
-	if (time < NFS_ATTRTIMEO(inode))
+	if (_nfs_revalidate_inode(NFS_DSERVER(dentry), dentry))
+		goto out_bad;
+
+	if (time_before(jiffies,dentry->d_time+NFS_ATTRTIMEO(inode)))
 		goto out_valid;
 
 	if (IS_ROOT(dentry))
 		goto out_valid;
 
+do_lookup:
 	/*
 	 * Do a new lookup and check the dentry attributes.
 	 */
 	error = nfs_proc_lookup(NFS_DSERVER(parent), NFS_FH(parent), 
 				dentry->d_name.name, &fhandle, &fattr);
+	if (dentry->d_inode == NULL) {
+		if (error == -ENOENT &&
+		    time_before(jiffies,dentry->d_time+NFS_REVALIDATE_INTERVAL))
+			goto out_valid;
+		goto out_bad;
+	}
 	if (error)
 		goto out_bad;
 
@@ -440,7 +428,7 @@
 
 	/* Filehandle matches? */
 	if (memcmp(dentry->d_fsdata, &fhandle, sizeof(struct nfs_fh))) {
-		if (dentry->d_count < 2 || nfs_revalidate(dentry))
+		if (dentry->d_count < 2)
 			goto out_bad;
 	}
 
@@ -451,6 +439,10 @@
 out_valid:
 	return 1;
 out_bad:
+	if (dentry->d_parent->d_inode)
+		nfs_invalidate_dircache(dentry->d_parent->d_inode);
+	if (inode && S_ISDIR(inode->i_mode))
+		nfs_invalidate_dircache(inode);
 	return 0;
 }
 
@@ -535,7 +527,7 @@
 }
 #endif
 
-static int nfs_lookup(struct inode *dir, struct dentry * dentry)
+static struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry)
 {
 	struct inode *inode;
 	int error;
@@ -581,7 +573,7 @@
 		}
 	}
 out:
-	return error;
+	return ERR_PTR(error);
 }
 
 /*
@@ -766,7 +758,7 @@
 {
 	struct qstr    sqstr;
 	struct dentry *sdentry;
-	int error;
+	struct dentry *res;
 
 	sqstr.name = silly;
 	sqstr.len  = slen;
@@ -776,10 +768,10 @@
 		sdentry = d_alloc(parent, &sqstr);
 		if (sdentry == NULL)
 			return ERR_PTR(-ENOMEM);
-		error = nfs_lookup(parent->d_inode, sdentry);
-		if (error) {
+		res = nfs_lookup(parent->d_inode, sdentry);
+		if (res) {
 			dput(sdentry);
-			return ERR_PTR(error);
+			return res;
 		}
 	}
 	return sdentry;
diff -urN linux-2.2.7-pre3/fs/nfs/file.c linux-2.2.7-pre4/fs/nfs/file.c
--- linux-2.2.7-pre3/fs/nfs/file.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/fs/nfs/file.c	1999-03-19 14:20:47.000000000 -0800
@@ -37,7 +37,6 @@
 static ssize_t nfs_file_write(struct file *, const char *, size_t, loff_t *);
 static int  nfs_file_flush(struct file *);
 static int  nfs_fsync(struct file *, struct dentry *dentry);
-static int  nfs_file_open(struct inode *inode, struct file *filp);
 
 static struct file_operations nfs_file_operations = {
 	NULL,			/* lseek - default */
@@ -47,7 +46,7 @@
 	NULL,			/* select - default */
 	NULL,			/* ioctl - default */
 	nfs_file_mmap,		/* mmap */
-	nfs_file_open,		/* open */
+	NULL,			/* no special open is needed */
 	nfs_file_flush,		/* flush */
 	NULL,			/* release */
 	nfs_fsync,		/* fsync */
@@ -105,19 +104,6 @@
 	return status;
 }
 
-/*
- * Open the file.
- * Just checks the cache is synchronized.
- */
-static int
-nfs_file_open(struct inode *inode, struct file *filp)
-{
-	struct dentry *dentry = filp->f_dentry;
-
-	return _nfs_revalidate_inode(NFS_DSERVER(dentry), dentry);
-}
-
-
 static ssize_t
 nfs_file_read(struct file * file, char * buf, size_t count, loff_t *ppos)
 {
diff -urN linux-2.2.7-pre3/fs/nfs/inode.c linux-2.2.7-pre4/fs/nfs/inode.c
--- linux-2.2.7-pre3/fs/nfs/inode.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/fs/nfs/inode.c	2003-08-15 15:05:52.000000000 -0700
@@ -37,6 +37,8 @@
 #define NFS_PARANOIA 1
 
 static struct inode * __nfs_fhget(struct super_block *, struct nfs_fattr *);
+static void nfs_zap_caches(struct inode *);
+static void nfs_invalidate_inode(struct inode *);
 
 static void nfs_read_inode(struct inode *);
 static void nfs_put_inode(struct inode *);
@@ -393,25 +395,61 @@
  * could cause file corruption. But since the dentry
  * count is 0 and all pending IO for a dentry has been
  * flushed when the count went to 0, we're safe here.
+ * Also returns the number of unhashed dentries
  */
-void nfs_free_dentries(struct inode *inode)
+static int
+nfs_free_dentries(struct inode *inode)
 {
 	struct list_head *tmp, *head = &inode->i_dentry;
+	int unhashed;
 
 restart:
 	tmp = head;
+	unhashed = 0;
 	while ((tmp = tmp->next) != head) {
 		struct dentry *dentry = list_entry(tmp, struct dentry, d_alias);
-printk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name,
-dentry->d_count, !list_empty(&dentry->d_hash));
+		dprintk("nfs_free_dentries: found %s/%s, d_count=%d, hashed=%d\n",
+			dentry->d_parent->d_name.name, dentry->d_name.name,
+			dentry->d_count, !list_empty(&dentry->d_hash));
 		if (!dentry->d_count) {
 			dget(dentry);
 			d_drop(dentry);
 			dput(dentry);
 			goto restart;
 		}
+		if (!list_empty(&dentry->d_hash))
+			unhashed++;
 	}
+	return unhashed;
+}
+
+/*
+ * Invalidate the local caches
+ */
+static void
+nfs_zap_caches(struct inode *inode)
+{
+	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+	NFS_CACHEINV(inode);
+
+	if (S_ISDIR(inode->i_mode))
+		nfs_invalidate_dircache(inode);
+	else
+		invalidate_inode_pages(inode);
+}
+
+/*
+ * Invalidate, but do not unhash, the inode
+ */
+static void
+nfs_invalidate_inode(struct inode *inode)
+{
+	umode_t save_mode = inode->i_mode;
+
+	make_bad_inode(inode);
+	inode->i_mode = save_mode;
+	nfs_inval(inode);
+	nfs_zap_caches(inode);
 }
 
 /*
@@ -513,7 +551,7 @@
 __nfs_fhget(struct super_block *sb, struct nfs_fattr *fattr)
 {
 	struct inode *inode;
-	int max_count;
+	int max_count, stale_inode, unhashed = 0;
 
 retry:
 	inode = iget(sb, fattr->fileid);
@@ -532,27 +570,30 @@
 	 * as the inode may have become a different object.
 	 * (We can probably handle modes changes here, too.)
 	 */
+	stale_inode = inode->i_mode &&
+		      ((fattr->mode ^ inode->i_mode) & S_IFMT);
+	stale_inode |= inode->i_count && inode->i_count == unhashed;
 	max_count = S_ISDIR(fattr->mode) ? 1 : fattr->nlink;
-	if (inode->i_count > max_count) {
-printk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
-inode->i_ino, inode->i_count, inode->i_nlink);
-		nfs_free_dentries(inode);
-		if (inode->i_count > max_count) {
-printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
-inode->i_ino, inode->i_count);
+	if (stale_inode || inode->i_count > max_count + unhashed) {
+		dprintk("__nfs_fhget: inode %ld busy, i_count=%d, i_nlink=%d\n",
+			inode->i_ino, inode->i_count, inode->i_nlink);
+		unhashed = nfs_free_dentries(inode);
+		if (stale_inode || inode->i_count > max_count + unhashed) {
+			printk("__nfs_fhget: inode %ld still busy, i_count=%d\n",
+				inode->i_ino, inode->i_count);
 			if (!list_empty(&inode->i_dentry)) {
 				struct dentry *dentry;
 				dentry = list_entry(inode->i_dentry.next,
 						 struct dentry, d_alias);
-printk("__nfs_fhget: killing %s/%s filehandle\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-				memset(dentry->d_fsdata, 0, 
+				printk("__nfs_fhget: killing %s/%s filehandle\n",
+					dentry->d_parent->d_name.name,
+					dentry->d_name.name);
+				memset(dentry->d_fsdata, 0,
 					sizeof(struct nfs_fh));
-			} else
-				printk("NFS: inode %ld busy, no aliases?\n",
-					inode->i_ino);
-			make_bad_inode(inode);
+			}
 			remove_inode_hash(inode);
+			nfs_invalidate_inode(inode);
+			unhashed = 0;
 		}
 		iput(inode);
 		goto retry;
@@ -673,10 +714,9 @@
 		int error;
 		u32 *fh;
 		struct nfs_fh fhandle;
-#ifdef NFS_PARANOIA
-printk("nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
-#endif
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s getattr failed, ino=%ld, error=%d\n",
+			dentry->d_parent->d_name.name,
+			dentry->d_name.name, inode->i_ino, status);
 		if (status != -ESTALE)
 			goto out;
 		/*
@@ -684,26 +724,25 @@
 		 * and find out what the filehandle should be.
 		 */
 		fh = (u32 *) NFS_FH(dentry);
-		printk("NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
+		dfprintk(PAGECACHE, "NFS: bad fh %08x%08x%08x%08x%08x%08x%08x%08x\n",
 			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
 		error = nfs_proc_lookup(server, NFS_FH(dentry->d_parent), 
 					dentry->d_name.name, &fhandle, &fattr);
 		if (error) {
-			printk("NFS: lookup failed, error=%d\n", error);
+			dfprintk(PAGECACHE, "NFS: lookup failed, error=%d\n", error);
 			goto out;
 		}
 		fh = (u32 *) &fhandle;
-		printk("            %08x%08x%08x%08x%08x%08x%08x%08x\n",
+		dfprintk(PAGECACHE, "            %08x%08x%08x%08x%08x%08x%08x%08x\n",
 			fh[0],fh[1],fh[2],fh[3],fh[4],fh[5],fh[6],fh[7]);
 		goto out;
 	}
 
 	status = nfs_refresh_inode(inode, &fattr);
 	if (status) {
-#ifdef NFS_PARANOIA
-printk("nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, inode->i_ino, status);
-#endif
+		dfprintk(PAGECACHE, "nfs_revalidate_inode: %s/%s refresh failed, ino=%ld, error=%d\n",
+			dentry->d_parent->d_name.name,
+			dentry->d_name.name, inode->i_ino, status);
 		goto out;
 	}
 	dfprintk(PAGECACHE, "NFS: %s/%s revalidation complete\n",
@@ -809,29 +848,18 @@
 printk("nfs_refresh_inode: inode %ld mode changed, %07o to %07o\n",
 inode->i_ino, inode->i_mode, fattr->mode);
 #endif
-	fattr->mode = inode->i_mode; /* save mode */
-	make_bad_inode(inode);
-	nfs_inval(inode);
-	inode->i_mode = fattr->mode; /* restore mode */
 	/*
 	 * No need to worry about unhashing the dentry, as the
 	 * lookup validation will know that the inode is bad.
-	 * (But we fall through to invalidate the caches.)
 	 */
+	nfs_invalidate_inode(inode);
+	goto out;
 
 out_invalid:
-	/*
-	 * Invalidate the local caches
-	 */
 #ifdef NFS_DEBUG_VERBOSE
 printk("nfs_refresh_inode: invalidating %ld pages\n", inode->i_nrpages);
 #endif
-	if (!S_ISDIR(inode->i_mode))
-		invalidate_inode_pages(inode);
-	else
-		nfs_invalidate_dircache(inode);
-	NFS_CACHEINV(inode);
-	NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode);
+	nfs_zap_caches(inode);
 	goto out;
 }
 
diff -urN linux-2.2.7-pre3/fs/ntfs/fs.c linux-2.2.7-pre4/fs/ntfs/fs.c
--- linux-2.2.7-pre3/fs/ntfs/fs.c	1999-04-12 10:05:58.000000000 -0700
+++ linux-2.2.7-pre4/fs/ntfs/fs.c	2003-08-15 15:05:52.000000000 -0700
@@ -215,7 +215,6 @@
 
 	ntfs_debug(DEBUG_OTHER, "ntfs_readdir ino %x mode %x\n",
 	       (unsigned)dir->i_ino,(unsigned int)dir->i_mode);
-	if(!dir || (dir->i_ino==0) || !S_ISDIR(dir->i_mode))return -EBADF;
 
 	ntfs_debug(DEBUG_OTHER, "readdir: Looking for file %x dircount %d\n",
 	       (unsigned)filp->f_pos,dir->i_count);
@@ -373,7 +372,7 @@
 	return 0;
 }
 			
-static int ntfs_lookup(struct inode *dir, struct dentry *d)
+static struct dentry *ntfs_lookup(struct inode *dir, struct dentry *d)
 {
 	struct inode *res=0;
 	char *item=0;
@@ -385,10 +384,10 @@
 	error=ntfs_decodeuni(NTFS_INO2VOL(dir),(char*)d->d_name.name,
 			     d->d_name.len,&walk.name,&walk.namelen);
 	if(error)
-		return error;
+		return ERR_PTR(-error);
 	item=ntfs_malloc(ITEM_SIZE);
 	if( !item )
-		return ENOMEM;
+		return ERR_PTR(-ENOMEM);
 	/* ntfs_getdir will place the directory entry into item,
 	   and the first long long is the MFT record number */
 	walk.type=BY_NAME;
@@ -402,7 +401,7 @@
 	ntfs_free(item);
 	ntfs_free(walk.name);
 	/* Always return success, the dcache will handle negative entries. */
-	return 0;
+	return NULL;
 }
 
 static struct file_operations ntfs_file_operations_nommap = {
@@ -829,7 +828,7 @@
 
 	error = ntfs_get_volumesize( NTFS_SB2VOL( sb ), &fs.f_blocks );
 	if( error )
-		return error;
+		return -error;
 	fs.f_bfree=ntfs_get_free_cluster_count(vol->bitmap);
 	fs.f_bavail=fs.f_bfree;
 
diff -urN linux-2.2.7-pre3/fs/ntfs/inode.c linux-2.2.7-pre4/fs/ntfs/inode.c
--- linux-2.2.7-pre3/fs/ntfs/inode.c	1999-04-12 10:05:58.000000000 -0700
+++ linux-2.2.7-pre4/fs/ntfs/inode.c	2003-08-15 15:05:52.000000000 -0700
@@ -150,6 +150,8 @@
 	ntfs_insert_fixups(buf,vol->blocksize);
 	io.param=buf;
 	io.size=vol->mft_recordsize;
+	io.fn_put = ntfs_put;
+	io.fn_get = ntfs_get;
 	error=ntfs_write_attr(vol->mft_ino,vol->at_data,0,
 			      (rcount-1)*vol->mft_recordsize,&io);
 	if(error)return error;
diff -urN linux-2.2.7-pre3/fs/proc/fd.c linux-2.2.7-pre4/fs/proc/fd.c
--- linux-2.2.7-pre3/fs/proc/fd.c	1998-11-15 10:15:31.000000000 -0800
+++ linux-2.2.7-pre4/fs/proc/fd.c	2003-08-15 15:05:52.000000000 -0700
@@ -19,7 +19,7 @@
 #include <asm/uaccess.h>
 
 static int proc_readfd(struct file *, void *, filldir_t);
-static int proc_lookupfd(struct inode *, struct dentry *);
+static struct dentry *proc_lookupfd(struct inode *, struct dentry *);
 
 static struct file_operations proc_fd_operations = {
 	NULL,			/* lseek - default */
@@ -67,7 +67,7 @@
  *
  * Thus just return -ENOENT instead.
  */
-static int proc_lookupfd(struct inode * dir, struct dentry * dentry)
+static struct dentry *proc_lookupfd(struct inode * dir, struct dentry * dentry)
 {
 	unsigned int ino, pid, fd, c;
 	struct task_struct * p;
@@ -77,13 +77,11 @@
 	int len, err;
 
 	err = -ENOENT;
-	if (!dir)
-		goto out;
 	ino = dir->i_ino;
 	pid = ino >> 16;
 	ino &= 0x0000ffff;
 
-	if (!pid || ino != PROC_PID_FD || !S_ISDIR(dir->i_mode))
+	if (!pid || ino != PROC_PID_FD)
 		goto out;
 
 	fd = 0;
@@ -121,10 +119,10 @@
 	if (inode) {
 		dentry->d_op = &proc_dentry_operations;
 		d_add(dentry, inode);
-		err = 0;
+		return NULL;
 	}
 out:
-	return err;
+	return ERR_PTR(err);
 }
 
 #define NUMBUF 10
@@ -137,10 +135,6 @@
 	int retval;
 	char buf[NUMBUF];
 
-	retval = -EBADF;
-	if (!inode || !S_ISDIR(inode->i_mode))
-		goto out;
-
 	retval = 0;
 	ino = inode->i_ino;
 	pid = ino >> 16;
diff -urN linux-2.2.7-pre3/fs/proc/openpromfs.c linux-2.2.7-pre4/fs/proc/openpromfs.c
--- linux-2.2.7-pre3/fs/proc/openpromfs.c	1998-11-18 09:06:05.000000000 -0800
+++ linux-2.2.7-pre4/fs/proc/openpromfs.c	2003-08-15 15:05:52.000000000 -0700
@@ -842,7 +842,6 @@
 	struct openpromfs_dev *d;
 	char buffer2[64];
 	
-	if (!inode || !S_ISDIR (inode->i_mode)) return -ENOTDIR;
 	ino = inode->i_ino;
 	i = filp->f_pos;
 	switch (i) {
diff -urN linux-2.2.7-pre3/fs/proc/root.c linux-2.2.7-pre4/fs/proc/root.c
--- linux-2.2.7-pre3/fs/proc/root.c	1999-01-15 15:38:59.000000000 -0800
+++ linux-2.2.7-pre4/fs/proc/root.c	2003-08-15 15:05:52.000000000 -0700
@@ -28,7 +28,7 @@
 #define FIRST_PROCESS_ENTRY 256
 
 static int proc_root_readdir(struct file *, void *, filldir_t);
-static int proc_root_lookup(struct inode *,struct dentry *);
+static struct dentry *proc_root_lookup(struct inode *,struct dentry *);
 static int proc_unlink(struct inode *, struct dentry *);
 
 static unsigned char proc_alloc_map[PROC_NDYNAMIC / 8] = {0};
@@ -769,16 +769,12 @@
  * Don't create negative dentries here, return -ENOENT by hand
  * instead.
  */
-int proc_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *proc_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct inode *inode;
 	struct proc_dir_entry * de;
 	int error;
 
-	error = -ENOTDIR;
-	if (!dir || !S_ISDIR(dir->i_mode))
-		goto out;
-
 	error = -ENOENT;
 	inode = NULL;
 	de = (struct proc_dir_entry *) dir->u.generic_ip;
@@ -800,13 +796,12 @@
 	if (inode) {
 		dentry->d_op = &proc_dentry_operations;
 		d_add(dentry, inode);
-		error = 0;
+		return NULL;
 	}
-out:
-	return error;
+	return ERR_PTR(error);
 }
 
-static int proc_root_lookup(struct inode * dir, struct dentry * dentry)
+static struct dentry *proc_root_lookup(struct inode * dir, struct dentry * dentry)
 {
 	unsigned int pid, c;
 	struct task_struct *p;
@@ -826,7 +821,7 @@
 	}
 
 	if (!proc_lookup(dir, dentry))
-		return 0;
+		return NULL;
 	
 	pid = 0;
 	name = dentry->d_name.name;
@@ -853,13 +848,13 @@
 		unsigned long ino = (pid << 16) + PROC_PID_INO;
 		inode = proc_get_inode(dir->i_sb, ino, &proc_pid);
 		if (!inode)
-			return -EINVAL;
+			return ERR_PTR(-EINVAL);
 		inode->i_flags|=S_IMMUTABLE;
 	}
 
 	dentry->d_op = &proc_dentry_operations;
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
 
 /*
@@ -879,8 +874,6 @@
 	int i;
 	struct inode *inode = filp->f_dentry->d_inode;
 
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -ENOTDIR;
 	ino = inode->i_ino;
 	de = (struct proc_dir_entry *) inode->u.generic_ip;
 	if (!de)
diff -urN linux-2.2.7-pre3/fs/qnx4/dir.c linux-2.2.7-pre4/fs/qnx4/dir.c
--- linux-2.2.7-pre3/fs/qnx4/dir.c	1998-09-01 10:43:13.000000000 -0700
+++ linux-2.2.7-pre4/fs/qnx4/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -35,9 +35,6 @@
 	blknum = inode->u.qnx4_i.i_first_xtnt.xtnt_blk - 1 +
 	    ((filp->f_pos >> 6) >> 3);
 
-	if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) {
-		return -EBADF;
-	}
 	QNX4DEBUG(("qnx4_readdir:i_size = %ld\n", (long) inode->i_size));
 	QNX4DEBUG(("filp->f_pos         = %ld\n", (long) filp->f_pos));
 	QNX4DEBUG(("BlkNum              = %ld\n", (long) blknum));
diff -urN linux-2.2.7-pre3/fs/qnx4/namei.c linux-2.2.7-pre4/fs/qnx4/namei.c
--- linux-2.2.7-pre3/fs/qnx4/namei.c	1998-12-18 07:09:35.000000000 -0800
+++ linux-2.2.7-pre4/fs/qnx4/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -108,7 +108,7 @@
 	return NULL;
 }
 
-int qnx4_lookup(struct inode *dir, struct dentry *dentry)
+struct dentry * qnx4_lookup(struct inode *dir, struct dentry *dentry)
 {
 	int ino;
 	struct qnx4_inode_entry *de;
@@ -116,17 +116,10 @@
 	struct buffer_head *bh;
 	const char *name = dentry->d_name.name;
 	int len = dentry->d_name.len;
-	struct inode *foundinode;
+	struct inode *foundinode = NULL;
 
-	if (!dir) {
-		return -EBADF;
-	}
-	if (!S_ISDIR(dir->i_mode)) {
-		return -EBADF;
-	}
-	if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino))) {
-		return -ENOENT;
-	}
+	if (!(bh = qnx4_find_entry(len, dir, name, &de, &ino)))
+		goto out;
 	/* The entry is linked, let's get the real info */
 	if ((de->di_status & QNX4_FILE_LINK) == QNX4_FILE_LINK) {
 		lnk = (struct qnx4_link_info *) de;
@@ -137,11 +130,12 @@
 
 	if ((foundinode = iget(dir->i_sb, ino)) == NULL) {
 		QNX4DEBUG(("qnx4: lookup->iget -> NULL\n"));
-		return -EACCES;
+		return ERR_PTR(-EACCES);
 	}
+out:
 	d_add(dentry, foundinode);
 
-	return 0;
+	return NULL;
 }
 
 #ifdef CONFIG_QNX4FS_RW
diff -urN linux-2.2.7-pre3/fs/romfs/inode.c linux-2.2.7-pre4/fs/romfs/inode.c
--- linux-2.2.7-pre3/fs/romfs/inode.c	1998-09-19 13:45:18.000000000 -0700
+++ linux-2.2.7-pre4/fs/romfs/inode.c	2003-08-15 15:05:52.000000000 -0700
@@ -267,9 +267,6 @@
 	int stored = 0;
 	char fsname[ROMFS_MAXFN];	/* XXX dynamic? */
 
-	if (!i || !S_ISDIR(i->i_mode))
-		return -EBADF;
-
 	maxoff = i->i_sb->u.romfs_sb.s_maxsize;
 
 	offset = filp->f_pos;
@@ -312,7 +309,7 @@
 	}
 }
 
-static int
+static struct dentry *
 romfs_lookup(struct inode *dir, struct dentry *dentry)
 {
 	unsigned long offset, maxoff;
@@ -323,10 +320,6 @@
 	const char *name;		/* got from dentry */
 	int len;
 
-	res = -EBADF;
-	if (!dir || !S_ISDIR(dir->i_mode))
-		goto out;
-
 	res = 0;			/* instead of ENOENT */
 	offset = dir->i_ino & ROMFH_MASK;
 	if (romfs_copyfrom(dir, &ri, offset, ROMFH_SIZE) <= 0)
@@ -379,7 +372,7 @@
 	}
 
 out:
-	return res;
+	return ERR_PTR(res);
 }
 
 /*
diff -urN linux-2.2.7-pre3/fs/smbfs/dir.c linux-2.2.7-pre4/fs/smbfs/dir.c
--- linux-2.2.7-pre3/fs/smbfs/dir.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/smbfs/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -22,7 +22,7 @@
 static int smb_readdir(struct file *, void *, filldir_t);
 static int smb_dir_open(struct inode *, struct file *);
 
-static int smb_lookup(struct inode *, struct dentry *);
+static struct dentry *smb_lookup(struct inode *, struct dentry *);
 static int smb_create(struct inode *, struct dentry *, int);
 static int smb_mkdir(struct inode *, struct dentry *, int);
 static int smb_rmdir(struct inode *, struct dentry *);
@@ -324,7 +324,7 @@
 	}
 }
 
-static int
+static struct dentry *
 smb_lookup(struct inode *dir, struct dentry *dentry)
 {
 	struct smb_fattr finfo;
@@ -360,7 +360,7 @@
 		}
 	}
 out:
-	return error;
+	return ERR_PTR(error);
 }
 
 /*
diff -urN linux-2.2.7-pre3/fs/sysv/dir.c linux-2.2.7-pre4/fs/sysv/dir.c
--- linux-2.2.7-pre3/fs/sysv/dir.c	1998-11-11 11:49:59.000000000 -0800
+++ linux-2.2.7-pre4/fs/sysv/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -69,14 +69,12 @@
 static int sysv_readdir(struct file * filp, void * dirent, filldir_t filldir)
 {
 	struct inode *inode = filp->f_dentry->d_inode;
-	struct super_block * sb;
+	struct super_block * sb = inode->i_sb;
 	unsigned int offset,i;
 	struct buffer_head * bh;
 	char* bh_data;
 	struct sysv_dir_entry * de, sde;
 
-	if (!inode || !(sb = inode->i_sb) || !S_ISDIR(inode->i_mode))
-		return -EBADF;
 	if ((unsigned long)(filp->f_pos) % SYSV_DIRSIZE)
 		return -EBADF;
 	while (filp->f_pos < inode->i_size) {
diff -urN linux-2.2.7-pre3/fs/sysv/namei.c linux-2.2.7-pre4/fs/sysv/namei.c
--- linux-2.2.7-pre3/fs/sysv/namei.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/sysv/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -103,17 +103,12 @@
 	return NULL;
 }
 
-int sysv_lookup(struct inode * dir, struct dentry * dentry)
+struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry)
 {
 	struct inode * inode = NULL;
 	struct sysv_dir_entry * de;
 	struct buffer_head * bh;
 
-	if (!dir)
-		return -ENOENT;
-	if (!S_ISDIR(dir->i_mode)) {
-		return -ENOENT;
-	}
 	bh = sysv_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de);
 
 	if (bh) {
@@ -122,10 +117,10 @@
 		inode = iget(dir->i_sb, ino);
 	
 		if (!inode) 
-			return -EACCES;
+			return ERR_PTR(-EACCES);
 	}
 	d_add(dentry, inode);
-	return 0;
+	return NULL;
 }
 
 /*
@@ -209,8 +204,6 @@
 	struct buffer_head * bh;
 	struct sysv_dir_entry * de;
 
-	if (!dir)
-		return -ENOENT;
 	inode = sysv_new_inode(dir);
 	if (!inode) 
 		return -ENOSPC;
@@ -239,8 +232,6 @@
 	struct buffer_head * bh;
 	struct sysv_dir_entry * de;
 
-	if (!dir)
-		return -ENOENT;
 	bh = sysv_find_entry(dir, dentry->d_name.name,
 			     dentry->d_name.len, &de);
 	if (bh) {
@@ -286,8 +277,6 @@
 	struct buffer_head * bh, *dir_block;
 	struct sysv_dir_entry * de;
 
-	if (!dir)
-		return -EINVAL;
 	bh = sysv_find_entry(dir, dentry->d_name.name,
                               dentry->d_name.len, &de);
 	if (bh) {
diff -urN linux-2.2.7-pre3/fs/ufs/dir.c linux-2.2.7-pre4/fs/ufs/dir.c
--- linux-2.2.7-pre3/fs/ufs/dir.c	1999-01-14 10:31:41.000000000 -0800
+++ linux-2.2.7-pre4/fs/ufs/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -43,13 +43,6 @@
 	int de_reclen;
 	unsigned flags, swab;
 
-
-	/* Isn't that already done in the upper layer???
-	 * the VFS layer really needs some explicit documentation!
-	 */
-	if (!inode || !S_ISDIR(inode->i_mode))
-		return -EBADF;
-
 	sb = inode->i_sb;
 	swab = sb->u.ufs_sb.s_swab;
 	flags = sb->u.ufs_sb.s_flags;
diff -urN linux-2.2.7-pre3/fs/ufs/namei.c linux-2.2.7-pre4/fs/ufs/namei.c
--- linux-2.2.7-pre3/fs/ufs/namei.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/ufs/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -185,7 +185,7 @@
 	return NULL;
 }
 
-int ufs_lookup(struct inode * dir, struct dentry *dentry)
+struct dentry *ufs_lookup(struct inode * dir, struct dentry *dentry)
 {
 	struct super_block * sb;
 	struct inode * inode;
@@ -199,7 +199,7 @@
 	swab = sb->u.ufs_sb.s_swab;
 	
 	if (dentry->d_name.len > UFS_MAXNAMLEN)
-		return -ENAMETOOLONG;
+		return ERR_PTR(-ENAMETOOLONG);
 
 	bh = ufs_find_entry (dir, dentry->d_name.name, dentry->d_name.len, &de);
 	inode = NULL;
@@ -208,11 +208,11 @@
 		brelse (bh);
 		inode = iget(sb, ino);
 		if (!inode) 
-			return -EACCES;
+			return ERR_PTR(-EACCES);
 	}
 	d_add(dentry, inode);
 	UFSD(("EXIT\n"))
-	return 0;
+	return NULL;
 }
 
 /*
diff -urN linux-2.2.7-pre3/fs/umsdos/dir.c linux-2.2.7-pre4/fs/umsdos/dir.c
--- linux-2.2.7-pre3/fs/umsdos/dir.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/umsdos/dir.c	2003-08-15 15:05:52.000000000 -0700
@@ -210,8 +210,8 @@
 		/*
 		 * Do a real lookup on the short name.
 		 */
-		dret = umsdos_lookup_dentry(filp->f_dentry, info.fake.fname,
-						 info.fake.len, 1);
+		dret = umsdos_covered(filp->f_dentry, info.fake.fname,
+						 info.fake.len);
 		ret = PTR_ERR(dret);
 		if (IS_ERR(dret))
 			break;
@@ -459,7 +459,7 @@
  * entry from the EMD file, and return ENOENT.
  */
 
-int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
+struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
 {				
 	struct dentry *dret = NULL;
 	struct inode *inode;
@@ -500,8 +500,7 @@
 info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
 
 	/* do a real lookup to get the short name ... */
-	dret = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
-					info.fake.len, 1);
+	dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
 	ret = PTR_ERR(dret);
 	if (IS_ERR(dret)) {
 printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n", 
@@ -563,7 +562,7 @@
 	dput(dret);
 out:
 	umsdos_endlookup (dir);
-	return ret;
+	return ERR_PTR(ret);
 
 out_remove:
 	printk(KERN_WARNING "UMSDOS:  entry %s/%s out of sync, erased\n",
@@ -581,19 +580,19 @@
  * Called by VFS; should fill dentry->d_inode via d_add.
  */
 
-int UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
+struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
 {
-	int ret;
+	struct dentry *ret;
 
 	ret = umsdos_lookup_x (dir, dentry, 0);
 
 	/* Create negative dentry if not found. */
-	if (ret == -ENOENT) {
+	if (ret == ERR_PTR(-ENOENT)) {
 		Printk ((KERN_DEBUG 
 			"UMSDOS_lookup: converting -ENOENT to negative\n"));
 		d_add (dentry, NULL);
 		dentry->d_op = &umsdos_dentry_operations;
-		ret = 0;
+		ret = NULL;
 	}
 	return ret;
 }
@@ -601,7 +600,6 @@
 struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
 {
 	struct dentry *result, *dentry;
-	int error;
 	struct qstr qstr;
 
 	qstr.name = name;
@@ -610,19 +608,18 @@
 	result = ERR_PTR(-ENOMEM);
 	dentry = d_alloc(parent, &qstr);
 	if (dentry) {
-		result = dentry;
 		/* XXXXXXXXXXXXXXXXXXX Race alert! */
-		error = UMSDOS_rlookup(parent->d_inode, result);
-		d_drop(result);
-		if (error)
+		result = UMSDOS_rlookup(parent->d_inode, dentry);
+		d_drop(dentry);
+		if (result)
 			goto out_fail;
+		return dentry;
 	}
 out:
 	return result;
 
 out_fail:
-	dput(result);
-	result = ERR_PTR(error);
+	dput(dentry);
 	goto out;
 }
 
@@ -636,7 +633,6 @@
 					int real)
 {
 	struct dentry *result, *dentry;
-	int error;
 	struct qstr qstr;
 
 	qstr.name = name;
@@ -647,20 +643,19 @@
 		result = ERR_PTR(-ENOMEM);
 		dentry = d_alloc(parent, &qstr);
 		if (dentry) {
-			result = dentry;
-			error = real ?
-				UMSDOS_rlookup(parent->d_inode, result) :
-				UMSDOS_lookup(parent->d_inode, result);
-			if (error)
+			result = real ?
+				UMSDOS_rlookup(parent->d_inode, dentry) :
+				UMSDOS_lookup(parent->d_inode, dentry);
+			if (result)
 				goto out_fail;
+			return dentry;
 		}
 	}
 out:
 	return result;
 
 out_fail:
-	dput(result);
-	result = ERR_PTR(error);
+	dput(dentry);
 	goto out;
 }
 
diff -urN linux-2.2.7-pre3/fs/umsdos/namei.c linux-2.2.7-pre4/fs/umsdos/namei.c
--- linux-2.2.7-pre3/fs/umsdos/namei.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/umsdos/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -175,18 +175,6 @@
 
 #endif
 
-/*
- * Check whether we can delete from the directory.
- */
-static int is_sticky(struct inode *dir, int uid)
-{
-	return !((dir->i_mode & S_ISVTX) == 0 || 
-		current->fsuid == uid ||
-		current->fsuid == dir->i_uid ||
-		capable (CAP_FOWNER));
-}
-
-
 static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
 				int errcod)
 {
@@ -696,9 +684,8 @@
 olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
 
 	/* Do a real lookup to get the short name dentry */
-	temp = umsdos_lookup_dentry(olddentry->d_parent,
-					old_info.fake.fname, 
-					old_info.fake.len, 1);
+	temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname, 
+					old_info.fake.len);
 	ret = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out_unlock;
@@ -784,16 +771,11 @@
 		goto out;
 
 	/* lookup the short name dentry */
-	temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-					info.fake.len, 1);
+	temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
 	ret = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out_remove;
 
-	/* Keep the short name dentry anonymous */ 
-	if (temp != dentry)
-		d_drop(temp);
-
 	/* Make sure the short name doesn't exist */
 	ret = -EEXIST;
 	if (temp->d_inode) {
@@ -812,16 +794,9 @@
 	inode = temp->d_inode;
 	down(&inode->i_sem);
 
-	/*
-	 * Note! The long and short name might be the same,
-	 * so check first before doing the instantiate ...
-	 */
-	if (dentry != temp) {
-if (dentry->d_inode)
-printk("umsdos_mkdir: dentry not negative!\n");
-		inode->i_count++;
-		d_instantiate(dentry, inode);
-	}
+	inode->i_count++;
+	d_instantiate(dentry, inode);
+
 	/* N.B. this should have an option to create the EMD ... */
 	umsdos_lookup_patch_new(dentry, &info);
 
@@ -921,21 +896,11 @@
 	umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
 	/* Call findentry to complete the mangling */
 	umsdos_findentry (dentry->d_parent, &info, 2);
-	temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-					info.fake.len, 1);
+	temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
 	ret = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out;
 	/*
-	 * If the short name is an alias, dput() it now;
-	 * otherwise d_drop() it to keep it anonymous.
-	 */
-	if (temp == dentry)
-		dput(temp);
-	else
-		d_drop(temp);
-
-	/*
 	 * Attempt to remove the msdos name.
 	 */
 	ret = msdos_rmdir (dir, temp);
@@ -951,8 +916,7 @@
 
 	/* dput() temp if we didn't do it above */
 out_dput:
-	if (temp != dentry)
-		dput(temp);
+	dput(temp);
 
 out:
 	Printk (("umsdos_rmdir %d\n", ret));
@@ -999,14 +963,6 @@
 
 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
 
-	ret = -EPERM;
-	/* check sticky bit */
-	if (is_sticky(dir, info.entry.uid)) {
-printk("umsdos_unlink: %s/%s is sticky\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-		goto out_unlock;
-	}
-
 	/*
 	 * Note! If this is a hardlink and the names are aliased,
 	 * the short-name lookup will return the hardlink dentry.
@@ -1018,8 +974,7 @@
 	}
 
 	/* Do a real lookup to get the short name dentry */
-	temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-					info.fake.len, 1);
+	temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
 	ret = PTR_ERR(temp);
 	if (IS_ERR(temp))
 		goto out_unlock;
@@ -1031,13 +986,6 @@
 		link = umsdos_solve_hlink(dget(temp));
 	}
 
-	/*
-	 * If the short and long names are aliased,
-	 * dput() it now so the dentry isn't busy.
-	 */
-	if (temp == dentry)
-		dput(temp);
-
 	/* Delete the EMD entry */
 	ret = umsdos_delentry (dentry->d_parent, &info, 0);
 	if (ret && ret != -ENOENT) {
@@ -1046,7 +994,7 @@
 		goto out_dput;
 	}
 
-	ret = msdos_unlink_umsdos (dir, temp);
+	ret = msdos_unlink(dir, temp);
 #ifdef UMSDOS_PARANOIA
 if (ret)
 printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
@@ -1055,12 +1003,9 @@
 
 	/* dput() temp if we didn't do it above */
 out_dput:
-	if (temp != dentry) {
-		d_drop(temp);
-		dput(temp);
-		if (!ret)
-			d_delete (dentry);
-	}
+	dput(temp);
+	if (!ret)
+		d_delete (dentry);
 
 out_unlock:
 	umsdos_unlockcreate (dir);
diff -urN linux-2.2.7-pre3/fs/umsdos/rdir.c linux-2.2.7-pre4/fs/umsdos/rdir.c
--- linux-2.2.7-pre3/fs/umsdos/rdir.c	1998-12-01 22:47:18.000000000 -0800
+++ linux-2.2.7-pre4/fs/umsdos/rdir.c	2003-08-15 15:05:52.000000000 -0700
@@ -79,9 +79,9 @@
  * In the real root directory (c:\), the directory ..
  * is the pseudo root (c:\linux).
  */
-int umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
+struct dentry *umsdos_rlookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo)
 {
-	int ret;
+	struct dentry *ret;
 
 	if (saved_root && dir == saved_root->d_inode && !nopseudo &&
 	    dentry->d_name.len == UMSDOS_PSDROOT_LEN &&
@@ -91,15 +91,16 @@
 		 * /linux won't show
 		 */
 		 
-		ret = -ENOENT;
+		ret = ERR_PTR(-ENOENT);
 		goto out;
 	}
 
 	ret = msdos_lookup (dir, dentry);
 	if (ret) {
 		printk(KERN_WARNING
-			"umsdos_rlookup_x: %s/%s failed, ret=%d\n",
-			dentry->d_parent->d_name.name, dentry->d_name.name,ret);
+			"umsdos_rlookup_x: %s/%s failed, ret=%ld\n",
+			dentry->d_parent->d_name.name, dentry->d_name.name,
+			PTR_ERR(ret));
 		goto out;
 	}
 	if (dentry->d_inode) {
@@ -119,7 +120,7 @@
 }
 
 
-int UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
+struct dentry *UMSDOS_rlookup ( struct inode *dir, struct dentry *dentry)
 {
 	return umsdos_rlookup_x (dir, dentry, 0);
 }
diff -urN linux-2.2.7-pre3/fs/vfat/namei.c linux-2.2.7-pre4/fs/vfat/namei.c
--- linux-2.2.7-pre3/fs/vfat/namei.c	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/fs/vfat/namei.c	2003-08-15 15:05:52.000000000 -0700
@@ -1140,11 +1140,30 @@
 	return res;
 }
 
-int vfat_lookup(struct inode *dir,struct dentry *dentry)
+/* Find a hashed dentry for inode; NULL if there are none */
+static struct dentry *find_alias(struct inode *inode)
+{
+	struct list_head *head, *next, *tmp;
+	struct dentry *alias;
+
+	head = &inode->i_dentry;
+	next = inode->i_dentry.next;
+	while (next != head) {
+		tmp = next;
+		next = tmp->next;
+		alias = list_entry(tmp, struct dentry, d_alias);
+		if (!list_empty(&alias->d_hash))
+			return dget(alias);
+	}
+	return NULL;
+}
+
+struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry)
 {
 	int res;
 	struct vfat_slot_info sinfo;
 	struct inode *result;
+	struct dentry *alias;
 	int table;
 	
 	PRINTK2(("vfat_lookup: name=%s, len=%d\n", 
@@ -1161,7 +1180,7 @@
 	}
 	PRINTK3(("vfat_lookup 4.5\n"));
 	if (!(result = iget(dir->i_sb,sinfo.ino)))
-		return -EACCES;
+		return ERR_PTR(-EACCES);
 	PRINTK3(("vfat_lookup 5\n"));
 	if (MSDOS_I(result)->i_busy) { /* mkdir in progress */
 		iput(result);
@@ -1169,6 +1188,15 @@
 		table++;
 		goto error;
 	}
+	alias = find_alias(result);
+	if (alias) {
+		if (d_invalidate(alias)==0)
+			dput(alias);
+		else {
+			iput(result);
+			return alias;
+		}
+	}
 	PRINTK3(("vfat_lookup 6\n"));
 error:
 	dentry->d_op = &vfat_dentry_ops[table];
@@ -1397,28 +1425,6 @@
 	return 0;
 }
 
-/* Drop all aliases */
-static void drop_aliases(struct dentry *dentry)
-{
-	struct list_head *head, *next, *tmp;
-	struct dentry *alias;
-
-	PRINTK1(("drop_replace_inodes: dentry=%p, inode=%p\n", dentry, inode));
-	head = &dentry->d_inode->i_dentry;
-	if (dentry->d_inode) {
-		next = dentry->d_inode->i_dentry.next;
-		while (next != head) {
-			tmp = next;
-			next = tmp->next;
-			alias = list_entry(tmp, struct dentry, d_alias);
-			if (alias == dentry)
-				continue;
-
-			d_drop(alias);
-		}
-	}
-}
-
 static int vfat_rmdirx(struct inode *dir,struct dentry* dentry)
 {
 	int res;
@@ -1430,12 +1436,6 @@
 	if (res >= 0 && sinfo.total_slots > 0) {
 		if (!list_empty(&dentry->d_hash))
 			return -EBUSY;
-		/* Take care of aliases */
-		if (dentry->d_inode->i_count > 1) {
-			shrink_dcache_parent(dentry->d_parent);
-			if (dentry->d_inode->i_count > 1)
-				return -EBUSY;
-		}
 		res = vfat_empty(dentry->d_inode);
 		if (res)
 			return res;
@@ -1535,10 +1535,8 @@
 
 	PRINTK1(("vfat_unlink: dentry=%p, inode=%p\n", dentry, dentry->d_inode));
 	res = vfat_unlinkx (dir,dentry,1);
-	if (res >= 0) {
-		drop_aliases(dentry);
+	if (res >= 0)
 		d_delete(dentry);
-	}
 	return res;
 }
 
@@ -1561,7 +1559,6 @@
 	loff_t old_offset,new_offset,old_longname_offset;
 	int old_slots,old_ino,new_ino,dotdot_ino;
 	struct inode *old_inode, *new_inode, *dotdot_inode;
-	struct dentry *walk;
 	int res, is_dir, i;
 	int locked = 0;
 	struct vfat_slot_info sinfo;
@@ -1589,16 +1586,6 @@
 	old_inode = old_dentry->d_inode;
 	is_dir = S_ISDIR(old_inode->i_mode);
 
-	if (is_dir) {
-		/* We can't use is_subdir() here. Even now. Arrgh. */
-		for (walk=new_dentry;walk!=walk->d_parent;walk=walk->d_parent) {
-			if (walk->d_inode != old_dentry->d_inode)
-				continue;
-			res = -EINVAL;
-			goto rename_done;
-		}
-	}
-
 	fat_lock_creation(); locked = 1;
 
 	if (new_dentry->d_inode) {
@@ -1620,25 +1607,9 @@
 		}
 
 		if (is_dir) {
-			/*
-			 * Target is a directory. No other owners will
-			 * be tolerated.
-			 */
-			res = -EBUSY;
-			/*
-			 * OK, let's try to get rid of other dentries.
-			 * No need to do it if i_count is 1.
-			 */
-			if (new_inode->i_count>1) {
-				shrink_dcache_parent(new_dentry->d_parent);
-				if (new_inode->i_count>1)
-					goto rename_done;
-			}
 			res = vfat_empty(new_inode);
 			if (res)
 				goto rename_done;
-		} else {
-			drop_aliases(new_dentry);
 		}
 		res = vfat_remove_entry(new_dir,&sinfo,new_inode);
 		if (res)
diff -urN linux-2.2.7-pre3/include/asm-alpha/keyboard.h linux-2.2.7-pre4/include/asm-alpha/keyboard.h
--- linux-2.2.7-pre3/include/asm-alpha/keyboard.h	1997-07-31 13:09:18.000000000 -0700
+++ linux-2.2.7-pre4/include/asm-alpha/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -18,7 +18,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -28,7 +27,6 @@
 
 #define kbd_setkeycode		pckbd_setkeycode
 #define kbd_getkeycode		pckbd_getkeycode
-#define kbd_pretranslate	pckbd_pretranslate
 #define kbd_translate		pckbd_translate
 #define kbd_unexpected_up	pckbd_unexpected_up
 #define kbd_leds		pckbd_leds
diff -urN linux-2.2.7-pre3/include/asm-alpha/semaphore.h linux-2.2.7-pre4/include/asm-alpha/semaphore.h
--- linux-2.2.7-pre3/include/asm-alpha/semaphore.h	1999-04-16 08:22:49.000000000 -0700
+++ linux-2.2.7-pre4/include/asm-alpha/semaphore.h	2003-08-15 15:05:52.000000000 -0700
@@ -53,24 +53,31 @@
 	   it's return address in $28.  The pv is loaded as usual.
 	   The gp is clobbered (in the module case) as usual.  */
 
+	/* This little bit of silliness is to get the GP loaded for
+	   a function that ordinarily wouldn't.  Otherwise we could
+	   have it done by the macro directly, which can be optimized
+	   the linker.  */
+	register void *pv __asm__("$27") = __down_failed;
+	
 	__asm__ __volatile__ (
 		"/* semaphore down operation */\n"
-		"1:	ldl_l	$27,%0\n"
-		"	subl	$27,1,$27\n"
-		"	mov	$27,$28\n"
-		"	stl_c	$28,%0\n"
+		"1:	ldl_l	$24,%1\n"
+		"	subl	$24,1,$24\n"
+		"	mov	$24,$28\n"
+		"	stl_c	$28,%1\n"
 		"	beq	$28,2f\n"
-		"	blt	$27,3f\n"
+		"	blt	$24,3f\n"
 		"4:	mb\n"
 		".section .text2,\"ax\"\n"
 		"2:	br	1b\n"
-		"3:	lda	$24,%0\n"
-		"	jsr	$28,__down_failed\n"
+		"3:	lda	$24,%1\n"
+		"	jsr	$28,($27),__down_failed\n"
 		"	ldgp	$29,0($28)\n"
 		"	br	4b\n"
 		".previous"
-		: : "m"(sem->count)
-		: "$24", "$27", "$28", "memory");
+		: "=r"(pv)
+		: "m"(sem->count), "r"(pv)
+		: "$24", "$28", "memory");
 }
 
 extern inline int down_interruptible(struct semaphore * sem)
@@ -81,27 +88,28 @@
 	   value is in $24.  */
 
 	register int ret __asm__("$24");
+	register void *pv __asm__("$27") = __down_failed_interruptible;
 
 	__asm__ __volatile__ (
 		"/* semaphore down interruptible operation */\n"
-		"1:	ldl_l	$27,%1\n"
-		"	subl	$27,1,$27\n"
-		"	mov	$27,$28\n"
-		"	stl_c	$28,%1\n"
+		"1:	ldl_l	$24,%2\n"
+		"	subl	$24,1,$24\n"
+		"	mov	$24,$28\n"
+		"	stl_c	$28,%2\n"
 		"	beq	$28,2f\n"
-		"	blt	$27,3f\n"
+		"	blt	$24,3f\n"
 		"	mov	$31,%0\n"
 		"4:	mb\n"
 		".section .text2,\"ax\"\n"
 		"2:	br	1b\n"
-		"3:	lda	$24,%1\n"
-		"	jsr	$28,__down_failed_interruptible\n"
+		"3:	lda	$24,%2\n"
+		"	jsr	$28,($27),__down_failed_interruptible\n"
 		"	ldgp	$29,0($28)\n"
 		"	br	4b\n"
 		".previous"
-		: "=r"(ret)
-		: "m"(sem->count)
-		: "$27", "$28", "memory");
+		: "=r"(ret), "=r"(pv)
+		: "m"(sem->count), "r"(pv)
+		: "$28", "memory");
 
 	return ret;
 }
@@ -171,26 +179,29 @@
 	   it's return address in $28.  The pv is loaded as usual.
 	   The gp is clobbered (in the module case) as usual.  */
 
+	register void *pv __asm__("$27") = __up_wakeup;
+
 	__asm__ __volatile__ (
 		"/* semaphore up operation */\n"
 		"	mb\n"
-		"1:	ldl_l	$27,%0\n"
-		"	addl	$27,1,$27\n"
-		"	mov	$27,$28\n"
-		"	stl_c	$28,%0\n"
+		"1:	ldl_l	$24,%1\n"
+		"	addl	$24,1,$24\n"
+		"	mov	$24,$28\n"
+		"	stl_c	$28,%1\n"
 		"	beq	$28,2f\n"
 		"	mb\n"
 		"	ble	$27,3f\n"
 		"4:\n"
 		".section .text2,\"ax\"\n"
 		"2:	br	1b\n"
-		"3:	lda	$24,%0\n"
-		"	jsr	$28,__up_wakeup\n"
+		"3:	lda	$24,%1\n"
+		"	jsr	$28,($27),__up_wakeup\n"
 		"	ldgp	$29,0($28)\n"
 		"	br	4b\n"
 		".previous"
-		: : "m"(sem->count)
-		: "$24", "$27", "$28", "memory");
+		: "=r"(pv)
+		: "m"(sem->count), "r"(pv)
+		: "$24", "$28", "memory");
 }
 
 #endif
diff -urN linux-2.2.7-pre3/include/asm-alpha/uaccess.h linux-2.2.7-pre4/include/asm-alpha/uaccess.h
--- linux-2.2.7-pre3/include/asm-alpha/uaccess.h	1999-04-15 05:42:31.000000000 -0700
+++ linux-2.2.7-pre4/include/asm-alpha/uaccess.h	2003-08-15 15:05:52.000000000 -0700
@@ -160,7 +160,7 @@
 		: "=r"(__gu_val), "=r"(__gu_err)	\
 		: "m"(__m(addr)), "1"(__gu_err))
 
-#ifdef __HAVE_CPU_BWX
+#ifdef __alpha_bwx__
 /* Those lucky bastards with ev56 and later CPUs can do byte/word moves.  */
 
 #define __get_user_16(addr)				\
@@ -274,7 +274,7 @@
 		: "=r"(__pu_err)				\
 		: "m"(__m(addr)), "rJ"(x), "0"(__pu_err))
 
-#ifdef __HAVE_CPU_BWX
+#ifdef __alpha_bwx__
 /* Those lucky bastards with ev56 and later CPUs can do byte/word moves.  */
 
 #define __put_user_16(x,addr)					\
@@ -363,15 +363,21 @@
 extern inline long
 __copy_tofrom_user_nocheck(void *to, const void *from, long len)
 {
+	/* This little bit of silliness is to get the GP loaded for
+	   a function that ordinarily wouldn't.  Otherwise we could
+	   have it done by the macro directly, which can be optimized
+	   the linker.  */
+	register void * pv __asm__("$27") = __copy_user;
+
 	register void * __cu_to __asm__("$6") = to;
 	register const void * __cu_from __asm__("$7") = from;
 	register long __cu_len __asm__("$0") = len;
 
 	__asm__ __volatile__(
-		"jsr $28,__copy_user"
-		: "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to)
-		: "0" (__cu_len), "1" (__cu_from), "2" (__cu_to)
-		: "$1","$2","$3","$4","$5","$27","$28","memory");
+		"jsr $28,(%3),__copy_user\n\tldgp $29,0($28)"
+		: "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to), "=r"(pv)
+		: "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), "3"(pv)
+		: "$1","$2","$3","$4","$5","$28","memory");
 
 	return __cu_len;
 }
@@ -380,14 +386,17 @@
 __copy_tofrom_user(void *to, const void *from, long len, const void *validate)
 {
 	if (__access_ok((long)validate, len, get_fs())) {
+		register void * pv __asm__("$27") = __copy_user;
 		register void * __cu_to __asm__("$6") = to;
 		register const void * __cu_from __asm__("$7") = from;
 		register long __cu_len __asm__("$0") = len;
 		__asm__ __volatile__(
-			"jsr $28,__copy_user"
-			: "=r" (__cu_len), "=r" (__cu_from), "=r" (__cu_to)
-			: "0" (__cu_len), "1" (__cu_from), "2" (__cu_to)
-			: "$1","$2","$3","$4","$5","$27","$28","memory");
+			"jsr $28,(%3),__copy_user\n\tldgp $29,0($28)"
+			: "=r"(__cu_len), "=r"(__cu_from), "=r"(__cu_to),
+			  "=r" (pv)
+			: "0" (__cu_len), "1" (__cu_from), "2" (__cu_to), 
+			  "3" (pv)
+			: "$1","$2","$3","$4","$5","$28","memory");
 		len = __cu_len;
 	}
 	return len;
@@ -423,13 +432,19 @@
 extern inline long
 __clear_user(void *to, long len)
 {
+	/* This little bit of silliness is to get the GP loaded for
+	   a function that ordinarily wouldn't.  Otherwise we could
+	   have it done by the macro directly, which can be optimized
+	   the linker.  */
+	register void * pv __asm__("$27") = __do_clear_user;
+
 	register void * __cl_to __asm__("$6") = to;
 	register long __cl_len __asm__("$0") = len;
 	__asm__ __volatile__(
-		"jsr $28,__do_clear_user"
-		: "=r"(__cl_len), "=r"(__cl_to)
-		: "0"(__cl_len), "1"(__cl_to)
-		: "$1","$2","$3","$4","$5","$27","$28","memory");
+		"jsr $28,(%2),__do_clear_user\n\tldgp $29,0($28)"
+		: "=r"(__cl_len), "=r"(__cl_to), "=r"(pv)
+		: "0"(__cl_len), "1"(__cl_to), "2"(pv)
+		: "$1","$2","$3","$4","$5","$28","memory");
 	return __cl_len;
 }
 
@@ -437,13 +452,14 @@
 clear_user(void *to, long len)
 {
 	if (__access_ok((long)to, len, get_fs())) {
+		register void * pv __asm__("$27") = __do_clear_user;
 		register void * __cl_to __asm__("$6") = to;
 		register long __cl_len __asm__("$0") = len;
 		__asm__ __volatile__(
-			"jsr $28,__do_clear_user"
-			: "=r"(__cl_len), "=r"(__cl_to)
-			: "0"(__cl_len), "1"(__cl_to)
-			: "$1","$2","$3","$4","$5","$27","$28","memory");
+			"jsr $28,(%2),__do_clear_user\n\tldgp $29,0($28)"
+			: "=r"(__cl_len), "=r"(__cl_to), "=r"(pv)
+			: "0"(__cl_len), "1"(__cl_to), "2"(pv)
+			: "$1","$2","$3","$4","$5","$28","memory");
 		len = __cl_len;
 	}
 	return len;
diff -urN linux-2.2.7-pre3/include/asm-arm/arch-arc/keyboard.h linux-2.2.7-pre4/include/asm-arm/arch-arc/keyboard.h
--- linux-2.2.7-pre3/include/asm-arm/arch-arc/keyboard.h	1998-12-17 09:05:42.000000000 -0800
+++ linux-2.2.7-pre4/include/asm-arm/arch-arc/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -19,11 +19,6 @@
 #define kbd_setkeycode(sc,kc)		(-EINVAL)
 #define kbd_getkeycode(sc)		(-EINVAL)
 
-/* Prototype: int kbd_pretranslate(scancode, raw_mode)
- * Returns  : 0 to ignore scancode
- */
-#define kbd_pretranslate(sc,rm)	(1)
-
 /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
  * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
  *            set to 0200 if scancode indicates release
diff -urN linux-2.2.7-pre3/include/asm-arm/arch-ebsa285/keyboard.h linux-2.2.7-pre4/include/asm-arm/arch-ebsa285/keyboard.h
--- linux-2.2.7-pre3/include/asm-arm/arch-ebsa285/keyboard.h	1998-12-17 09:05:43.000000000 -0800
+++ linux-2.2.7-pre4/include/asm-arm/arch-ebsa285/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -19,7 +19,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -29,7 +28,6 @@
 
 #define kbd_setkeycode			pckbd_setkeycode
 #define kbd_getkeycode			pckbd_getkeycode
-#define kbd_pretranslate		pckbd_pretranslate
 #define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \
 		pckbd_translate(sc & 0x7f, kcp, rm);})
 
@@ -50,11 +48,6 @@
 #define kbd_setkeycode(sc,kc)		(-EINVAL)
 #define kbd_getkeycode(sc)		(-EINVAL)
 
-/* Prototype: int kbd_pretranslate(scancode, raw_mode)
- * Returns  : 0 to ignore scancode
- */
-#define kbd_pretranslate(sc,rm)		(1)
-
 /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
  * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
  *            set to 0200 if scancode indicates release
diff -urN linux-2.2.7-pre3/include/asm-arm/arch-rpc/keyboard.h linux-2.2.7-pre4/include/asm-arm/arch-rpc/keyboard.h
--- linux-2.2.7-pre3/include/asm-arm/arch-rpc/keyboard.h	1998-12-17 09:05:43.000000000 -0800
+++ linux-2.2.7-pre4/include/asm-arm/arch-rpc/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -10,7 +10,6 @@
 
 #define NR_SCANCODES 128
 
-extern int ps2kbd_pretranslate(unsigned char scancode);
 extern int ps2kbd_translate(unsigned char scancode, unsigned char *keycode_p, char *up_flag_p);
 extern void ps2kbd_leds(unsigned char leds);
 extern void ps2kbd_init_hw(void);
@@ -19,11 +18,6 @@
 #define kbd_setkeycode(sc,kc)		(-EINVAL)
 #define kbd_getkeycode(sc)		(-EINVAL)
 
-/* Prototype: int kbd_pretranslate(scancode, raw_mode)
- * Returns  : 0 to ignore scancode
- */
-#define kbd_pretranslate(sc,rm)		ps2kbd_pretranslate(sc)
-
 /* Prototype: int kbd_translate(scancode, *keycode, *up_flag, raw_mode)
  * Returns  : 0 to ignore scancode, *keycode set to keycode, *up_flag
  *            set to 0200 if scancode indicates release
diff -urN linux-2.2.7-pre3/include/asm-arm/arch-vnc/keyboard.h linux-2.2.7-pre4/include/asm-arm/arch-vnc/keyboard.h
--- linux-2.2.7-pre3/include/asm-arm/arch-vnc/keyboard.h	1998-12-17 09:05:43.000000000 -0800
+++ linux-2.2.7-pre4/include/asm-arm/arch-vnc/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -14,7 +14,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -24,7 +23,6 @@
 
 #define kbd_setkeycode			pckbd_setkeycode
 #define kbd_getkeycode			pckbd_getkeycode
-#define kbd_pretranslate		pckbd_pretranslate
 #define kbd_translate(sc, kcp, ufp, rm) ({ *ufp = sc & 0200; \
 		pckbd_translate(sc & 0x7f, kcp, rm);})
 
diff -urN linux-2.2.7-pre3/include/asm-i386/keyboard.h linux-2.2.7-pre4/include/asm-i386/keyboard.h
--- linux-2.2.7-pre3/include/asm-i386/keyboard.h	1997-07-31 13:09:18.000000000 -0700
+++ linux-2.2.7-pre4/include/asm-i386/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -18,7 +18,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -28,7 +27,6 @@
 
 #define kbd_setkeycode		pckbd_setkeycode
 #define kbd_getkeycode		pckbd_getkeycode
-#define kbd_pretranslate	pckbd_pretranslate
 #define kbd_translate		pckbd_translate
 #define kbd_unexpected_up	pckbd_unexpected_up
 #define kbd_leds		pckbd_leds
diff -urN linux-2.2.7-pre3/include/asm-m68k/keyboard.h linux-2.2.7-pre4/include/asm-m68k/keyboard.h
--- linux-2.2.7-pre3/include/asm-m68k/keyboard.h	1999-01-19 10:58:34.000000000 -0800
+++ linux-2.2.7-pre4/include/asm-m68k/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -27,11 +27,6 @@
     return scancode > 127 ? -EINVAL : scancode;
 }
 
-static __inline__ int kbd_pretranslate(unsigned char scancode, char raw_mode)
-{
-    return 1;
-}
-
 static __inline__ int kbd_translate(unsigned char scancode,
 				    unsigned char *keycode, char raw_mode)
 {
diff -urN linux-2.2.7-pre3/include/asm-mips/keyboard.h linux-2.2.7-pre4/include/asm-mips/keyboard.h
--- linux-2.2.7-pre3/include/asm-mips/keyboard.h	1998-10-20 13:52:53.000000000 -0700
+++ linux-2.2.7-pre4/include/asm-mips/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -19,7 +19,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -29,7 +28,6 @@
 
 #define kbd_setkeycode		pckbd_setkeycode
 #define kbd_getkeycode		pckbd_getkeycode
-#define kbd_pretranslate	pckbd_pretranslate
 #define kbd_translate		pckbd_translate
 #define kbd_unexpected_up	pckbd_unexpected_up
 #define kbd_leds		pckbd_leds
diff -urN linux-2.2.7-pre3/include/asm-ppc/keyboard.h linux-2.2.7-pre4/include/asm-ppc/keyboard.h
--- linux-2.2.7-pre3/include/asm-ppc/keyboard.h	1999-03-19 10:50:09.000000000 -0800
+++ linux-2.2.7-pre4/include/asm-ppc/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -28,7 +28,6 @@
 
 extern int mackbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int mackbd_getkeycode(unsigned int scancode);
-extern int mackbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int mackbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
 extern int mackbd_unexpected_up(unsigned char keycode);
@@ -37,7 +36,6 @@
 
 extern int pckbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pckbd_getkeycode(unsigned int scancode);
-extern int pckbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pckbd_translate(unsigned char scancode, unsigned char *keycode,
 			   char raw_mode);
 extern char pckbd_unexpected_up(unsigned char keycode);
@@ -84,23 +82,6 @@
 		return mackbd_getkeycode(x);
 }
 
-static inline int kbd_pretranslate(unsigned char x,char y)
-{
-	if ( is_prep || (_machine == _MACH_mbx) )
-		return pckbd_pretranslate(x,y);
-	else if ( is_chrp )
-#ifndef CONFIG_MAC_KEYBOARD
-		return pckbd_pretranslate(x,y);
-#else
-		if ( adb_hardware == ADB_NONE )
-			return pckbd_pretranslate(x,y);
-		else
-			return mackbd_pretranslate(x,y);
-#endif
-	else
-		return mackbd_pretranslate(x,y);
-}
-
 static inline int kbd_translate(unsigned char keycode, unsigned char *keycodep,
 		     char raw_mode)
 {
diff -urN linux-2.2.7-pre3/include/asm-sparc/keyboard.h linux-2.2.7-pre4/include/asm-sparc/keyboard.h
--- linux-2.2.7-pre3/include/asm-sparc/keyboard.h	1998-10-04 10:22:44.000000000 -0700
+++ linux-2.2.7-pre4/include/asm-sparc/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -18,7 +18,6 @@
 
 extern int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pcikbd_getkeycode(unsigned int scancode);
-extern int pcikbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
 			    char raw_mode);
 extern char pcikbd_unexpected_up(unsigned char keycode);
@@ -28,7 +27,6 @@
 
 #define kbd_setkeycode			pcikbd_setkeycode
 #define kbd_getkeycode			pcikbd_getkeycode
-#define kbd_pretranslate		pcikbd_pretranslate
 #define kbd_translate			pcikbd_translate
 #define kbd_unexpected_up		pcikbd_unexpected_up
 #define kbd_leds			pcikbd_leds
diff -urN linux-2.2.7-pre3/include/asm-sparc64/keyboard.h linux-2.2.7-pre4/include/asm-sparc64/keyboard.h
--- linux-2.2.7-pre3/include/asm-sparc64/keyboard.h	1998-01-12 15:15:58.000000000 -0800
+++ linux-2.2.7-pre4/include/asm-sparc64/keyboard.h	2003-08-15 15:05:52.000000000 -0700
@@ -18,7 +18,6 @@
 
 extern int pcikbd_setkeycode(unsigned int scancode, unsigned int keycode);
 extern int pcikbd_getkeycode(unsigned int scancode);
-extern int pcikbd_pretranslate(unsigned char scancode, char raw_mode);
 extern int pcikbd_translate(unsigned char scancode, unsigned char *keycode,
 			    char raw_mode);
 extern char pcikbd_unexpected_up(unsigned char keycode);
@@ -28,7 +27,6 @@
 
 #define kbd_setkeycode			pcikbd_setkeycode
 #define kbd_getkeycode			pcikbd_getkeycode
-#define kbd_pretranslate		pcikbd_pretranslate
 #define kbd_translate			pcikbd_translate
 #define kbd_unexpected_up		pcikbd_unexpected_up
 #define kbd_leds			pcikbd_leds
diff -urN linux-2.2.7-pre3/include/linux/adfs_fs.h linux-2.2.7-pre4/include/linux/adfs_fs.h
--- linux-2.2.7-pre3/include/linux/adfs_fs.h	1998-12-27 22:18:28.000000000 -0800
+++ linux-2.2.7-pre4/include/linux/adfs_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -155,7 +155,7 @@
 extern int adfs_map_lookup (struct super_block *sb, int frag_id, int offset);
 
 /* namei.c */
-extern int adfs_lookup (struct inode *dir, struct dentry *dentry);
+extern struct dentry *adfs_lookup (struct inode *dir, struct dentry *dentry);
 
 /* super.c */
 extern int init_adfs_fs (void);
diff -urN linux-2.2.7-pre3/include/linux/affs_fs.h linux-2.2.7-pre4/include/linux/affs_fs.h
--- linux-2.2.7-pre3/include/linux/affs_fs.h	1998-12-27 22:20:08.000000000 -0800
+++ linux-2.2.7-pre4/include/linux/affs_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -60,7 +60,7 @@
 /* namei.c */
 
 extern int	affs_hash_name(const unsigned char *name, int len, int intl, int hashsize);
-extern int	affs_lookup(struct inode *dir, struct dentry *dentry);
+extern struct dentry *affs_lookup(struct inode *dir, struct dentry *dentry);
 extern int	affs_unlink(struct inode *dir, struct dentry *dentry);
 extern int	affs_create(struct inode *dir, struct dentry *dentry, int mode);
 extern int	affs_mkdir(struct inode *dir, struct dentry *dentry, int mode);
diff -urN linux-2.2.7-pre3/include/linux/ext2_fs.h linux-2.2.7-pre4/include/linux/ext2_fs.h
--- linux-2.2.7-pre3/include/linux/ext2_fs.h	1998-12-27 22:18:28.000000000 -0800
+++ linux-2.2.7-pre4/include/linux/ext2_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -572,7 +572,7 @@
 
 /* namei.c */
 extern void ext2_release (struct inode *, struct file *);
-extern int ext2_lookup (struct inode *, struct dentry *);
+extern struct dentry *ext2_lookup (struct inode *, struct dentry *);
 extern int ext2_create (struct inode *,struct dentry *,int);
 extern int ext2_mkdir (struct inode *,struct dentry *,int);
 extern int ext2_rmdir (struct inode *,struct dentry *);
diff -urN linux-2.2.7-pre3/include/linux/fb.h linux-2.2.7-pre4/include/linux/fb.h
--- linux-2.2.7-pre3/include/linux/fb.h	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/fb.h	2003-08-15 15:05:52.000000000 -0700
@@ -31,6 +31,7 @@
 #define FB_TYPE_PLANES			1	/* Non interleaved planes */
 #define FB_TYPE_INTERLEAVED_PLANES	2	/* Interleaved planes	*/
 #define FB_TYPE_TEXT			3	/* Text/attributes	*/
+#define FB_TYPE_VGA_PLANES		4	/* EGA/VGA planes	*/
 
 #define FB_AUX_TEXT_MDA		0	/* Monochrome text */
 #define FB_AUX_TEXT_CGA		1	/* CGA/EGA/VGA Color text */
@@ -297,7 +298,7 @@
 
 struct fb_info {
    char modename[40];			/* default video mode */
-   int node;
+   kdev_t node;
    int flags;
 #define FBINFO_FLAG_MODULE	1	/* Low-level driver is a module */
    struct fb_ops *fbops;
diff -urN linux-2.2.7-pre3/include/linux/fs.h linux-2.2.7-pre4/include/linux/fs.h
--- linux-2.2.7-pre3/include/linux/fs.h	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -254,18 +254,8 @@
 	return test_bit(BH_Protected, &bh->b_state);
 }
 
-/*
- * Deprecated - we don't keep per-buffer reference flags
- * any more.
- *
- * We _could_ try to update the page reference, but that
- * doesn't seem to really be worth it either. If we did,
- * it would look something like this:
- *
- *	#define buffer_page(bh)		(mem_map + MAP_NR((bh)->b_data))
- *	#define touch_buffer(bh)	set_bit(PG_referenced, &buffer_page(bh)->flags)
- */
-#define touch_buffer(bh)	do { } while (0)
+#define buffer_page(bh)		(mem_map + MAP_NR((bh)->b_data))
+#define touch_buffer(bh)	set_bit(PG_referenced, &buffer_page(bh)->flags)
 
 #include <linux/pipe_fs_i.h>
 #include <linux/minix_fs_i.h>
@@ -607,7 +597,7 @@
 struct inode_operations {
 	struct file_operations * default_file_ops;
 	int (*create) (struct inode *,struct dentry *,int);
-	int (*lookup) (struct inode *,struct dentry *);
+	struct dentry * (*lookup) (struct inode *,struct dentry *);
 	int (*link) (struct dentry *,struct inode *,struct dentry *);
 	int (*unlink) (struct inode *,struct dentry *);
 	int (*symlink) (struct inode *,struct dentry *,const char *);
diff -urN linux-2.2.7-pre3/include/linux/irda.h linux-2.2.7-pre4/include/linux/irda.h
--- linux-2.2.7-pre3/include/linux/irda.h	1969-12-31 16:00:00.000000000 -0800
+++ linux-2.2.7-pre4/include/linux/irda.h	2003-08-15 15:05:52.000000000 -0700
@@ -0,0 +1,120 @@
+/*********************************************************************
+ *                
+ * Filename:      irda.h
+ * Version:       
+ * Description:   
+ * Status:        Experimental.
+ * Author:        Dag Brattli <dagb@cs.uit.no>
+ * Created at:    Mon Mar  8 14:06:12 1999
+ * Modified at:   Mon Mar 22 14:14:54 1999
+ * Modified by:   Dag Brattli <dagb@cs.uit.no>
+ * 
+ *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
+ *      
+ *     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.
+ *  
+ *     Neither Dag Brattli nor University of Tromsø admit liability nor
+ *     provide warranty for any of this software. This material is 
+ *     provided "AS-IS" and at no charge.
+ *     
+ ********************************************************************/
+
+#ifndef KERNEL_IRDA_H
+#define KERNEL_IRDA_H
+
+/* Hint bit positions for first hint byte */
+#define HINT_PNP         0x01
+#define HINT_PDA         0x02
+#define HINT_COMPUTER    0x04
+#define HINT_PRINTER     0x08
+#define HINT_MODEM       0x10
+#define HINT_FAX         0x20
+#define HINT_LAN         0x40
+#define HINT_EXTENSION   0x80
+
+/* Hint bit positions for second hint byte (first extension byte) */
+#define HINT_TELEPHONY   0x01
+#define HINT_FILE_SERVER 0x02
+#define HINT_COMM        0x04
+#define HINT_MESSAGE     0x08
+#define HINT_HTTP        0x10
+#define HINT_OBEX        0x20
+
+/* IrLMP character code values */
+#define CS_ASCII       0x00
+#define	CS_ISO_8859_1  0x01
+#define	CS_ISO_8859_2  0x02
+#define	CS_ISO_8859_3  0x03
+#define	CS_ISO_8859_4  0x04
+#define	CS_ISO_8859_5  0x05
+#define	CS_ISO_8859_6  0x06
+#define	CS_ISO_8859_7  0x07
+#define	CS_ISO_8859_8  0x08
+#define	CS_ISO_8859_9  0x09
+#define CS_UNICODE     0xff
+
+#define SOL_IRLMP      266 /* Same as SOL_IRDA for now */
+#define SOL_IRTTP      266 /* Same as SOL_IRDA for now */
+
+#define IRLMP_ENUMDEVICES        1
+#define IRLMP_IAS_SET            2
+#define IRLMP_IAS_QUERY          3
+#define IRLMP_DISCOVERY_MASK_SET 4
+
+#define IRTTP_QOS_SET            5
+#define IRTTP_QOS_GET            6
+#define IRTTP_MAX_SDU_SIZE       7
+
+#define IAS_MAX_STRING           256
+#define IAS_MAX_OCTET_STRING     1024
+#define IAS_MAX_CLASSNAME        64
+#define IAS_MAX_ATTRIBNAME       256
+
+#define LSAP_ANY                 0xff
+
+struct sockaddr_irda {
+	sa_family_t   sir_family;   /* AF_IRDA */
+	unsigned char sir_lsap_sel; /* LSAP/TSAP selector */
+	unsigned int  sir_addr;     /* Device address */
+	char          sir_name[25]; /* Usually <service>:IrDA:TinyTP */
+};
+
+struct irda_device_info {
+	unsigned int  saddr;       /* Address of remote device */
+	unsigned int  daddr;       /* Link where it was discovered */
+	char          info[22];     /* Description */
+	unsigned char charset;      /* Charset used for description */
+	unsigned char hints[2];     /* Hint bits */
+};
+
+struct irda_device_list {
+       unsigned int len;
+       struct irda_device_info dev[0];
+};
+
+struct irda_ias_set {
+	char irda_class_name[IAS_MAX_CLASSNAME];
+	char irda_attrib_name[IAS_MAX_ATTRIBNAME];
+	unsigned int irda_attrib_type;
+	union {
+		unsigned int irda_attrib_int;
+		struct {
+			unsigned short len;
+			u_char OctetSeq[IAS_MAX_OCTET_STRING];
+		} irda_attrib_octet_seq;
+		struct {
+			unsigned char len;
+			unsigned char charset;
+			unsigned char string[IAS_MAX_STRING];
+		} irda_attrib_string;
+	} attribute;
+};
+
+#endif /* KERNEL_IRDA_H */
+
+
+
+
diff -urN linux-2.2.7-pre3/include/linux/iso_fs.h linux-2.2.7-pre4/include/linux/iso_fs.h
--- linux-2.2.7-pre3/include/linux/iso_fs.h	1998-12-27 22:18:30.000000000 -0800
+++ linux-2.2.7-pre4/include/linux/iso_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -189,7 +189,7 @@
 
 extern int isofs_open(struct inode * inode, struct file * filp);
 extern void isofs_release(struct inode * inode, struct file * filp);
-extern int isofs_lookup(struct inode * dir, struct dentry *);
+extern struct dentry *isofs_lookup(struct inode * dir, struct dentry *);
 extern unsigned long isofs_count_free_inodes(struct super_block *sb);
 extern int isofs_new_block(int dev);
 extern int isofs_free_block(int dev, int block);
diff -urN linux-2.2.7-pre3/include/linux/kbd_ll.h linux-2.2.7-pre4/include/linux/kbd_ll.h
--- linux-2.2.7-pre3/include/linux/kbd_ll.h	1997-06-16 16:36:00.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/kbd_ll.h	2003-08-15 15:05:52.000000000 -0700
@@ -7,6 +7,6 @@
 
 extern struct pt_regs *kbd_pt_regs;
 
-void handle_scancode(unsigned char scancode);
+void handle_scancode(unsigned char scancode, int down);
 
 #endif	/* _KBD_LL_H */
diff -urN linux-2.2.7-pre3/include/linux/minix_fs.h linux-2.2.7-pre4/include/linux/minix_fs.h
--- linux-2.2.7-pre3/include/linux/minix_fs.h	1998-11-22 09:34:01.000000000 -0800
+++ linux-2.2.7-pre4/include/linux/minix_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -89,7 +89,7 @@
 
 #ifdef __KERNEL__
 
-extern int minix_lookup(struct inode * dir, struct dentry *dentry);
+extern struct dentry *minix_lookup(struct inode * dir, struct dentry *dentry);
 extern int minix_create(struct inode * dir, struct dentry *dentry, int mode);
 extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode);
 extern int minix_rmdir(struct inode * dir, struct dentry *dentry);
diff -urN linux-2.2.7-pre3/include/linux/msdos_fs.h linux-2.2.7-pre4/include/linux/msdos_fs.h
--- linux-2.2.7-pre3/include/linux/msdos_fs.h	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/msdos_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -271,7 +271,7 @@
 
 /* msdos.c - these are for Umsdos */
 extern void msdos_read_inode(struct inode *inode);
-extern int msdos_lookup(struct inode *dir,struct dentry *);
+extern struct dentry *msdos_lookup(struct inode *dir,struct dentry *);
 extern int msdos_create(struct inode *dir,struct dentry *dentry,int mode);
 extern int msdos_rmdir(struct inode *dir,struct dentry *dentry);
 extern int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode);
@@ -312,7 +312,7 @@
 extern struct super_block *vfat_read_super(struct super_block *sb,void *data,
 					   int silent);
 extern void vfat_read_inode(struct inode *inode);
-extern int vfat_lookup(struct inode *dir,struct dentry *);
+extern struct dentry *vfat_lookup(struct inode *dir,struct dentry *);
 
 /* vfat/vfatfs_syms.c */
 extern struct file_system_type vfat_fs_type;
diff -urN linux-2.2.7-pre3/include/linux/proc_fs.h linux-2.2.7-pre4/include/linux/proc_fs.h
--- linux-2.2.7-pre3/include/linux/proc_fs.h	1999-04-16 14:28:30.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/proc_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -382,7 +382,7 @@
  * of the /proc/<pid> subdirectories.
  */
 extern int proc_readdir(struct file *, void *, filldir_t);
-extern int proc_lookup(struct inode *, struct dentry *);
+extern struct dentry *proc_lookup(struct inode *, struct dentry *);
 
 struct openpromfs_dev {
  	struct openpromfs_dev *next;
diff -urN linux-2.2.7-pre3/include/linux/qnx4_fs.h linux-2.2.7-pre4/include/linux/qnx4_fs.h
--- linux-2.2.7-pre3/include/linux/qnx4_fs.h	1998-08-31 13:01:35.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/qnx4_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -95,7 +95,7 @@
 #define QNX4DEBUG(X) (void) 0
 #endif
 
-extern int qnx4_lookup(struct inode *dir, struct dentry *dentry);
+extern struct dentry *qnx4_lookup(struct inode *dir, struct dentry *dentry);
 extern unsigned long qnx4_count_free_inodes(struct super_block *sb);
 extern unsigned long qnx4_count_free_blocks(struct super_block *sb);
 
diff -urN linux-2.2.7-pre3/include/linux/sysctl.h linux-2.2.7-pre4/include/linux/sysctl.h
--- linux-2.2.7-pre3/include/linux/sysctl.h	1999-03-21 07:22:00.000000000 -0800
+++ linux-2.2.7-pre4/include/linux/sysctl.h	2003-08-15 15:05:52.000000000 -0700
@@ -56,9 +56,15 @@
 	CTL_PROC=4,		/* Process info */
 	CTL_FS=5,		/* Filesystems */
 	CTL_DEBUG=6,		/* Debugging */
-	CTL_DEV=7		/* Devices */
+	CTL_DEV=7,		/* Devices */
+	CTL_BUS=8		/* Buses */
 };
 
+/* CTL_BUS names: */
+enum
+{
+	BUS_ISA=1		/* ISA */
+};
 
 /* CTL_KERN names: */
 enum
@@ -133,9 +139,17 @@
 	NET_IPV6=12,
 	NET_X25=13,
 	NET_TR=14,
-	NET_DECNET=15
+	NET_DECNET=15,
+	NET_ECONET=16
 };
 
+/* /proc/sys/bus/isa */
+enum
+{
+	BUS_ISA_MEM_BASE=1,
+	BUS_ISA_PORT_BASE=2,
+	BUS_ISA_PORT_SHIFT=3
+};
 
 /* /proc/sys/net/core */
 enum
diff -urN linux-2.2.7-pre3/include/linux/sysv_fs.h linux-2.2.7-pre4/include/linux/sysv_fs.h
--- linux-2.2.7-pre3/include/linux/sysv_fs.h	1999-04-16 14:29:31.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/sysv_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -367,7 +367,7 @@
  * Function prototypes
  */
 
-extern int sysv_lookup(struct inode * dir, struct dentry * dentry);
+extern struct dentry *sysv_lookup(struct inode * dir, struct dentry * dentry);
 extern int sysv_create(struct inode * dir, struct dentry * dentry, int mode);
 extern int sysv_mkdir(struct inode * dir, struct dentry * dentry, int mode);
 extern int sysv_rmdir(struct inode * dir, struct dentry * dentry);
diff -urN linux-2.2.7-pre3/include/linux/ufs_fs.h linux-2.2.7-pre4/include/linux/ufs_fs.h
--- linux-2.2.7-pre3/include/linux/ufs_fs.h	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/ufs_fs.h	2003-08-15 15:05:52.000000000 -0700
@@ -540,7 +540,7 @@
 extern struct buffer_head * ufs_bread (struct inode *, unsigned, int, int *);
 
 /* namei.c */
-extern int ufs_lookup (struct inode *, struct dentry *);
+extern struct dentry *ufs_lookup (struct inode *, struct dentry *);
 extern int ufs_mkdir(struct inode *, struct dentry *, int);
 extern int ufs_rmdir (struct inode *, struct dentry *);
 extern int ufs_unlink (struct inode *, struct dentry *);
diff -urN linux-2.2.7-pre3/include/linux/umsdos_fs.p linux-2.2.7-pre4/include/linux/umsdos_fs.p
--- linux-2.2.7-pre3/include/linux/umsdos_fs.p	1999-04-12 10:03:45.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/umsdos_fs.p	2003-08-15 15:05:52.000000000 -0700
@@ -9,8 +9,8 @@
 char * umsdos_d_path(struct dentry *, char *, int);
 void umsdos_lookup_patch_new(struct dentry *, struct umsdos_info *);
 int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry);
-int umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo);
-int UMSDOS_lookup(struct inode *, struct dentry *);
+struct dentry *umsdos_lookup_x ( struct inode *dir, struct dentry *dentry, int nopseudo);
+struct dentry *UMSDOS_lookup(struct inode *, struct dentry *);
 struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int);
 struct dentry *umsdos_covered(struct dentry *, char *, int);
 
@@ -106,8 +106,8 @@
 		   struct dentry *new_dentry);
 
 /* rdir.c 22/03/95 03.31.42 */
-int umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo);
-int UMSDOS_rlookup (struct inode *dir, struct dentry *dentry);
+struct dentry *umsdos_rlookup_x (struct inode *dir, struct dentry *dentry, int nopseudo);
+struct dentry *UMSDOS_rlookup (struct inode *dir, struct dentry *dentry);
 
 /* symlink.c 23/01/95 03.38.30 */
 
diff -urN linux-2.2.7-pre3/include/linux/wireless.h linux-2.2.7-pre4/include/linux/wireless.h
--- linux-2.2.7-pre3/include/linux/wireless.h	1999-04-15 16:29:55.000000000 -0700
+++ linux-2.2.7-pre4/include/linux/wireless.h	2003-08-15 15:05:52.000000000 -0700
@@ -1,7 +1,7 @@
 /*
  * This file define a set of standard wireless extensions
  *
- * Version :	6	18.2.99
+ * Version :	7	23.4.99
  *
  * Authors :	Jean Tourrilhes - HPLB - <jt@hplb.hpl.hp.com>
  */
@@ -85,7 +85,11 @@
  *
  * V5 to V6
  * --------
- *	- 802.11 support
+ *	- 802.11 support (ESSID ioctls)
+ *
+ * V6 to V7
+ * --------
+ *	- define IW_ESSID_MAX_SIZE and IW_MAX_AP
  */
 
 /* -------------------------- IOCTL LIST -------------------------- */
@@ -123,6 +127,7 @@
 /* As the ESSID is a string up to 32 bytes long, it doesn't fit within the
  * 'iwreq' structure, so we need to use the 'data' member to point to a
  * string in user space, like it is done for RANGE...
+ * The "flags" member indicate if the ESSID is active or not.
  */
 
 /* ------------------------- IOCTL STUFF ------------------------- */
@@ -169,6 +174,13 @@
 /* Maximum of address that you may set with SPY */
 #define IW_MAX_SPY		8
 
+/* Maximum of address that you may get in the
+   list of access points in range */
+#define IW_MAX_AP		8
+
+/* Maximum size of the ESSID string */
+#define IW_ESSID_MAX_SIZE	32
+
 /****************************** TYPES ******************************/
 
 /* --------------------------- SUBTYPES --------------------------- */
@@ -278,7 +290,7 @@
 			caddr_t	pointer;	/* Pointer to the data
 						 * (in user space) */
 			__u16	length;		/* fields or byte size */
-			__u16	flags;		/* Unused */
+			__u16	flags;		/* Optional params */
 		}	data;
 	}	u;
 };
diff -urN linux-2.2.7-pre3/include/net/irda/discovery.h linux-2.2.7-pre4/include/net/irda/discovery.h
--- linux-2.2.7-pre3/include/net/irda/discovery.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/discovery.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr  6 16:53:53 1999
- * Modified at:   Tue Apr  6 20:44:35 1999
+ * Modified at:   Thu Apr 22 11:04:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -37,6 +37,7 @@
 #include <net/irda/irqueue.h>
 
 #define DISCOVERY_EXPIRE_TIMEOUT 6*HZ
+#define DISCOVERY_DEFAULT_SLOTS  0
 
 /*
  * The DISCOVERY structure is used for both discovery requests and responses
diff -urN linux-2.2.7-pre3/include/net/irda/ircomm_common.h linux-2.2.7-pre4/include/net/irda/ircomm_common.h
--- linux-2.2.7-pre3/include/net/irda/ircomm_common.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/ircomm_common.h	2003-08-15 15:05:52.000000000 -0700
@@ -28,8 +28,12 @@
 #include <net/irda/irmod.h> 
 
 typedef enum {
-	COMM_DISCOVERY,
         COMM_IDLE,
+
+	COMM_DISCOVERY_WAIT,
+	COMM_QUERYPARAM_WAIT,
+	COMM_QUERYLSAP_WAIT,
+
 	COMM_WAITI,
 	COMM_WAITR,
 	COMM_CONN,
@@ -53,6 +57,12 @@
 	IRCOMM_DATA_REQUEST,
 	LMP_DATA_INDICATION,
 	IRCOMM_CONTROL_REQUEST,
+	
+	DISCOVERY_INDICATION,
+	GOT_PARAMETERS,
+	GOT_LSAPSEL,
+	QUERYIAS_ERROR,
+
 } IRCOMM_EVENT;
 
 typedef enum {
@@ -172,6 +182,9 @@
 
  	__u32 daddr;        /* Device address of the peer device */ 
 	__u32 saddr;
+	__u32 skey;
+	__u32 ckey;
+	int                 queryias_lock;
 	int                 ias_type;
 	int disconnect_priority; /* P_NORMAL or P_HIGH. see irttp.h */
 	struct notify_t notify;     /* container of callbacks */
@@ -206,6 +219,7 @@
 	__u8 peer_port_type;
 
 	__u8 servicetype;    
+	__u8 peer_servicetype;    
 	__u8 data_format;   
 	__u8 peer_data_format;   
 	__u8 flow_ctrl;
@@ -241,8 +255,7 @@
 
 
 
-int  ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype); 
-void ircomm_connect_request(struct ircomm_cb *self);
+void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype);
 void ircomm_connect_response(struct ircomm_cb *self, struct sk_buff *userdata,
 			     __u32 maxsdusize);
 void ircomm_disconnect_request(struct ircomm_cb *self,
diff -urN linux-2.2.7-pre3/include/net/irda/irda_device.h linux-2.2.7-pre4/include/net/irda/irda_device.h
--- linux-2.2.7-pre3/include/net/irda/irda_device.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irda_device.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Haris Zukanovic <haris@stud.cs.uit.no>
  * Created at:    Tue Apr 14 12:41:42 1998
- * Modified at:   Wed Apr  7 17:17:16 1999
+ * Modified at:   Tue Apr 20 11:06:28 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Haris Zukanovic, <haris@stud.cs.uit.no>
@@ -36,15 +36,18 @@
 #include <net/irda/irda.h>
 #include <net/irda/qos.h>
 #include <net/irda/irqueue.h>
+#include <net/irda/irlap_frame.h>
 
 /* Some non-standard interface flags (should not conflict with any in if.h) */
-#define IFF_SIR 	0x01 /* Supports SIR speeds */
-#define IFF_MIR 	0x02 /* Supports MIR speeds */
-#define IFF_FIR 	0x04 /* Supports FIR speeds */
-#define IFF_PIO   	0x08 /* Supports PIO transfer of data */
-#define IFF_DMA		0x10 /* Supports DMA transfer of data */
-#define IFF_SHM         0x20 /* Supports shared memory data transfers */
-#define IFF_DONGLE      0x40 /* Interface has a dongle attached */
+#define IFF_SIR 	0x0001 /* Supports SIR speeds */
+#define IFF_MIR 	0x0002 /* Supports MIR speeds */
+#define IFF_FIR 	0x0004 /* Supports FIR speeds */
+#define IFF_VFIR        0x0008 /* Supports VFIR speeds */
+#define IFF_PIO   	0x0010 /* Supports PIO transfer of data */
+#define IFF_DMA		0x0020 /* Supports DMA transfer of data */
+#define IFF_SHM         0x0040 /* Supports shared memory data transfers */
+#define IFF_DONGLE      0x0080 /* Interface has a dongle attached */
+#define IFF_AIR         0x0100 /* Supports A(dvanced)IR standards */
 
 #define IO_XMIT 0x01
 #define IO_RECV 0x02
@@ -65,18 +68,17 @@
 	int dongle_id;        /* Dongle or transceiver currently used */
 };
 
-/* Buffer specific info */
+/* IO buffer specific info (inspired by struct sk_buff) */
 struct iobuff_t {
 	int state;            /* Receiving state (transmit state not used) */
 	int in_frame;         /* True if receiving frame */
 
-	__u8 *data;	      /* the buffer */
-	__u8 *head;	      /* start of data in buffer */
+	__u8 *head;	      /* start of buffer */
+	__u8 *data;	      /* start of data in buffer */
 	__u8 *tail;           /* end of data in buffer */
 
-	int offset;	      /* Usually data + offset = head */
-	int len;	      /* currently used bytes in buffer */
-	int truesize;	      /* total size of the data area */
+	int len;	      /* length of data */
+	int truesize;	      /* total size of buffer */
 	__u16 fcs;
 
 	int flags;            /* Allocation flags (GFP_KERNEL | GFP_DMA ) */
@@ -89,7 +91,7 @@
  * stuff from IrDA port implementations.
  */
 struct irda_device {
-	QUEUE q; /* Must be first */
+	QUEUE q;               /* Must be first */
 
         int  magic;	       /* Our magic bullet */
 	char name[16];         /* Name of device "irda0" */
@@ -109,18 +111,18 @@
 	struct iobuff_t tx_buff;
 	struct iobuff_t rx_buff;
 
-	int xbofs;
-	int media_busy;
 	/* spinlock_t lock; */ /* For serializing operations */
 	
 	/* Media busy stuff */
+	int media_busy;
 	struct timer_list media_busy_timer;
 
-	/* Driver specific implementation */
+	/* Callbacks for driver specific implementation */
         void (*change_speed)(struct irda_device *driver, int baud);
- 	int (*is_receiving)(struct irda_device *);     /* receiving? */
+ 	int  (*is_receiving)(struct irda_device *);    /* receiving? */
 	/* int (*is_tbusy)(struct irda_device *); */   /* transmitting? */
 	void (*wait_until_sent)(struct irda_device *);
+	void (*set_caddr)(struct irda_device *);      /* Set connection addr */
 };
 
 extern hashbin_t *irda_device;
@@ -143,8 +145,28 @@
 
 int irda_device_setup(struct device *dev);
 
-inline unsigned short irda_get_mtt(struct sk_buff *skb);
-
 void setup_dma(int channel, char *buffer, int count, int mode);
 
+/*
+ * Function irda_get_mtt (skb)
+ *
+ *    Utility function for getting the minimum turnaround time out of 
+ *    the skb, where it has been hidden in the cb field.
+ */
+inline static __u16 irda_get_mtt(struct sk_buff *skb)
+{
+	__u16 mtt;
+
+	if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC)
+		mtt = 10000;
+	else
+		mtt = ((struct irlap_skb_cb *)(skb->cb))->mtt;
+
+	ASSERT(mtt <= 10000, return 10000;);
+	
+	return mtt;
+}
+
 #endif
+
+
diff -urN linux-2.2.7-pre3/include/net/irda/irda.h linux-2.2.7-pre4/include/net/irda/irda.h
--- linux-2.2.7-pre3/include/net/irda/irda.h	1999-04-16 14:29:06.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irda.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Dec  9 21:13:12 1997
- * Modified at:   Tue Apr  6 20:31:08 1999
+ * Modified at:   Wed Apr 21 17:49:00 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -43,14 +43,15 @@
 #define ALIGN __attribute__((aligned))
 #define PACK __attribute__((packed))
 
-/* use 0 for production, 1 for verification, >2 for debug */
+
 #ifdef CONFIG_IRDA_DEBUG
 
 extern __u32 irda_debug;
 
-#define IRDA_DEBUG 0
+/* use 0 for production, 1 for verification, >2 for debug */
+#define IRDA_DEBUG_LEVEL 0
 
-#define DEBUG(n, args...) if (irda_debug >= (n)) printk( KERN_DEBUG args)
+#define DEBUG(n, args...) if (irda_debug >= (n)) printk(KERN_DEBUG args)
 #define ASSERT(expr, func) \
 if(!(expr)) { \
         printk( "Assertion failed! %s,%s,%s,line=%d\n",\
@@ -61,6 +62,12 @@
 #define ASSERT(expr, func)
 #endif /* CONFIG_IRDA_DEBUG */
 
+#define WARNING(args...) printk(KERN_WARNING args)
+#define MESSAGE(args...) printk(KERN_INFO args)
+#define ERROR(args...)   printk(KERN_ERR args)
+
+#define MSECS_TO_JIFFIES(ms) (ms*HZ/1000)
+
 /*
  *  Magic numbers used by Linux/IR. Random numbers which must be unique to 
  *  give the best protection
@@ -112,6 +119,8 @@
 
 	int nslots;           /* Number of slots to use for discovery */
 
+	int errno;
+
 	struct sock *sk;
 	struct wait_queue *ias_wait;       /* Wait for LM-IAS answer */
 
diff -urN linux-2.2.7-pre3/include/net/irda/iriap.h linux-2.2.7-pre4/include/net/irda/iriap.h
--- linux-2.2.7-pre3/include/net/irda/iriap.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/iriap.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Mon Mar 22 13:15:04 1999
+ * Modified at:   Wed Apr 21 16:37:21 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -51,9 +51,10 @@
 #define IAS_SUCCESS        0
 #define IAS_CLASS_UNKNOWN  1
 #define IAS_ATTRIB_UNKNOWN 2
+#define IAS_DISCONNECT     10
 
-typedef void (*CONFIRM_CALLBACK)( __u16 obj_id, struct ias_value *value,
-				  void *priv);
+typedef void (*CONFIRM_CALLBACK)(int result, __u16 obj_id, 
+				 struct ias_value *value, void *priv);
 
 struct iriap_cb {
 	QUEUE queue; /* Must be first */
diff -urN linux-2.2.7-pre3/include/net/irda/irkbd.h linux-2.2.7-pre4/include/net/irda/irkbd.h
--- linux-2.2.7-pre3/include/net/irda/irkbd.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irkbd.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,91 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irkbd.h
- * Version:       0.2
- * Description:   IrDA Keyboard/Mouse driver (Tekram IR-660)
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Mon Mar  1 00:24:19 1999
- * Modified at:   Thu Mar 11 14:54:00 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
- *      
- *     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.
- *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#ifndef IRKBD_H
-#define IRKBD_H
-
-/* Some commands */
-#define IRKBD_CMD_INIT_KBD   0xfe
-#define IRKBD_CMD_INIT_MOUSE 0xff
-#define IRKBD_CMD_ENABLE     0x41
-#define IRKBD_CMD_LED        0x31
-#define IRKBD_CMD_KDB_SPEED  0x33
-
-/* Some responses */
-#define IRKBD_RSP_KBDOK      0x11
-#define IRKBD_RSP_KBDERR     0x12
-#define IRKBD_RSP_MSOK       0x21
-#define IRKBD_RSP_MSERR      0x22
-#define IRKBD_RSP_LEDOK      0x31
-#define IRKBD_RSP_KBDSPEEDOK 0x33
-#define IRKBD_RSP_RSPN41     0x41
-
-#define IRKBD_RATE       2 /* Polling rate, should be 15 ms */
-#define IRKBD_TIMEOUT  100 /* 1000 ms */
-
-#define SUBFRAME_MASK     0xc0
-#define SUBFRAME_MOUSE    0x80
-#define SUBFRAME_KEYBOARD 0x40
-#define SUBFRAME_RESPONSE 0x00
-
-#define IRKBD_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER)
-
-#define IRKBD_BUF_SIZE 4096 /* Must be power of 2! */
-
-enum {
-	IRKBD_IDLE,       /* Not connected */
-	IRKBD_INIT_KBD,   /* Initializing keyboard */
-	IRKBD_INIT_MOUSE, /* Initializing mouse */
-	IRKBD_POLLING,    /* Polling device */
-};
-
-/* Main structure */
-struct irkbd_cb {
-	struct miscdevice dev;
-	char devname[9];    /* name of the registered device */
-	int state;
-
-	int count;          /* Open count */
-
-	__u32 saddr;        /* my local address */
-	__u32 daddr;        /* peer address */
-
-	struct tsap_cb *tsap;		
-	__u8 dtsap_sel;     /* remote TSAP address */
-	__u8 stsap_sel;     /* local TSAP address */
-
-	struct timer_list watchdog_timer;
-
-	LOCAL_FLOW tx_flow;
-	LOCAL_FLOW rx_flow;
-
-	__u8 scancodes[IRKBD_BUF_SIZE]; /* Buffer for mouse events */
-	int head;
-	int tail;
-
-	struct wait_queue *read_wait;
-	struct fasync_struct *async;
-};
-
-#endif /* IRKBD_H */
diff -urN linux-2.2.7-pre3/include/net/irda/irlan_client.h linux-2.2.7-pre4/include/net/irda/irlan_client.h
--- linux-2.2.7-pre3/include/net/irda/irlan_client.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irlan_client.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Feb 25 21:05:53 1999
+ * Modified at:   Thu Apr 22 14:13:34 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -30,6 +30,7 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 
+#include <net/irda/irias_object.h>
 #include <net/irda/irlan_event.h>
 
 void irlan_client_start_kick_timer(struct irlan_cb *self, int timeout);
@@ -38,7 +39,7 @@
 
 void irlan_client_open_ctrl_tsap( struct irlan_cb *self);
 
-void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb);
-void irlan_client_get_value_confirm( __u16 obj_id, struct ias_value *value, 
-				     void *priv);
+void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb);
+void irlan_client_get_value_confirm(int result, __u16 obj_id, 
+				    struct ias_value *value, void *priv);
 #endif
diff -urN linux-2.2.7-pre3/include/net/irda/irlan_common.h linux-2.2.7-pre4/include/net/irda/irlan_common.h
--- linux-2.2.7-pre3/include/net/irda/irlan_common.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irlan_common.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Tue Apr  6 16:19:41 1999
+ * Modified at:   Thu Apr 22 14:30:37 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -121,7 +121,6 @@
 	int broadcast_open;
 
 	struct timer_list kick_timer;
-	int start_new_provider;
 };
 
 /*
@@ -183,6 +182,10 @@
 
 struct irlan_cb *irlan_open(__u32 saddr, __u32 daddr, int netdev);
 void irlan_close(struct irlan_cb *self);
+void irlan_close_tsaps(struct irlan_cb *self);
+void irlan_mod_inc_use_count(void);
+void irlan_mod_dec_use_count(void);
+
 int  irlan_register_netdev(struct irlan_cb *self);
 void irlan_ias_register(struct irlan_cb *self, __u8 tsap_sel);
 void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout);
@@ -204,7 +207,7 @@
 int irlan_insert_array_param(struct sk_buff *skb, char *name, __u8 *value, 
 			     __u16 value_len);
 
-int irlan_get_param(__u8 *buf, char *name, char *value, __u16 *len);
+int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len);
 void print_ret_code(__u8 code);
 
 extern hashbin_t *irlan;
diff -urN linux-2.2.7-pre3/include/net/irda/irlan_eth.h linux-2.2.7-pre4/include/net/irda/irlan_eth.h
--- linux-2.2.7-pre3/include/net/irda/irlan_eth.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irlan_eth.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:36:58 1998
- * Modified at:   Mon Mar 22 12:57:11 1999
+ * Modified at:   Thu Apr 22 14:09:37 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -25,6 +25,9 @@
 #ifndef IRLAN_ETH_H
 #define IRLAN_ETH_H
 
+int  irlan_eth_init(struct device *dev);
+int  irlan_eth_open(struct device *dev);
+int  irlan_eth_close(struct device *dev);
 int  irlan_eth_receive(void *instance, void *sap, struct sk_buff *skb);
 int  irlan_eth_xmit(struct sk_buff *skb, struct device *dev);
 
diff -urN linux-2.2.7-pre3/include/net/irda/irlan_provider.h linux-2.2.7-pre4/include/net/irda/irlan_provider.h
--- linux-2.2.7-pre3/include/net/irda/irlan_provider.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irlan_provider.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Mon Mar  8 15:32:35 1999
+ * Modified at:   Thu Apr 22 14:29:16 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -46,12 +46,12 @@
 void irlan_provider_connect_response(struct irlan_cb *, struct tsap_cb *);
 
 int irlan_parse_open_data_cmd(struct irlan_cb *self, struct sk_buff *skb);
-int irlan_provider_extract_params(struct irlan_cb *self, int cmd,
-				  struct sk_buff *skb);
+int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
+				 struct sk_buff *skb);
 
 void irlan_provider_send_reply(struct irlan_cb *self, int command, 
 			       int ret_code);
-void irlan_provider_open_ctrl_tsap( struct irlan_cb *self);
+int irlan_provider_open_ctrl_tsap(struct irlan_cb *self);
 
 #endif
 
diff -urN linux-2.2.7-pre3/include/net/irda/irlap_frame.h linux-2.2.7-pre4/include/net/irda/irlap_frame.h
--- linux-2.2.7-pre3/include/net/irda/irlap_frame.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irlap_frame.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Fri Mar 26 14:10:53 1999
+ * Modified at:   Fri Apr 23 09:33:55 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -117,8 +117,6 @@
 	int vr;    /* next frame to receive */
 };
 
-__inline__ void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb);
-
 void irlap_send_discovery_xid_frame( struct irlap_cb *, int S, __u8 s, 
 				     __u8 command, discovery_t *discovery);
 void irlap_send_snrm_frame( struct irlap_cb *, struct qos_info *);
diff -urN linux-2.2.7-pre3/include/net/irda/irlap.h linux-2.2.7-pre4/include/net/irda/irlap.h
--- linux-2.2.7-pre3/include/net/irda/irlap.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irlap.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Mar 26 15:15:17 1999
+ * Modified at:   Fri Apr 23 09:51:15 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -219,12 +219,12 @@
 
 int  irlap_generate_rand_time_slot( int S, int s);
 void irlap_initiate_connection_state( struct irlap_cb *);
-void irlap_flush_all_queues( struct irlap_cb *);
-void irlap_change_speed( struct irlap_cb *, int);
-void irlap_wait_min_turn_around( struct irlap_cb *, struct qos_info *);
-
-void irlap_init_qos_capabilities( struct irlap_cb *, struct qos_info *);
-void irlap_apply_default_connection_parameters( struct irlap_cb *self);
-void irlap_apply_connection_parameters( struct irlap_cb *, struct qos_info *);
+void irlap_flush_all_queues(struct irlap_cb *);
+void irlap_change_speed(struct irlap_cb *, int);
+void irlap_wait_min_turn_around(struct irlap_cb *, struct qos_info *);
+
+void irlap_init_qos_capabilities(struct irlap_cb *, struct qos_info *);
+void irlap_apply_default_connection_parameters(struct irlap_cb *self);
+void irlap_apply_connection_parameters(struct irlap_cb *, struct qos_info *);
 
 #endif
diff -urN linux-2.2.7-pre3/include/net/irda/irlmp.h linux-2.2.7-pre4/include/net/irda/irlmp.h
--- linux-2.2.7-pre3/include/net/irda/irlmp.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irlmp.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Tue Apr  6 20:05:14 1999
+ * Modified at:   Fri Apr 23 09:15:07 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -202,12 +202,12 @@
 void irlmp_register_link(struct irlap_cb *, __u32 saddr, struct notify_t *);
 void irlmp_unregister_link(__u32 saddr);
 
-int  irlmp_connect_request( struct lsap_cb *, __u8 dlsap_sel, 
-			    __u32 saddr, __u32 daddr,
-			    struct qos_info *, struct sk_buff *);
-void irlmp_connect_indication( struct lsap_cb *self, struct sk_buff *skb);
-void irlmp_connect_response( struct lsap_cb *, struct sk_buff *);
-void irlmp_connect_confirm( struct lsap_cb *, struct sk_buff *);
+int  irlmp_connect_request(struct lsap_cb *, __u8 dlsap_sel, 
+			   __u32 saddr, __u32 daddr,
+			   struct qos_info *, struct sk_buff *);
+void irlmp_connect_indication(struct lsap_cb *self, struct sk_buff *skb);
+void irlmp_connect_response(struct lsap_cb *, struct sk_buff *);
+void irlmp_connect_confirm(struct lsap_cb *, struct sk_buff *);
 struct lsap_cb *irlmp_dup(struct lsap_cb *self, void *instance);
 
 void irlmp_disconnect_indication(struct lsap_cb *self, LM_REASON reason, 
@@ -219,17 +219,17 @@
 void irlmp_do_discovery(int nslots);
 discovery_t *irlmp_get_discovery_response(void);
 
-void irlmp_data_request( struct lsap_cb *, struct sk_buff *);
-void irlmp_udata_request( struct lsap_cb *, struct sk_buff *);
-void irlmp_data_indication( struct lsap_cb *, struct sk_buff *);
-void irlmp_udata_indication( struct lsap_cb *, struct sk_buff *);
+void irlmp_data_request(struct lsap_cb *, struct sk_buff *);
+inline void irlmp_udata_request(struct lsap_cb *, struct sk_buff *);
+inline void irlmp_data_indication(struct lsap_cb *, struct sk_buff *);
+inline void irlmp_udata_indication(struct lsap_cb *, struct sk_buff *);
 
 void irlmp_status_request(void);
-void irlmp_status_indication( LINK_STATUS link, LOCK_STATUS lock);
+void irlmp_status_indication(LINK_STATUS link, LOCK_STATUS lock);
 
-int  irlmp_slsap_inuse( __u8 slsap);
+int  irlmp_slsap_inuse(__u8 slsap);
 __u8 irlmp_find_free_slsap(void);
-LM_REASON irlmp_convert_lap_reason( LAP_REASON);
+LM_REASON irlmp_convert_lap_reason(LAP_REASON);
 
 __u32 irlmp_get_saddr(struct lsap_cb *self);
 __u32 irlmp_get_daddr(struct lsap_cb *self);
diff -urN linux-2.2.7-pre3/include/net/irda/irlpt_cli.h linux-2.2.7-pre4/include/net/irda/irlpt_cli.h
--- linux-2.2.7-pre3/include/net/irda/irlpt_cli.h	1999-03-07 15:26:43.000000000 -0800
+++ linux-2.2.7-pre4/include/net/irda/irlpt_cli.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Feb 21 18:54:38 1998
- * Modified at:   Mon Jan 11 15:58:16 1999
+ * Modified at:   Wed Apr 21 16:46:26 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998, Thomas Davis, <ratbert@radiks.net>
@@ -34,7 +34,7 @@
  * if it's static, it doesn't go in here.
  */
 
-void irlpt_client_get_value_confirm(__u16 obj_id, 
+void irlpt_client_get_value_confirm(int result, __u16 obj_id, 
 				    struct ias_value *value, 
 				    void *priv);
 void irlpt_client_connect_indication( void *instance, 
diff -urN linux-2.2.7-pre3/include/net/irda/irmod.h linux-2.2.7-pre4/include/net/irda/irmod.h
--- linux-2.2.7-pre3/include/net/irda/irmod.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irmod.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:58:52 1997
- * Modified at:   Tue Mar 16 22:27:41 1999
+ * Modified at:   Fri Apr  9 11:13:39 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  *
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -101,7 +101,22 @@
 int irmod_init_module(void);
 void irmod_cleanup_module(void);
 
-inline int irda_lock(int *lock);
+/*
+ * Function irda_lock (lock)
+ *
+ *    Lock variable. Returns false if the lock is already set.
+ *    
+ */
+static inline int irda_lock(int *lock) 
+{
+	if (test_and_set_bit( 0, (void *) lock))  {
+		DEBUG(3, __FUNCTION__ 
+		      "(), Trying to lock, already locked variable!\n");
+		return FALSE;
+        }  
+	return TRUE;
+}
+
 inline int irda_unlock(int *lock);
 
 void irda_notify_init(struct notify_t *notify);
diff -urN linux-2.2.7-pre3/include/net/irda/irobex.h linux-2.2.7-pre4/include/net/irda/irobex.h
--- linux-2.2.7-pre3/include/net/irda/irobex.h	1999-04-15 05:42:41.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irobex.h	1969-12-31 16:00:00.000000000 -0800
@@ -1,114 +0,0 @@
-/*********************************************************************
- *                
- * Filename:      irobex.h
- * Version:       0.8
- * Description:   
- * Status:        Experimental.
- * Author:        Dag Brattli <dagb@cs.uit.no>
- * Created at:    Sat Jul  4 22:43:57 1998
- * Modified at:   Thu Mar 11 16:11:54 1999
- * Modified by:   Dag Brattli <dagb@cs.uit.no>
- * 
- *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
- *      
- *     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.
- *  
- *     Neither Dag Brattli nor University of Tromsø admit liability nor
- *     provide warranty for any of this software. This material is 
- *     provided "AS-IS" and at no charge.
- *     
- ********************************************************************/
-
-#ifndef IROBEX_H
-#define IROBEX_H
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/skbuff.h>
-#include <linux/miscdevice.h>
-
-#include <net/irda/timer.h>
-#include <net/irda/qos.h>
-#include <net/irda/irmod.h>
-
-#define LOW_THRESHOLD      4
-#define HIGH_THRESHOLD     8
-#define IROBEX_MAX_QUEUE  12
-
-/* Small structure to be used by the IOCTL call */
-struct irobex_ioc_t {
-     __u32 daddr;
-};
-
-#define IROBEX_IOC_MAGIC 'k'
-
-#define IROBEX_IOCSCONNECT    _IOW(IROBEX_IOC_MAGIC, 1, 4)
-#define IROBEX_IOCSDISCONNECT _IOW(IROBEX_IOC_MAGIC, 2, 4)
-#define IROBEX_IOC_MAXNR 2
-
-#define IROBEX_MAX_HEADER (TTP_HEADER+LMP_HEADER+LAP_HEADER)
-
-typedef enum {
-	OBEX_IDLE,       /* Doing nothing */
-	OBEX_DISCOVER,   /* Trying to discovery remote device */
-	OBEX_QUERY,      /* Querying remote LM-IAS */
-	OBEX_CONN,       /* Trying to connect to remote device */
-	OBEX_DATA,       /* Data transfer ready */
-} OBEX_STATE;
-
-struct irobex_cb {
-	QUEUE queue;        /* Must be first! */
-
-        int magic;          /* magic used to detect corruption of the struct */
-
-	OBEX_STATE state;   /* Current state */
-
-	__u32 saddr;        /* my local address */
-	__u32 daddr;        /* peer address */
-	unsigned long time_discovered;
-
-	__u32 ckey;           /* IrLMP client handle */
-	__u32 skey;           /* IrLMP service handle */
-
-        char devname[9];    /* name of the registered device */
-	struct tsap_cb *tsap;
-	int eof;
-
-	__u8 dtsap_sel;         /* remote TSAP address */
-	__u8 stsap_sel;         /* local TSAP address */
-
-	int irlap_data_size;
-
-	struct miscdevice dev;
-
-	int count;                /* open count */
-
-	struct sk_buff_head rx_queue; /* Receive queue */
-
-	struct wait_queue *read_wait;
-	struct wait_queue *write_wait;
-
-	struct fasync_struct *async;
-
-	struct timer_list watchdog_timer;
-
-	LOCAL_FLOW tx_flow;
-	LOCAL_FLOW rx_flow;
-};
-
-int irobex_init(void);
-
-void irobex_watchdog_timer_expired( unsigned long data);
-
-inline void irobex_start_watchdog_timer( struct irobex_cb *self, int timeout) 
-{
-	irda_start_timer( &self->watchdog_timer, timeout, (unsigned long) self,
-			  irobex_watchdog_timer_expired);
-}
-
-extern struct irobex_cb *irobex;
-
-#endif
diff -urN linux-2.2.7-pre3/include/net/irda/irttp.h linux-2.2.7-pre4/include/net/irda/irttp.h
--- linux-2.2.7-pre3/include/net/irda/irttp.h	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/include/net/irda/irttp.h	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Mon Mar 22 13:17:30 1999
+ * Modified at:   Sat Apr 10 10:19:56 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -93,7 +93,7 @@
 	__u32 rx_max_sdu_size; /* Max receive user data size */
 
 	int tx_sdu_busy;       /* TxSdu.busy */
-	int tx_max_sdu_size;   /* Max transmit user data size */
+	__u32 tx_max_sdu_size; /* Max transmit user data size */
 
 	int close_pend;        /* Close, but disconnect_pend */
 	int disconnect_pend;   /* Disconnect, but still data to send */
diff -urN linux-2.2.7-pre3/init/main.c linux-2.2.7-pre4/init/main.c
--- linux-2.2.7-pre3/init/main.c	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/init/main.c	2003-08-15 15:05:52.000000000 -0700
@@ -184,6 +184,7 @@
 extern void u14_34f_setup(char *str, int *ints);
 extern void fdomain_setup(char *str, int *ints);
 extern void ibmmca_scsi_setup(char *str, int *ints);
+extern void fd_mcs_setup(char *str, int *ints);
 extern void in2000_setup(char *str, int *ints);
 extern void NCR53c406a_setup(char *str, int *ints);
 extern void sym53c416_setup(char *str, int *ints);
@@ -709,6 +710,9 @@
 #ifdef CONFIG_SCSI_IBMMCA
         { "ibmmcascsi=", ibmmca_scsi_setup },
 #endif
+#ifdef CONFIG_SCSI_FD_MCS
+	{ "fd_mcs=", fd_mcs_setup },
+#endif
 #if defined(CONFIG_SCSI_DC390T) && ! defined(CONFIG_SCSI_DC390T_NOGENSUPP)
         { "tmscsim=", dc390_setup },
 #endif
diff -urN linux-2.2.7-pre3/MAINTAINERS linux-2.2.7-pre4/MAINTAINERS
--- linux-2.2.7-pre3/MAINTAINERS	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/MAINTAINERS	2003-08-15 15:05:52.000000000 -0700
@@ -650,6 +650,11 @@
 W:	http://www.torque.net/sg
 S:	Maintained
 
+SCSI GENERIC
+L:	linux-scsi@vger.rutgers.edu
+M:	douglas.gilbert@rbcds.com
+S:	Maintained
+
 SCSI SUBSYSTEM
 L:	linux-scsi@vger.rutgers.edu
 S:	Unmaintained
@@ -771,7 +776,7 @@
 L:	linux-kernel@vger.rutgers.edu
 S:	Maintained
 
-USB HUB DRIVER
+USB HUB AND UHCI DRIVERS
 P:	Johannes Erdfelt
 M:	jerdfelt@sventech.com
 L:	linux-usb@peloncho.fis.ucm.es
@@ -798,9 +803,9 @@
 W:	http://roadrunner.swansea.linux.org.uk/v4l.shtml
 S:	Maintained
 
-WAN ROUTER AND SANGOMA WANPIPE DRIVERS (X.25, FRAME RELAY, PPP)
-P:     Gene Kozin
-M:     genek@compuserve.com
+WAN ROUTER & SANGOMA WANPIPE DRIVERS & API (X.25, FRAME RELAY, PPP, CISCO HDLC)
+P:     Jaspreet Singh
+M:     jaspreet@sangoma.com
 M:     dm@sangoma.com
 W:     http://www.sangoma.com
 S:     Supported
diff -urN linux-2.2.7-pre3/Makefile linux-2.2.7-pre4/Makefile
--- linux-2.2.7-pre3/Makefile	2003-08-15 15:05:52.000000000 -0700
+++ linux-2.2.7-pre4/Makefile	2003-08-15 15:05:52.000000000 -0700
@@ -175,7 +175,7 @@
 endif
 
 ifeq ($(CONFIG_USB),y)
-DRIVERS := $(DRIVERS) drivers/uusbd/usb.a
+DRIVERS := $(DRIVERS) drivers/usb/usb.a
 endif
 
 ifeq ($(CONFIG_I2O),y)
diff -urN linux-2.2.7-pre3/net/802/tr.c linux-2.2.7-pre4/net/802/tr.c
--- linux-2.2.7-pre3/net/802/tr.c	1998-12-16 13:35:50.000000000 -0800
+++ linux-2.2.7-pre4/net/802/tr.c	2003-08-15 15:05:52.000000000 -0700
@@ -30,7 +30,6 @@
 #include <linux/trdevice.h>
 #include <linux/skbuff.h>
 #include <linux/errno.h>
-#include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/net.h>
 #include <linux/proc_fs.h>
@@ -68,6 +67,8 @@
  
 rif_cache rif_table[RIF_TABLE_SIZE]={ NULL, };
 
+static spinlock_t rif_lock = SPIN_LOCK_UNLOCKED;
+
 #define RIF_TIMEOUT 60*10*HZ
 #define RIF_CHECK_INTERVAL 60*HZ
 
@@ -230,6 +231,9 @@
 	unsigned int hash;
 	rif_cache entry;
 	unsigned char *olddata;
+	unsigned long flags;
+	
+	spin_lock_irqsave(&rif_lock, flags);
 
 	/*
 	 *	Broadcasts are single route as stated in RFC 1042 
@@ -298,6 +302,8 @@
 	else 
 		slack = 18 - ((ntohs(trh->rcf) & TR_RCF_LEN_MASK)>>8);
 	olddata = skb->data;
+	spin_unlock_irqrestore(&rif_lock, flags);
+
 	skb_pull(skb, slack);
 	memmove(skb->data, olddata, sizeof(struct trh_hdr) - slack);
 }
@@ -312,7 +318,11 @@
 	int i;
 	unsigned int hash, rii_p = 0;
 	rif_cache entry;
+	unsigned long flags;
+
 
+	spin_lock_irqsave(&rif_lock, flags);
+	
 	/*
 	 *	Firstly see if the entry exists
 	 */
@@ -350,6 +360,7 @@
 		if(!entry) 
 		{
 			printk(KERN_DEBUG "tr.c: Couldn't malloc rif cache entry !\n");
+			spin_unlock_irqrestore(&rif_lock, flags);
 			return;
 		}
 
@@ -391,6 +402,7 @@
 		    }                                         
            	entry->last_used=jiffies;               
 	}
+	spin_unlock_irqrestore(&rif_lock, flags);
 }
 
 /*
@@ -402,9 +414,8 @@
 	int i;
 	unsigned long now=jiffies,flags;
 
-	save_flags(flags);
-	cli();
-
+	spin_lock_irqsave(&rif_lock, flags);
+	
 	for(i=0; i < RIF_TABLE_SIZE;i++) 
 	{
 		rif_cache entry, *pentry=rif_table+i;	
@@ -422,7 +433,8 @@
 				pentry=&entry->next;
 		}
 	}
-	restore_flags(flags);
+	
+	spin_unlock_irqrestore(&rif_lock, flags);
 
 	/*
 	 *	Reset the timer
diff -urN linux-2.2.7-pre3/net/irda/af_irda.c linux-2.2.7-pre4/net/irda/af_irda.c
--- linux-2.2.7-pre3/net/irda/af_irda.c	1999-04-16 08:20:23.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/af_irda.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 31 10:12:43 1998
- * Modified at:   Wed Apr  7 17:32:27 1999
+ * Modified at:   Thu Apr 22 12:08:04 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       af_netroom.c, af_ax25.c, af_rose.c, af_x25.c etc.
  * 
@@ -39,6 +39,7 @@
 #include <net/irda/iriap.h>
 #include <net/irda/irias_object.h>
 #include <net/irda/irttp.h>
+#include <net/irda/discovery.h>
 
 extern int  irda_init(void);
 extern void irda_cleanup(void);
@@ -237,8 +238,8 @@
  *    Got answer from remote LM-IAS
  *
  */
-static void irda_get_value_confirm(__u16 obj_id, struct ias_value *value, 
-				   void *priv)
+static void irda_get_value_confirm(int result, __u16 obj_id, 
+				   struct ias_value *value, void *priv)
 {
 	struct irda_sock *self;
 	
@@ -251,11 +252,14 @@
 		return;
 
 	/* Check if request succeeded */
-	if (!value) {
+	if (result != IAS_SUCCESS) {
 		DEBUG(0, __FUNCTION__ "(), IAS query failed!\n");
 
+		self->errno = result;
+
 		/* Wake up any processes waiting for result */
 		wake_up_interruptible(&self->ias_wait);
+
 		return;
 	}
 
@@ -673,7 +677,7 @@
 	self->mask = 0xffff;
 	self->rx_flow = self->tx_flow = FLOW_START;
 	self->max_sdu_size_rx = SAR_DISABLE; /* Default value */
-	self->nslots = 6; /* Default for now */
+	self->nslots = DISCOVERY_DEFAULT_SLOTS;
 
 	/* Notify that we are using the irda module, so nobody removes it */
 	irda_mod_inc_use_count();
@@ -857,6 +861,12 @@
 	return copied;
 }
 
+/*
+ * Function irda_shutdown (sk, how)
+ *
+ *    
+ *
+ */
 static int irda_shutdown( struct socket *sk, int how)
 {
 	DEBUG( 0, __FUNCTION__ "()\n");
@@ -866,6 +876,12 @@
 }
 
 
+/*
+ * Function irda_poll (file, sock, wait)
+ *
+ *    
+ *
+ */
 unsigned int irda_poll(struct file *file, struct socket *sock, 
 		       struct poll_table_struct *wait)
 {
diff -urN linux-2.2.7-pre3/net/irda/discovery.c linux-2.2.7-pre4/net/irda/discovery.c
--- linux-2.2.7-pre3/net/irda/discovery.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/discovery.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Apr  6 15:33:50 1999
- * Modified at:   Tue Apr  6 20:26:46 1999
+ * Modified at:   Sun Apr 11 00:41:58 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1999 Dag Brattli, All Rights Reserved.
@@ -46,7 +46,7 @@
 {
 	discovery_t *old;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
 	/* Check if we have discovered this device before */
 	old = hashbin_remove(cachelog, discovery->daddr, NULL);
@@ -67,7 +67,7 @@
 {
 	discovery_t *discovery;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
 	/*
 	 *  If log is missing this means that IrLAP was unable to perform the
@@ -100,7 +100,7 @@
 {
 	discovery_t *discovery, *curr;
 
-	DEBUG(3, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
 	discovery = (discovery_t *) hashbin_get_first(log);
 	while (discovery != NULL) {
diff -urN linux-2.2.7-pre3/net/irda/ircomm/ircomm_common.c linux-2.2.7-pre4/net/irda/ircomm/ircomm_common.c
--- linux-2.2.7-pre3/net/irda/ircomm/ircomm_common.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/ircomm/ircomm_common.c	2003-08-15 15:05:52.000000000 -0700
@@ -41,13 +41,21 @@
 
 #include <net/irda/ircomm_common.h>
 
-static char *revision_date = "Tue Mar  2 02:03:58 1999";
+static char *revision_date = "Sun Apr 18 00:40:19 1999";
 
 
-static void ircomm_state_discovery(struct ircomm_cb *self,
-				   IRCOMM_EVENT event, struct sk_buff *skb );
 static void ircomm_state_idle( struct ircomm_cb *self, IRCOMM_EVENT event, 
 			       struct sk_buff *skb );
+
+static void ircomm_state_discoverywait( struct ircomm_cb *self, IRCOMM_EVENT event, 
+					struct sk_buff *skb );
+
+static void ircomm_state_queryparamwait( struct ircomm_cb *self, IRCOMM_EVENT event, 
+					 struct sk_buff *skb );
+
+static void ircomm_state_querylsapwait( struct ircomm_cb *self, IRCOMM_EVENT event, 
+					struct sk_buff *skb );
+
 static void ircomm_state_waiti( struct ircomm_cb *self, IRCOMM_EVENT event, 
 				struct sk_buff *skb );
 static void ircomm_state_waitr( struct ircomm_cb *self, IRCOMM_EVENT event, 
@@ -63,13 +71,14 @@
 static int ircomm_proc_read(char *buf, char **start, off_t offset,
 			    int len, int unused);
 
+static void start_discovering(struct ircomm_cb *self);
 static void query_lsapsel(struct ircomm_cb * self);
-static void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value, 
-				     void *priv);
+static void query_parameters(struct ircomm_cb *self);
+static void queryias_done(struct ircomm_cb *self);
+static void ircomm_getvalue_confirm(int result, __u16 obj_id, 
+				    struct ias_value *value, void *priv);
 
 
-static __u32 ckey;
-static __u32 skey;
 struct ircomm_cb *discovering_instance;
 
 /*
@@ -86,8 +95,12 @@
 
 
 static char *ircommstate[] = {
-	"DISCOVERY",
 	"IDLE",
+
+	"DISCOVERY_WAIT",
+	"QUERYPARAM_WAIT",
+	"QUERYLSAP_WAIT",
+
 	"WAITI",
 	"WAITR",
 	"CONN",
@@ -126,6 +139,11 @@
 	"IRCOMM_DATA_REQUEST",
 	"LMP_DATA_INDICATION",
 	"IRCOMM_CONTROL_REQUEST",
+
+	"DISCOVERY_INDICATION",
+	"GOT_PARAMETERS",
+	"GOT_LSAPSEL",
+	"QUERYIAS_ERROR",
 };
 
 #ifdef CONFIG_PROC_FS
@@ -141,8 +159,12 @@
 static void (*state[])( struct ircomm_cb *self, IRCOMM_EVENT event,
 			struct sk_buff *skb) = 
 {
-	ircomm_state_discovery,
 	ircomm_state_idle,
+
+	ircomm_state_discoverywait,
+	ircomm_state_queryparamwait,
+	ircomm_state_querylsapwait,
+
 	ircomm_state_waiti,
 	ircomm_state_waitr,
 	ircomm_state_conn,
@@ -376,6 +398,146 @@
 
 }
 
+
+/*
+ * ircomm_discovery_indication()
+ *    Remote device is discovered, try query the remote IAS to see which
+ *    device it is, and which services it has.
+ */
+
+static void ircomm_discovery_indication(discovery_t *discovery)
+{
+	struct ircomm_cb *self;
+
+	self = discovering_instance;
+	if(self == NULL)
+		return;
+	ASSERT(self->magic == IRCOMM_MAGIC, return;);
+
+	self->daddr = discovery->daddr;
+	self->saddr = discovery->saddr;
+
+	DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr);
+
+	ircomm_do_event(self, DISCOVERY_INDICATION, NULL);
+	return;
+}
+
+/*
+ * ircomm_getvalue_confirm()
+ * handler for iriap_getvaluebyclass_request() 
+ */
+static void ircomm_getvalue_confirm(int result, __u16 obj_id, 
+				    struct ias_value *value, void *priv)
+{
+	struct ircomm_cb *self = (struct ircomm_cb *) priv;
+	struct sk_buff *skb= NULL;
+	__u8 *frame;
+	__u8 servicetype = 0 ;
+	ASSERT( self != NULL, return;);
+	ASSERT( self->magic == IRCOMM_MAGIC, return;);
+
+	/* Check if request succeeded */
+	if (result != IAS_SUCCESS) {
+		DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
+		ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+		return;
+	}
+
+	DEBUG(4, __FUNCTION__"():type(%d)\n", value->type);
+
+	self->ias_type = value->type;
+	switch(value->type){
+ 	case IAS_OCT_SEQ:
+		
+		DEBUG(4, __FUNCTION__"():got octet sequence:\n");
+#if 0
+		{
+			int i;
+			for ( i=0;i<value->len;i++)
+				printk("%02x",
+				       (__u8)(*(value->t.oct_seq + i)));
+			printk("\n");
+		}
+#endif
+		skb = dev_alloc_skb((value->len) + 2);
+		ASSERT(skb != NULL, ircomm_do_event(self, QUERYIAS_ERROR, NULL);return;);
+		frame = skb_put(skb,2);
+		/* MSB first */
+		frame[0] = ( value->len >> 8 ) & 0xff;
+		frame[1] = value->len & 0xff;
+		
+		frame = skb_put(skb,value->len);
+		memcpy(frame, value->t.oct_seq, value->len);
+		ircomm_parse_tuples(self, skb, IAS_PARAM);
+		kfree_skb(skb);
+
+		/* 
+		 * check if servicetype we want is available 
+		 */
+
+		DEBUG(0,__FUNCTION__"():peer capability is:\n");
+		DEBUG(0,"3wire raw: %s\n",
+		      ((self->peer_servicetype & THREE_WIRE_RAW) ? "yes":"no"));
+		DEBUG(0,"3wire    : %s\n",
+		      ((self->peer_servicetype & THREE_WIRE) ? "yes":"no"));
+		DEBUG(0,"9wire    : %s\n",
+		      ((self->peer_servicetype & NINE_WIRE) ? "yes":"no"));
+		DEBUG(0,"IEEE1284 : %s\n",
+		      ((self->peer_servicetype & CENTRONICS) ? "yes":"no"));
+
+		self->servicetype &= self->peer_servicetype;
+		if(!(self->servicetype)){
+			DEBUG(0,__FUNCTION__"(): servicetype mismatch!\n");
+			ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+			break;
+		}
+
+		/*
+		 * then choose better one 
+		 */
+		if(self->servicetype & THREE_WIRE_RAW)
+			servicetype = THREE_WIRE_RAW;
+		if(self->servicetype & THREE_WIRE)
+			servicetype = THREE_WIRE;
+		if(self->servicetype & NINE_WIRE)
+			servicetype = NINE_WIRE;
+		if(self->servicetype & CENTRONICS)
+			servicetype = CENTRONICS;
+
+		self->servicetype = servicetype;
+
+		/* enter next state */
+		ircomm_do_event(self, GOT_PARAMETERS, NULL);
+		break;
+
+	case IAS_INTEGER:
+		/* LsapSel seems to be sent to me */	
+		DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer);
+
+		if ( value->t.integer == -1){
+			DEBUG( 0, __FUNCTION__"():invalid value!\n");
+			ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+			return;
+		}
+		self->dlsap = value->t.integer;
+		ircomm_do_event(self, GOT_LSAPSEL, NULL);
+		break;
+
+	case IAS_MISSING:
+		DEBUG( 0, __FUNCTION__":got IAS_MISSING\n");
+		ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+		break;
+   
+	default:
+		DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n");
+		ircomm_do_event(self, QUERYIAS_ERROR, NULL);
+		break;
+	}
+}
+
+
+
 /* 
  * ----------------------------------------------------------------------
  * Impl. of actions (descrived in section 7.4 of the reference)
@@ -583,19 +745,6 @@
 }
 
 
-/* 
- * we currently need dummy (discovering) state for debugging,
- * which state is not defined in the reference.
- */
-
-static void ircomm_state_discovery( struct ircomm_cb *self,
-				    IRCOMM_EVENT event, struct sk_buff *skb )
-{
-	printk(KERN_ERR __FUNCTION__"():why call me? something is wrong..\n");
-	if(skb)
-		dev_kfree_skb( skb);
-}
-
 
 /*
  * ircomm_state_idle
@@ -607,8 +756,11 @@
 	switch(event){
 	case IRCOMM_CONNECT_REQUEST:
 
-		ircomm_next_state(self, COMM_WAITI);
-		issue_connect_request( self, skb );
+		/* ircomm_next_state(self, COMM_WAITI); */
+		/* issue_connect_request( self, skb ); */
+
+		ircomm_next_state(self, COMM_DISCOVERY_WAIT);
+		start_discovering(self);
 		break;
 		
 	case TTP_CONNECT_INDICATION:
@@ -631,6 +783,121 @@
 }
 
 /*
+ * ircomm_state_discoverywait
+ */
+static void ircomm_state_discoverywait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+				       struct sk_buff *skb )
+{
+	switch(event){
+
+	case TTP_CONNECT_INDICATION:
+
+		ircomm_next_state(self, COMM_WAITR);
+		queryias_done(self);
+		connect_indication( self, self->qos, skb);
+		break;
+
+	case DISCOVERY_INDICATION:
+		ircomm_next_state(self, COMM_QUERYPARAM_WAIT);
+		query_parameters(self);
+		break;
+
+	case IRCOMM_DISCONNECT_REQUEST:
+		ircomm_next_state(self, COMM_IDLE);
+		queryias_done(self);
+		break;
+
+	case QUERYIAS_ERROR:
+		ircomm_next_state(self, COMM_IDLE);
+		disconnect_indication(self, NULL);
+		queryias_done(self);
+		break;
+
+	default:
+		DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+		      event, ircommevent[event]);
+	}
+}
+
+/*
+ * ircomm_state_queryparamwait
+ */
+
+static void ircomm_state_queryparamwait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+					struct sk_buff *skb )
+{
+	switch(event){
+
+	case TTP_CONNECT_INDICATION:
+
+		ircomm_next_state(self, COMM_WAITR);
+		connect_indication( self, self->qos, skb);
+		break;
+
+	case GOT_PARAMETERS:
+		
+		ircomm_next_state(self, COMM_QUERYLSAP_WAIT);
+		query_lsapsel( self );
+		break;
+
+	case IRCOMM_DISCONNECT_REQUEST:
+		ircomm_next_state(self, COMM_IDLE);
+		queryias_done(self);
+		break;
+
+	case QUERYIAS_ERROR:
+		ircomm_next_state(self, COMM_IDLE);
+		disconnect_indication(self, NULL);
+		queryias_done(self);
+		break;
+
+	default:
+		DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+		      event, ircommevent[event]);
+	}
+}
+
+/*
+ * ircomm_state_querylsapwait
+ */
+
+static void ircomm_state_querylsapwait(struct ircomm_cb *self, IRCOMM_EVENT event, 
+				       struct sk_buff *skb )
+{
+	switch(event){
+
+	case TTP_CONNECT_INDICATION:
+
+		ircomm_next_state(self, COMM_WAITR);
+		connect_indication( self, self->qos, skb);
+		break;
+
+	case GOT_LSAPSEL:
+		
+		ircomm_next_state(self, COMM_WAITI);
+		queryias_done(self);
+		issue_connect_request( self, skb );
+		break;
+
+	case IRCOMM_DISCONNECT_REQUEST:
+		ircomm_next_state(self, COMM_IDLE);
+		queryias_done(self);
+		break;
+
+	case QUERYIAS_ERROR:
+		ircomm_next_state(self, COMM_IDLE);
+		disconnect_indication(self, NULL);
+		queryias_done(self);
+		break;
+
+
+	default:
+		DEBUG(0,__FUNCTION__"():unknown event =%d(%s)\n",
+		      event, ircommevent[event]);
+	}
+}
+
+/*
  * ircomm_state_waiti
  */
 
@@ -688,6 +955,7 @@
 	case IRCOMM_DISCONNECT_REQUEST:
 		ircomm_next_state(self, COMM_IDLE);
 		issue_disconnect_request(self, skb);
+		queryias_done(self);
 		break;
 
 	case TTP_DISCONNECT_INDICATION:
@@ -695,6 +963,19 @@
 		disconnect_indication(self, skb);
 		break;
 
+	case DISCOVERY_INDICATION:
+		DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
+		queryias_done(self);
+		break;
+	case GOT_PARAMETERS:
+		DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
+		queryias_done(self);
+		break;
+	case GOT_LSAPSEL:
+		DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
+		queryias_done(self);
+		break;
+
 /* 	case LMP_DISCONNECT_INDICATION: */
 /* 		disconnect_indication();		 */
 /* 		ircomm_next_state(self, COMM_IDLE);		 */
@@ -732,11 +1013,26 @@
 	case IRCOMM_DISCONNECT_REQUEST:
 		ircomm_next_state(self, COMM_IDLE);
 		issue_disconnect_request(self, skb);
+		queryias_done(self);
 		break;
 /* 	case LM_DISCONNECT_INDICATION: */
 /* 		disconnect_indication(); */
 /* 		ircomm_next_state(self, COMM_IDLE); */
 /* 		break; */
+
+	case DISCOVERY_INDICATION:
+		DEBUG(0, __FUNCTION__"():DISCOVERY_INDICATION\n");
+		queryias_done(self);
+		break;
+	case GOT_PARAMETERS:
+		DEBUG(0, __FUNCTION__"():GOT_PARAMETERS\n");
+		queryias_done(self);
+		break;
+	case GOT_LSAPSEL:
+		DEBUG(0, __FUNCTION__"():GOT_LSAPSEL\n");
+		queryias_done(self);
+		break;
+
 	default:
 		DEBUG(0,"ircomm_state_conn:unknown event =%d(%s)\n",
 		      event, ircommevent[event]);
@@ -744,6 +1040,7 @@
 }
 
 
+
 /*
  *  ----------------------------------------------------------------------
  *  IrCOMM service interfaces and supporting functions
@@ -751,172 +1048,97 @@
  *  ----------------------------------------------------------------------
  */
 
-int ircomm_query_ias_and_connect(struct ircomm_cb *self, __u8 servicetype)
-{
-	int retval=0;
-	__u16 hints;
-
-	ASSERT( self != NULL, return -EFAULT;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return -EFAULT;);
-	DEBUG(4,__FUNCTION__"():servicetype = %d\n",servicetype);
+/* 
+ * start_discovering()
+ *
+ * start discovering and enter DISCOVERY_WAIT state
+ */
 
-	/*
-	 * wait if another instance is discovering now
-	 */  
-	if(discovering_instance){
-		interruptible_sleep_on( &self->discovery_wait);
-		if(signal_pending(current)){
-			return -EINTR; /* cought a signal */
-		}
-		if(self->state == COMM_CONN)
-			return 0;  /* got connected */
-	}
-	ASSERT(discovering_instance == NULL, return -EFAULT;);
-	discovering_instance = self;
+static void start_discovering(struct ircomm_cb *self)
+{
+	__u16  hints; 
+	ASSERT( self != NULL, return;);
+	ASSERT( self->magic == IRCOMM_MAGIC, return;);
+	DEBUG(4,__FUNCTION__"():servicetype = %d\n",self->servicetype);
 	
-	/*
-	 * start discovering
-	 */
+
 	hints = irlmp_service_to_hint(S_COMM);
 
 	DEBUG(0,__FUNCTION__"():start discovering..\n");
 	switch (ircomm_cs) {
 	case 0:
-		skey = irlmp_register_service(hints);
-		ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+		MOD_INC_USE_COUNT;
+		self->queryias_lock = 1;
+		discovering_instance = self;
+		self->skey = irlmp_register_service(hints);
+		self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
 					     NULL);
 		break;
 		
 	case 1:    /* client only */
+		MOD_INC_USE_COUNT;
+		self->queryias_lock = 1;
+		discovering_instance = self;
 		DEBUG( 0, __FUNCTION__"():client only mode\n");
-		ckey = irlmp_register_client(hints, ircomm_discovery_indication,
+		self->ckey = irlmp_register_client(hints, ircomm_discovery_indication,
 					     NULL);
 		break;
 
 	case 2:     /*  server only  */
 	default:
 		DEBUG( 0, __FUNCTION__"():server only mode\n");
-		skey = irlmp_register_service(hints);
+		self->skey = irlmp_register_service(hints);
 		discovering_instance = NULL;
-		return 0;
+		break;
 	}
+	
+	return;
+}
 
+/*
+ * queryias_done(self)
+ *
+ * called when discovery process got wrong results, completed, or terminated.
+ */
 
-	/*
-	 * waiting for discovery
-	 */
-	interruptible_sleep_on( &self->discovery_wait);
-	if(signal_pending(current)){
-		retval = -EINTR; goto bailout; /* cought a signal */
+static void queryias_done(struct ircomm_cb *self)
+{
+	DEBUG(0, __FUNCTION__"():\n");
+	if(self->queryias_lock){
+		self->queryias_lock = 0;
+		discovering_instance = NULL;
+		MOD_DEC_USE_COUNT;
+		irlmp_unregister_client(self->ckey);
 	}
-	if(self->state == COMM_CONN)
-		goto bailout;     /* got connected */
+	if(ircomm_cs != 1)
+		irlmp_unregister_service(self->skey);
+	return;
+}
 
-	/*
-	 * query Parameters field of IAS and waiting for answer
-	 */
 
-	self->servicetype = 0;
+
+static void query_parameters(struct ircomm_cb *self)
+{
+
 	DEBUG(0, __FUNCTION__"():querying IAS: Parameters..\n");
 	iriap_getvaluebyclass_request( "IrDA:IrCOMM", "Parameters",
 				       self->saddr, self->daddr,
 				       ircomm_getvalue_confirm, self );
+}
 
-	interruptible_sleep_on( &self->ias_wait);
-	if(signal_pending(current)){
-		retval = -EINTR; goto bailout; /* cought a signal */
-	}
-	if(self->state == COMM_CONN)
-		goto bailout;     /* got connected */
-
-
-	/* really got Parameters field? */
-	if(self->ias_type != IAS_OCT_SEQ){
-		retval = -EFAULT;
-		goto bailout;
-	}
-
-	/* 
-	 * check if servicetype we want is available 
-	 */
-	self->peer_cap = self->servicetype;
-
-	DEBUG(0,__FUNCTION__"():peer capability is:\n");
-	DEBUG(0,"3wire raw: %s\n",((self->servicetype & THREE_WIRE_RAW) ? "yes":"no"));
-	DEBUG(0,"3wire    : %s\n",((self->servicetype & THREE_WIRE) ? "yes":"no"));
-	DEBUG(0,"9wire    : %s\n",((self->servicetype & NINE_WIRE) ? "yes":"no"));
-	DEBUG(0,"IEEE1284 : %s\n",((self->servicetype & CENTRONICS) ? "yes":"no"));
-
-	self->servicetype &= servicetype;
-	if(!(self->servicetype)){
-		retval = -ENODEV;
-		goto bailout;
-	}
-
-	/*
-	 * then choose better one 
-	 */
 
-	if(self->servicetype & THREE_WIRE_RAW)
-		servicetype = THREE_WIRE_RAW;
-	if(self->servicetype & THREE_WIRE)
-		servicetype = THREE_WIRE;
-	if(self->servicetype & NINE_WIRE)
-		servicetype = NINE_WIRE;
-	if(self->servicetype & CENTRONICS)
-		servicetype = CENTRONICS;
+static void query_lsapsel(struct ircomm_cb * self)
+{
+	DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
 
-	self->servicetype = servicetype;
-#if 1
-	/*
-	 * waiting for discovery again 
-	 */
-	interruptible_sleep_on( &self->discovery_wait);
-	if(signal_pending(current)){
-		retval = -EINTR; goto bailout; /* cought a signal */
-	}
-	if(self->state == COMM_CONN)
-		goto bailout;     /* got connected */
-#endif
-	/*
-	 * query lsapsel field and waiting for answer
-	 */
-	query_lsapsel(self);
-	interruptible_sleep_on( &self->ias_wait);
-	if(signal_pending(current)){
-		retval = -EINTR; goto bailout; /* cought a signal */
-	}
-	if(self->state == COMM_CONN)
-		goto bailout;     /* got connected */
-
-	/* really got Lsapsel field? */
-	if(self->ias_type != IAS_INTEGER){
-		retval = -EFAULT;
-		goto bailout;
-	} 
-#if 1
-	/*
-	 * waiting for discovery again...
-	 */
-	interruptible_sleep_on( &self->discovery_wait);
-	if(signal_pending(current)){
-		retval = -EINTR; goto bailout; /* cought a signal */
+	if (!(self->servicetype & THREE_WIRE_RAW)) {
+		iriap_getvaluebyclass_request( 
+			"IrDA:IrCOMM", "IrDA:TinyTP:LsapSel",
+			self->saddr, self->daddr,
+			ircomm_getvalue_confirm, self );
+	} else {
+		DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n");
 	}
-	if(self->state == COMM_CONN)
-		goto bailout;     /* got connected */
-#endif
-
-	/* succeed! ready to connect */
-	discovering_instance = NULL;
-	ircomm_connect_request(self);
-	return 0; 
-
- bailout:
-	/* failed.  not ready to connect */
-	discovering_instance = NULL;
-	irlmp_unregister_service(skey);
-	irlmp_unregister_client(ckey);
-	return retval;
 }
 
 /* 
@@ -926,7 +1148,7 @@
  */
 
 
-void ircomm_connect_request(struct ircomm_cb *self)
+void ircomm_connect_request(struct ircomm_cb *self, __u8 servicetype)
 {
 	/*
 	 * TODO:build a packet which contains "initial control parameters"
@@ -939,7 +1161,8 @@
 
 	DEBUG(0, __FUNCTION__"():sending connect_request...\n");
 
-	ircomm_control_request(self, SERVICETYPE); /*servictype*/
+	self->servicetype= servicetype;
+	/* ircomm_control_request(self, SERVICETYPE); */ /*servictype*/
 
 	self->maxsdusize = SAR_DISABLE;
 	ircomm_do_event( self, IRCOMM_CONNECT_REQUEST, NULL);
@@ -986,6 +1209,7 @@
 	ASSERT( self->magic == IRCOMM_MAGIC, return;);
 	DEBUG(0,__FUNCTION__"()\n");
 
+#if 0
 	/* unregister layer */
 	switch (ircomm_cs) {
 	case 1:    /* client only */
@@ -1001,6 +1225,7 @@
 		irlmp_unregister_service(skey);
 		break;
 	}
+#endif
 
 	self->disconnect_priority = priority;
 	if(priority != P_HIGH)
@@ -1353,7 +1578,7 @@
 			break;
 		
 		case SERVICETYPE:
-			self->servicetype = data[2];
+			self->peer_servicetype = data[2];
 			break;
 
 		case PORT_TYPE:
@@ -1482,128 +1707,6 @@
 
 
 
-/*
- * ircomm_getvalue_confirm()
- * handler for iriap_getvaluebyclass_request() 
- */
-
-static void ircomm_getvalue_confirm( __u16 obj_id, struct ias_value *value,
-				     void *priv)
-{
-	struct ircomm_cb *self = (struct ircomm_cb *) priv;
-	struct sk_buff *skb= NULL;
-	__u8 *frame;
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IRCOMM_MAGIC, return;);
-
-	/* Check if request succeeded */
-	if ( !value) {
-		DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
-		return;
-	}
-
-	DEBUG(4, __FUNCTION__"():type(%d)\n", value->type);
-
-	self->ias_type = value->type;
-	switch(value->type){
- 	case IAS_OCT_SEQ:
-		
-		DEBUG(4, __FUNCTION__"():got octet sequence:\n");
-#if 0
-		{
-			int i;
-			for ( i=0;i<value->len;i++)
-				printk("%02x",
-				       (__u8)(*(value->t.oct_seq + i)));
-			printk("\n");
-		}
-#endif
-		skb = dev_alloc_skb((value->len) + 2);
-		ASSERT(skb != NULL, return;);
-		frame = skb_put(skb,2);
-		/* MSB first */
-		frame[0] = ( value->len >> 8 ) & 0xff;
-		frame[1] = value->len & 0xff;
-		
-		frame = skb_put(skb,value->len);
-		memcpy(frame, value->t.oct_seq, value->len);
-		ircomm_parse_tuples(self, skb, IAS_PARAM);
-		kfree_skb(skb);
-
-		wake_up_interruptible( &self->ias_wait);
-		break;
-
-	case IAS_INTEGER:
-		/* LsapSel seems to be sent to me */	
-		DEBUG(0, __FUNCTION__"():got lsapsel = %d\n", value->t.integer);
-
-		if ( value->t.integer == -1){
-			DEBUG( 0, __FUNCTION__"():invalid value!\n");
-			return;
-		}
-
-		if(self->state == COMM_IDLE){
-			self->dlsap = value->t.integer;
-
-			wake_up_interruptible( &self->ias_wait);
-		}
-		break;
-
-	case IAS_MISSING:
-		DEBUG( 0, __FUNCTION__":got IAS_MISSING\n");
-		break;
-   
-	default:
-		DEBUG( 0, __FUNCTION__":got unknown (strange?)type!\n");
-		break;
-	}
-}
-
-
-/*
- * query_lsapsel()
- *    quering the remote IAS to ask which
- *    dlsap we should use
- */
-
-static void query_lsapsel(struct ircomm_cb * self)
-{
-	DEBUG(0, __FUNCTION__"():querying IAS: Lsapsel...\n");
-
-	if (!(self->servicetype & THREE_WIRE_RAW)) {
-		iriap_getvaluebyclass_request( 
-			"IrDA:IrCOMM", "IrDA:TinyTP:LsapSel",
-			self->saddr, self->daddr,
-			ircomm_getvalue_confirm, self );
-	} else {
-		DEBUG(0, __FUNCTION__ "THREE_WIRE_RAW is not implemented!\n");
-	}
-}
-
-/*
- * ircomm_discovery_indication()
- *    Remote device is discovered, try query the remote IAS to see which
- *    device it is, and which services it has.
- */
-
-static void ircomm_discovery_indication(discovery_t *discovery)
-{
-	struct ircomm_cb *self;
-
-	self = discovering_instance;
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRCOMM_MAGIC, return;);
-
-	self->daddr = discovery->daddr;
-	self->saddr = discovery->saddr;
-
-	DEBUG( 0, __FUNCTION__"():daddr=%08x\n", self->daddr);
-
-	wake_up_interruptible( &self->discovery_wait);
-	return;
-}
-
-
 struct ircomm_cb * ircomm_open_instance( struct notify_t client_notify)
 {
 	int i;
diff -urN linux-2.2.7-pre3/net/irda/ircomm/irvtd_driver.c linux-2.2.7-pre4/net/irda/ircomm/irvtd_driver.c
--- linux-2.2.7-pre3/net/irda/ircomm/irvtd_driver.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/ircomm/irvtd_driver.c	2003-08-15 15:05:52.000000000 -0700
@@ -51,7 +51,7 @@
 static int irvtd_refcount;
 struct irvtd_cb **irvtd = NULL;
 
-static char *revision_date = "Wed Mar 10 15:33:03 1999";
+static char *revision_date = "Sun Apr 18 17:31:53 1999";
 
 
 /*
@@ -74,6 +74,7 @@
 void irvtd_start(struct tty_struct *tty);
 void irvtd_hangup(struct tty_struct *tty);
 void irvtd_flush_buffer(struct tty_struct *tty);
+void irvtd_flush_chars(struct tty_struct *tty);
 
 static void change_speed(struct irvtd_cb *driver);
 static void irvtd_write_to_tty( struct irvtd_cb *);
@@ -91,14 +92,6 @@
 
 
 /*
- * ----------------------------------------------------------------------
- * 
- *
-
- * ----------------------------------------------------------------------
- */
-
-/*
  **********************************************************************
  *
  * ircomm_receive_data() and friends
@@ -122,11 +115,13 @@
 	struct sk_buff *skb;
 	struct tty_struct *tty = driver->tty;
 	
+	if(driver->rx_disable)
+		return;
+
 	skb = skb_dequeue(&driver->rxbuff);
 	if(skb == NULL)
 		return; /* there's nothing */
 
-
 	/* 
 	 * we should parse controlchannel field here. 
 	 * (see process_data() in ircomm.c)
@@ -244,6 +239,7 @@
 		irttp_flow_request(driver->comm->tsap, FLOW_STOP);
 		driver->ttp_stoprx = 1;
 	}
+	irvtd_write_to_tty(driver);
 	return 0;
 }
 
@@ -268,7 +264,7 @@
 	
 	driver->timer.data     = (unsigned long) driver;
 	driver->timer.function = &irvtd_timer_expired;
-	driver->timer.expires  = jiffies + (HZ / 20);  /* 50msec */
+	driver->timer.expires  = jiffies + (HZ / 5);  /* 200msec */
 	
 	add_timer( &driver->timer);
 }
@@ -282,13 +278,10 @@
 	ASSERT(driver->magic == IRVTD_MAGIC,return;);
 	DEBUG(4, __FUNCTION__"()\n");
 
-	if(!(driver->tty->hw_stopped) && !(driver->tx_disable))
-		irvtd_send_data_request(driver);
+	irvtd_send_data_request(driver);
+
+	irvtd_write_to_tty(driver);
 
-	if(!(driver->rx_disable)){
-		irvtd_write_to_tty(driver);
-	}
-	
 	/* start our timer again and again */
 	irvtd_start_timer(driver);
 }
@@ -302,6 +295,8 @@
 	ASSERT(skb != NULL,return;);
 	DEBUG(4, __FUNCTION__"()\n");
 
+	if(driver->tty->hw_stopped || driver->tx_disable)
+		return;
 	if(!skb->len)
 		return;   /* no data to send */
 
@@ -315,7 +310,7 @@
 	}
 #endif
 
-	DEBUG(4, __FUNCTION__"():sending %d bytes\n",(int)skb->len );
+	DEBUG(1, __FUNCTION__"():sending %d octets\n",(int)skb->len );
 	driver->icount.tx += skb->len;
 	err = ircomm_data_request(driver->comm, driver->txbuff);
 	if (err){
@@ -327,7 +322,7 @@
 	/* allocate a new frame */
 	skb = driver->txbuff = dev_alloc_skb(driver->comm->max_txbuff_size);
 	if (skb == NULL){
-		printk(__FUNCTION__"():flush_txbuff():alloc_skb failed!\n");
+		printk(__FUNCTION__"():alloc_skb failed!\n");
 	} else {
 		skb_reserve(skb, COMM_HEADER_SIZE);
 	}
@@ -369,10 +364,11 @@
 	/*
 	 * sending initial control parameters here
 	 */
-#if 1
 	if(driver->comm->servicetype ==	THREE_WIRE_RAW)
 		return;                /* do nothing */
 
+	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
+
 	ircomm_control_request(driver->comm, SERVICETYPE);
 	ircomm_control_request(driver->comm, DATA_RATE);
 	ircomm_control_request(driver->comm, DATA_FORMAT);
@@ -389,7 +385,6 @@
 		break;
 	default:
 	}
-#endif
 	
 	driver->tx_disable = 0;
 	wake_up_interruptible(&driver->open_wait);
@@ -414,15 +409,27 @@
 
 	DEBUG(4,"irvtd_connect_indication:sending connect_response...\n");
 
-	/*TODO: connect_response should send initialcontrolparameters! TH*/
-
 	ircomm_connect_response(comm, NULL, SAR_DISABLE );
 
+	driver->tx_disable = 0;
+
 	/*
-	 * set default value
+	 * send initial control parameters
 	 */
+	if(driver->comm->servicetype ==	THREE_WIRE_RAW)
+		return;                /* do nothing */
+
+	driver->comm->dte |= (MCR_DTR | MCR_RTS | DELTA_DTR | DELTA_RTS);
+
+	switch(driver->comm->servicetype){
+	case NINE_WIRE:
+		ircomm_control_request(driver->comm, DTELINE_STATE);
+		break;
+	default:
+	}
+
+
 	driver->msr |= (MSR_DCD|MSR_RI|MSR_DSR|MSR_CTS);
-	driver->tx_disable = 0;
 	wake_up_interruptible(&driver->open_wait);
 }
 
@@ -445,7 +452,13 @@
 	DEBUG(4,"irvtd_disconnect_indication:\n");
 
 	driver->tx_disable = 1;
-	driver->disconnect_pend = 1;
+	if(skb_queue_empty(&driver->rxbuff)){
+		/* disconnect */
+		driver->rx_disable = 1;
+		tty_hangup(driver->tty);
+	} else {
+		driver->disconnect_pend = 1;
+	}
 }
 
 /*
@@ -559,6 +572,12 @@
         }
 	break;
 
+	case FLOW_CONTROL:
+	case DATA_RATE:
+	case XON_XOFF_CHAR:
+	case DTELINE_STATE:
+		/* (maybe) nothing to do  */
+		break;
 	default:
 		DEBUG(0,__FUNCTION__"():PI = 0x%02x is not implemented\n",
 		      (int)driver->comm->pi);
@@ -624,19 +643,6 @@
 	while (1) {
 		current->state = TASK_INTERRUPTIBLE;
 		
-		if (driver->comm->state == COMM_CONN){
-			/* 
-			 * signal DTR and RTS
-			 */
-			driver->comm->dte = driver->mcr |= (MCR_DTR  |
-							    MCR_RTS  |
-							    DELTA_DTR|
-							    DELTA_RTS );
-
-			ircomm_control_request(driver->comm, DTELINE_STATE);
-		}
-
-
 		if (tty_hung_up_p(filp) ||
 		    !(driver->flags & ASYNC_INITIALIZED)) {
 #ifdef DO_RESTART
@@ -755,7 +761,6 @@
 
 static int irvtd_startup(struct irvtd_cb *driver)
 {
-	int retval = 0;
 	struct ias_object* obj;
 	struct notify_t irvtd_notify;
 
@@ -805,17 +810,13 @@
 	irias_insert_object( obj);
 
 	driver->flags |= ASYNC_INITIALIZED;
+
 	/*
 	 * discover a peer device
 	 *	   TODO: other servicetype(i.e. 3wire,3wireraw) support
 	 */
-	retval = ircomm_query_ias_and_connect(driver->comm, NINE_WIRE);
-	if(retval){
-		DEBUG(0, __FUNCTION__"(): ircomm_query_ias returns %d\n",
-		      retval);
-		return retval;
-	}
-
+	ircomm_connect_request(driver->comm, NINE_WIRE);
+	
 	/*
 	 * TODO:we have to initialize control-channel here!
 	 *   i.e.set something into RTS,CTS and so on....
@@ -931,7 +932,7 @@
 	ASSERT(driver->magic == IRVTD_MAGIC, return;);
 	ASSERT(driver->comm != NULL, return;);
 
-	DEBUG(0, __FUNCTION__"():\n");	
+	DEBUG(1, __FUNCTION__"():\n");	
 	if(!tty->closing)
 		return;   /* nothing to do */
 	
@@ -944,7 +945,7 @@
 	orig_jiffies = jiffies;
 
 	while (driver->comm->tsap->disconnect_pend) {
-		DEBUG(0, __FUNCTION__"():wait..\n");
+		DEBUG(1, __FUNCTION__"():wait..\n");
 		current->state = TASK_INTERRUPTIBLE;
 		current->counter = 0;	/* make us low-priority */
 		schedule_timeout(HZ);    /* 1sec */
@@ -964,7 +965,7 @@
 	if (!(driver->flags & ASYNC_INITIALIZED))
 		return;
 
-	DEBUG(0,__FUNCTION__"()\n");
+	DEBUG(1,__FUNCTION__"()\n");
 
 	/*
 	 * This comment is written in serial.c:
@@ -1017,7 +1018,7 @@
 	int line;
 	unsigned long flags;
 
-	DEBUG(0, __FUNCTION__"():refcount= %d\n",irvtd_refcount);
+	DEBUG(1, __FUNCTION__"():refcount= %d\n",irvtd_refcount);
 
 	ASSERT(driver != NULL, return;);
 	ASSERT(driver->magic == IRVTD_MAGIC, return;);
@@ -1030,7 +1031,7 @@
 		 * upper tty layer caught a HUP signal and called irvtd_hangup()
 		 * before. so we do nothing here.
 		 */
-		DEBUG(0, __FUNCTION__"():tty_hung_up_p.\n");
+		DEBUG(1, __FUNCTION__"():tty_hung_up_p.\n");
 		MOD_DEC_USE_COUNT;
 		restore_flags(flags);
 		return;
@@ -1142,7 +1143,6 @@
 
 	DEBUG(4, __FUNCTION__"()\n");
 
-
 	save_flags(flags);
 	while(1){
 		cli();
@@ -1164,11 +1164,23 @@
 		wrote += c;
 		count -= c;
 		buf += c;
+		irvtd_send_data_request(driver);
 	}
 	restore_flags(flags);
 	return (wrote);
 }
 
+void irvtd_flush_chars(struct tty_struct *tty)
+{
+	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
+	ASSERT( driver != NULL, return;);
+	ASSERT( driver->magic == IRVTD_MAGIC, return;);
+
+	DEBUG(4, __FUNCTION__"()\n");
+	irvtd_send_data_request(driver);
+}
+
+
 /*
  * Function irvtd_put_char (tty, ch)
  *
@@ -1606,14 +1618,14 @@
 
 static void irvtd_send_xchar(struct tty_struct *tty, char ch){
 
-	DEBUG(0, __FUNCTION__"():\n");
+	DEBUG(1, __FUNCTION__"():\n");
 	irvtd_put_char(tty, ch);
 }
 
 void irvtd_throttle(struct tty_struct *tty){
 	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
 
-	DEBUG(0, "irvtd_throttle:\n");
+	DEBUG(1, "irvtd_throttle:\n");
 
 	if (I_IXOFF(tty))
 		irvtd_put_char(tty, STOP_CHAR(tty));
@@ -1628,7 +1640,7 @@
 
 void irvtd_unthrottle(struct tty_struct *tty){
 	struct irvtd_cb *driver = (struct irvtd_cb *)tty->driver_data;
-	DEBUG(0, "irvtd_unthrottle:\n");
+	DEBUG(1, "irvtd_unthrottle:\n");
 
 	if (I_IXOFF(tty))
 		irvtd_put_char(tty, START_CHAR(tty));
@@ -1760,7 +1772,7 @@
         irvtd_drv.close = irvtd_close;
         irvtd_drv.write = irvtd_write;
         irvtd_drv.put_char = irvtd_put_char;
-	irvtd_drv.flush_chars = NULL;
+	irvtd_drv.flush_chars = irvtd_flush_chars;
         irvtd_drv.write_room = irvtd_write_room;
 	irvtd_drv.chars_in_buffer = irvtd_chars_in_buffer; 
         irvtd_drv.flush_buffer = irvtd_flush_buffer;
@@ -1916,7 +1928,7 @@
 		memset( irvtd[i], 0, sizeof(struct irvtd_cb));
 		irvtd[i]->magic = IRVTD_MAGIC;
 		irvtd[i]->line = i;
-		irvtd[i]->closing_wait = 30*HZ ;
+		irvtd[i]->closing_wait = 10*HZ ;
 		irvtd[i]->close_delay = 5*HZ/10 ; 
 	}
 
diff -urN linux-2.2.7-pre3/net/irda/irda_device.c linux-2.2.7-pre4/net/irda/irda_device.c
--- linux-2.2.7-pre3/net/irda/irda_device.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irda_device.c	2003-08-15 15:05:52.000000000 -0700
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      irda_device.c
- * Version:       0.4
+ * Version:       0.5
  * Description:   Abstract device driver layer and helper functions
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Wed Sep  2 20:22:08 1998
- * Modified at:   Wed Apr  7 17:16:54 1999
+ * Modified at:   Wed Apr 21 09:48:19 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli, All Rights Reserved.
@@ -129,26 +129,28 @@
 
 	/* Allocate memory if needed */
 	if (self->rx_buff.truesize > 0) {
-		self->rx_buff.data = ( __u8 *) kmalloc(self->rx_buff.truesize,
+		self->rx_buff.head = ( __u8 *) kmalloc(self->rx_buff.truesize,
 						       self->rx_buff.flags);
-		if (self->rx_buff.data == NULL)
+		if (self->rx_buff.head == NULL)
 			return -ENOMEM;
 
-		memset(self->rx_buff.data, 0, self->rx_buff.truesize);
+		memset(self->rx_buff.head, 0, self->rx_buff.truesize);
 	}
 	if (self->tx_buff.truesize > 0) {
-		self->tx_buff.data = ( __u8 *) kmalloc(self->tx_buff.truesize, 
+		self->tx_buff.head = ( __u8 *) kmalloc(self->tx_buff.truesize, 
 						       self->tx_buff.flags);
-		if (self->tx_buff.data == NULL)
+		if (self->tx_buff.head == NULL)
 			return -ENOMEM;
 
-		memset(self->tx_buff.data, 0, self->tx_buff.truesize);
+		memset(self->tx_buff.head, 0, self->tx_buff.truesize);
 	}
 	
       	self->magic = IRDA_DEVICE_MAGIC;
 
 	self->rx_buff.in_frame = FALSE;
 	self->rx_buff.state = OUTSIDE_FRAME;
+	self->tx_buff.data = self->tx_buff.head;
+	self->rx_buff.data = self->rx_buff.head;
 
 	/* Initialize timers */
 	init_timer(&self->media_busy_timer);	
@@ -184,7 +186,7 @@
 	/* Open network device */
 	dev_open(&self->netdev);
 
-	printk("IrDA device %s registered.\n", self->name);
+	MESSAGE("IrDA: Registred device %s\n", self->name);
 
 	irda_device_set_media_busy(self, FALSE);
 
@@ -197,8 +199,6 @@
 	/* It's now safe to initilize the saddr */
 	memcpy(self->netdev.dev_addr, &self->irlap->saddr, 4);
 
-	DEBUG(4, __FUNCTION__ "()->\n");
-
 	return 0;
 }
 
@@ -226,11 +226,11 @@
 	/* Stop timers */
 	del_timer(&self->media_busy_timer);
 
-	if (self->tx_buff.data)
-		kfree(self->tx_buff.data);
+	if (self->tx_buff.head)
+		kfree(self->tx_buff.head);
 
-	if (self->rx_buff.data)
-		kfree(self->rx_buff.data);
+	if (self->rx_buff.head)
+		kfree(self->rx_buff.head);
 
 	self->magic = 0;
 }
@@ -463,26 +463,6 @@
 }
 
 /*
- * Function irda_get_mtt (skb)
- *
- *    Utility function for getting the minimum turnaround time out of 
- *    the skb, where it has been hidden in the cb field.
- */
-inline unsigned short irda_get_mtt(struct sk_buff *skb)
-{
-	unsigned short mtt;
-
-	if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC)
-		mtt = 10000;
-	else
-		mtt = ((struct irlap_skb_cb *)(skb->cb))->mtt;
-
-	ASSERT(mtt <= 10000, return 10000;);
-	
-	return mtt;
-}
-
-/*
  * Function setup_dma (idev, buffer, count, mode)
  *
  *    Setup the DMA channel
@@ -561,7 +541,6 @@
 			       self->description);
 		
 		len += irda_device_print_flags(self, buf+len);
-
 		len += sprintf(buf+len, "\tbps\tmaxtt\tdsize\twinsize\taddbofs\tmintt\tldisc\n");
 		
 		len += sprintf(buf+len, "\t%d\t", 
diff -urN linux-2.2.7-pre3/net/irda/iriap.c linux-2.2.7-pre4/net/irda/iriap.c
--- linux-2.2.7-pre3/net/irda/iriap.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/iriap.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Aug 21 00:02:07 1997
- * Modified at:   Tue Mar 23 19:38:46 1999
+ * Modified at:   Fri Apr 23 09:57:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -31,6 +31,7 @@
 #include <linux/irda.h>
 
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irttp.h>
@@ -172,6 +173,7 @@
 		DEBUG( 0, "iriap_open: Unable to allocated LSAP!\n");
 		return NULL;
 	}
+	slsap_sel = lsap->slsap_sel;
 	DEBUG( 4, __FUNCTION__ "(), source LSAP sel=%02x\n", slsap_sel);
 	
 	self->magic = IAS_MAGIC;
@@ -179,7 +181,7 @@
 	self->slsap_sel = slsap_sel;
 	self->mode = mode;
 
-	/* init_timer( &self->watchdog_timer); */
+	init_timer( &self->watchdog_timer);
 
 	hashbin_insert( iriap, (QUEUE*) self, slsap_sel, NULL);
 	
@@ -204,7 +206,7 @@
 	ASSERT( self != NULL, return;);
 	ASSERT( self->magic == IAS_MAGIC, return;);
 
-	/* del_timer( &self->watchdog_timer); */
+	del_timer( &self->watchdog_timer);
 
 	self->magic = 0;
 
@@ -258,7 +260,7 @@
 
 	ASSERT( iriap != NULL, return;);
 
-	/* del_timer( &self->watchdog_timer); */
+	del_timer( &self->watchdog_timer);
 
 	if ( self->mode == IAS_CLIENT) {
 		DEBUG( 4, __FUNCTION__ "(), disconnect as client\n");
@@ -267,8 +269,8 @@
 		 * Inform service user that the request failed by sending 
 		 * it a NULL value.
 		 */
-		if ( self->confirm)
- 			self->confirm( 0, NULL, self->priv);
+		if (self->confirm)
+ 			self->confirm(IAS_DISCONNECT, 0, NULL, self->priv);
 		
 		
 		iriap_do_client_event( self, IAP_LM_DISCONNECT_INDICATION, 
@@ -348,9 +350,9 @@
  *    Retreive all values from attribute in all objects with given class
  *    name
  */
-void iriap_getvaluebyclass_request( char *name, char *attr, 
-				    __u32 saddr, __u32 daddr,
-				    CONFIRM_CALLBACK callback, void *priv)
+void iriap_getvaluebyclass_request(char *name, char *attr, 
+				   __u32 saddr, __u32 daddr,
+				   CONFIRM_CALLBACK callback, void *priv)
 {
 	struct sk_buff *skb;
 	struct iriap_cb *self;
@@ -358,9 +360,9 @@
 	int name_len, attr_len;
 	__u8 slsap = LSAP_ANY;  /* Source LSAP to use */
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 	
-	self = iriap_open( slsap, IAS_CLIENT);
+	self = iriap_open(slsap, IAS_CLIENT);
 	if (!self)
 		return;
 
@@ -376,29 +378,29 @@
 	 */
 	self->operation = GET_VALUE_BY_CLASS; 
 
-	/* Give ourselves 7 secs to finish this operation */
-	/* iriap_start_watchdog_timer( self, 700); */
+	/* Give ourselves 10 secs to finish this operation */
+	iriap_start_watchdog_timer(self, 10*HZ);
 	
 	skb = dev_alloc_skb( 64);
 	if (!skb)
 		return;
 
-	name_len = strlen( name);
-	attr_len = strlen( attr);
+	name_len = strlen(name);
+	attr_len = strlen(attr);
 
 	/* Reserve space for MUX and LAP header */
- 	skb_reserve( skb, LMP_CONTROL_HEADER+LAP_HEADER);
-	skb_put( skb, 3+name_len+attr_len);
+ 	skb_reserve(skb, LMP_CONTROL_HEADER+LAP_HEADER);
+	skb_put(skb, 3+name_len+attr_len);
 	frame = skb->data;
 
 	/* Build frame */
 	frame[0] = IAP_LST | GET_VALUE_BY_CLASS;
 	frame[1] = name_len;                       /* Insert length of name */
-	memcpy( frame+2, name, name_len);          /* Insert name */
+	memcpy(frame+2, name, name_len);           /* Insert name */
 	frame[2+name_len] = attr_len;              /* Insert length of attr */
-	memcpy( frame+3+name_len, attr, attr_len); /* Insert attr */
+	memcpy(frame+3+name_len, attr, attr_len);  /* Insert attr */
 
-	iriap_do_client_event( self, IAP_CALL_REQUEST_GVBC, skb);
+	iriap_do_client_event(self, IAP_CALL_REQUEST_GVBC, skb);
 }
 
 /*
@@ -415,7 +417,6 @@
 	int charset;
 	__u32 value_len;
 	__u32 tmp_cpu32;
-	__u16 tmp_cpu16;
 	__u16 obj_id;
 	__u16 len;
 	__u8  type;
@@ -430,14 +431,14 @@
 	n = 2;
 
 	/* Get length, MSB first */
-	memcpy(&len, fp+n, 2); n += 2;
-	be16_to_cpus(&len); 
+	len = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2;
 
 	DEBUG(4, __FUNCTION__ "(), len=%d\n", len);
 
 	/* Get object ID, MSB first */
-	memcpy(&obj_id, fp+n, 2); n += 2;
-	be16_to_cpus(&obj_id);
+	obj_id = be16_to_cpu(get_unaligned((__u16 *)(fp+n))); n += 2;
+/* 	memcpy(&obj_id, fp+n, 2); n += 2; */
+/* 	be16_to_cpus(&obj_id); */
 
 	type = fp[n++];
 	DEBUG( 4, __FUNCTION__ "(), Value type = %d\n", type);
@@ -484,9 +485,8 @@
 		value = irias_new_string_value(fp+n);
 		break;
 	case IAS_OCT_SEQ:
-		memcpy(&tmp_cpu16, fp+n, 2);  n += 2;
-		be16_to_cpus(&tmp_cpu16);
-		value_len = tmp_cpu16;
+		value_len = be16_to_cpu(get_unaligned((__u16 *)(fp+n)));
+		n += 2;
 		
 		/* FIXME:should be 1024, but.... */
 		DEBUG(0, __FUNCTION__ "():octet sequence:len=%d\n", value_len);
@@ -499,11 +499,11 @@
 		break;
 	}
 	
-	if (self->confirm)
-		self->confirm(obj_id, value, self->priv);
-	
 	/* Finished, close connection! */
 	iriap_disconnect_request(self);
+
+	if (self->confirm)
+		self->confirm(IAS_SUCCESS, obj_id, value, self->priv);
 }
 
 /*
@@ -550,7 +550,7 @@
 	fp[n++] = ret_code;
 
 	/* Insert list length (MSB first) */
-	tmp_be16 = __constant_htons( 0x0001);
+	tmp_be16 = __constant_htons(0x0001);
 	memcpy(fp+n, &tmp_be16, 2);  n += 2; 
 
 	/* Insert object identifier ( MSB first) */
@@ -703,17 +703,17 @@
 {
 	struct iriap_cb *self;
 	
-	self = ( struct iriap_cb *) instance;
+	self = (struct iriap_cb *) instance;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
-	ASSERT( userdata != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
+	ASSERT(userdata != NULL, return;);
 	
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 	
 	/* del_timer( &self->watchdog_timer); */
 
-	iriap_do_client_event( self, IAP_LM_CONNECT_CONFIRM, userdata);
+	iriap_do_client_event(self, IAP_LM_CONNECT_CONFIRM, userdata);
 }
 
 /*
@@ -778,7 +778,7 @@
 	}
 
 	if (~opcode & IAP_ACK) {
-		DEBUG(0, __FUNCTION__ "() Got ack frame!\n");
+		DEBUG(2, __FUNCTION__ "() Got ack frame!\n");
 	/* 	return; */
 	}
 
@@ -797,9 +797,21 @@
 			break;
 		case IAS_CLASS_UNKNOWN:
 			printk(KERN_WARNING "IrIAP No such class!\n");
+			/* Finished, close connection! */
+			iriap_disconnect_request(self);
+
+			if (self->confirm)
+				self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, 
+					      self->priv);
 			break;
 		case IAS_ATTRIB_UNKNOWN:
 			printk(KERN_WARNING "IrIAP No such attribute!\n");
+		       	/* Finished, close connection! */
+			iriap_disconnect_request(self);
+
+			if (self->confirm)
+				self->confirm(IAS_CLASS_UNKNOWN, 0, NULL, 
+					      self->priv);
 			break;
 		}
 		iriap_do_call_event( self, IAP_RECV_F_LST, skb);
@@ -854,18 +866,20 @@
 	}
 }
 
+/*
+ * Function iriap_watchdog_timer_expired (data)
+ *
+ *    
+ *
+ */
 void iriap_watchdog_timer_expired( unsigned long data)
 {
 	struct iriap_cb *self = ( struct iriap_cb *) data;
 	
-	DEBUG( 0, __FUNCTION__ "()\n");
-
-	return;
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == IAS_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == IAS_MAGIC, return;);
 
-	DEBUG( 0, __FUNCTION__ "() Timeout! closing myself!\n");
+	DEBUG(0, __FUNCTION__ "() Timeout! closing myself!\n");
 	iriap_close( self);
 }
 
diff -urN linux-2.2.7-pre3/net/irda/irlan/irlan_client.c linux-2.2.7-pre4/net/irda/irlan/irlan_client.c
--- linux-2.2.7-pre3/net/irda/irlan/irlan_client.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlan/irlan_client.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Wed Apr  7 16:56:35 1999
+ * Modified at:   Thu Apr 22 23:03:55 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane, <loz@holmes.demon.co.uk>
@@ -30,7 +30,6 @@
 #include <linux/errno.h>
 #include <linux/init.h>
 #include <linux/netdevice.h>
-#include <linux/inetdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/if_arp.h>
 #include <net/arp.h>
@@ -106,7 +105,7 @@
 {
 	struct irmanager_event mgr_event;
 
-	DEBUG(2, __FUNCTION__ "()\n");
+	DEBUG(0, __FUNCTION__ "()\n");
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -122,8 +121,8 @@
 	if (self->dev.start) {
 		/* Open TSAPs */
 		irlan_client_open_ctrl_tsap(self);
-		irlan_provider_open_ctrl_tsap(self);
-		irlan_open_data_tsap(self);
+ 		irlan_provider_open_ctrl_tsap(self);
+ 		irlan_open_data_tsap(self);
 		
 		irlan_do_client_event(self, IRLAN_DISCOVERY_INDICATION, NULL);
 	} else if (self->notify_irmanager) {
@@ -162,7 +161,7 @@
 	struct irlan_cb *self, *entry;
 	__u32 saddr, daddr;
 	
-	DEBUG(2, __FUNCTION__"()\n");
+	DEBUG(0, __FUNCTION__"()\n");
 
 	ASSERT(irlan != NULL, return;);
 	ASSERT(discovery != NULL, return;);
@@ -171,8 +170,7 @@
 	daddr = discovery->daddr;
 
 	/* 
-	 *  Check if we already have an instance for dealing with this 
-	 *  provider.
+	 *  Check if we already dealing with this provider.
 	 */
 	self = (struct irlan_cb *) hashbin_find(irlan, daddr, NULL);
       	if (self) {
@@ -190,7 +188,7 @@
 	 */
 	self = hashbin_find(irlan, DEV_ADDR_ANY, NULL);
 	if (self) {
-		DEBUG(2, __FUNCTION__ "(), Found instance with DEV_ADDR_ANY!\n");
+		DEBUG(0, __FUNCTION__ "(), Found instance with DEV_ADDR_ANY!\n");
 		/*
 		 * Rehash instance, now we have a client (daddr) to serve.
 		 */
@@ -200,27 +198,16 @@
 		self->daddr = daddr;
 		self->saddr = saddr;
 
-		DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
+		DEBUG(0, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
 		hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
 		
 		/* Check if network device has been registered */
 		if (!self->netdev_registered)
 			irlan_register_netdev(self);
 		
-		/* Remember that we might have to start a new provider */
-		self->client.start_new_provider = TRUE;
-	} else {
-		DEBUG(2, __FUNCTION__ "(), Found none, starting new one!\n");
-		/* No instance available, so we have to start one! */
-		self = irlan_open(saddr, daddr, TRUE);
-		if (!self) {
-			DEBUG(2, __FUNCTION__ "(), irlan_open failed!\n");
-			return;
-		}
-		ASSERT( self != NULL, return;);
+		/* Restart watchdog timer */
+		irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
 	}
-	/* Restart watchdog timer */
-	irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
 }
 	
 /*
@@ -367,13 +354,12 @@
 }
 
 /*
- * Function irlan_client_extract_params (skb)
+ * Function irlan_client_parse_response (self, skb)
  *
  *    Extract all parameters from received buffer, then feed them to 
  *    check_params for parsing
- *
  */
-void irlan_client_extract_params(struct irlan_cb *self, struct sk_buff *skb)
+void irlan_client_parse_response(struct irlan_cb *self, struct sk_buff *skb)
 {
 	__u8 *frame;
 	__u8 *ptr;
@@ -392,7 +378,7 @@
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 	
 	if (!skb) {
-		DEBUG(2, __FUNCTION__ "(), Got NULL skb!\n");
+		ERROR( __FUNCTION__ "(), Got NULL skb!\n");
 		return;
 	}
 	frame = skb->data;
@@ -423,7 +409,7 @@
 
 	/* For all parameters */
  	for (i=0; i<count;i++) {
-		ret = irlan_get_param(ptr, name, value, &val_len);
+		ret = irlan_extract_param(ptr, name, value, &val_len);
 		if (ret == -1) {
 			DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
 			break;
@@ -445,9 +431,6 @@
 static void irlan_check_response_param(struct irlan_cb *self, char *param, 
 				       char *value, int val_len) 
 {
-#ifdef CONFIG_IRLAN_GRATUITOUS_ARP
-	struct in_device *in_dev;
-#endif
 	__u16 tmp_cpu; /* Temporary value in host order */
 	__u8 *bytes;
 	int i;
@@ -550,21 +533,6 @@
 		      bytes[5]);
 		for (i = 0; i < 6; i++) 
 			self->dev.dev_addr[i] = bytes[i];
-
-#ifdef CONFIG_IRLAN_GRATUITOUS_ARP
-		/* 
-		 * When we get a new MAC address do a gratuitous ARP. This
-		 * is useful if we have changed access points on the same
-		 * subnet.  
-		 */
-		DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
-		in_dev = self->dev.ip_ptr;
-		arp_send(ARPOP_REQUEST, ETH_P_ARP, 
-			  in_dev->ifa_list->ifa_address,
-			  &self->dev, 
-			  in_dev->ifa_list->ifa_address,
-			  NULL, self->dev.dev_addr, NULL);
-#endif
 	}
 }
 
@@ -574,8 +542,8 @@
  *    Got results from remote LM-IAS
  *
  */
-void irlan_client_get_value_confirm(__u16 obj_id, struct ias_value *value,
-				    void *priv) 
+void irlan_client_get_value_confirm(int result, __u16 obj_id, 
+				    struct ias_value *value, void *priv) 
 {
 	struct irlan_cb *self;
 	
@@ -587,7 +555,7 @@
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
 
 	/* Check if request succeeded */
-	if (!value) {
+	if (result != IAS_SUCCESS) {
 		DEBUG(2, __FUNCTION__ "(), got NULL value!\n");
 		irlan_do_client_event(self, IRLAN_IAS_PROVIDER_NOT_AVAIL, 
 				      NULL);
diff -urN linux-2.2.7-pre3/net/irda/irlan/irlan_client_event.c linux-2.2.7-pre4/net/irda/irlan/irlan_client_event.c
--- linux-2.2.7-pre3/net/irda/irlan/irlan_client_event.c	1999-03-07 15:26:44.000000000 -0800
+++ linux-2.2.7-pre4/net/irda/irlan/irlan_client_event.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Thu Feb  4 16:08:07 1999
+ * Modified at:   Thu Apr 22 12:23:22 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -226,7 +226,7 @@
 	case IRLAN_DATA_INDICATION:
 		ASSERT(skb != NULL, return -1;);
 	
-		irlan_client_extract_params(self, skb);
+		irlan_client_parse_response(self, skb);
 		
 		irlan_next_client_state(self, IRLAN_MEDIA);
 		
@@ -266,7 +266,7 @@
 
 	switch(event) {
 	case IRLAN_DATA_INDICATION:
-		irlan_client_extract_params(self, skb);
+		irlan_client_parse_response(self, skb);
 		irlan_open_data_channel(self);
 		irlan_next_client_state(self, IRLAN_OPEN);
 		break;
@@ -305,7 +305,7 @@
 
 	switch(event) {
 	case IRLAN_DATA_INDICATION:
-		irlan_client_extract_params(self, skb);
+		irlan_client_parse_response(self, skb);
 		
 		/*
 		 *  Check if we have got the remote TSAP for data 
@@ -336,11 +336,6 @@
 					      IRLAN_MTU, NULL);
 			
 			irlan_next_client_state(self, IRLAN_DATA);
-
-			if (self->client.start_new_provider) {
-				irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
-				self->client.start_new_provider = FALSE;
-			}
 			break;
 		default:
 			DEBUG(2, __FUNCTION__ "(), unknown access type!\n");
@@ -468,7 +463,7 @@
 
 	switch(event) {
 	case IRLAN_DATA_INDICATION:
-		irlan_client_extract_params(self, skb);
+		irlan_client_parse_response(self, skb);
 		break;		
 	case IRLAN_LMP_DISCONNECT: /* FALLTHROUGH */
 	case IRLAN_LAP_DISCONNECT:
diff -urN linux-2.2.7-pre3/net/irda/irlan/irlan_common.c linux-2.2.7-pre4/net/irda/irlan/irlan_common.c
--- linux-2.2.7-pre3/net/irda/irlan/irlan_common.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlan/irlan_common.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Wed Apr  7 17:03:21 1999
+ * Modified at:   Thu Apr 22 23:13:47 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -112,9 +112,11 @@
 void irlan_watchdog_timer_expired(unsigned long data)
 {
 	struct irmanager_event mgr_event;
-	struct irlan_cb *self = (struct irlan_cb *) data;
+	struct irlan_cb *self, *entry;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	DEBUG(0, __FUNCTION__ "()\n");
+
+	self = (struct irlan_cb *) data;
 
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -132,147 +134,38 @@
 		 *  by the user.
 		 */
 		self->notify_irmanager = FALSE;
-	} else
-		irlan_close(self);
-}
-
-void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout)
-{
-	DEBUG(4, __FUNCTION__ "()\n");
-	
-	irda_start_timer(&self->watchdog_timer, timeout, (unsigned long) self,
-			 irlan_watchdog_timer_expired);
-}
-
-/*
- * Function irlan_eth_open (dev)
- *
- *    Network device has been opened by user
- *
- */
-static int irlan_eth_open(struct device *dev)
-{
-	struct irlan_cb *self;
-	
-	DEBUG(4, __FUNCTION__ "()\n");
-
-	ASSERT(dev != NULL, return -1;);
-
-	self = (struct irlan_cb *) dev->priv;
-
-	ASSERT(self != NULL, return -1;);
-
-	/* Ready to play! */
-/* 	dev->tbusy = 0; */ /* Wait until data link is ready */
-	dev->interrupt = 0;
-	dev->start = 1;
-
-	self->notify_irmanager = TRUE;
+	} else {
+		DEBUG(0, __FUNCTION__ "(), recycling instance!\n");
+		if (self->netdev_registered) {
+			DEBUG(0, __FUNCTION__ "(), removing netdev!\n");
+			unregister_netdev(&self->dev);
+			self->netdev_registered = FALSE;
+		}
+
+		/* Unbind from daddr */
+		entry = hashbin_remove(irlan, self->daddr, NULL);
+		ASSERT(entry == self, return;);
 
-	/* We are now open, so time to do some work */
-	irlan_client_wakeup(self, self->saddr, self->daddr);
+		self->daddr = DEV_ADDR_ANY;
+		self->saddr = DEV_ADDR_ANY;
 
-	MOD_INC_USE_COUNT;
-	
-	return 0;
+		DEBUG(2, __FUNCTION__ "(), daddr=%08x\n", self->daddr);
+		hashbin_insert(irlan, (QUEUE*) self, self->daddr, NULL);
+	}
 }
 
 /*
- * Function irlan_eth_close (dev)
+ * Function irlan_start_watchdog_timer (self, timeout)
  *
- *    Stop the ether network device, his function will usually be called by
- *    ifconfig down. We should now disconnect the link, We start the 
- *    close timer, so that the instance will be removed if we are unable
- *    to discover the remote device after the disconnect.
- */
-static int irlan_eth_close(struct device *dev)
-{
-	struct irlan_cb *self = (struct irlan_cb *) dev->priv;
-
-	DEBUG(4, __FUNCTION__ "()\n");
-	
-	/* Stop device */
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	MOD_DEC_USE_COUNT;
-
-	irlan_close_data_channel(self);
-
-	irlan_close_tsaps(self);
-
-	irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
-	irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);	
-	
-	irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
-
-	/* Device closed by user! */
-	if (self->notify_irmanager)
-		self->notify_irmanager = FALSE;
-	else
-		self->notify_irmanager = TRUE;
-
-	return 0;
-}
-/*
- * Function irlan_eth_init (dev)
- *
- *    The network device initialization function.
+ *    
  *
  */
-int irlan_eth_init(struct device *dev)
+void irlan_start_watchdog_timer(struct irlan_cb *self, int timeout)
 {
-	struct irmanager_event mgr_event;
-	struct irlan_cb *self;
-
-	DEBUG(4, __FUNCTION__"()\n");
-
-	ASSERT(dev != NULL, return -1;);
-       
-	self = (struct irlan_cb *) dev->priv;
-
-	dev->open               = irlan_eth_open;
-	dev->stop               = irlan_eth_close;
-	dev->hard_start_xmit    = irlan_eth_xmit; 
-	dev->get_stats	        = irlan_eth_get_stats;
-	dev->set_multicast_list = irlan_eth_set_multicast_list;
-
-	dev->tbusy = 1;
-	
-	ether_setup(dev);
+	DEBUG(4, __FUNCTION__ "()\n");
 	
-	dev->tx_queue_len = TTP_MAX_QUEUE;
-
-#if 0
-	/*  
-	 *  OK, since we are emulating an IrLAN sever we will have to give
-	 *  ourself an ethernet address!
-	 *  FIXME: this must be more dynamically
-	 */
-	dev->dev_addr[0] = 0x40;
-	dev->dev_addr[1] = 0x00;
-	dev->dev_addr[2] = 0x00;
-	dev->dev_addr[3] = 0x00;
-	dev->dev_addr[4] = 0x23;
-	dev->dev_addr[5] = 0x45;
-#endif
-	/* 
-	 * Network device has now been registered, so tell irmanager about
-	 * it, so it can be configured with network parameters
-	 */
-	mgr_event.event = EVENT_IRLAN_START;
-	sprintf(mgr_event.devname, "%s", self->ifname);
-	irmanager_notify(&mgr_event);
-
-	/* 
-	 * We set this so that we only notify once, since if 
-	 * configuration of the network device fails, the user
-	 * will have to sort it out first anyway. No need to 
-	 * try again.
-	 */
-	self->notify_irmanager = FALSE;
-
-	return 0;
+	irda_start_timer(&self->watchdog_timer, timeout, (unsigned long) self,
+			 irlan_watchdog_timer_expired);
 }
 
 /*
@@ -312,8 +205,12 @@
 	/* Start the first IrLAN instance */
  	new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
 
+	irlan_open_data_tsap(new);
+ 	irlan_client_open_ctrl_tsap(new);
+	irlan_provider_open_ctrl_tsap(new);
+
 	/* Do some fast discovery! */
-	irlmp_discovery_request(8);
+	irlmp_discovery_request(DISCOVERY_DEFAULT_SLOTS);
 
 	return 0;
 }
@@ -345,7 +242,7 @@
 {
 	int i=0;
 
-	DEBUG(4, __FUNCTION__ "()\n");
+	DEBUG(0, __FUNCTION__ "()\n");
 
 	/* Check if we should call the device eth<x> or irlan<x> */
 	if (!eth) {
@@ -416,10 +313,6 @@
 	irlan_next_client_state(self, IRLAN_IDLE);
 	irlan_next_provider_state(self, IRLAN_IDLE);
 
-	irlan_open_data_tsap(self);
-  	irlan_provider_open_ctrl_tsap(self);
-	irlan_client_open_ctrl_tsap(self);
-
 	/* Register network device now, or wait until some later time? */
 	if (netdev)
 		irlan_register_netdev(self);
@@ -436,7 +329,7 @@
  */
 static void __irlan_close(struct irlan_cb *self)
 {
-	DEBUG(2, __FUNCTION__ "()\n");
+	DEBUG(0, __FUNCTION__ "()\n");
 	
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -447,11 +340,13 @@
 	/* Close all open connections and remove TSAPs */
 	irlan_close_tsaps(self);
 
-	if (self->netdev_registered)
+	if (self->netdev_registered) {
 		unregister_netdev(&self->dev);
+		self->netdev_registered = FALSE;
+	}
 	
 	self->magic = 0;
-	kfree(self);
+ 	kfree(self);
 }
 
 /*
@@ -464,7 +359,7 @@
 {
 	struct irlan_cb *entry;
 	
-	DEBUG(2, __FUNCTION__ "()\n");
+	DEBUG(0, __FUNCTION__ "()\n");
 
         ASSERT(self != NULL, return;);
 	ASSERT(self->magic == IRLAN_MAGIC, return;);
@@ -572,7 +467,7 @@
 
 	switch(reason) {
 	case LM_USER_REQUEST: /* User request */
-		irlan_close(self);
+		//irlan_close(self);
 		break;
 	case LM_LAP_DISCONNECT: /* Unexpected IrLAP disconnect */
 		irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
@@ -636,7 +531,7 @@
 	self->stsap_sel_data = self->tsap_data->stsap_sel;
 }
 
-static void irlan_close_tsaps(struct irlan_cb *self)
+void irlan_close_tsaps(struct irlan_cb *self)
 {
 	DEBUG(4, __FUNCTION__ "()\n");
 
@@ -1122,12 +1017,12 @@
 }
 
 /*
- * Function irlan_get_response_param (buf, param, value)
+ * Function irlan_extract_param (buf, name, value, len)
  *
  *    Extracts a single parameter name/value pair from buffer and updates
  *    the buffer pointer to point to the next name/value pair. 
  */
-int irlan_get_param(__u8 *buf, char *name, char *value, __u16 *len)
+int irlan_extract_param(__u8 *buf, char *name, char *value, __u16 *len)
 {
 	__u8 name_len;
 	__u16 val_len;
@@ -1276,6 +1171,20 @@
 	}
 }
 
+void irlan_mod_inc_use_count(void)
+{
+#ifdef MODULE
+	MOD_INC_USE_COUNT;
+#endif
+}
+
+void irlan_mod_dec_use_count(void)
+{
+#ifdef MODULE
+	MOD_DEC_USE_COUNT;
+#endif
+}
+
 #ifdef MODULE
 
 MODULE_AUTHOR("Dag Brattli <dagb@cs.uit.no>");
diff -urN linux-2.2.7-pre3/net/irda/irlan/irlan_eth.c linux-2.2.7-pre4/net/irda/irlan/irlan_eth.c
--- linux-2.2.7-pre3/net/irda/irlan/irlan_eth.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlan/irlan_eth.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Thu Oct 15 08:37:58 1998
- * Modified at:   Mon Mar 22 17:41:59 1999
+ * Modified at:   Thu Apr 22 14:26:39 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
@@ -27,15 +27,150 @@
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
+#include <linux/inetdevice.h>
 #include <linux/if_arp.h>
 #include <net/arp.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
 #include <net/irda/irlan_common.h>
+#include <net/irda/irlan_client.h>
+#include <net/irda/irlan_event.h>
 #include <net/irda/irlan_eth.h>
 
 /*
+ * Function irlan_eth_init (dev)
+ *
+ *    The network device initialization function.
+ *
+ */
+int irlan_eth_init(struct device *dev)
+{
+	struct irmanager_event mgr_event;
+	struct irlan_cb *self;
+
+	DEBUG(0, __FUNCTION__"()\n");
+
+	ASSERT(dev != NULL, return -1;);
+       
+	self = (struct irlan_cb *) dev->priv;
+
+	dev->open               = irlan_eth_open;
+	dev->stop               = irlan_eth_close;
+	dev->hard_start_xmit    = irlan_eth_xmit; 
+	dev->get_stats	        = irlan_eth_get_stats;
+	dev->set_multicast_list = irlan_eth_set_multicast_list;
+
+	dev->tbusy = 1;
+	
+	ether_setup(dev);
+	
+	dev->tx_queue_len = TTP_MAX_QUEUE;
+
+#if 0
+	/*  
+	 *  OK, since we are emulating an IrLAN sever we will have to give
+	 *  ourself an ethernet address!
+	 *  FIXME: this must be more dynamically
+	 */
+	dev->dev_addr[0] = 0x40;
+	dev->dev_addr[1] = 0x00;
+	dev->dev_addr[2] = 0x00;
+	dev->dev_addr[3] = 0x00;
+	dev->dev_addr[4] = 0x23;
+	dev->dev_addr[5] = 0x45;
+#endif
+	/* 
+	 * Network device has now been registered, so tell irmanager about
+	 * it, so it can be configured with network parameters
+	 */
+	mgr_event.event = EVENT_IRLAN_START;
+	sprintf(mgr_event.devname, "%s", self->ifname);
+	irmanager_notify(&mgr_event);
+
+	/* 
+	 * We set this so that we only notify once, since if 
+	 * configuration of the network device fails, the user
+	 * will have to sort it out first anyway. No need to 
+	 * try again.
+	 */
+	self->notify_irmanager = FALSE;
+
+	return 0;
+}
+
+/*
+ * Function irlan_eth_open (dev)
+ *
+ *    Network device has been opened by user
+ *
+ */
+int irlan_eth_open(struct device *dev)
+{
+	struct irlan_cb *self;
+	
+	DEBUG(0, __FUNCTION__ "()\n");
+
+	ASSERT(dev != NULL, return -1;);
+
+	self = (struct irlan_cb *) dev->priv;
+
+	ASSERT(self != NULL, return -1;);
+
+	/* Ready to play! */
+/* 	dev->tbusy = 0; */ /* Wait until data link is ready */
+	dev->interrupt = 0;
+	dev->start = 1;
+
+	self->notify_irmanager = TRUE;
+
+	/* We are now open, so time to do some work */
+	irlan_client_wakeup(self, self->saddr, self->daddr);
+
+	irlan_mod_inc_use_count();
+	
+	return 0;
+}
+
+/*
+ * Function irlan_eth_close (dev)
+ *
+ *    Stop the ether network device, his function will usually be called by
+ *    ifconfig down. We should now disconnect the link, We start the 
+ *    close timer, so that the instance will be removed if we are unable
+ *    to discover the remote device after the disconnect.
+ */
+int irlan_eth_close(struct device *dev)
+{
+	struct irlan_cb *self = (struct irlan_cb *) dev->priv;
+
+	DEBUG(0, __FUNCTION__ "()\n");
+	
+	/* Stop device */
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	irlan_mod_dec_use_count();
+
+	irlan_close_data_channel(self);
+
+	irlan_close_tsaps(self);
+
+	irlan_do_client_event(self, IRLAN_LMP_DISCONNECT, NULL);
+	irlan_do_provider_event(self, IRLAN_LMP_DISCONNECT, NULL);	
+	
+	irlan_start_watchdog_timer(self, IRLAN_TIMEOUT);
+
+	/* Device closed by user! */
+	if (self->notify_irmanager)
+		self->notify_irmanager = FALSE;
+	else
+		self->notify_irmanager = TRUE;
+
+	return 0;
+}
+
+/*
  * Function irlan_eth_tx (skb)
  *
  *    Transmits ethernet frames over IrDA link.
@@ -220,6 +355,30 @@
 }
 
 /*
+ * Function irlan_etc_send_gratuitous_arp (dev)
+ *
+ *    Send gratuitous ARP to announce that we have changed
+ *    hardware address, so that all peers updates their ARP tables
+ */
+void irlan_etc_send_gratuitous_arp(struct device *dev) 
+{
+	struct in_device *in_dev;
+
+	/* 
+	 * When we get a new MAC address do a gratuitous ARP. This
+	 * is useful if we have changed access points on the same
+	 * subnet.  
+	 */
+	DEBUG(4, "IrLAN: Sending gratuitous ARP\n");
+	in_dev = dev->ip_ptr;
+	arp_send(ARPOP_REQUEST, ETH_P_ARP, 
+		 in_dev->ifa_list->ifa_address,
+		 &dev, 
+		 in_dev->ifa_list->ifa_address,
+		 NULL, dev->dev_addr, NULL);
+}
+
+/*
  * Function set_multicast_list (dev)
  *
  *    Configure the filtering of the device
diff -urN linux-2.2.7-pre3/net/irda/irlan/irlan_provider.c linux-2.2.7-pre4/net/irda/irlan/irlan_provider.c
--- linux-2.2.7-pre3/net/irda/irlan/irlan_provider.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlan/irlan_provider.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Tue Apr  6 19:08:20 1999
+ * Modified at:   Thu Apr 22 14:28:52 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * Sources:       skeleton.c by Donald Becker <becker@CESDIS.gsfc.nasa.gov>
  *                slip.c by Laurence Culhane,   <loz@holmes.demon.co.uk>
@@ -129,7 +129,7 @@
 	ASSERT(tsap == self->provider.tsap_ctrl,return;);
 	ASSERT(self->provider.state == IRLAN_IDLE, return;);
 
-	/* Check if this provider is unused */
+	/* Check if this provider is currently unused */
 	if (self->daddr == DEV_ADDR_ANY) {
 		/*
 		 * Rehash instance, now we have a client (daddr) to serve.
@@ -168,14 +168,6 @@
 	if ((self->access_type == ACCESS_PEER) && 
 	    (self->client.state == IRLAN_IDLE))
 		irlan_client_wakeup(self, self->saddr, self->daddr);
-
-	/* 
-	 * This provider is now in use, so start a new provider instance to
-         * serve other clients. This will also change the LM-IAS entry so that
-	 * other clients don't try to connect to us, now that we are busy.
-	 */
-	new = irlan_open(DEV_ADDR_ANY, DEV_ADDR_ANY, FALSE);
-	self->client.start_new_provider = FALSE;
 }
 
 /*
@@ -231,20 +223,20 @@
 {
 	int ret;
 	
-	ret = irlan_provider_extract_params(self, CMD_OPEN_DATA_CHANNEL, skb);
+	ret = irlan_provider_parse_command(self, CMD_OPEN_DATA_CHANNEL, skb);
 
 	return ret;
 }
 
 /*
- * Function extract_params (skb)
+ * Function parse_command (skb)
  *
  *    Extract all parameters from received buffer, then feed them to 
  *    check_params for parsing
  *
  */
-int irlan_provider_extract_params(struct irlan_cb *self, int cmd,
-				  struct sk_buff *skb) 
+int irlan_provider_parse_command(struct irlan_cb *self, int cmd,
+				 struct sk_buff *skb) 
 {
 	__u8 *frame;
 	__u8 *ptr;
@@ -285,7 +277,7 @@
 	
 	/* For all parameters */
  	for (i=0; i<count;i++) {
-		ret = irlan_get_param(ptr, name, value, &val_len);
+		ret = irlan_extract_param(ptr, name, value, &val_len);
 		if (ret < 0) {
 			DEBUG(2, __FUNCTION__ "(), IrLAN, Error!\n");
 			break;
@@ -394,19 +386,19 @@
  *    Register provider support so we can accept incomming connections.
  * 
  */
-void irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
+int irlan_provider_open_ctrl_tsap(struct irlan_cb *self)
 {
 	struct notify_t notify;
 	struct tsap_cb *tsap;
 	
 	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == IRLAN_MAGIC, return;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == IRLAN_MAGIC, return -1;);
 
 	/* Check if already open */
 	if (self->provider.tsap_ctrl)
-		return;
+		return -1;
 	
 	/*
 	 *  First register well known control TSAP
@@ -421,11 +413,13 @@
 	tsap = irttp_open_tsap(LSAP_ANY, 1, &notify);
 	if (!tsap) {
 		DEBUG(2, __FUNCTION__ "(), Got no tsap!\n");
-		return;
+		return -1;
 	}
 	self->provider.tsap_ctrl = tsap;
 
 	/* Register with LM-IAS */
-	irlan_ias_register(self,tsap->stsap_sel);
+	irlan_ias_register(self, tsap->stsap_sel);
+
+	return 0;
 }
 
diff -urN linux-2.2.7-pre3/net/irda/irlan/irlan_provider_event.c linux-2.2.7-pre4/net/irda/irlan/irlan_provider_event.c
--- linux-2.2.7-pre3/net/irda/irlan/irlan_provider_event.c	1999-03-07 15:26:44.000000000 -0800
+++ linux-2.2.7-pre4/net/irda/irlan/irlan_provider_event.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:37 1997
- * Modified at:   Wed Feb  3 21:43:06 1999
+ * Modified at:   Thu Apr 22 10:46:28 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -108,8 +108,15 @@
 	switch(event) {
 	case IRLAN_GET_INFO_CMD:
 		/* Be sure to use 802.3 in case of peer mode */
-		if (self->access_type == ACCESS_PEER)
+		if (self->access_type == ACCESS_PEER) {
 			self->media = MEDIA_802_3;
+			
+			/* Check if client has started yet */
+			if (self->client.state == IRLAN_IDLE) {
+				/* This should get the client going */
+				irlmp_discovery_request(8);
+			}
+		}
 
 		irlan_provider_send_reply(self, CMD_GET_PROVIDER_INFO, 
 					  RSP_SUCCESS);
@@ -165,7 +172,7 @@
 
 	switch(event) {
 	case IRLAN_FILTER_CONFIG_CMD:
-		irlan_provider_extract_params(self, CMD_FILTER_OPERATION, skb);
+		irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
 		irlan_provider_send_reply(self, CMD_FILTER_OPERATION, 
 					  RSP_SUCCESS);
 		/* Keep state */
@@ -207,7 +214,7 @@
 
 	switch(event) {
 	case IRLAN_FILTER_CONFIG_CMD:
-		irlan_provider_extract_params(self, CMD_FILTER_OPERATION, skb);
+		irlan_provider_parse_command(self, CMD_FILTER_OPERATION, skb);
 		irlan_provider_send_reply(self, CMD_FILTER_OPERATION, 
 					  RSP_SUCCESS);
 		break;
diff -urN linux-2.2.7-pre3/net/irda/irlap.c linux-2.2.7-pre4/net/irda/irlap.c
--- linux-2.2.7-pre3/net/irda/irlap.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlap.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Tue Apr  6 21:07:08 1999
+ * Modified at:   Fri Apr 23 10:12:29 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -44,9 +44,9 @@
 #include <net/irda/irlap_comp.h>
 
 hashbin_t *irlap = NULL;
-int sysctl_slot_timeout = SLOT_TIMEOUT;
+int sysctl_slot_timeout = SLOT_TIMEOUT * 1000 / HZ;
 
-static void __irlap_close( struct irlap_cb *self);
+static void __irlap_close(struct irlap_cb *self);
 
 static char *lap_reasons[] = {
 	"ERROR, NOT USED",
@@ -301,27 +301,21 @@
  *    IrLMP for further processing
  *
  */
-inline void irlap_data_indication( struct irlap_cb *self, struct sk_buff *skb) 
+inline void irlap_data_indication(struct irlap_cb *self, struct sk_buff *skb) 
 {
-	DEBUG( 4, __FUNCTION__ "()\n"); 
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-
 	/* Hide LAP header from IrLMP layer */
-	skb_pull( skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
+	skb_pull(skb, LAP_ADDR_HEADER+LAP_CTRL_HEADER);
 
 #ifdef CONFIG_IRDA_COMPRESSION
-	if ( self->qos_tx.compression.value) {
-		skb = irlap_decompress_frame( self, skb);
-		if ( !skb) {
-			DEBUG( 1, __FUNCTION__ "(), Decompress error!\n");
+	if (self->qos_tx.compression.value) {
+		skb = irlap_decompress_frame(self, skb);
+		if (!skb) {
+			DEBUG(1, __FUNCTION__ "(), Decompress error!\n");
 			return;
 		}
 	}
 #endif
-	irlmp_link_data_indication( self->notify.instance, LAP_RELIABLE, skb);
+	irlmp_link_data_indication(self->notify.instance, LAP_RELIABLE, skb);
 }
 
 /*
@@ -515,22 +509,22 @@
 		info.discovery = discovery;
 		
 		/* Check if the slot timeout is within limits */
-		if ( sysctl_slot_timeout < 2) {
-			DEBUG( 1, __FUNCTION__ 
-			       "(), to low value for slot timeout!\n");
-			sysctl_slot_timeout = 2;
+		if (sysctl_slot_timeout < 20) {
+			ERROR(__FUNCTION__ 
+			      "(), to low value for slot timeout!\n");
+			sysctl_slot_timeout = 20;
 		}
 		/* 
 		 * Highest value is actually 8, but we allow higher since
 		 * some devices seems to require it.
 		 */
-		if ( sysctl_slot_timeout > 16) {
-			DEBUG( 1, __FUNCTION__ 
-			       "(), to high value for slot timeout!\n");
-			sysctl_slot_timeout = 16;
+		if (sysctl_slot_timeout > 160) {
+			ERROR(__FUNCTION__ 
+			      "(), to high value for slot timeout!\n");
+			sysctl_slot_timeout = 160;
 		}
 
-		self->slot_timeout = sysctl_slot_timeout;
+		self->slot_timeout = sysctl_slot_timeout * HZ / 1000;
 		
 		irlap_do_event( self, DISCOVERY_REQUEST, NULL, &info);
 	} else { 
@@ -807,24 +801,18 @@
 {
 	int usecs;
 	int speed;
-	int bytes = 0;
+	int bytes ;
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( qos != NULL, return;);
-
 	/* Get QoS values.  */
 	speed = qos->baud_rate.value;
 	usecs = qos->min_turn_time.value;
 
 	/* No need to calculate XBOFs for speeds over 115200 bps */
-	if ( speed > 115200) {
+	if (speed > 115200) {
 		self->mtt_required = usecs;
 		return;
 	}
 	
-	DEBUG( 4, __FUNCTION__ "(), delay=%d usecs\n", usecs); 
-	
 	/*  
 	 *  Send additional BOF's for the next frame for the requested
 	 *  min turn time, so now we must calculate how many chars (XBOF's) we 
@@ -832,8 +820,6 @@
 	 */
 	bytes = speed * usecs / 10000000;
 
-	DEBUG( 4, __FUNCTION__ "(), xbofs delay = %d\n", bytes);
-	
 	self->xbofs_delay = bytes;
 }
 
@@ -1028,7 +1014,7 @@
 	self->qos_tx.data_size.value = 64;
 	self->qos_tx.additional_bofs.value = 11;
 
-	irlap_flush_all_queues( self);
+	irlap_flush_all_queues(self);
 
 	self->disconnect_pending = FALSE;
 }
@@ -1079,11 +1065,10 @@
 
 	/* 
 	 *  Initialize timeout values, some of the rules are listed on 
-	 *  page 92 in IrLAP. Divide by 10 since the kernel timers has a
-	 *  resolution of 10 ms.
+	 *  page 92 in IrLAP.
 	 */
-	self->poll_timeout = qos->max_turn_time.value / 10;
-	self->final_timeout = qos->max_turn_time.value / 10;
+	self->poll_timeout = qos->max_turn_time.value * HZ / 1000;
+	self->final_timeout = qos->max_turn_time.value * HZ / 1000;
 	self->wd_timeout = self->poll_timeout * 2;
 
 #ifdef CONFIG_IRDA_COMPRESSION
diff -urN linux-2.2.7-pre3/net/irda/irlap_event.c linux-2.2.7-pre4/net/irda/irlap_event.c
--- linux-2.2.7-pre3/net/irda/irlap_event.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlap_event.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sat Aug 16 00:59:29 1997
- * Modified at:   Fri Mar 26 14:24:09 1999
+ * Modified at:   Fri Apr 23 11:55:12 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>,
@@ -40,36 +40,40 @@
 
 #include <net/irda/irda_device.h>
 
-static int irlap_state_ndm    ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_query  ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reply  ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_conn   ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_setup  ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_offline( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_xmit_p ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_pclose ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_nrm_p  ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
+#if CONFIG_IRDA_FAST_RR
+int sysctl_fast_poll_increase = 50;
+#endif
+
+static int irlap_state_ndm    (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_query  (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_reply  (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_conn   (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_setup  (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_offline(struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_xmit_p (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_pclose (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_nrm_p  (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
 static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, 
 				  struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reset  ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_nrm_s  ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_xmit_s ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_sclose ( struct irlap_cb *self, IRLAP_EVENT event, 
-				struct sk_buff *skb, struct irlap_info *info);
-static int irlap_state_reset_check( struct irlap_cb *, IRLAP_EVENT event, 
-				    struct sk_buff *, struct irlap_info *);
+static int irlap_state_reset  (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_nrm_s  (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_xmit_s (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_sclose (struct irlap_cb *self, IRLAP_EVENT event, 
+			       struct sk_buff *skb, struct irlap_info *info);
+static int irlap_state_reset_check(struct irlap_cb *, IRLAP_EVENT event, 
+				   struct sk_buff *, struct irlap_info *);
 
 static const char *irlap_event[] = {
 	"DISCOVERY_REQUEST",
@@ -145,37 +149,37 @@
 /*
  * Function irda_poll_timer_expired (data)
  *
- *    
- *
+ *    Poll timer has expired. Normally we must now send a RR frame to the
+ *    remote device
  */
-static void irlap_poll_timer_expired( unsigned long data)
+static void irlap_poll_timer_expired(unsigned long data)
 {
 	struct irlap_cb *self = (struct irlap_cb *) data;
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 	
-	irlap_do_event( self, POLL_TIMER_EXPIRED, NULL, NULL);
+	irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
 }
 
-void irlap_start_poll_timer( struct irlap_cb *self, int timeout)
+void irlap_start_poll_timer(struct irlap_cb *self, int timeout)
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LAP_MAGIC, return;);
 
 #ifdef CONFIG_IRDA_FAST_RR
-	if ( skb_queue_len( &self->tx_list) == 0) {
-		if ( self->fast_RR == TRUE) {
+	if (skb_queue_len(&self->tx_list) == 0) {
+		if (self->fast_RR == TRUE) {
 			/*
 			 *  Assert that the fast poll timer has not reached the
 			 *  normal poll timer yet
 			 */
-			if ( self->fast_RR_timeout < timeout) {
+			if (self->fast_RR_timeout < timeout) {
 				/*
 				 *  FIXME: this should be a more configurable
 				 *         function
 				 */
-				self->fast_RR_timeout += 15;
+				self->fast_RR_timeout += (sysctl_fast_poll_increase * HZ/1000);
 
 				/* Use this fast(er) timeout instead */
 				timeout = self->fast_RR_timeout;
@@ -183,17 +187,20 @@
 		} else {
 			self->fast_RR = TRUE;
 
-			/* Start with just 1 ms */
-			self->fast_RR_timeout = 1;
-			timeout = 1;
+			/* Start with just 0 ms */
+			self->fast_RR_timeout = 0;
+			timeout = 0;
 		}
 	} else
 		self->fast_RR = FALSE;
 
-	DEBUG( 4, __FUNCTION__ "(), Timeout=%d\n", timeout);
+	DEBUG(4, __FUNCTION__ "(), Timeout=%d\n", timeout);
 #endif
-	irda_start_timer( &self->poll_timer, timeout, 
-			  (unsigned long) self, irlap_poll_timer_expired);
+	if (timeout == 0)
+		irlap_do_event(self, POLL_TIMER_EXPIRED, NULL, NULL);
+	else
+		irda_start_timer(&self->poll_timer, timeout, 
+				 (unsigned long) self, irlap_poll_timer_expired);
 }
 
 /*
@@ -338,25 +345,25 @@
 	case DISCOVERY_REQUEST:		
 		ASSERT( info != NULL, return -1;);
 
-	 	if ( irda_device_is_media_busy( self->irdev)) {
+	 	if (irda_device_is_media_busy(self->irdev)) {
  			DEBUG(0, __FUNCTION__ "(), media busy!\n"); 
 			/* irlap->log.condition = MEDIA_BUSY; */
 			
 			/* Always switch state before calling upper layers */
-			irlap_next_state( self, LAP_NDM); 
+			irlap_next_state(self, LAP_NDM); 
 			
 			/* This will make IrLMP try again */
- 			irlap_discovery_confirm( self, NULL);
+ 			irlap_discovery_confirm(self, NULL);
 			return 0;
 	 	} 
 		
 		self->S = info->S;
 		self->s = info->s;
-		irlap_send_discovery_xid_frame( self, info->S, info->s, TRUE,
-						info->discovery);
+		irlap_send_discovery_xid_frame(self, info->S, info->s, TRUE,
+					       info->discovery);
 		self->s++;
 
-		irlap_start_slot_timer( self, self->slot_timeout);
+		irlap_start_slot_timer(self, self->slot_timeout);
 		irlap_next_state(self, LAP_QUERY);
 		break;
 
@@ -440,38 +447,38 @@
 		irlap_next_state( self, LAP_QUERY); 
 		break;
 	case SLOT_TIMER_EXPIRED:
-		if ( self->s < self->S) {
-			irlap_send_discovery_xid_frame( self, self->S, 
-							self->s, TRUE,
-							self->discovery_cmd);
+		if (self->s < self->S) {
+			irlap_send_discovery_xid_frame(self, self->S, 
+						       self->s, TRUE,
+						       self->discovery_cmd);
 			self->s++;
-			irlap_start_slot_timer( self, self->slot_timeout);
+			irlap_start_slot_timer(self, self->slot_timeout);
 			
 			/* Keep state */
-			irlap_next_state( self, LAP_QUERY);
+			irlap_next_state(self, LAP_QUERY);
 		} else {
 			/* This is the final slot! */
-			irlap_send_discovery_xid_frame( self, self->S, 0xff, 
-							TRUE,
-							self->discovery_cmd);
+			irlap_send_discovery_xid_frame(self, self->S, 0xff, 
+						       TRUE,
+						       self->discovery_cmd);
 
 			/* Always switch state before calling upper layers */
-			irlap_next_state( self, LAP_NDM);
+			irlap_next_state(self, LAP_NDM);
 	
 			/*
 			 *  We are now finished with the discovery procedure, 
 			 *  so now we must return the results
 			 */
-			irlap_discovery_confirm( self, self->discovery_log);
+			irlap_discovery_confirm(self, self->discovery_log);
 		}
 		break;
 	default:
 		DEBUG(2, __FUNCTION__ "(), Unknown event %d, %s\n", event, 
 		      irlap_event[event]);
 
-		if ( skb != NULL) {
+		if (skb)
 			dev_kfree_skb( skb);
-		}
+
 		ret = -1;
 		break;
 	}
@@ -485,37 +492,37 @@
  *    are waiting for the right time slot to send a response XID frame
  * 
  */
-static int irlap_state_reply( struct irlap_cb *self, IRLAP_EVENT event, 
-			      struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_reply(struct irlap_cb *self, IRLAP_EVENT event, 
+			     struct sk_buff *skb, struct irlap_info *info) 
 {
 	discovery_t *discovery_rsp;
 	int ret=0;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
+	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-	switch( event) {
+	switch(event) {
 	case QUERY_TIMER_EXPIRED:
 		DEBUG(2, __FUNCTION__ "(), QUERY_TIMER_EXPIRED <%ld>\n",
 		      jiffies);
-		irlap_next_state( self, LAP_NDM);
+		irlap_next_state(self, LAP_NDM);
 		break;
 	case RECV_DISCOVERY_XID_CMD:
-		ASSERT( info != NULL, return -1;);
+		ASSERT(info != NULL, return -1;);
 		/*
 		 *  Last frame?
 		 */
-		if ( info->s == 0xff) {
-			del_timer( &self->query_timer);
+		if (info->s == 0xff) {
+			del_timer(&self->query_timer);
 			
 			/* info->log.condition = REMOTE; */
 
 			/* Always switch state before calling upper layers */
-			irlap_next_state( self, LAP_NDM);
+			irlap_next_state(self, LAP_NDM);
 
-			irlap_discovery_indication( self, info->discovery); 
+			irlap_discovery_indication(self, info->discovery); 
 		} else if ((info->s >= self->slot) && (!self->frame_sent)) {
 			discovery_rsp = irlmp_get_discovery_response();
 			discovery_rsp->daddr = info->daddr;
@@ -549,17 +556,17 @@
  *    layer to accept or refuse connection 
  *
  */
-static int irlap_state_conn( struct irlap_cb *self, IRLAP_EVENT event, 
-			     struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_conn(struct irlap_cb *self, IRLAP_EVENT event, 
+			    struct sk_buff *skb, struct irlap_info *info) 
 {
 	int ret = 0;
 
-	DEBUG( 4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
+	DEBUG(4, __FUNCTION__ "(), event=%s\n", irlap_event[ event]);
 
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-	switch( event) {
+	switch (event) {
 	case CONNECT_RESPONSE:
 		skb_pull( skb, 11);
 
@@ -762,7 +769,7 @@
 	DEBUG( 4, __FUNCTION__ "(), event=%s, vs=%d, vr=%d", 
 	       irlap_event[ event], self->vs, self->vr); 
 		
-	switch( event) {
+	switch (event) {
 	case SEND_I_CMD:
 		ASSERT( skb != NULL, return -1;);
 		DEBUG( 4, __FUNCTION__ "(), Window=%d\n", self->window);
@@ -822,7 +829,7 @@
 		} else {
 			DEBUG( 4, __FUNCTION__ 
 			       "(), Unable to send! remote busy?\n");
-			skb_queue_head( &self->tx_list, skb);
+			skb_queue_head(&self->tx_list, skb);
 
 			/*
 			 *  The next ret is important, because it tells 
@@ -831,19 +838,19 @@
 			ret = -EPROTO;
 		}
 		break;
+	case POLL_TIMER_EXPIRED:
+		irlap_send_rr_frame(self, CMD_FRAME);
+		irlap_start_final_timer(self, self->final_timeout);
+		irlap_next_state(self, LAP_NRM_P);
+		break;
 	case DISCONNECT_REQUEST:
-		del_timer( &self->poll_timer);
-		irlap_wait_min_turn_around( self, &self->qos_tx);
-		irlap_send_disc_frame( self);
-		irlap_flush_all_queues( self);
-		irlap_start_final_timer( self, self->final_timeout);
+		del_timer(&self->poll_timer);
+		irlap_wait_min_turn_around(self, &self->qos_tx);
+		irlap_send_disc_frame(self);
+		irlap_flush_all_queues(self);
+		irlap_start_final_timer(self, self->final_timeout);
 		self->retry_count = 0;
-		irlap_next_state( self, LAP_PCLOSE);
-		break;
-	case POLL_TIMER_EXPIRED:
-		irlap_send_rr_frame( self, CMD_FRAME);
-		irlap_start_final_timer( self, self->final_timeout);
-		irlap_next_state( self, LAP_NRM_P);
+		irlap_next_state(self, LAP_PCLOSE);
 		break;
 	default:
 		DEBUG(0, __FUNCTION__ "(), Unknown event %s\n", 
@@ -916,117 +923,18 @@
  *   transmit any frames and is expecting to receive frames only from the
  *   secondary to which transmission permissions has been given.
  */
-static int irlap_state_nrm_p( struct irlap_cb *self, IRLAP_EVENT event, 
-			      struct sk_buff *skb, struct irlap_info *info) 
+static int irlap_state_nrm_p(struct irlap_cb *self, IRLAP_EVENT event, 
+			     struct sk_buff *skb, struct irlap_info *info) 
 {
 	int ret = 0;
 	int ns_status;
 	int nr_status;
 
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
 
-	switch( event) {
-	case RECV_RR_RSP:
-		DEBUG( 4, __FUNCTION__ "(), RECV_RR_FRAME: "
-		       "Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n",
-		       self->retry_count, info->nr, self->va, self->vs, 
-		       self->vr);
-
-		ASSERT( info != NULL, return -1;);
-
-		/*  
-		 *  If you get a RR, the remote isn't busy anymore, 
-		 *  no matter what the NR 
-		 */
-		self->remote_busy = FALSE;
-
-		/* 
-		 *  Nr as expected? 
-		 */
-		ret = irlap_validate_nr_received( self, info->nr);
-		if ( ret == NR_EXPECTED) {	
-			/* Stop final timer */
-			del_timer( &self->final_timer);
-			
-			/* Update Nr received */
-			irlap_update_nr_received( self, info->nr);
-			
-			/*
-			 *  Got expected NR, so reset the retry_count. This 
-			 *  is not done by the IrLAP standard , which is 
-			 *  strange! DB.
-			 */
-			self->retry_count = 0;			
-			irlap_wait_min_turn_around( self, &self->qos_tx);
-
-			/* Start poll timer */
-			irlap_start_poll_timer( self, self->poll_timeout);
-
-			irlap_next_state( self, LAP_XMIT_P);
-		} else if ( ret == NR_UNEXPECTED) {
-			ASSERT( info != NULL, return -1;);	
-			/* 
-			 *  Unexpected nr! 
-			 */
-			
-			/* Update Nr received */
-			irlap_update_nr_received( self, info->nr);
-
-			DEBUG( 4, "RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, "
-			       "vs=%d, vr=%d\n",
-			       self->retry_count, info->nr, self->va, 
-			       self->vs, self->vr);
-			
-			/* Resend rejected frames */
-			irlap_resend_rejected_frames( self, CMD_FRAME);
-			
-			/*
-			 *  Start only if not running, DB
-			 *  TODO: Should this one be here?
-			 */
-			/* if ( !self->final_timer.prev) */
-/* 				irda_start_timer( FINAL_TIMER, self->final_timeout);  */
-
-			/* Keep state */
-			irlap_next_state( self, LAP_NRM_P);
-		} else if ( ret == NR_INVALID) {
-			DEBUG(1, "irlap_state_nrm_p: received RR with "
-			      "invalid nr !\n");
-			del_timer( &self->final_timer);
-
-			irlap_next_state( self, LAP_RESET_WAIT);
-
-			irlap_disconnect_indication( self, 
-						     LAP_RESET_INDICATION);
-			self->xmitflag = TRUE;
-		}
-		if (skb)
-			dev_kfree_skb( skb);
-		break;
-	case RECV_RNR_FRAME:
-		DEBUG( 4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, "
-		       "nr=%d, va=%d, vs=%d, vr=%d\n",
-		       self->retry_count, info->nr, self->va, self->vs, 
-		       self->vr);
-
-		ASSERT( info != NULL, return -1;);
-
-		/* Stop final timer */
-		del_timer( &self->final_timer);
-		self->remote_busy = TRUE;
-
-		/* Update Nr received */
-		irlap_update_nr_received( self, info->nr);
-			
-		/* Start poll timer */
-		irlap_start_poll_timer( self, self->poll_timeout);
-
-		irlap_next_state( self, LAP_XMIT_P);
-
-		dev_kfree_skb( skb);
-		break;
-	case RECV_I_RSP:
+	switch (event) {
+	case RECV_I_RSP: /* Optimize for the common case */
 		/* FIXME: must check for remote_busy below */
 #ifdef CONFIG_IRDA_FAST_RR
 		/* 
@@ -1039,8 +947,8 @@
 
 		ASSERT( info != NULL, return -1;);
 
-		ns_status = irlap_validate_ns_received( self, info->ns);
-		nr_status = irlap_validate_nr_received( self, info->nr);
+		ns_status = irlap_validate_ns_received(self, info->ns);
+		nr_status = irlap_validate_nr_received(self, info->nr);
 
 		/* 
 		 *  Check for expected I(nformation) frame
@@ -1049,7 +957,7 @@
 			/* 
 			 *  poll bit cleared?
 			 */
-			if ( !info->pf) {
+			if (!info->pf) {
 				self->vr = (self->vr + 1) % 8;
 			
 				/* Update Nr received */
@@ -1058,16 +966,16 @@
 				self->ack_required = TRUE;
 				
 				/* Keep state, do not move this line */
-				irlap_next_state( self, LAP_NRM_P);
+				irlap_next_state(self, LAP_NRM_P);
 				
-				irlap_data_indication( self, skb);
+				irlap_data_indication(self, skb);
 			} else {
-				del_timer( &self->final_timer);
+				del_timer(&self->final_timer);
 
 				self->vr = (self->vr + 1) % 8;
 			
 				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
+				irlap_update_nr_received(self, info->nr);
 		
 				/*  
 				 *  Got expected NR, so reset the
@@ -1077,13 +985,17 @@
 				self->retry_count = 0;
 				self->ack_required = TRUE;
 			
-				/* This is the last frame */
-				irlap_start_poll_timer( self, self->poll_timeout);
-				irlap_wait_min_turn_around( self, &self->qos_tx);
-				/* Do not move this line */
-				irlap_next_state( self, LAP_XMIT_P);
+				irlap_wait_min_turn_around(self, &self->qos_tx);
+				/* 
+				 * Important to switch state before calling
+				 * upper layers
+				 */
+				irlap_next_state(self, LAP_XMIT_P);
 			
-				irlap_data_indication( self, skb);
+				irlap_data_indication(self, skb);
+
+				/* This is the last frame */
+				irlap_start_poll_timer(self, self->poll_timeout);
 			}
 			break;
 			
@@ -1091,8 +1003,7 @@
 		/*
 		 *  Unexpected next to send (Ns)
 		 */
-		if (( ns_status == NS_UNEXPECTED) && 
-		    ( nr_status == NR_EXPECTED)) 
+		if ((ns_status == NS_UNEXPECTED) && (nr_status == NR_EXPECTED))
 		{
 			if ( !info->pf) {
 				irlap_update_nr_received( self, info->nr);
@@ -1125,8 +1036,7 @@
 		/* 
 		 *  Unexpected next to receive (Nr) 
 		 */
-		if (( ns_status == NS_EXPECTED) && 
-		    ( nr_status == NR_UNEXPECTED))
+		if ((ns_status == NS_EXPECTED) && (nr_status == NR_UNEXPECTED))
 		{
 			if ( info->pf) {
 				self->vr = (self->vr + 1) % 8;
@@ -1169,8 +1079,8 @@
 		 *  Unexpected next to send (Ns) and next to receive (Nr)
 		 *  Not documented by IrLAP!
 		 */
-		if (( ns_status == NS_UNEXPECTED) && 
-		    ( nr_status == NR_UNEXPECTED)) 
+		if ((ns_status == NS_UNEXPECTED) && 
+		    (nr_status == NR_UNEXPECTED)) 
 		{
 			DEBUG( 4, "IrLAP: unexpected nr and ns!\n");
 			if ( info->pf) {
@@ -1194,37 +1104,137 @@
 		/*
 		 *  Invalid NR or NS
 		 */
-		if (( nr_status == NR_INVALID) || ( ns_status == NS_INVALID)) {
-			if ( info->pf) {
-				del_timer( &self->final_timer);
+		if ((nr_status == NR_INVALID) || (ns_status == NS_INVALID)) {
+			if (info->pf) {
+				del_timer(&self->final_timer);
 				
-				irlap_next_state( self, LAP_RESET_WAIT);
+				irlap_next_state(self, LAP_RESET_WAIT);
 
-				irlap_disconnect_indication( self, LAP_RESET_INDICATION);
+				irlap_disconnect_indication(self, LAP_RESET_INDICATION);
 				self->xmitflag = TRUE;
 			} else {
-				del_timer( &self->final_timer);
+				del_timer(&self->final_timer);
 				
-				irlap_disconnect_indication( self, LAP_RESET_INDICATION);
+				irlap_disconnect_indication(self, LAP_RESET_INDICATION);
 				
 				self->xmitflag = FALSE;
 			}
 			break;
 		}
 		DEBUG(1, __FUNCTION__ "(), Not implemented!\n");
-		DEBUG(1, __FUNCTION__ "(), event=%s, ns_status=%d, nr_status=%d\n", 
-		       irlap_event[ event], ns_status, nr_status);
+		DEBUG(1, __FUNCTION__ 
+		      "(), event=%s, ns_status=%d, nr_status=%d\n", 
+		      irlap_event[ event], ns_status, nr_status);
 		break;
 	case RECV_UI_FRAME:
 		/*  poll bit cleared?  */
-		if ( !info->pf) {
-			irlap_unit_data_indication( self, skb);
-			irlap_next_state( self, LAP_NRM_P);
+		if (!info->pf) {
+			irlap_unit_data_indication(self, skb);
+			irlap_next_state(self, LAP_NRM_P);
 		} else {
+			del_timer(&self->final_timer);
+			irlap_unit_data_indication(self, skb);
+			irlap_start_poll_timer(self, self->poll_timeout);
+		}
+		break;
+	case RECV_RR_RSP:
+		DEBUG(4, __FUNCTION__ "(), RECV_RR_FRAME: "
+		      "Retrans:%d, nr=%d, va=%d, vs=%d, vr=%d\n",
+		      self->retry_count, info->nr, self->va, self->vs, 
+		      self->vr);
+
+		ASSERT(info != NULL, return -1;);
+
+		/*  
+		 *  If you get a RR, the remote isn't busy anymore, 
+		 *  no matter what the NR 
+		 */
+		self->remote_busy = FALSE;
+
+		/* 
+		 *  Nr as expected? 
+		 */
+		ret = irlap_validate_nr_received(self, info->nr);
+		if (ret == NR_EXPECTED) {	
+			/* Stop final timer */
+			del_timer(&self->final_timer);
+			
+			/* Update Nr received */
+			irlap_update_nr_received(self, info->nr);
+			
+			/*
+			 *  Got expected NR, so reset the retry_count. This 
+			 *  is not done by the IrLAP standard , which is 
+			 *  strange! DB.
+			 */
+			self->retry_count = 0;			
+			irlap_wait_min_turn_around(self, &self->qos_tx);
+
+			irlap_next_state(self, LAP_XMIT_P);
+
+			/* Start poll timer */
+			irlap_start_poll_timer(self, self->poll_timeout);
+		} else if (ret == NR_UNEXPECTED) {
+			ASSERT( info != NULL, return -1;);	
+			/* 
+			 *  Unexpected nr! 
+			 */
+			
+			/* Update Nr received */
+			irlap_update_nr_received( self, info->nr);
+
+			DEBUG( 4, "RECV_RR_FRAME: Retrans:%d, nr=%d, va=%d, "
+			       "vs=%d, vr=%d\n",
+			       self->retry_count, info->nr, self->va, 
+			       self->vs, self->vr);
+			
+			/* Resend rejected frames */
+			irlap_resend_rejected_frames( self, CMD_FRAME);
+			
+			/*
+			 *  Start only if not running, DB
+			 *  TODO: Should this one be here?
+			 */
+			/* if ( !self->final_timer.prev) */
+/* 				irda_start_timer( FINAL_TIMER, self->final_timeout);  */
+
+			/* Keep state */
+			irlap_next_state( self, LAP_NRM_P);
+		} else if (ret == NR_INVALID) {
+			DEBUG(1, "irlap_state_nrm_p: received RR with "
+			      "invalid nr !\n");
 			del_timer( &self->final_timer);
-			irlap_unit_data_indication( self, skb);
-			irlap_start_poll_timer( self, self->poll_timeout);
+
+			irlap_next_state( self, LAP_RESET_WAIT);
+
+			irlap_disconnect_indication( self, 
+						     LAP_RESET_INDICATION);
+			self->xmitflag = TRUE;
 		}
+		if (skb)
+			dev_kfree_skb( skb);
+		break;
+	case RECV_RNR_FRAME:
+		DEBUG( 4, "irlap_state_nrm_p: RECV_RNR_FRAME: Retrans:%d, "
+		       "nr=%d, va=%d, vs=%d, vr=%d\n",
+		       self->retry_count, info->nr, self->va, self->vs, 
+		       self->vr);
+
+		ASSERT( info != NULL, return -1;);
+
+		/* Stop final timer */
+		del_timer( &self->final_timer);
+		self->remote_busy = TRUE;
+
+		/* Update Nr received */
+		irlap_update_nr_received( self, info->nr);
+
+		irlap_next_state( self, LAP_XMIT_P);
+			
+		/* Start poll timer */
+		irlap_start_poll_timer( self, self->poll_timeout);
+
+		dev_kfree_skb( skb);
 		break;
 	case RECV_FRMR_RSP:
 		del_timer( &self->final_timer);
@@ -1322,8 +1332,8 @@
  *    awaiting reset of disconnect request.
  *
  */
-int irlap_state_reset_wait( struct irlap_cb *self, IRLAP_EVENT event, 
-			    struct sk_buff *skb, struct irlap_info *info)
+static int irlap_state_reset_wait(struct irlap_cb *self, IRLAP_EVENT event, 
+				  struct sk_buff *skb, struct irlap_info *info)
 {
 	int ret = 0;
 	
@@ -1368,19 +1378,19 @@
  *    reply.
  *
  */
-int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event, 
-		       struct sk_buff *skb, struct irlap_info *info)
+static int irlap_state_reset( struct irlap_cb *self, IRLAP_EVENT event, 
+			      struct sk_buff *skb, struct irlap_info *info)
 {
 	int ret = 0;
 	
-	DEBUG( 3, __FUNCTION__ "(), event = %s\n", irlap_event[event]);
+	DEBUG(3, __FUNCTION__ "(), event = %s\n", irlap_event[event]);
 	
-	ASSERT( self != NULL, return -1;);
-	ASSERT( self->magic == LAP_MAGIC, return -1;);
+	ASSERT(self != NULL, return -1;);
+	ASSERT(self->magic == LAP_MAGIC, return -1;);
 	
-	switch( event) {
+	switch(event) {
 	case RECV_DISC_FRAME:
-		del_timer( &self->final_timer);
+		del_timer(&self->final_timer);
 
 		irlap_apply_default_connection_parameters( self);
 
@@ -1398,8 +1408,10 @@
 		irlap_reset_confirm();
 		
 		self->remote_busy = FALSE;
-		irlap_start_poll_timer( self, self->poll_timeout);
+
 		irlap_next_state( self, LAP_XMIT_P);
+
+		irlap_start_poll_timer( self, self->poll_timeout);
 		break;
 	case FINAL_TIMER_EXPIRED:
 		if ( self->retry_count < 3) {
@@ -1540,53 +1552,8 @@
 	ASSERT( self != NULL, return -1;);
 	ASSERT( self->magic == LAP_MAGIC, return -1;);
 
-	switch( event) {
-	case RECV_RR_CMD:
-		self->retry_count = 0;
-
-		/* 
-		 *  Nr as expected? 
-		 */
-		nr_status = irlap_validate_nr_received( self, info->nr);
-		if ( nr_status == NR_EXPECTED) {
-			if (( skb_queue_len( &self->tx_list) > 0) && 
-			    ( self->window > 0)) {
-				self->remote_busy = FALSE;
-				
-				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
-				del_timer( &self->wd_timer);
-				
-				irlap_wait_min_turn_around( self, &self->qos_tx);
-				irlap_next_state( self, LAP_XMIT_S);
-			} else {			
-				self->remote_busy = FALSE;
-				/* Update Nr received */
-				irlap_update_nr_received( self, info->nr);
-				irlap_wait_min_turn_around( self, &self->qos_tx);
-				
-				irlap_send_rr_frame( self, RSP_FRAME);
-				
-				irlap_start_wd_timer( self, self->wd_timeout);
-				irlap_next_state( self, LAP_NRM_S);
-			}
-		} else if ( nr_status == NR_UNEXPECTED) {
-			self->remote_busy = FALSE;
-			irlap_update_nr_received( self, info->nr);
-			irlap_resend_rejected_frames( self, RSP_FRAME);
-
-			irlap_start_wd_timer( self, self->wd_timeout);
-
-			/* Keep state */
-			irlap_next_state( self, LAP_NRM_S); 
-		} else {
-			DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
-		} 
-		if ( skb)
-			dev_kfree_skb( skb);
-
-		break;
-	case RECV_I_CMD:
+	switch(event) {
+	case RECV_I_CMD: /* Optimize for the common case */
 		/* FIXME: must check for remote_busy below */
 		DEBUG( 4, __FUNCTION__ "(), event=%s nr=%d, vs=%d, ns=%d, "
 		       "vr=%d, pf=%d\n", irlap_event[event], info->nr, 
@@ -1765,6 +1732,51 @@
 			}
 		}
 		break;
+	case RECV_RR_CMD:
+		self->retry_count = 0;
+
+		/* 
+		 *  Nr as expected? 
+		 */
+		nr_status = irlap_validate_nr_received( self, info->nr);
+		if ( nr_status == NR_EXPECTED) {
+			if (( skb_queue_len( &self->tx_list) > 0) && 
+			    ( self->window > 0)) {
+				self->remote_busy = FALSE;
+				
+				/* Update Nr received */
+				irlap_update_nr_received( self, info->nr);
+				del_timer( &self->wd_timer);
+				
+				irlap_wait_min_turn_around( self, &self->qos_tx);
+				irlap_next_state( self, LAP_XMIT_S);
+			} else {			
+				self->remote_busy = FALSE;
+				/* Update Nr received */
+				irlap_update_nr_received( self, info->nr);
+				irlap_wait_min_turn_around( self, &self->qos_tx);
+				
+				irlap_send_rr_frame( self, RSP_FRAME);
+				
+				irlap_start_wd_timer( self, self->wd_timeout);
+				irlap_next_state( self, LAP_NRM_S);
+			}
+		} else if ( nr_status == NR_UNEXPECTED) {
+			self->remote_busy = FALSE;
+			irlap_update_nr_received( self, info->nr);
+			irlap_resend_rejected_frames( self, RSP_FRAME);
+
+			irlap_start_wd_timer( self, self->wd_timeout);
+
+			/* Keep state */
+			irlap_next_state( self, LAP_NRM_S); 
+		} else {
+			DEBUG(1, __FUNCTION__ "(), invalid nr not implemented!\n");
+		} 
+		if ( skb)
+			dev_kfree_skb( skb);
+
+		break;
 	case RECV_SNRM_CMD:
 		del_timer( &self->wd_timer);
 		DEBUG(1, __FUNCTION__ "(), received SNRM cmd\n");
@@ -1897,7 +1909,3 @@
 
 	return ret;
 }
-
-
-
-
diff -urN linux-2.2.7-pre3/net/irda/irlap_frame.c linux-2.2.7-pre4/net/irda/irlap_frame.c
--- linux-2.2.7-pre3/net/irda/irlap_frame.c	1999-04-16 08:20:23.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlap_frame.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 10:27:26 1997
- * Modified at:   Tue Apr  6 16:35:21 1999
+ * Modified at:   Fri Apr 23 09:30:42 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Resrved.
@@ -48,13 +48,10 @@
  *    need to do this since it's per packet relevant information.
  *
  */
-void irlap_insert_mtt( struct irlap_cb *self, struct sk_buff *skb)
+static inline void irlap_insert_mtt(struct irlap_cb *self, struct sk_buff *skb)
 {
 	struct irlap_skb_cb *cb;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-
 	cb = (struct irlap_skb_cb *) skb->cb;
 	
 	cb->magic = LAP_MAGIC;
@@ -71,8 +68,6 @@
 	
 	/* Reset XBOF's delay (used only for getting min turn time) */
 	self->xbofs_delay = 0;
-
-	DEBUG( 4, __FUNCTION__ "(), using %d xbofs\n", cb->xbofs);
 }
 
 /*
@@ -83,10 +78,11 @@
  */
 void irlap_queue_xmit(struct irlap_cb *self, struct sk_buff *skb)
 {
-	/* Some init stuff */
+	/* Some common init stuff */
 	skb->dev = self->netdev;
 	skb->h.raw = skb->nh.raw = skb->mac.raw = skb->data;
  	skb->protocol = htons(ETH_P_IRDA);
+	skb->priority = TC_PRIO_BESTEFFORT;
 
 	/* 
 	 * Insert MTT (min. turn time) into skb, so that the device driver 
@@ -534,13 +530,10 @@
  *    Build and transmit RR (Receive Ready) frame. Notice that it is currently
  *    only possible to send RR frames with the poll bit set.
  */
-void irlap_send_rr_frame( struct irlap_cb *self, int command) 
+void irlap_send_rr_frame(struct irlap_cb *self, int command) 
 {
-	struct sk_buff *skb = NULL;
+	struct sk_buff *skb;
 	__u8 *frame;
-	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
 
 	skb = dev_alloc_skb(32);
 	if (!skb)
@@ -553,8 +546,6 @@
 
 	frame[1] = RR | PF_BIT | (self->vr << 5);
 
-   	DEBUG(4, __FUNCTION__ "(), vr=%d, %ld\n", self->vr, jiffies); 
-
 	irlap_queue_xmit(self, skb);
 }
 
@@ -569,27 +560,7 @@
 				       struct sk_buff *skb, 
 				       struct irlap_info *info, int command)
 {
-	__u8 *frame;
-
-	frame = skb->data;
-	info->nr = frame[1] >> 5;
-
-	DEBUG(4, __FUNCTION__ "(), nr=%d, %ld\n", info->nr, jiffies);
-
-	/*
-	 *  Make sure the state-machine is in the right state for receiving, 
-	 *  if not, then we just discard the received frame for now!
-	 *  TODO: check if we should queue this frame, or make tty tell that
-	 *  it is receiving frames until the frame is delivered instead of
-	 *  until it is outside a frame.
-	 */
-#if 0
-	if ((self->state != LAP_NRM_P) && (self->state != LAP_NRM_S)) {
-		DEBUG(0, __FUNCTION__ "(), Wrong state, dropping frame!\n");
-		dev_kfree_skb(skb);
-		return;
-	}
-#endif
+	info->nr = skb->data[1] >> 5;
 
 	/* Check if this is a command or a response frame */
 	if (command)
@@ -676,16 +647,7 @@
 {
 	struct sk_buff *tx_skb;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-
-	/* Initialize variables */
-	tx_skb = NULL;
-
-	if ( skb->data[1] == I_FRAME) {
+	if (skb->data[1] == I_FRAME) {
 
 		/*  
 		 *  Insert frame sequence number (Vs) in control field before
@@ -693,10 +655,10 @@
 		 */
 		skb->data[1] = I_FRAME | (self->vs << 1);
 		
-		/* * Copy buffer */
-		tx_skb = skb_clone( skb, GFP_ATOMIC);
-		if ( tx_skb == NULL) {
-			dev_kfree_skb( skb);
+		/* Copy buffer */
+		tx_skb = skb_clone(skb, GFP_ATOMIC);
+		if (tx_skb == NULL) {
+			dev_kfree_skb(skb);
 			return;
 		}
 		
@@ -704,12 +666,12 @@
 		 *  make sure the skb->sk accounting of memory usage is sane
 		 */
 		if (skb->sk != NULL)
-			skb_set_owner_w( tx_skb, skb->sk);
+			skb_set_owner_w(tx_skb, skb->sk);
 		
 		/* 
 		 *  Insert frame in store, in case of retransmissions 
 		 */
-		skb_queue_tail( &self->wx_list, skb);
+		skb_queue_tail(&self->wx_list, skb);
 		
 		self->vs = (self->vs + 1) % 8;
 		self->ack_required = FALSE;		
@@ -718,7 +680,7 @@
 		irlap_send_i_frame( self, tx_skb, CMD_FRAME);
 	} else {
 		DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n");
-		irlap_send_ui_frame( self, skb, CMD_FRAME);
+		irlap_send_ui_frame(self, skb, CMD_FRAME);
 		self->window -= 1;
 	}
 }
@@ -731,17 +693,8 @@
 {
 	struct sk_buff *tx_skb;
 
-	DEBUG( 4, __FUNCTION__ "()\n");
-
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-
-	/* Initialize variables */
-	tx_skb = NULL;
-
 	/* Is this reliable or unreliable data? */
-	if ( skb->data[1] == I_FRAME) {
+	if (skb->data[1] == I_FRAME) {
 		
 		/*  
 		 *  Insert frame sequence number (Vs) in control field before
@@ -750,9 +703,9 @@
 		skb->data[1] = I_FRAME | (self->vs << 1);
 		
 		/* Copy buffer */
-		tx_skb = skb_clone( skb, GFP_ATOMIC);
-		if ( tx_skb == NULL) {
-			dev_kfree_skb( skb);
+		tx_skb = skb_clone(skb, GFP_ATOMIC);
+		if (tx_skb == NULL) {
+			dev_kfree_skb(skb);
 			return;
 		}
 		
@@ -760,20 +713,20 @@
 		 *  make sure the skb->sk accounting of memory usage is sane
 		 */
 		if (skb->sk != NULL)
-			skb_set_owner_w( tx_skb, skb->sk);
+			skb_set_owner_w(tx_skb, skb->sk);
 		
 		/* 
 		 *  Insert frame in store, in case of retransmissions 
 		 */
-		skb_queue_tail( &self->wx_list, skb);
+		skb_queue_tail(&self->wx_list, skb);
 		
 		/*  
 		 *  Set poll bit if necessary. We do this to the copied
 		 *  skb, since retransmitted need to set or clear the poll
-		 *  bit depending on when * they are sent.  
+		 *  bit depending on when they are sent.  
 		 */
 		/* Stop P timer */
-		del_timer( &self->poll_timer);
+		del_timer(&self->poll_timer);
 		
 		tx_skb->data[1] |= PF_BIT;
 		
@@ -781,24 +734,24 @@
 		self->ack_required = FALSE;
 		self->window = self->window_size;
 
-		irlap_start_final_timer( self, self->final_timeout);
+		irlap_start_final_timer(self, self->final_timeout);
 
-		irlap_send_i_frame( self, tx_skb, CMD_FRAME);
+		irlap_send_i_frame(self, tx_skb, CMD_FRAME);
 	} else {
-		DEBUG( 4, __FUNCTION__ "(), sending unreliable frame\n");
+		DEBUG(4, __FUNCTION__ "(), sending unreliable frame\n");
 
-		del_timer( &self->poll_timer);
+		del_timer(&self->poll_timer);
 
-		if ( self->ack_required) {
-			irlap_send_ui_frame( self, skb, CMD_FRAME);
-			irlap_send_rr_frame( self, CMD_FRAME);
+		if (self->ack_required) {
+			irlap_send_ui_frame(self, skb, CMD_FRAME);
+			irlap_send_rr_frame(self, CMD_FRAME);
 			self->ack_required = FALSE;
 		} else {
 			skb->data[1] |= PF_BIT;
-			irlap_send_ui_frame( self, skb, CMD_FRAME);
+			irlap_send_ui_frame(self, skb, CMD_FRAME);
 		}
 		self->window = self->window_size;
-		irlap_start_final_timer( self, self->final_timeout);
+		irlap_start_final_timer(self, self->final_timeout);
 	}
 }
 
@@ -926,7 +879,7 @@
 	ASSERT( self != NULL, return;);
 	ASSERT( self->magic == LAP_MAGIC, return;);
 
-	DEBUG( 4, __FUNCTION__ "(), retry_count=%d\n", self->retry_count);
+	DEBUG(2, __FUNCTION__ "(), retry_count=%d\n", self->retry_count);
 
 	/* Initialize variables */
 	skb = tx_skb = NULL;
@@ -939,7 +892,11 @@
 	while ( skb != NULL) {
 		irlap_wait_min_turn_around( self, &self->qos_tx);
 
-		tx_skb = skb_clone( skb, GFP_ATOMIC);
+		/* We copy the skb to be retransmitted since we will have to 
+		 * modify it. Cloning will confuse packet sniffers 
+		 */
+		/* tx_skb = skb_clone( skb, GFP_ATOMIC); */
+		tx_skb = skb_copy(skb, GFP_ATOMIC);
 		if ( tx_skb == NULL) {
 			/* Unlink tx_skb from list */
 			tx_skb->next = tx_skb->prev = NULL;
@@ -997,12 +954,12 @@
 			 *  If send window > 1 then send frame with pf 
 			 *  bit cleared
 			 */ 
-			if (( self->window > 1) && 
-			    skb_queue_len( &self->tx_list) > 0) 
+			if ((self->window > 1) && 
+			    skb_queue_len(&self->tx_list) > 0) 
 			{
-				irlap_send_data_primary( self, skb);
+				irlap_send_data_primary(self, skb);
 			} else {
-				irlap_send_data_primary_poll( self, skb);
+				irlap_send_data_primary_poll(self, skb);
 			}
 		}
 	}
@@ -1057,6 +1014,15 @@
 	/* Insert next to receive (Vr) */
 	frame[1] |= (self->vr << 5);  /* insert nr */
 
+#if 0
+	{
+		int ns;
+		ns = (frame[1] >> 1) & 0x07; /* Next to send */
+
+		DEBUG(0, __FUNCTION__ "(), ns=%d\n", ns);
+	}
+#endif
+
 	irlap_queue_xmit(self, skb);
 }
 
@@ -1070,30 +1036,13 @@
 				      struct sk_buff *skb, 
 				      struct irlap_info *info, int command) 
 {
-	__u8 *frame;
-
-	frame = skb->data;
-
-	info->nr = frame[1] >> 5;          /* Next to receive */
-	info->pf = frame[1] & PF_BIT;      /* Final bit */
-	info->ns = (frame[1] >> 1) & 0x07; /* Next to send */
+	info->nr = skb->data[1] >> 5;          /* Next to receive */
+	info->pf = skb->data[1] & PF_BIT;      /* Final bit */
+	info->ns = (skb->data[1] >> 1) & 0x07; /* Next to send */
 
  	DEBUG(4, __FUNCTION__"(), ns=%d, nr=%d, pf=%d, %ld\n", 
 	      info->ns, info->nr, info->pf>>4, jiffies); 
 
-	/*
-	 *  Make sure the state-machine is in the right state for receiving, 
-	 *  if not, then we just discard the received frame for now!
-	 *  TODO: check if we should queue this frame, or make tty tell that
-	 *  it is receiving frames until the frame is delivered instead of
-	 *  until it is outside a frame.
-	 */
-	if ((self->state != LAP_NRM_P) && ( self->state != LAP_NRM_S)) {
-		DEBUG(0, __FUNCTION__ "(), Wrong state, dropping frame!\n");
-		dev_kfree_skb(skb);
-		return;
-	}
-
 	/* Check if this is a command or a response frame */
 	if (command)
 		irlap_do_event(self, RECV_I_CMD, skb, info);
@@ -1266,7 +1215,7 @@
 
 	ASSERT( self != NULL, return -1;);
 	ASSERT( self->magic == LAP_MAGIC, return -1;);
-	ASSERT(( skb != NULL) && (skb->len > 1), return -1;);
+	ASSERT( skb->len > 1, return -1;);
 	
 	frame = skb->data;
 
diff -urN linux-2.2.7-pre3/net/irda/irlmp.c linux-2.2.7-pre4/net/irda/irlmp.c
--- linux-2.2.7-pre3/net/irda/irlmp.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlmp.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Stable.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 17 20:54:32 1997
- * Modified at:   Wed Apr  7 17:31:48 1999
+ * Modified at:   Fri Apr 23 09:13:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -719,9 +719,12 @@
  */
 void irlmp_discovery_request(int nslots)
 {
-
 	DEBUG(4, __FUNCTION__ "(), nslots=%d\n", nslots);
 
+	/* Check if user wants to override the default */
+	if (nslots == DISCOVERY_DEFAULT_SLOTS)
+		nslots = sysctl_discovery_slots;
+
 	/* 
 	 * If discovery is already running, then just return the current 
 	 * discovery log
@@ -877,10 +880,8 @@
  *    Send some data to peer device
  *
  */
-void irlmp_data_request( struct lsap_cb *self, struct sk_buff *skb) 
+void irlmp_data_request(struct lsap_cb *self, struct sk_buff *skb) 
 {
- 	DEBUG(4, __FUNCTION__ "()\n"); 
-
 	ASSERT(skb != NULL, return;);
 	ASSERT(self != NULL, return;);
 	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
@@ -898,14 +899,8 @@
  *    Got data from LAP layer so pass it up to upper layer
  *
  */
-void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) 
+inline void irlmp_data_indication(struct lsap_cb *self, struct sk_buff *skb) 
 {
- 	DEBUG(4, __FUNCTION__ "()\n"); 
-
-	ASSERT(self != NULL, return;);
-	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT(skb != NULL, return;);
-
 	/* Hide LMP header from layer above */
 	skb_pull(skb, LMP_HEADER);
 
diff -urN linux-2.2.7-pre3/net/irda/irlmp_event.c linux-2.2.7-pre4/net/irda/irlmp_event.c
--- linux-2.2.7-pre3/net/irda/irlmp_event.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlmp_event.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Thu Apr  8 16:26:41 1999
+ * Modified at:   Fri Apr 23 08:57:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -114,16 +114,16 @@
 };
 
 /* Do connection control events */
-void irlmp_do_lsap_event( struct lsap_cb *self, IRLMP_EVENT event, 
-			  struct sk_buff *skb)
+void irlmp_do_lsap_event(struct lsap_cb *self, IRLMP_EVENT event, 
+			 struct sk_buff *skb)
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
 
-	DEBUG( 4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
-	       irlmp_event[ event], irlmp_state[ self->lsap_state]);
+	DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
+	      irlmp_event[ event], irlmp_state[ self->lsap_state]);
 
-	(*lsap_state[ self->lsap_state]) ( self, event, skb);
+	(*lsap_state[self->lsap_state]) (self, event, skb);
 }
 
 /*
@@ -132,23 +132,21 @@
  *    Do IrLAP control events
  *
  */
-void irlmp_do_lap_event( struct lap_cb *self, IRLMP_EVENT event, 
-			 struct sk_buff *skb) 
+void irlmp_do_lap_event(struct lap_cb *self, IRLMP_EVENT event, 
+			struct sk_buff *skb) 
 {
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
 	
-	DEBUG( 4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
-	       irlmp_event[event], 
-	       irlmp_state[self->lap_state]);
+	DEBUG(4, __FUNCTION__ "(), EVENT = %s, STATE = %s\n",
+	      irlmp_event[event], 
+	      irlmp_state[self->lap_state]);
 
-	(*lap_state[ self->lap_state]) ( self, event, skb);
+	(*lap_state[self->lap_state]) (self, event, skb);
 }
 
 void irlmp_discovery_timer_expired( unsigned long data)
 {
-/* 	struct irlmp_cb *self = ( struct irlmp_cb *) data; */
-	
 	DEBUG(4, "IrLMP, discovery timer expired!\n");
 	
 	if (sysctl_discovery)
@@ -306,8 +304,8 @@
  *    ACTIVE, IrLAP connection is active
  *
  */
-static void irlmp_state_active( struct lap_cb *self, IRLMP_EVENT event, 
-				struct sk_buff *skb)
+static void irlmp_state_active(struct lap_cb *self, IRLMP_EVENT event, 
+			       struct sk_buff *skb)
 {
 	struct lsap_cb *lsap;
 	struct lsap_cb *lsap_current;
@@ -343,7 +341,7 @@
 		/* Keep state */
 		break;
 	case LM_LAP_DISCONNECT_REQUEST:
-		DEBUG( 4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
+		DEBUG(4, __FUNCTION__ "(), LM_LAP_DISCONNECT_REQUEST\n");
 
 		/*
 		 *  Need to find out if we should close IrLAP or not. If there
@@ -357,7 +355,7 @@
 		break;
 	case LM_LAP_IDLE_TIMEOUT:
 		if (hashbin_get_size(self->lsaps) == 0) {
-			DEBUG(0, __FUNCTION__ 
+			DEBUG(2, __FUNCTION__ 
 			      "(), no more LSAPs so time to close IrLAP\n");
 			irlmp_next_lap_state(self, LAP_STANDBY);
 			
@@ -365,7 +363,7 @@
 		}
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
-		DEBUG( 4, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n");
+		DEBUG(4, __FUNCTION__ "(), IRLAP_DISCONNECT_INDICATION\n");
 	
 		irlmp_next_lap_state( self, LAP_STANDBY);		
 		
@@ -525,18 +523,36 @@
  *    DATA_TRANSFER_READY
  *
  */
-static void irlmp_state_dtr( struct lsap_cb *self, IRLMP_EVENT event, 
-			     struct sk_buff *skb) 
+static void irlmp_state_dtr(struct lsap_cb *self, IRLMP_EVENT event, 
+			    struct sk_buff *skb) 
 {
 	LM_REASON reason;
 
- 	DEBUG( 4, __FUNCTION__ "()\n");
+ 	DEBUG(4, __FUNCTION__ "()\n");
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LSAP_MAGIC, return;);
-	ASSERT( self->lap != NULL, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LSAP_MAGIC, return;);
+	ASSERT(self->lap != NULL, return;);
 
-	switch( event) {
+	switch (event) {
+	case LM_DATA_REQUEST: /* Optimize for the common case */
+		irlmp_send_data_pdu(self->lap, self->dlsap_sel, 
+				    self->slsap_sel, FALSE, skb);
+		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
+		break;
+	case LM_DATA_INDICATION: /* Optimize for the common case */
+		irlmp_data_indication(self, skb); 
+		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
+		break;
+	case LM_UDATA_REQUEST:
+		ASSERT(skb != NULL, return;);
+		irlmp_send_data_pdu(self->lap, self->dlsap_sel, 
+				    self->slsap_sel, TRUE, skb);
+		break;
+	case LM_UDATA_INDICATION:
+		irlmp_udata_indication(self, skb); 
+		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
+		break;
 	case LM_CONNECT_REQUEST:
 		DEBUG(0, __FUNCTION__ "(), LM_CONNECT_REQUEST, "
 		      "error, LSAP already connected\n");
@@ -548,65 +564,45 @@
 		/* Keep state */
 		break;
 	case LM_DISCONNECT_REQUEST:
-		ASSERT( skb != NULL, return;);
+		ASSERT(skb != NULL, return;);
 
-		irlmp_send_lcf_pdu( self->lap, self->dlsap_sel, 
-				    self->slsap_sel, DISCONNECT, skb);
-		irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+		irlmp_send_lcf_pdu(self->lap, self->dlsap_sel, 
+				   self->slsap_sel, DISCONNECT, skb);
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 		
 		/* Try to close the LAP connection if its still there */
-		if ( self->lap) {
-			DEBUG( 4, __FUNCTION__ "(), trying to close IrLAP\n");
-			irlmp_do_lap_event( self->lap, 
-					    LM_LAP_DISCONNECT_REQUEST, 
-					    NULL);
+		if (self->lap) {
+			DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
+			irlmp_do_lap_event(self->lap, 
+					   LM_LAP_DISCONNECT_REQUEST, 
+					   NULL);
 		}
-
-		break;
-	case LM_DATA_REQUEST:
-		ASSERT( skb != NULL, return;);
-		irlmp_send_data_pdu( self->lap, self->dlsap_sel, 
-				     self->slsap_sel, FALSE, skb);
-		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
-		break;
-	case LM_UDATA_REQUEST:
-		ASSERT( skb != NULL, return;);
-		irlmp_send_data_pdu( self->lap, self->dlsap_sel, 
-				     self->slsap_sel, TRUE, skb);
-		break;
-	case LM_DATA_INDICATION:
-		irlmp_data_indication( self, skb); 
-		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
-		break;
-	case LM_UDATA_INDICATION:
-		irlmp_udata_indication( self, skb); 
-		/* irlmp_next_lsap_state( DATA_TRANSFER_READY, info->handle);*/
 		break;
 	case LM_LAP_DISCONNECT_INDICATION:
-		irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 
-		reason = irlmp_convert_lap_reason( self->lap->reason);
+		reason = irlmp_convert_lap_reason(self->lap->reason);
 
-		irlmp_disconnect_indication( self, reason, NULL);
+		irlmp_disconnect_indication(self, reason, NULL);
 		break;
 	case LM_DISCONNECT_INDICATION:
-		irlmp_next_lsap_state( self, LSAP_DISCONNECTED);
+		irlmp_next_lsap_state(self, LSAP_DISCONNECTED);
 			
-		ASSERT( self->lap != NULL, return;);
-		ASSERT( self->lap->magic == LMP_LAP_MAGIC, return;);
+		ASSERT(self->lap != NULL, return;);
+		ASSERT(self->lap->magic == LMP_LAP_MAGIC, return;);
 	
 		ASSERT(skb != NULL, return;);
 		ASSERT(skb->len > 3, return;);
 		reason = skb->data[3];
 
 		 /* Try to close the LAP connection */
-		DEBUG( 4, __FUNCTION__ "(), trying to close IrLAP\n");
+		DEBUG(4, __FUNCTION__ "(), trying to close IrLAP\n");
 		irlmp_do_lap_event(self->lap, LM_LAP_DISCONNECT_REQUEST, NULL);
 
-		irlmp_disconnect_indication( self, reason, skb);
+		irlmp_disconnect_indication(self, reason, skb);
 		break;
 	default:
-		DEBUG( 4, __FUNCTION__ "(), Unknown event %d\n", event);
+		DEBUG(4, __FUNCTION__ "(), Unknown event %d\n", event);
 		break;	
 	}	
 }
diff -urN linux-2.2.7-pre3/net/irda/irlmp_frame.c linux-2.2.7-pre4/net/irda/irlmp_frame.c
--- linux-2.2.7-pre3/net/irda/irlmp_frame.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlmp_frame.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Aug 19 02:09:59 1997
- * Modified at:   Tue Apr  6 18:31:11 1999
+ * Modified at:   Fri Apr 23 09:12:23 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>
@@ -34,30 +34,24 @@
 #include <net/irda/irlmp_frame.h>
 #include <net/irda/discovery.h>
 
-static struct lsap_cb *irlmp_find_lsap( struct lap_cb *self, __u8 dlsap, 
-					__u8 slsap, int status, hashbin_t *);
+static struct lsap_cb *irlmp_find_lsap(struct lap_cb *self, __u8 dlsap, 
+				       __u8 slsap, int status, hashbin_t *);
 
-inline void irlmp_send_data_pdu( struct lap_cb *self, __u8 dlsap, __u8 slsap,
-				 int expedited, struct sk_buff *skb)
+inline void irlmp_send_data_pdu(struct lap_cb *self, __u8 dlsap, __u8 slsap,
+				int expedited, struct sk_buff *skb)
 {
 	__u8 *frame;
 
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-
 	frame = skb->data;
 
 	frame[0] = dlsap;
 	frame[1] = slsap;
 
-	if ( expedited) {
+	if (expedited) {
 		DEBUG( 4, __FUNCTION__ "(), sending expedited data\n");
 		irlap_data_request( self->irlap, skb, FALSE);
-	} else {
-		DEBUG( 4, __FUNCTION__ "(), sending reliable data\n");
-		irlap_data_request( self->irlap, skb, TRUE);	
-	}
+	} else
+		irlap_data_request( self->irlap, skb, TRUE);
 }
 
 /*
@@ -98,18 +92,17 @@
  *    Used by IrLAP to pass received data frames to IrLMP layer
  *
  */
-void irlmp_link_data_indication( struct lap_cb *self, int reliable, 
-				 struct sk_buff *skb)
+void irlmp_link_data_indication(struct lap_cb *self, int reliable, 
+			        struct sk_buff *skb)
 {
-	__u8 *fp;
-	__u8  slsap_sel;   /* Source (this) LSAP address */
-	__u8  dlsap_sel;   /* Destination LSAP address */
 	struct lsap_cb *lsap;
+	__u8   slsap_sel;   /* Source (this) LSAP address */
+	__u8   dlsap_sel;   /* Destination LSAP address */
+	__u8   *fp;
 	
-	ASSERT( self != NULL, return;);
-	ASSERT( self->magic == LMP_LAP_MAGIC, return;);
-	ASSERT( skb != NULL, return;);
-	ASSERT( skb->len > 2, return;);
+	ASSERT(self != NULL, return;);
+	ASSERT(self->magic == LMP_LAP_MAGIC, return;);
+	ASSERT(skb->len > 2, return;);
 
 	fp = skb->data;
 
@@ -124,7 +117,7 @@
 	 *  Check if this is an incoming connection, since we must deal with
 	 *  it in a different way than other established connections.
 	 */
-	if ((fp[0] & CONTROL_BIT) && ( fp[2] == CONNECT_CMD)) {
+	if ((fp[0] & CONTROL_BIT) && (fp[2] == CONNECT_CMD)) {
 		DEBUG(3,"Incoming connection, source LSAP=%d, dest LSAP=%d\n",
 		      slsap_sel, dlsap_sel);
 		
@@ -184,10 +177,17 @@
 			break;
 		}
 	} else if (reliable == LAP_RELIABLE) {
-		/* Must be pure data */
-		irlmp_do_lsap_event( lsap, LM_DATA_INDICATION, skb);
+		/* Optimize and bypass the state machine if possible */
+		if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
+			irlmp_data_indication(lsap, skb);
+		else
+			irlmp_do_lsap_event(lsap, LM_DATA_INDICATION, skb);
 	} else if (reliable == LAP_UNRELIABLE) {
-		irlmp_do_lsap_event( lsap, LM_UDATA_INDICATION, skb);
+		/* Optimize and bypass the state machine if possible */
+		if (lsap->lsap_state == LSAP_DATA_TRANSFER_READY)
+			irlmp_data_indication(lsap, skb);
+		else
+			irlmp_do_lsap_event(lsap, LM_UDATA_INDICATION, skb);
 	}
 }
 
@@ -297,8 +297,6 @@
 	irlmp_add_discovery_log(irlmp->cachelog, log);
       
 	irlmp_do_lap_event(self, LM_LAP_DISCOVERY_CONFIRM, NULL);
-
-	DEBUG( 4, __FUNCTION__ "() -->\n");
 }
 
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
@@ -324,36 +322,31 @@
 {
 	struct lsap_cb *lsap;
 	
-	ASSERT( self != NULL, return NULL;);
-	ASSERT( self->magic == LMP_LAP_MAGIC, return NULL;);
-
 	/* 
 	 *  Optimize for the common case. We assume that the last frame
 	 *  received is in the same connection as the last one, so check in
 	 *  cache first to avoid the linear search
 	 */
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
-	if (( irlmp->cache.valid) && 
-	    ( irlmp->cache.slsap_sel == slsap_sel) && 
-	    ( irlmp->cache.dlsap_sel == dlsap_sel)) 
+	if ((irlmp->cache.valid) && 
+	    (irlmp->cache.slsap_sel == slsap_sel) && 
+	    (irlmp->cache.dlsap_sel == dlsap_sel)) 
 	{
 		return (irlmp->cache.lsap);
 	}
 #endif
-	lsap = ( struct lsap_cb *) hashbin_get_first(queue);
-	while ( lsap != NULL) {
+	lsap = (struct lsap_cb *) hashbin_get_first(queue);
+	while (lsap != NULL) {
 		/* 
 		 *  If this is an incomming connection, then the destination 
 		 *  LSAP selector may have been specified as LM_ANY so that 
 		 *  any client can connect. In that case we only need to check
 		 *  if the source LSAP (in our view!) match!
 		 */
-		if (( status == CONNECT_CMD) && 
-		    ( lsap->slsap_sel == slsap_sel) &&      
-		    ( lsap->dlsap_sel == LSAP_ANY)) 
+		if ((status == CONNECT_CMD) && 
+		    (lsap->slsap_sel == slsap_sel) &&      
+		    (lsap->dlsap_sel == LSAP_ANY)) 
 		{
-			DEBUG( 4,"Incoming connection: Setting dlsap_sel=%d\n",
-			       dlsap_sel);
 			lsap->dlsap_sel = dlsap_sel;
 			
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
@@ -364,15 +357,15 @@
 		/*
 		 *  Check if source LSAP and dest LSAP selectors match.
 		 */
-		if (( lsap->slsap_sel == slsap_sel) && 
-		    ( lsap->dlsap_sel == dlsap_sel)) 
+		if ((lsap->slsap_sel == slsap_sel) && 
+		    (lsap->dlsap_sel == dlsap_sel)) 
 		{
 #ifdef CONFIG_IRDA_CACHE_LAST_LSAP
-			irlmp_update_cache( lsap);
+			irlmp_update_cache(lsap);
 #endif
 			return lsap;
 		}
-		lsap = ( struct lsap_cb *) hashbin_get_next( queue);
+		lsap = ( struct lsap_cb *) hashbin_get_next(queue);
 	}
 
 	/* Sorry not found! */
diff -urN linux-2.2.7-pre3/net/irda/irlpt/irlpt_cli.c linux-2.2.7-pre4/net/irda/irlpt/irlpt_cli.c
--- linux-2.2.7-pre3/net/irda/irlpt/irlpt_cli.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irlpt/irlpt_cli.c	2003-08-15 15:05:52.000000000 -0700
@@ -518,8 +518,8 @@
  *    Fixed to match changes in iriap.h, DB.
  *
  */
-void irlpt_client_get_value_confirm(__u16 obj_id, struct ias_value *value, 
-				    void *priv)
+void irlpt_client_get_value_confirm(int result, __u16 obj_id, 
+				    struct ias_value *value, void *priv)
 {
 	struct irlpt_info info;
 	struct irlpt_cb *self;
@@ -534,7 +534,7 @@
 	ASSERT( self->magic == IRLPT_MAGIC, return;);
 
 	/* Check if request succeeded */
-	if ( !value) {
+	if (result != IAS_SUCCESS) {
 		DEBUG( 0, __FUNCTION__ "(), got NULL value!\n");
 		irlpt_client_do_event( self, IAS_PROVIDER_NOT_AVAIL, NULL, 
 				       &info);
diff -urN linux-2.2.7-pre3/net/irda/irmod.c linux-2.2.7-pre4/net/irda/irmod.c
--- linux-2.2.7-pre3/net/irda/irmod.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irmod.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Dec 15 13:55:39 1997
- * Modified at:   Mon Mar 29 09:06:52 1999
+ * Modified at:   Mon Apr 12 11:31:01 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
@@ -50,12 +50,12 @@
 struct irda_cb irda; /* One global instance */
 
 #ifdef CONFIG_IRDA_DEBUG
-__u32 irda_debug = IRDA_DEBUG;
+__u32 irda_debug = IRDA_DEBUG_LEVEL;
 #endif
 
 extern void irda_proc_register(void);
 extern void irda_proc_unregister(void);
-extern int irda_sysctl_register(void);
+extern int  irda_sysctl_register(void);
 extern void irda_sysctl_unregister(void);
 
 extern void irda_proto_init(struct net_proto *pro);
@@ -267,22 +267,6 @@
 #endif /* MODULE */
 
 /*
- * Function irda_lock (lock)
- *
- *    Lock variable. Returns false if the lock is already set.
- *    
- */
-inline int irda_lock(int *lock) 
-{
-	if (test_and_set_bit( 0, (void *) lock))  {
-		DEBUG(3, __FUNCTION__ 
-		      "(), Trying to lock, already locked variable!\n");
-		return FALSE;
-        }  
-	return TRUE;
-}
-
-/*
  * Function irda_unlock (lock)
  *
  *    Unlock variable. Returns false if lock is already unlocked
diff -urN linux-2.2.7-pre3/net/irda/irsysctl.c linux-2.2.7-pre4/net/irda/irsysctl.c
--- linux-2.2.7-pre3/net/irda/irsysctl.c	1999-03-07 15:26:44.000000000 -0800
+++ linux-2.2.7-pre4/net/irda/irsysctl.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun May 24 22:12:06 1998
- * Modified at:   Mon Jan 25 13:55:54 1999
+ * Modified at:   Fri Apr 23 09:46:38 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1997 Dag Brattli, All Rights Reserved.
@@ -36,6 +36,7 @@
 extern int sysctl_discovery;
 extern int sysctl_discovery_slots;
 extern int sysctl_slot_timeout;
+extern int sysctl_fast_poll_increase;
 int sysctl_compression = 0;
 extern char sysctl_devname[];
 
@@ -52,7 +53,11 @@
 	{ COMPRESSION, "compression", &sysctl_compression,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 #ifdef CONFIG_IRDA_DEBUG
-	{ DEBUG, "debug", &irda_debug,
+        { DEBUG, "debug", &irda_debug,
+	  sizeof(int), 0644, NULL, &proc_dointvec },
+#endif
+#ifdef CONFIG_IRDA_FAST_RR
+        { SLOTS, "fast_poll_increase", &sysctl_fast_poll_increase,
 	  sizeof(int), 0644, NULL, &proc_dointvec },
 #endif
 	{ SLOTS, "discovery_slots", &sysctl_discovery_slots,
diff -urN linux-2.2.7-pre3/net/irda/irttp.c linux-2.2.7-pre4/net/irda/irttp.c
--- linux-2.2.7-pre3/net/irda/irttp.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/irttp.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Sun Aug 31 20:14:31 1997
- * Modified at:   Thu Mar 25 10:27:08 1999
+ * Modified at:   Sat Apr 10 10:32:21 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -28,6 +28,7 @@
 #include <linux/init.h>
 
 #include <asm/byteorder.h>
+#include <asm/unaligned.h>
 
 #include <net/irda/irda.h>
 #include <net/irda/irmod.h>
@@ -639,7 +640,6 @@
 			  struct sk_buff *userdata) 
 {
 	struct sk_buff *skb;
-	__u16 tmp_be;
 	__u8 *frame;
 	__u8 n;
 	
@@ -703,8 +703,8 @@
 		frame[2] = 0x01; /* MaxSduSize */
 		frame[3] = 0x02; /* Value length */
 
-		tmp_be = cpu_to_be16((__u16) max_sdu_size);
-		memcpy(frame+4, &tmp_be, 2);
+		put_unaligned(cpu_to_be16((__u16) max_sdu_size), 
+			      (__u16 *)(frame+4));
 	} else {
 		/* Insert plain TTP header */
 		frame = skb_push(skb, TTP_HEADER);
@@ -728,11 +728,10 @@
 			   __u32 max_seg_size, struct sk_buff *skb) 
 {
 	struct tsap_cb *self;
-	__u16 tmp_cpu;
-	__u8 *frame;
-	__u8 n;
 	int parameters;
+	__u8 *frame;
 	__u8 plen, pi, pl;
+	__u8 n;
 
 	DEBUG(4, __FUNCTION__ "()\n");
 	
@@ -770,14 +769,26 @@
 		pi   = frame[2];
 		pl   = frame[3];
 
-		ASSERT(pl == 2, return;);
-
-		memcpy(&tmp_cpu, frame+4, 2); /* Align value */
-		be16_to_cpus(&tmp_cpu);       /* Convert to host order */
-		self->tx_max_sdu_size = tmp_cpu;
+		switch (pl) {
+		case 1:
+			self->tx_max_sdu_size = *(frame+4);
+			break;
+		case 2:
+			self->tx_max_sdu_size = 
+				be16_to_cpu(get_unaligned((__u16 *)(frame+4)));
+			break;
+		case 4:
+			self->tx_max_sdu_size = 
+				be32_to_cpu(get_unaligned((__u32 *)(frame+4)));
+			break;
+		default:
+			printk(KERN_ERR __FUNCTION__ 
+			       "() illegal value length for max_sdu_size!\n");
+			self->tx_max_sdu_size = 0;
+		};
 
 		DEBUG(4, __FUNCTION__ "(), RxMaxSduSize=%d\n", 
-		       self->tx_max_sdu_size);
+		      self->tx_max_sdu_size);
 	}
 	
 	DEBUG(4, __FUNCTION__ "() send=%d,avail=%d,remote=%d\n", 
@@ -804,11 +815,10 @@
 {
 	struct tsap_cb *self;
 	struct lsap_cb *lsap;
-	__u16 tmp_cpu;
-	__u8 *frame;
 	int parameters;
-	int n;
+	__u8 *frame;
 	__u8 plen, pi, pl;
+	__u8 n;
 
 	self = (struct tsap_cb *) instance;
 
@@ -818,9 +828,6 @@
 
 	lsap = (struct lsap_cb *) sap;
 
-	/* FIXME: just remove this when we know its working */
-	ASSERT(max_seg_size == qos->data_size.value, return;);
-
 	self->max_seg_size = max_seg_size-LMP_HEADER-LAP_HEADER;
 
 	DEBUG(4, __FUNCTION__ "(), TSAP sel=%02x\n", self->stsap_sel);
@@ -836,18 +843,31 @@
 	
 	parameters = frame[0] & 0x80;	
 	if (parameters) {
-		DEBUG(4, __FUNCTION__ "(), Contains parameters!\n");
+		DEBUG(3, __FUNCTION__ "(), Contains parameters!\n");
 		plen = frame[1];
 		pi   = frame[2];
 		pl   = frame[3];
 
-		ASSERT(pl == 2, return;);
+		switch (pl) {
+		case 1:
+			self->tx_max_sdu_size = *(frame+4);
+			break;
+		case 2:
+			self->tx_max_sdu_size = 
+				be16_to_cpu(get_unaligned((__u16 *)(frame+4)));
+			break;
+		case 4:
+			self->tx_max_sdu_size = 
+				be32_to_cpu(get_unaligned((__u32 *)(frame+4)));
+			break;
+		default:
+			printk(KERN_ERR __FUNCTION__ 
+			       "() illegal value length for max_sdu_size!\n");
+			self->tx_max_sdu_size = 0;
+		};
 
-		memcpy(&tmp_cpu, frame+4, 2); /* Align value */
-		be16_to_cpus(&tmp_cpu);       /* Convert to host order */
 
-		self->tx_max_sdu_size = tmp_cpu;
-		DEBUG(4, __FUNCTION__ "(), MaxSduSize=%d\n", 
+		DEBUG(3, __FUNCTION__ "(), MaxSduSize=%d\n", 
 		      self->tx_max_sdu_size);
 	}
 
@@ -873,7 +893,6 @@
 			    struct sk_buff *userdata)
 {
 	struct sk_buff *skb;
-	__u32 tmp_be;
 	__u8 *frame;
 	__u8 n;
 
@@ -932,8 +951,8 @@
 		frame[2] = 0x01; /* MaxSduSize */
 		frame[3] = 0x02; /* Value length */
 
-		tmp_be = cpu_to_be16((__u16)max_sdu_size);
-		memcpy(frame+4, &tmp_be, 2);
+		put_unaligned(cpu_to_be16((__u16) max_sdu_size), 
+			      (__u16 *)(frame+4));
 	} else {
 		/* Insert TTP header */
 		frame = skb_push(skb, TTP_HEADER);
diff -urN linux-2.2.7-pre3/net/irda/qos.c linux-2.2.7-pre4/net/irda/qos.c
--- linux-2.2.7-pre3/net/irda/qos.c	1999-03-07 15:26:44.000000000 -0800
+++ linux-2.2.7-pre4/net/irda/qos.c	2003-08-15 15:05:52.000000000 -0700
@@ -6,7 +6,7 @@
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Tue Sep  9 00:00:26 1997
- * Modified at:   Mon Feb  1 09:56:21 1999
+ * Modified at:   Mon Apr 12 11:49:24 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, All Rights Reserved.
@@ -70,7 +70,7 @@
 	qos->compression.bits     &= new->compression.bits;
 #endif
 
-	irda_qos_bits_to_value( qos);
+	irda_qos_bits_to_value(qos);
 }
 
 /*
diff -urN linux-2.2.7-pre3/net/irda/wrapper.c linux-2.2.7-pre4/net/irda/wrapper.c
--- linux-2.2.7-pre3/net/irda/wrapper.c	1999-04-15 05:42:42.000000000 -0700
+++ linux-2.2.7-pre4/net/irda/wrapper.c	2003-08-15 15:05:52.000000000 -0700
@@ -1,12 +1,12 @@
 /*********************************************************************
  *                
  * Filename:      wrapper.c
- * Version:       1.0
+ * Version:       1.1
  * Description:   SIR wrapper layer
  * Status:        Experimental.
  * Author:        Dag Brattli <dagb@cs.uit.no>
  * Created at:    Mon Aug  4 20:40:53 1997
- * Modified at:   Fri Mar 26 21:52:53 1999
+ * Modified at:   Wed Apr 21 12:45:55 1999
  * Modified by:   Dag Brattli <dagb@cs.uit.no>
  * 
  *     Copyright (c) 1998 Dag Brattli <dagb@cs.uit.no>, 
@@ -34,9 +34,7 @@
 #include <net/irda/irlap_frame.h>
 #include <net/irda/irda_device.h>
 
-#define MIN_LENGTH 14
-
-inline static int stuff_byte( __u8 byte, __u8 *buf);
+inline static int stuff_byte(__u8 byte, __u8 *buf);
 
 /*
  * Function async_wrap (skb, *tx_buff)
@@ -44,17 +42,17 @@
  *    Makes a new buffer with wrapping and stuffing, should check that 
  *    we don't get tx buffer overflow.
  */
-int async_wrap_skb( struct sk_buff *skb, __u8 *tx_buff, int buffsize)
+int async_wrap_skb(struct sk_buff *skb, __u8 *tx_buff, int buffsize)
 {
-	__u8 byte;
-	int i, n;
+ 	int i;
+	int n;
 	int xbofs;
 	union {
 		__u16 value;
 		__u8 bytes[2];
 	} fcs;
 
-	ASSERT( skb != NULL, return 0;);
+	ASSERT(skb != NULL, return 0;);
 
 	/* Initialize variables */
 	fcs.value = INIT_FCS;
@@ -72,33 +70,31 @@
 	 */
 	if (((struct irlap_skb_cb *)(skb->cb))->magic != LAP_MAGIC) {
 		DEBUG(1, __FUNCTION__ "(), wrong magic in skb!\n");
-		xbofs = 11;
+		xbofs = 10;
 	} else
 		xbofs = ((struct irlap_skb_cb *)(skb->cb))->xbofs;
 
-	for (i=0; i<xbofs; i++) {
- 		tx_buff[n++] = XBOF; 
- 	}
-
+#if 0
+ 	for (i=0; i<xbofs; i++)
+  		tx_buff[n++] = XBOF;
+#else
+	memset(tx_buff+n, XBOF, xbofs);
+	n += xbofs;
+#endif
 	/* Start of packet character BOF */
 	tx_buff[n++] = BOF;
 
 	/* Insert frame and calc CRC */
 	for (i=0; i < skb->len; i++) {
-		byte = skb->data[i];
-		
 		/*
 		 *  Check for the possibility of tx buffer overflow. We use
 		 *  bufsize-5 since the maximum number of bytes that can be 
 		 *  transmitted after this point is 5.
 		 */
-		if ( n > buffsize-5) {
-			printk( KERN_WARNING 
-				"IrDA Wrapper: TX-buffer overflow!\n");
-			return n;
-		}
-		n+=stuff_byte( byte, tx_buff+n);
-		fcs.value = IR_FCS( fcs.value, byte);
+		ASSERT(n < (buffsize-5), return n;);
+
+		n += stuff_byte(skb->data[i], tx_buff+n);
+		fcs.value = IR_FCS(fcs.value, skb->data[i]);
 	}
 	
 	/* Insert CRC in little endian format (LSB first) */
@@ -111,7 +107,16 @@
 	n += stuff_byte(fcs.bytes[0], tx_buff+n);
 #endif
 	tx_buff[n++] = EOF;
-	
+
+#if 0
+	{
+		int i;
+		
+		for (i=0;i<n;i++)
+			printk("%02x", tx_buff[i]);
+		printk("\n");
+	}
+#endif
 	return n;
 }
 
@@ -121,10 +126,10 @@
  *    Got a frame, make a copy of it, and pass it up the stack!
  *
  */
-static inline void async_bump( struct irda_device *idev, __u8 *buf, int len)
+static inline void async_bump(struct irda_device *idev, __u8 *buf, int len)
 {
        	struct sk_buff *skb;
- 
+
 	skb = dev_alloc_skb(len+1);
 	if (!skb)  {
 		idev->stats.rx_dropped++;
@@ -132,18 +137,14 @@
 	}
 
 	/*  Align IP header to 20 bytes */
-	skb_reserve( skb, 1);
+	skb_reserve(skb, 1);
 	
-	ASSERT( len-2 > 0, return;);
-
         /* Copy data without CRC */
-	skb_put( skb, len-2);
-	memcpy( skb->data, buf, len-2); 
+	memcpy(skb_put(skb, len-2), buf, len-2); 
 	
 	/* 
 	 *  Feed it to IrLAP layer 
 	 */
-	/* memcpy(skb_put(skb,count), ax->rbuff, count); */
 	skb->dev = &idev->netdev;
 	skb->mac.raw  = skb->data;
 	skb->protocol = htons(ETH_P_IRDA);
@@ -159,18 +160,18 @@
  *    Parse and de-stuff frame received from the IR-port
  *
  */
-void async_unwrap_char( struct irda_device *idev, __u8 byte) 
+void async_unwrap_char(struct irda_device *idev, __u8 byte) 
 {
 	/* State machine for receiving frames */	   
-	switch( idev->rx_buff.state) {
+	switch (idev->rx_buff.state) {
 	case OUTSIDE_FRAME:
-		switch( byte) {
+		switch(byte) {
 		case BOF:
 			idev->rx_buff.state = BEGIN_FRAME;
 			idev->rx_buff.in_frame = TRUE;
 			break;
 		case XBOF:
-			idev->xbofs++;
+			/* idev->xbofs++; */
 			break;
 		case EOF:
 			irda_device_set_media_busy( idev, TRUE);
@@ -180,9 +181,8 @@
 		}
 		break;
 	case BEGIN_FRAME:
-		switch ( byte) {
+		switch (byte) {
 		case BOF:
-			
 			/* Continue */
 			break;
 		case CE:
@@ -198,28 +198,29 @@
 			break;
 		default:
 			/* Got first byte of frame */
-			idev->rx_buff.data[ idev->rx_buff.len++] = byte;
+			idev->rx_buff.data = idev->rx_buff.head;
+			idev->rx_buff.len = 0;
+
+			idev->rx_buff.data[idev->rx_buff.len++] = byte;
 			
-			idev->rx_buff.fcs = IR_FCS( INIT_FCS, byte);
+			idev->rx_buff.fcs = IR_FCS(INIT_FCS, byte);
 			idev->rx_buff.state = INSIDE_FRAME;
 			break;
 		}
 		break;
 	case LINK_ESCAPE:
-		switch ( byte) {
+		switch (byte) {
 		case BOF:
 			/* New frame? */
 			idev->rx_buff.state = BEGIN_FRAME;
-			idev->rx_buff.len = 0;
-			irda_device_set_media_busy( idev, TRUE);
+			irda_device_set_media_busy(idev, TRUE);
 			break;
 		case CE:
-			DEBUG( 4, "WARNING: State not defined\n");
+			DEBUG(4, "WARNING: State not defined\n");
 			break;
 		case EOF:
 			/* Abort frame */
 			idev->rx_buff.state = OUTSIDE_FRAME;
-			idev->rx_buff.len = 0;
 			break;
 		default:
 			/* 
@@ -227,28 +228,25 @@
 			 *  following CE, IrLAP p.114 
 			 */
 			byte ^= IR_TRANS;
-			if ( idev->rx_buff.len < idev->rx_buff.truesize)  {
-				idev->rx_buff.data[ idev->rx_buff.len++] = byte;
-			
+			if (idev->rx_buff.len < idev->rx_buff.truesize)  {
+				idev->rx_buff.data[idev->rx_buff.len++] = byte;
 				idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs,
 							   byte);
 				idev->rx_buff.state = INSIDE_FRAME;
 			} else {
-				DEBUG( 1, __FUNCTION__ 
+				DEBUG(1, __FUNCTION__ 
 				       "(), Rx buffer overflow, aborting\n");
 				idev->rx_buff.state = OUTSIDE_FRAME;
-				idev->rx_buff.len = 0;
 			}
 			break;
 		}
 		break;
 	case INSIDE_FRAME:
-		switch ( byte) {
+		switch (byte) {
 		case BOF:
 			/* New frame? */
 			idev->rx_buff.state = BEGIN_FRAME;
-			idev->rx_buff.len = 0;
-			irda_device_set_media_busy( idev, TRUE);
+			irda_device_set_media_busy(idev, TRUE);
 			break;
 		case CE:
 			/* Stuffed char */
@@ -262,14 +260,12 @@
 			/* 
 			 *  Test FCS and deliver frame if it's good
 			 */			
-			if ( idev->rx_buff.fcs == GOOD_FCS) {
-				async_bump( idev, idev->rx_buff.data, 
-					    idev->rx_buff.len);
-				idev->rx_buff.len = 0;
+			if (idev->rx_buff.fcs == GOOD_FCS) {
+				async_bump(idev, idev->rx_buff.data, 
+					   idev->rx_buff.len);
 			} else {
 				/* Wrong CRC, discard frame!  */
-				irda_device_set_media_busy( idev, TRUE); 
-				idev->rx_buff.len = 0;
+				irda_device_set_media_busy(idev, TRUE); 
 
 				idev->stats.rx_errors++;
 				idev->stats.rx_crc_errors++;
@@ -277,16 +273,14 @@
 			break;
 		default:
 			/* Next byte of frame */
-			if ( idev->rx_buff.len < idev->rx_buff.truesize)  {
-				idev->rx_buff.data[ idev->rx_buff.len++] = byte;
-				
-				idev->rx_buff.fcs = IR_FCS( idev->rx_buff.fcs,
-							    byte);
+			if (idev->rx_buff.len < idev->rx_buff.truesize)  {
+				idev->rx_buff.data[idev->rx_buff.len++] = byte;
+				idev->rx_buff.fcs = IR_FCS(idev->rx_buff.fcs,
+							   byte);
 			} else {
-				DEBUG( 1, __FUNCTION__ 
-				       "(), Rx buffer overflow, aborting\n");
+				DEBUG(1, __FUNCTION__ 
+				      "(), Rx buffer overflow, aborting\n");
 				idev->rx_buff.state = OUTSIDE_FRAME;
-				idev->rx_buff.len = 0;
 			}
 			break;
 		}
@@ -301,9 +295,9 @@
  *    buf. The buffer must at all times be able to have two bytes inserted.
  * 
  */
-inline static int stuff_byte( __u8 byte, __u8 *buf) 
+inline static int stuff_byte(__u8 byte, __u8 *buf) 
 {
-	switch ( byte) {
+	switch (byte) {
 	case BOF: /* FALLTHROUGH */
 	case EOF: /* FALLTHROUGH */
 	case CE:
diff -urN linux-2.2.7-pre3/net/netsyms.c linux-2.2.7-pre4/net/netsyms.c
--- linux-2.2.7-pre3/net/netsyms.c	1999-03-22 11:20:51.000000000 -0800
+++ linux-2.2.7-pre4/net/netsyms.c	2003-08-15 15:05:52.000000000 -0700
@@ -21,6 +21,9 @@
 #include <net/dst.h>
 #include <net/checksum.h>
 #include <linux/etherdevice.h>
+#ifdef CONFIG_HIPPI
+#include <linux/hippidevice.h>
+#endif
 #include <net/pkt_sched.h>
 
 #ifdef CONFIG_BRIDGE
@@ -45,6 +48,8 @@
 #include <linux/igmp.h>
 
 extern struct net_proto_family inet_family_ops;
+extern __u32 sysctl_wmem_max;
+extern __u32 sysctl_rmem_max;
 
 #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
 #include <linux/in6.h>
@@ -475,6 +480,15 @@
 
 EXPORT_SYMBOL(if_port_text);
 
+#ifdef CONFIG_HIPPI
+EXPORT_SYMBOL(hippi_type_trans);
+EXPORT_SYMBOL(init_hippi_dev);
+EXPORT_SYMBOL(unregister_hipdev);
+#endif
+
+EXPORT_SYMBOL(sysctl_wmem_max);
+EXPORT_SYMBOL(sysctl_rmem_max);
+
 #if defined(CONFIG_ATALK) || defined(CONFIG_ATALK_MODULE) 
 #include<linux/if_ltalk.h>
 EXPORT_SYMBOL(ltalk_setup);
diff -urN linux-2.2.7-pre3/net/sched/sch_cbq.c linux-2.2.7-pre4/net/sched/sch_cbq.c
--- linux-2.2.7-pre3/net/sched/sch_cbq.c	1999-03-21 07:22:00.000000000 -0800
+++ linux-2.2.7-pre4/net/sched/sch_cbq.c	2003-08-15 15:05:52.000000000 -0700
@@ -30,7 +30,6 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/notifier.h>
-#include <linux/module.h>
 #include <net/ip.h>
 #include <net/route.h>
 #include <linux/skbuff.h>
diff -urN linux-2.2.7-pre3/net/sched/sch_sfq.c linux-2.2.7-pre4/net/sched/sch_sfq.c
--- linux-2.2.7-pre3/net/sched/sch_sfq.c	1999-03-21 07:22:00.000000000 -0800
+++ linux-2.2.7-pre4/net/sched/sch_sfq.c	2003-08-15 15:05:52.000000000 -0700
@@ -14,7 +14,6 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/bitops.h>
-#include <linux/module.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
