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

diff -urN linux-2.2.19-pre16/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-2.2.19-pre16/Documentation/Configure.help	Mon Dec  3 22:16:35 2001
+++ linux/Documentation/Configure.help	Mon Dec  3 22:16:42 2001
@@ -11910,7 +11910,7 @@
   called sc.o. See Documentation/isdn/README.sc and
   http://www.spellcast.com for more information.
 
-Eicon.Diehl active card support
+Eicon active card support
 CONFIG_ISDN_DRV_EICON
   Say Y here if you have an Eicon active ISDN card. In order to use
   this card, additional firmware is necessary, which has to be loaded
@@ -11918,6 +11918,16 @@
   latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
   
+Eicon legacy driver
+CONFIG_ISDN_DRV_EICON_OLD
+  Say Y here to use your Eicon active ISDN card with ISDN4Linux
+  isdn module.
+
+Eicon Diva Server card support
+CONFIG_ISDN_DRV_EICON_PCI
+  Say Y here if you have an Eicon Diva Server (BRI/PRI/4BRI) ISDN card.
+  Please read Documentation/isdn/README.eicon for more information.
+
 Eicon old-type card support
 CONFIG_ISDN_DRV_EICON_ISA
   Say Y here if you have an old-type Eicon active ISDN card. In order
@@ -11925,6 +11935,14 @@
   loaded into the card using the eiconctrl utility which is part of
   the latest isdn4k-utils package. Please read the file
   Documentation/isdn/README.eicon for more information.
+
+Eicon driver type standalone
+CONFIG_ISDN_DRV_EICON_DIVAS
+  Enable this option if you want the eicon driver as standalone
+  version with no interface to the ISDN4Linux isdn module. If you
+  say Y here, the eicon module only supports the Diva Server PCI
+  cards and will provide its own IDI interface. You should say N
+  here.
 
 Support AT-Fax Class 2 commands
 CONFIG_ISDN_TTY_FAX
diff -urN linux-2.2.19-pre16/Documentation/isdn/README.eicon linux/Documentation/isdn/README.eicon
--- linux-2.2.19-pre16/Documentation/isdn/README.eicon	Mon Dec  3 22:16:35 2001
+++ linux/Documentation/isdn/README.eicon	Mon Dec  3 22:16:42 2001
@@ -100,17 +100,6 @@
 the necessary D-Channel traces for isdnlog.
 
 
-FILECHECK:
-A part of the eicon driver source code files are provided
-by Eicon Technology. In order to get the best support from Eicon,
-these files are tested with a checksum, just to know if the files
-were modified. This does *not* mean, you are not allowed to modify the
-driver. If you want to improve the driver or you fix a bug, please do
-so and let me (or Eicon) know, about the necessary changes. So
-every user knows, if the driver he uses is modified or checked with
-Eicon files. When the driver has been loaded, in the syslog you will
-find something like "verified" or "modified" right after the version.
-
 
 Thanks to 
 	Deutsche Mailbox Saar-Lor-Lux GmbH
diff -urN linux-2.2.19-pre16/MAINTAINERS linux/MAINTAINERS
--- linux-2.2.19-pre16/MAINTAINERS	Mon Dec  3 22:16:35 2001
+++ linux/MAINTAINERS	Mon Dec  3 22:16:42 2001
@@ -545,6 +545,13 @@
 L:	isdn4linux@listserv.isdn4linux.de
 S:	Maintained
 
+ISDN SUBSYSTEM (Eicon active card driver)
+P:	Armin Schindler
+M:	mac@melware.de
+L:	isdn4linux@listserv.isdn4linux.de
+W:	http://www.melware.net
+S:	Maintained
+
 JOYSTICK DRIVER
 P:	Vojtech Pavlik
 M:	vojtech@suse.cz
diff -urN linux-2.2.19-pre16/Makefile linux/Makefile
--- linux-2.2.19-pre16/Makefile	Mon Dec  3 22:16:35 2001
+++ linux/Makefile	Mon Dec  3 22:16:42 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 2
 SUBLEVEL = 19
-EXTRAVERSION = pre16
+EXTRAVERSION = pre17
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/)
 
diff -urN linux-2.2.19-pre16/drivers/block/ide-pmac.c linux/drivers/block/ide-pmac.c
--- linux-2.2.19-pre16/drivers/block/ide-pmac.c	Sun Dec 10 16:49:41 2000
+++ linux/drivers/block/ide-pmac.c	Mon Dec  3 22:16:42 2001
@@ -905,7 +905,8 @@
 	 * Problem: This can schedule. I moved the block device
 	 * wakeup almost late by priority because of that.
 	 */
-	DRIVER(drive)->media_change(drive);
+	if (DRIVER(drive))
+		DRIVER(drive)->media_change(drive);
 
 	/* We kick the VFS too (see fix in ide.c revalidate) */
 	check_disk_change(MKDEV(HWIF(drive)->major, (drive->select.b.unit) << PARTN_BITS));
diff -urN linux-2.2.19-pre16/drivers/cdrom/cdrom.c linux/drivers/cdrom/cdrom.c
--- linux-2.2.19-pre16/drivers/cdrom/cdrom.c	Sun Dec 10 16:49:41 2000
+++ linux/drivers/cdrom/cdrom.c	Mon Dec  3 22:16:42 2001
@@ -1140,15 +1140,18 @@
 
 static int dvd_read_physical(struct cdrom_device_info *cdi, dvd_struct *s)
 {
-	int ret, i;
-	u_char buf[4 + 4 * 20], *base;
+	unsigned char buf[20], *base;
 	struct dvd_layer *layer;
 	struct cdrom_generic_command cgc;
 	struct cdrom_device_ops *cdo = cdi->ops;
+	int ret, layer_num = s->physical.layer_num;
+
+	if (layer_num >= DVD_LAYERS)
+		return -EINVAL;
 
 	init_cdrom_command(&cgc, buf, sizeof(buf));
 	cgc.cmd[0] = GPCMD_READ_DVD_STRUCTURE;
-	cgc.cmd[6] = s->physical.layer_num;
+	cgc.cmd[6] = layer_num;
 	cgc.cmd[7] = s->type;
 	cgc.cmd[9] = cgc.buflen & 0xff;
 
@@ -1156,26 +1159,26 @@
 		return ret;
 
 	base = &buf[4];
-	layer = &s->physical.layer[0];
+	layer = &s->physical.layer[layer_num];
 
-	/* place the data... really ugly, but at least we won't have to
-	   worry about endianess in userspace or here. */
-	for (i = 0; i < 4; ++i, base += 20, ++layer) {
-		memset(layer, 0, sizeof(*layer));
-		layer->book_version = base[0] & 0xf;
-		layer->book_type = base[0] >> 4;
-		layer->min_rate = base[1] & 0xf;
-		layer->disc_size = base[1] >> 4;
-		layer->layer_type = base[2] & 0xf;
-		layer->track_path = (base[2] >> 4) & 1;
-		layer->nlayers = (base[2] >> 5) & 3;
-		layer->track_density = base[3] & 0xf;
-		layer->linear_density = base[3] >> 4;
-		layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
-		layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
-		layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
-		layer->bca = base[16] >> 7;
-	}
+	/*
+	 * place the data... really ugly, but at least we won't have to
+	 * worry about endianess in userspace.
+	 */
+	memset(layer, 0, sizeof(*layer));
+	layer->book_version = base[0] & 0xf;
+	layer->book_type = base[0] >> 4;
+	layer->min_rate = base[1] & 0xf;
+	layer->disc_size = base[1] >> 4;
+	layer->layer_type = base[2] & 0xf;
+	layer->track_path = (base[2] >> 4) & 1;
+	layer->nlayers = (base[2] >> 5) & 3;
+	layer->track_density = base[3] & 0xf;
+	layer->linear_density = base[3] >> 4;
+	layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
+	layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
+	layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
+	layer->bca = base[16] >> 7;
 
 	return 0;
 }
diff -urN linux-2.2.19-pre16/drivers/char/Makefile linux/drivers/char/Makefile
--- linux-2.2.19-pre16/drivers/char/Makefile	Mon Dec  3 22:16:35 2001
+++ linux/drivers/char/Makefile	Mon Dec  3 22:16:42 2001
@@ -200,7 +200,13 @@
   endif
 endif
 
-obj-$(CONFIG_SX) += sx.o generic_serial.o
+ifeq ($(CONFIG_SX),y)
+O_OBJS += sx.o generic_serial.o
+else
+  ifeq ($(CONFIG_SX),m)
+  M_OBJS += sx.o generic_serial.o
+  endif
+endif
 
 ifeq ($(CONFIG_RIO),y)
 O_OBJS += rio/rio.o generic_serial.o
diff -urN linux-2.2.19-pre16/drivers/char/cpia.c linux/drivers/char/cpia.c
--- linux-2.2.19-pre16/drivers/char/cpia.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/char/cpia.c	Mon Dec  3 22:16:42 2001
@@ -3211,7 +3211,7 @@
 		DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm.format, vm.frame,
 		    vm.width, vm.height);
 #endif
-		if (vm.frame<0||vm.frame>FRAME_NUM) {
+		if (vm.frame<0||vm.frame>=FRAME_NUM) {
 			retval = -EINVAL;
 			break;
 		}
diff -urN linux-2.2.19-pre16/drivers/char/misc.c linux/drivers/char/misc.c
--- linux-2.2.19-pre16/drivers/char/misc.c	Mon Dec  3 22:16:35 2001
+++ linux/drivers/char/misc.c	Mon Dec  3 22:16:42 2001
@@ -139,8 +139,17 @@
 
 int misc_register(struct miscdevice * misc)
 {
+	struct miscdevice *c;
+
 	if (misc->next || misc->prev)
 		return -EBUSY;
+	c = misc_list.next;
+
+	while ((c != &misc_list) && (c->minor != misc->minor))
+		c = c->next;
+	if (c != &misc_list)
+		return -EBUSY;
+
 	if (misc->minor == MISC_DYNAMIC_MINOR) {
 		int i = DYNAMIC_MINORS;
 		while (--i >= 0)
diff -urN linux-2.2.19-pre16/drivers/char/sx.c linux/drivers/char/sx.c
--- linux-2.2.19-pre16/drivers/char/sx.c	Sun Dec 10 16:49:42 2000
+++ linux/drivers/char/sx.c	Mon Dec  3 22:16:42 2001
@@ -1799,6 +1799,20 @@
 }
 
 
+static void sx_break (struct tty_struct * tty, int flag)
+{
+	struct sx_port *port = tty->driver_data;
+	int rv;
+
+	if (flag) 
+		rv = sx_send_command (port, HS_START, -1, HS_IDLE_BREAK);
+	else 
+		rv = sx_send_command (port, HS_STOP, -1, HS_IDLE_OPEN);
+	if (rv != 1) printk (KERN_ERR "sx: couldn't send break (%x).\n",
+			read_sx_byte (port->board, CHAN_OFFSET (port, hi_hstat)));
+}
+
+
 static int sx_ioctl (struct tty_struct * tty, struct file * filp, 
                      unsigned int cmd, unsigned long arg)
 {
@@ -1867,7 +1881,6 @@
 			sx_reconfigure_port(port);
 		}
 		break;
-
 	default:
 		rc = -ENOIOCTLCMD;
 		break;
@@ -2247,6 +2260,7 @@
 	sx_driver.table = sx_table;
 	sx_driver.termios = sx_termios;
 	sx_driver.termios_locked = sx_termios_locked;
+	sx_driver.break_ctl = sx_break;
 
 	sx_driver.open	= sx_open;
 	sx_driver.close = gs_close;
diff -urN linux-2.2.19-pre16/drivers/net/3c527.c linux/drivers/net/3c527.c
--- linux-2.2.19-pre16/drivers/net/3c527.c	Mon Dec  3 22:16:35 2001
+++ linux/drivers/net/3c527.c	Mon Dec  3 22:16:42 2001
@@ -1,7 +1,8 @@
-/* 3c527.c: 3Com Etherlink/MC32 driver for Linux
+/* 3c527.c: 3Com Etherlink/MC32 driver for Linux 2.2
  *
  *	(c) Copyright 1998 Red Hat Software Inc
- *	Written by Alan Cox.
+ *	Written by Alan Cox. 
+ *      Modified by Richard Procter (rnp@netlink.co.nz)
  *
  *	Based on skeleton.c written 1993-94 by Donald Becker and ne2.c
  *	(for the MCA stuff) written by Wim Dumon.
@@ -10,33 +11,70 @@
  *	documentation.
  *
  *	This software may be used and distributed according to the terms
- *	of the GNU Public License, incorporated herein by reference.
+ *	of the GNU General Public License, incorporated herein by reference.
  *
  */
 
 static const char *version =
-	"3c527.c:v0.06 1999/09/16 Alan Cox (alan@redhat.com)\n";
+	"3c527.c:v0.5 1999/09/16 Alan Cox (alan@redhat.com)\n";
 
-/* Modified by Richard Procter (rprocter@mcs.vuw.ac.nz, rnp@netlink.co.nz) */
-
-/*
- *	Things you need
- *	o	The databook.
- *
- *	Traps for the unwary
+/**
+ * DOC: Traps for the unwary
  *
  *	The diagram (Figure 1-1) and the POS summary disagree with the
  *	"Interrupt Level" section in the manual.
  *
+ *	The manual contradicts itself when describing the minimum number 
+ *	buffers in the 'configure lists' command. 
+ *	My card accepts a buffer config of 4/4. 
+ *
+ *	Setting the SAV BP bit does not save bad packets, but
+ *	only enables RX on-card stats collection. 
+ *
  *	The documentation in places seems to miss things. In actual fact
  *	I've always eventually found everything is documented, it just
  *	requires careful study.
  *
- *      The manual contradicts itself when describing the minimum number 
- *      buffers in the 'configure lists' command. 
- *      My card accepts a buffer config of 4/4. 
+ * DOC: Theory Of Operation
  *
- */
+ *	The 3com 3c527 is a 32bit MCA bus mastering adapter with a large
+ *	amount of on board intelligence that housekeeps a somewhat dumber
+ *	Intel NIC. For performance we want to keep the transmit queue deep
+ *	as the card can transmit packets while fetching others from main
+ *	memory by bus master DMA. Transmission and reception are driven by
+ *	circular buffer queues.
+ *
+ *	The mailboxes can be used for controlling how the card traverses
+ *	its buffer rings, but are used only for inital setup in this
+ *	implementation.  The exec mailbox allows a variety of commands to
+ *	be executed. Each command must complete before the next is
+ *	executed. Primarily we use the exec mailbox for controlling the
+ *	multicast lists.  We have to do a certain amount of interesting
+ *	hoop jumping as the multicast list changes can occur in interrupt
+ *	state when the card has an exec command pending. We defer such
+ *	events until the command completion interrupt.
+ *
+ *	A copy break scheme (taken from 3c59x.c) is employed whereby
+ *	received frames exceeding a configurable length are passed
+ *	directly to the higher networking layers without incuring a copy,
+ *	in what amounts to a time/space trade-off.
+ *	 
+ *	The card also keeps a large amount of statistical information
+ *	on-board. In a perfect world, these could be used safely at no
+ *	cost. However, lacking information to the contrary, processing
+ *	them without races would involve so much extra complexity as to
+ *	make it unworthwhile to do so. In the end, a hybrid SW/HW
+ *	implementation was made necessary --- see mc32_update_stats().  
+ *
+ * DOC: Notes
+ *	
+ *	It should be possible to use two or more cards, but at this stage
+ *	only by loading two copies of the same module.
+ *
+ *	The on-board 82586 NIC has trouble receiving multiple
+ *	back-to-back frames and so is likely to drop packets from fast
+ *	senders.
+**/
 
 #include <linux/module.h>
 
@@ -61,8 +99,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
-
-#include <linux/proc_fs.h>
+#include <linux/if_ether.h>
 
 #include "3c527.h"
 
@@ -82,15 +119,20 @@
 static unsigned int mc32_debug = NET_DEBUG;
 
 /* The number of low I/O ports used by the ethercard. */
-#define NETCARD_IO_EXTENT	8
+#define MC32_IO_EXTENT	8
 
 /* As implemented, values must be a power-of-2 -- 4/8/16/32 */ 
-
-#define TX_RING_LEN     16       /* Typically the card supports 37  */
+#define TX_RING_LEN     32       /* Typically the card supports 37  */
 #define RX_RING_LEN     8        /*     "       "        "          */
 
+/* Copy break point, see above for details. 
+ * Setting to > 1512 effectively disables this feature.	*/	    
 #define RX_COPYBREAK    200      /* Value from 3c59x.c */
 
+/* Issue the 82586 workaround command - this is for "busy lans", but
+ * basically means for all lans now days - has a performance (latency) 
+ * cost, but best set. */ 
+static const int WORKAROUND_82586=1;
 
 /* Pointers to buffers and their on-card records */
 struct mc32_ring_desc 
@@ -113,14 +155,16 @@
 	u16 rx_chain;           /* Receive list start offset */
         u16 tx_len;             /* Transmit list count */ 
         u16 rx_len;             /* Receive list count */
+
 	u32 base;
-	u16 rx_halted;
-	u16 tx_halted;
 	u16 exec_pending;
 	u16 mc_reload_wait;	/* a multicast load request is pending */
+	u32 mc_list_valid;	/* True when the mclist is set */
+	u16 xceiver_state;      /* Current transceiver state. bitmapped */ 
+	u16 desired_state;      /* The state we want the transceiver to be in */ 
 	atomic_t tx_count;	/* buffers left */
 	struct wait_queue *event;
-	
+
 	struct mc32_ring_desc tx_ring[TX_RING_LEN];	/* Host Transmit ring */
 	struct mc32_ring_desc rx_ring[RX_RING_LEN];	/* Host Receive ring */
 
@@ -128,8 +172,6 @@
 	u16 tx_ring_head;       /* index to tx en-queue end */
 
 	u16 rx_ring_tail;       /* index to rx de-queue end */ 
-
-	u32 mc_list_valid;	/* True when the mclist is set */
 };
 
 /* The station (ethernet) address prefix, used for a sanity check. */
@@ -149,8 +191,14 @@
 };
 
 
-/* Index to functions, as function prototypes. */
+/* Macros for ring index manipulations */ 
+static inline u16 next_rx(u16 rx) { return (rx+1)&(RX_RING_LEN-1); };
+static inline u16 prev_rx(u16 rx) { return (rx-1)&(RX_RING_LEN-1); };
+
+static inline u16 next_tx(u16 tx) { return (tx+1)&(TX_RING_LEN-1); };
 
+
+/* Index to functions, as function prototypes. */
 extern int mc32_probe(struct device *dev);
 
 static int	mc32_probe1(struct device *dev, int ioaddr);
@@ -162,14 +210,15 @@
 static struct	net_device_stats *mc32_get_stats(struct device *dev);
 static void	mc32_set_multicast_list(struct device *dev);
 static void	mc32_reset_multicast_list(struct device *dev);
-static void     mc32_flush_tx_ring(struct mc32_local *lp);
 
-/*
- * Check for a network adaptor of this type, and return '0' iff one exists.
- * If dev->base_addr == 0, probe all likely locations.
- * If dev->base_addr == 1, always return failure.
- * If dev->base_addr == 2, allocate space for the device and return success
- * (detachable devices only).
+/**
+ * mc32_probe:
+ * @dev: device to probe
+ *
+ * Because MCA bus is a real bus and we can scan for cards we could do a
+ * single scan for all boards here. Right now we use the passed in device
+ * structure and scan for only one board. This needs fixing for modules
+ * in paticular.
  */
 
 __initfunc(int mc32_probe(struct device *dev))
@@ -203,15 +252,21 @@
 	return -ENODEV;
 }
 
-/*
- * This is the real probe routine. Linux has a history of friendly device
- * probes on the ISA bus. A good device probes avoids doing writes, and
- * verifies that the correct device exists and functions.
+/**
+ * mc32_probe1:
+ * @dev:  Device structure to fill in
+ * @slot: The MCA bus slot being used by this card
+ *
+ * Decode the slot data and configure the card structures. Having done this we
+ * can reset the card and configure it. The card does a full self test cycle
+ * in firmware so we have to wait for it to return and post us either a 
+ * failure case or some addresses we use to find the board internals.
  */
+
 __initfunc(static int mc32_probe1(struct device *dev, int slot))
 {
 	static unsigned version_printed = 0;
-	int i;
+	int i, err;
 	u8 POS;
 	u32 base;
 	struct mc32_local *lp;
@@ -347,20 +402,21 @@
 	 *	Grab the IRQ
 	 */
 
-	if(request_irq(dev->irq, &mc32_interrupt, 0, cardname, dev))
-	{
-		printk("%s: unable to get IRQ %d.\n",
-				   dev->name, dev->irq);
-		return -EAGAIN;
+	i = request_irq(dev->irq, &mc32_interrupt, SA_SHIRQ, dev->name, dev); 
+	if(i) {
+		printk("%s: unable to get IRQ %d.\n", dev->name, dev->irq);
+		return i; 
 	}
 
+	request_region(dev->base_addr, MC32_IO_EXTENT, cardname);
+
 	/* Initialize the device structure. */
 	if (dev->priv == NULL) {
 		dev->priv = kmalloc(sizeof(struct mc32_local), GFP_KERNEL);
-		if (dev->priv == NULL)
+		if (dev->priv == NULL)	
 		{
-			free_irq(dev->irq, dev);
-			return -ENOMEM;
+			err = -ENOMEM;
+			goto err_exit_irq; 
 		}
 	}
 
@@ -378,8 +434,8 @@
 		if(i==1000)
 		{
 			printk("%s: failed to boot adapter.\n", dev->name);
-			free_irq(dev->irq, dev);
-			return -ENODEV;
+			err = -ENODEV; 
+			goto err_exit_free;
 		}
 		udelay(1000);
 		if(inb(dev->base_addr+2)&(1<<5))
@@ -393,8 +449,8 @@
 				base<0x0A?" test failure":"");
 		else
 			printk("%s: unknown failure %d.\n", dev->name, base);
-		free_irq(dev->irq, dev);
-		return -ENODEV;
+		err = -ENODEV; 
+		goto err_exit_free;
 	}
 	
 	base=0;
@@ -409,8 +465,8 @@
 			if(n>100)
 			{
 				printk(KERN_ERR "%s: mailbox read fail (%d).\n", dev->name, i);
-				free_irq(dev->irq, dev);
-				return -ENODEV;
+				err = -ENODEV;
+				goto err_exit_free;
 			}
 		}
 
@@ -446,56 +502,63 @@
 	dev->get_stats		= mc32_get_stats;
 	dev->set_multicast_list = mc32_set_multicast_list;
 	
-	lp->rx_halted		= 1;
-	lp->tx_halted		= 1;
+	lp->xceiver_state = HALTED; 
+	
+	lp->tx_ring_tail=lp->tx_ring_head=0;
 
 	/* Fill in the fields of the device structure with ethernet values. */
 	ether_setup(dev);
 	
 	return 0;
+
+err_exit_free:
+	kfree(dev->priv);
+err_exit_irq:
+	free_irq(dev->irq, dev);
+	release_region(dev->base_addr, MC32_IO_EXTENT);
+	return err;
 }
 
-/*
- *	Polled command stuff 
+
+/**
+ *	mc32_ready_poll:
+ *	@dev:	The device to wait for
+ *	
+ *	Wait until the card becomes ready to accept a command via the
+ *	command register. This tells us nothing about the completion
+ *	status of any pending commands and takes very little time at all.
  */
  
-static void mc32_ring_poll(struct device *dev)
+static void mc32_ready_poll(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
 	while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR));
 }
 
 
-/*
- *	Send exec commands. This requires a bit of explaining.
+/**
+ *	mc32_command_nowait:
+ *	@dev: The 3c527 to issue the command to
+ *	@cmd: The command word to write to the mailbox
+ *	@data: A data block if the command expects one
+ *	@len: Length of the data block
  *
- *	You feed the card a command, you wait, it interrupts you get a 
- *	reply. All well and good. The complication arises because you use
- *	commands for filter list changes which come in at bh level from things
- *	like IPV6 group stuff.
- *
- *	We have a simple state machine
- *
- *	0	- nothing issued
- *	1	- command issued, wait reply
- *	2	- reply waiting - reader then goes to state 0
- *	3	- command issued, trash reply. In which case the irq
- *		  takes it back to state 0
- */
- 
-
-/*
- *	Send command from interrupt state
+ *	Send a command from interrupt state. If there is a command
+ *	currently being executed then we return an error of -1. It simply
+ *	isn't viable to wait around as commands may be slow. Providing we
+ *	get in, we busy wait for the board to become ready to accept the
+ *	command and issue it. We do not wait for the command to complete
+ *	--- the card will interrupt us when it's done.
  */
 
 static int mc32_command_nowait(struct device *dev, u16 cmd, void *data, int len)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	
+
 	if(lp->exec_pending)
 		return -1;
-		
+	
 	lp->exec_pending=3;
 	lp->exec_box->mbox=0;
 	lp->exec_box->mbox=cmd;
@@ -509,9 +572,35 @@
 }
 
 
-/*
- *	Send command and block for results. On completion spot and reissue
- *	multicasts
+/**
+ *	mc32_command: 
+ *	@dev: The 3c527 card to issue the command to
+ *	@cmd: The command word to write to the mailbox
+ *	@data: A data block if the command expects one
+ *	@len: Length of the data block
+ *
+ *	Sends exec commands in a user context. This permits us to wait around
+ *	for the replies and also to wait for the command buffer to complete
+ *	from a previous command before we execute our command. After our 
+ *	command completes we will complete any pending multicast reload
+ *	we blocked off by hogging the exec buffer.
+ *
+ *	You feed the card a command, you wait, it interrupts you get a 
+ *	reply. All well and good. The complication arises because you use
+ *	commands for filter list changes which come in at bh level from things
+ *	like IPV6 group stuff.
+ *
+ *	We have a simple state machine
+ *
+ *	0	- nothing issued
+ *
+ *	1	- command issued, wait reply
+ *
+ *	2	- reply waiting - reader then goes to state 0
+ *
+ *	3	- command issued, trash reply. In which case the irq
+ *		  takes it back to state 0
+ *
  */
   
 static int mc32_command(struct device *dev, u16 cmd, void *data, int len)
@@ -552,7 +641,7 @@
 	cli();
 
 	while(lp->exec_pending!=2)
-	  sleep_on(&lp->event);
+		sleep_on(&lp->event);
 	lp->exec_pending=0;
 	restore_flags(flags);
 	
@@ -564,89 +653,111 @@
 	 */
 		
 	if(lp->mc_reload_wait)
+	{
 		mc32_reset_multicast_list(dev);
+	}
 
 	return ret;
 }
 
 
-/*
- *	RX abort
- */
- 
-static void mc32_rx_abort(struct device *dev)
-{
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	int ioaddr = dev->base_addr;
+/**
+ *	mc32_start_transceiver: 
+ *	@dev: The 3c527 card to issue the command to
+ *
+ *	This may be called from the interrupt state, where it is used
+ *	to restart the rx ring if the card runs out of rx buffers. 
+ *	
+ * 	First, we check if it's ok to start the transceiver. We then show
+ * 	the card where to start in the rx ring and issue the
+ * 	commands to start reception and transmission. We don't wait
+ * 	around for these to complete.
+ */ 
 
-	mc32_ring_poll(dev);	
-	
-	lp->rx_box->mbox=0;
-	outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);	/* Suspend reception */
-	
-	mc32_ring_poll(dev);	
-}
+static void mc32_start_transceiver(struct device *dev) {
 
- 
-/*
- *	RX enable
- */
- 
-static void mc32_rx_begin(struct device *dev)
-{
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
 
-	/* Tell the card start reception at the first descriptor */ 
-	lp->rx_box->data[0]=lp->rx_chain; 
- 
-	mc32_ring_poll(dev);	
-	
-	lp->rx_box->mbox=0;
-	outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);	/* GO */
+	/* Ignore RX overflow on device closure */ 
+	if (lp->desired_state==HALTED)  
+		return; 
 
-	mc32_ring_poll(dev);
-	lp->rx_halted=0;
-}
+	mc32_ready_poll(dev); 
 
-static void mc32_tx_abort(struct device *dev)
-{
-	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	int ioaddr = dev->base_addr;
-		
-	mc32_ring_poll(dev);
-	
 	lp->tx_box->mbox=0;
-	outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);	/* Suspend */
+	lp->rx_box->mbox=0;
+
+	/* Give the card the offset to the post-EOL-bit RX descriptor */ 
+	lp->rx_box->data[0]=lp->rx_ring[prev_rx(lp->rx_ring_tail)].p->next; 
 
-	mc32_flush_tx_ring(lp); 
+	outb(HOST_CMD_START_RX, ioaddr+HOST_CMD);      
 
-	mc32_ring_poll(dev);
+	mc32_ready_poll(dev); 
+	outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);   /* card ignores this on RX restart */ 
+	
+	/* We are not interrupted on start completion */ 
+	lp->xceiver_state=RUNNING; 
 }
 
-/*
- *	TX enable
- */
- 
-static void mc32_tx_begin(struct device *dev)
+
+/**
+ *	mc32_halt_transceiver: 
+ *	@dev: The 3c527 card to issue the command to
+ *
+ *	We issue the commands to halt the card's transceiver. In fact,
+ *	after some experimenting we now simply tell the card to
+ *	suspend. When issuing aborts occasionally odd things happened.
+ *
+ *	We then sleep until the card has notified us that both rx and
+ *	tx have been suspended.
+ */ 
+
+static void mc32_halt_transceiver(struct device *dev) 
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	int ioaddr = dev->base_addr;
-	
-	mc32_ring_poll(dev);
+	unsigned long flags;
+
+	mc32_ready_poll(dev);	
 
 	lp->tx_box->mbox=0;
-	outb(HOST_CMD_RESTRT_TX, ioaddr+HOST_CMD);	/* GO */
+	lp->rx_box->mbox=0;
 
-	mc32_ring_poll(dev);	
-	lp->tx_halted=0;
-}
+	outb(HOST_CMD_SUSPND_RX, ioaddr+HOST_CMD);			
+	mc32_ready_poll(dev); 
+	outb(HOST_CMD_SUSPND_TX, ioaddr+HOST_CMD);	
+		
+	save_flags(flags);
+	cli();
+		
+	while(lp->xceiver_state!=HALTED) 
+		sleep_on(&lp->event); 
+		
+	restore_flags(flags);	
+} 
 
-	
-/*
- *	Load the rx ring.
+
+/**
+ *	mc32_load_rx_ring:
+ *	@dev: 3c527 to build the ring for
+ *
+ *	This initalises the on-card and driver datastructures to
+ *	the point where mc32_start_transceiver() can be called.
+ *
+ *	The card sets up the receive ring for us. We are required to use the
+ *	ring it provides although we can change the size of the ring.
+ *
+ * 	We allocate an sk_buff for each ring entry in turn and
+ * 	initalise its house-keeping info. At the same time, we read
+ * 	each 'next' pointer in our rx_ring array. This reduces slow
+ * 	shared-memory reads and makes it easy to access predecessor
+ * 	descriptors.
+ *
+ *	We then set the end-of-list bit for the last entry so that the
+ * 	card will know when it has run out of buffers.
  */
- 
+	 
 static int mc32_load_rx_ring(struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
@@ -681,23 +792,55 @@
 
 	lp->rx_ring[i-1].p->control |= CONTROL_EOL;
 
-	lp->rx_ring_tail=0; 
+	lp->rx_ring_tail=0;
 
-	lp->rx_box->mbox=0;   /* check: needed ? */
 	return 0;
 }	
 
-static void mc32_flush_rx_ring(struct mc32_local *lp)
+
+/**
+ *	mc32_flush_rx_ring:
+ *	@lp: Local data of 3c527 to flush the rx ring of
+ *
+ *	Free the buffer for each ring slot. This may be called 
+ *      before mc32_load_rx_ring(), eg. on error in mc32_open().
+ */
+
+static void mc32_flush_rx_ring(struct device *dev)
 {
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+	
+	struct sk_buff *skb;
 	int i; 
-	for(i=0; i < RX_RING_LEN; i++) { 
-		kfree_skb(lp->rx_ring[i].skb);
+
+	for(i=0; i < RX_RING_LEN; i++) 
+	{ 
+		skb = lp->rx_ring[i].skb;
+		if (skb!=NULL) {
+			kfree_skb(skb);
+			skb=NULL; 
+		}
 		lp->rx_ring[i].p=NULL; 
 	} 
 }
 
 
-/* Load the addresses of the on-card buffer descriptors into main memory */ 
+/**
+ *	mc32_load_tx_ring: 
+ *	@dev: The 3c527 card to issue the command to
+ *
+ *	This sets up the host transmit data-structures. 
+ *
+ *	First, we obtain from the card it's current postion in the tx
+ *	ring, so that we will know where to begin transmitting
+ *	packets.
+ * 	
+ * 	Then, we read the 'next' pointers from the on-card tx ring into
+ *  	our tx_ring array to reduce slow shared-mem reads. Finally, we
+ * 	intitalise the tx house keeping variables.
+ * 
+ */ 
+
 static void mc32_load_tx_ring(struct device *dev)
 { 
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
@@ -707,9 +850,6 @@
 
 	tx_base=lp->tx_box->data[0]; 
 
-	/* Read the 'next' pointers from the on-card list into      */
-	/* our tx_ring array so we can reduce slow shared-mem reads */ 
-
 	for(i=0;i<lp->tx_len;i++) 
 	{
 		p=bus_to_virt(lp->base+tx_base);
@@ -719,16 +859,31 @@
 		tx_base=p->next;
 	}
 
+	/* -1 so that tx_ring_head cannot "lap" tx_ring_tail,           */
+	/* which would be bad news for mc32_tx_ring as cur. implemented */ 
+
+	atomic_set(&lp->tx_count, TX_RING_LEN-1); 
 	lp->tx_ring_head=lp->tx_ring_tail=0; 
 } 
 
-static void mc32_flush_tx_ring(struct mc32_local *lp)
+
+/**
+ *	mc32_flush_tx_ring:
+ *	@lp: Local data of 3c527 to flush the tx ring of
+ *
+ *	We have to consider two cases here. We want to free the pending
+ *	buffers only. If the ring buffer head is past the start then the
+ *	ring segment we wish to free wraps through zero. The tx ring 
+ *	house-keeping variables are then reset.
+ */
+
+static void mc32_flush_tx_ring(struct device *dev)
 {
+	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	
 	if(lp->tx_ring_tail!=lp->tx_ring_head)
 	{
-		int i;
-	
+		int i;	
 		if(lp->tx_ring_tail < lp->tx_ring_head)
 		{
 			for(i=lp->tx_ring_tail;i<lp->tx_ring_head;i++)
@@ -755,29 +910,37 @@
 		}
 	}
 	
-	/* -1 so that tx_ring_head cannot "lap" tx_ring_tail, */
-	/* which would be bad news for mc32_tx_ring as cur. implemented */ 
-	atomic_set(&lp->tx_count, TX_RING_LEN-1); 
+	atomic_set(&lp->tx_count, 0); 
 	lp->tx_ring_tail=lp->tx_ring_head=0;
 }
  	
-/*
- * Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'ifconfig' program is run.
+
+/**
+ *	mc32_open
+ *	@dev: device to open
+ *
+ *	The user is trying to bring the card into ready state. This requires
+ *	a brief dialogue with the card. Firstly we enable interrupts and then
+ *	'indications'. Without these enabled the card doesn't bother telling
+ *	us what it has done. This had me puzzled for a week.
+ *
+ *	We configure the number of card descriptors, then load the network
+ *	address and multicast filters. Turn on the workaround mode. This
+ *	works around a bug in the 82586 - it asks the firmware to do
+ *	so. It has a performance (latency) hit but is needed on busy
+ *	[read most] lans. We load the ring with buffers then we kick it
+ *	all off.
  */
 
 static int mc32_open(struct device *dev)
 {
 	int ioaddr = dev->base_addr;
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	u16 zero_word=0;
 	u8 one=1;
 	u8 regs;
 	u16 descnumbuffs[2] = {TX_RING_LEN, RX_RING_LEN};
-	
-	dev->tbusy = 0;
-	dev->interrupt = 0;
-	dev->start = 1;
+
+	MOD_INC_USE_COUNT;
 
 	/*
 	 *	Interrupts enabled
@@ -795,18 +958,20 @@
 	mc32_command(dev, 4, &one, 2);
 
 	/*
-	 *	Send the command sequence "abort, resume" for RX and TX.
-	 *	The abort cleans up the buffer chains if needed.
+	 *	Poke it to make sure it's really dead. 
 	 */
 
-	mc32_rx_abort(dev);
-	mc32_tx_abort(dev);
-	
-	/* Ask card to set up on-card descriptors to our spec */ 
+	mc32_halt_transceiver(dev); 
+	mc32_flush_tx_ring(dev); 
+
+	/* 
+	 *	Ask card to set up on-card descriptors to our spec 
+	 */ 
 
 	if(mc32_command(dev, 8, descnumbuffs, 4)) { 
 		printk("%s: %s rejected our buffer configuration!\n",
 	 	       dev->name, cardname);
+		mc32_close(dev); 
 		return -ENOBUFS; 
 	}
 	
@@ -823,34 +988,50 @@
 	
 	/* Set the filters */
 	mc32_set_multicast_list(dev);
-	
-	/* Issue the 82586 workaround command - this is for "busy lans",
-	   but basically means for all lans now days - has a performance
-	   cost but best set */
-	   
-	/* mc32_command(dev, 0x0D, &zero_word, 2); */   /* 82586 bug workaround on  */
-
-	/* Load the ring we just initialised */
+		   
+	if (WORKAROUND_82586) { 
+		u16 zero_word=0;
+		mc32_command(dev, 0x0D, &zero_word, 2);   /* 82586 bug workaround on  */
+	}
 
 	mc32_load_tx_ring(dev);
 	
-	if(mc32_load_rx_ring(dev))
+	if(mc32_load_rx_ring(dev)) 
 	{
 		mc32_close(dev);
 		return -ENOBUFS;
 	}
-	
-	/* And the resume command goes last */
 
-	mc32_rx_begin(dev);
-	mc32_tx_begin(dev);
+	lp->desired_state = RUNNING; 
 	
-	MOD_INC_USE_COUNT;
+	/* And finally, set the ball rolling... */
+
+	mc32_start_transceiver(dev);
+
+	dev->tbusy = 0;
+	dev->interrupt = 0;
+	dev->start = 1;
 
 	return 0;
 }
 
 
+/**
+ *	mc32_send_packet:
+ *	@skb: buffer to transmit
+ *	@dev: 3c527 to send it out of
+ *
+ *	Transmit a buffer. This normally means throwing the buffer onto
+ *	the transmit queue as the queue is quite large. If the queue is
+ *	full then we set tx_busy and return. Once the interrupt handler
+ *	gets messages telling it to reclaim transmit queue entries we will
+ *	clear tx_busy and the kernel will start calling this again.
+ *
+ *	We use cli rather than spinlocks. Since I have no access to an SMP
+ *	MCA machine I don't plan to change it. It is probably the top 
+ *	performance hit for this driver on SMP however.
+ */
+
 static int mc32_send_packet(struct sk_buff *skb, struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
@@ -898,8 +1079,7 @@
 		/* P is the last sending/sent buffer as a pointer */
 		p=lp->tx_ring[lp->tx_ring_head].p; 
 		
-		lp->tx_ring_head++;
-		lp->tx_ring_head&=(TX_RING_LEN-1); 
+		lp->tx_ring_head=next_tx(lp->tx_ring_head); 
 
 		/* NP is the buffer we will be loading */
 		np=lp->tx_ring[lp->tx_ring_head].p; 
@@ -907,7 +1087,7 @@
 	        /* We will need this to flush the buffer out */
 		lp->tx_ring[lp->tx_ring_head].skb=skb;
    	   
-		np->length = (skb->len < 60) ? 60 : skb->len; 
+		np->length = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len; 
 			
 		np->data	= virt_to_bus(skb->data);
    		np->status	= 0;
@@ -923,58 +1103,76 @@
 	return 0;
 }
 
+
+/**
+ *	mc32_update_stats:
+ *	@dev: 3c527 to service
+ *
+ * 
+ *	Query and reset the on-card stats. There's the small possibility
+ *	of a race here, which would result in an underestimation of
+ *	actual errors. As such, we'd prefer to keep all our stats
+ *	collection in software. As a rule, we do. However it can't be
+ *	used for rx errors and collisions as, by default, the card discards
+ *	bad rx packets. 
+ *
+ *	Setting the SAV BP in the rx filter command supposedly
+ *	stops this behaviour. However, testing shows that it only seems to
+ *	enable the collation of on-card rx statistics --- the driver
+ *	never sees an RX descriptor with an error status set.
+ *
+ */
+
 static void mc32_update_stats(struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
 	volatile struct mc32_stats *st = lp->stats; 
-	
-        u32 rx_errors=0; 
-
-	/* The databook isn't at all clear about whether      */ 
-        /* the host should suspend rx/tx here to avoid races. */
-        /* Assuming that it should, my code here is probably  */
-        /* a bit dodgey - RP                                  */
-
-	/* TO DO: count rx_errors, tx_errors, figure out how to measure colisions */     
-
-	/* RX */ 
-
-    	rx_errors += lp->net_stats.rx_crc_errors += st->rx_crc_errors;
-	st->rx_crc_errors = 0; 
 
-    	rx_errors += lp->net_stats.rx_length_errors += st->rx_tooshort_errors;
-	st->rx_tooshort_errors = 0; 
-
-	rx_errors += lp->net_stats.rx_length_errors += st->rx_toolong_errors;
-	st->rx_toolong_errors = 0; 
-
-	rx_errors += lp->net_stats.rx_fifo_errors += st->rx_overrun_errors; 
-	st->rx_overrun_errors = 0; 
-
-	rx_errors += lp->net_stats.rx_frame_errors += st->rx_alignment_errors;
-	st->rx_alignment_errors = 0; 
-
-	rx_errors += lp->net_stats.rx_missed_errors += st->rx_outofresource_errors;
-	st->rx_outofresource_errors = 0; 
-
-	lp->net_stats.rx_errors = rx_errors;
-	
-        /* TX */ 
-
-	/* How to count collisions when you're only 
-           told frames which had 1 or 2-15? - RP */
-	
-	lp->net_stats.collisions += (st->tx_max_collisions * 16); 
-	st->tx_max_collisions = 0;  
-
-	lp->net_stats.tx_carrier_errors += st->tx_carrier_errors; 
-	st->tx_carrier_errors = 0; 
+	u32 rx_errors=0; 
+      
+	rx_errors+=lp->net_stats.rx_crc_errors   +=st->rx_crc_errors;         
+	                                           st->rx_crc_errors=0;
+	rx_errors+=lp->net_stats.rx_fifo_errors  +=st->rx_overrun_errors;   
+	                                           st->rx_overrun_errors=0; 
+	rx_errors+=lp->net_stats.rx_frame_errors +=st->rx_alignment_errors; 
+ 	                                           st->rx_alignment_errors=0;
+	rx_errors+=lp->net_stats.rx_length_errors+=st->rx_tooshort_errors; 
+	                                           st->rx_tooshort_errors=0;
+	rx_errors+=lp->net_stats.rx_missed_errors+=st->rx_outofresource_errors;
+	                                           st->rx_outofresource_errors=0; 
+        lp->net_stats.rx_errors=rx_errors; 
+						   
+	/* Number of packets which saw one collision */
+	lp->net_stats.collisions+=st->dataC[10];
+	st->dataC[10]=0; 
+
+	/* Number of packets which saw 2--15 collisions */ 
+	lp->net_stats.collisions+=st->dataC[11]; 
+	st->dataC[11]=0; 
+}	
 
-	lp->net_stats.tx_fifo_errors += st->tx_underrun_errors; 
-	st->tx_underrun_errors = 0; 
-	
-}
 
+/**
+ *	mc32_rx_ring:
+ *	@dev: 3c527 that needs its receive ring processing
+ *
+ *
+ *	We have received one or more indications from the card that a
+ *	receive has completed. The buffer ring thus contains dirty
+ *	entries. We walk the ring by iterating over the circular rx_ring
+ *	array, starting at the next dirty buffer (which happens to be the
+ *	one we finished up at last time around).
+ *
+ *	For each completed packet, we will either copy it and pass it up
+ * 	the stack or, if the packet is near MTU sized, we allocate
+ *	another buffer and flip the old one up the stack.
+ * 
+ *	We must succeed in keeping a buffer on the ring. If neccessary we
+ *	will toss a received packet rather than lose a ring entry. Once
+ *	the first uncompleted descriptor is found, we move the
+ *	End-Of-List bit to include the buffers just processed.
+ *
+ */
 
 static void mc32_rx_ring(struct device *dev)
 {
@@ -999,10 +1197,6 @@
 			struct sk_buff *skb; 
 			struct sk_buff *newskb; 
 
-#ifdef DEBUG_IRQ 
- 			printk("skb_header %p has frame, x==%d\n", p, x); 
-#endif 
-
 			/* Try to save time by avoiding a copy on big frames */
 
 			if ((length > RX_COPYBREAK) 
@@ -1019,18 +1213,9 @@
 			{
 				skb=dev_alloc_skb(length+2);  
 
-				if(skb==NULL) 
-				{ 
+				if(skb==NULL) {
 					lp->net_stats.rx_dropped++; 
-
-					p->length = 1532; 
-					p->status = 0;
-					p->control = 0; 	        
-					
-					rx_ring_tail++;
-					rx_ring_tail&=(RX_RING_LEN-1); 
-
-					continue; /* better to use a goto? */ 
+					goto dropped; 
 				}
 
 				skb_reserve(skb,2);
@@ -1044,36 +1229,42 @@
  			lp->net_stats.rx_bytes+=skb->len; 
 			netif_rx(skb); 
 		}
-		else    /* NOT COMPLETED_OK */
-		{
-		        /* There was some sort of reception error.     */
-                        /* This case should never occur unless         */
-			/* the card is asked to upload damaged frames.  */
-  
-			/* do nothing */ 
-		}
 
+	dropped:
 		p->length = 1532; 
 		p->status = 0;
-		p->control = 0; 	        
-
-		rx_ring_tail++;
-		rx_ring_tail&=(RX_RING_LEN-1); 
+		
+		rx_ring_tail=next_rx(rx_ring_tail); 
 	}
         while(x++<48);  
 
-	/* If there was actually a frame to be processed, */ 
-	/* place the EL bit at the descriptor prior to the one to be filled next */ 
+	/* If there was actually a frame to be processed, place the EOL bit */ 
+	/* at the descriptor prior to the one to be filled next */ 
 
-	if (rx_ring_tail != rx_old_tail) { 
-		lp->rx_ring[(rx_ring_tail-1)&(RX_RING_LEN-1)].p->control |=  CONTROL_EOL; 
-		lp->rx_ring[(rx_old_tail-1)&(RX_RING_LEN-1)].p->control  &= ~CONTROL_EOL; 
+	if (rx_ring_tail != rx_old_tail) 
+	{ 
+		lp->rx_ring[prev_rx(rx_ring_tail)].p->control |=  CONTROL_EOL; 
+		lp->rx_ring[prev_rx(rx_old_tail)].p->control  &= ~CONTROL_EOL; 
 
 		lp->rx_ring_tail=rx_ring_tail; 
 	}
 }
 
 
+/**
+ *	mc32_tx_ring:
+ *	@dev: 3c527 that needs its transmit ring processing
+ *
+ *
+ *	This operates in a similar fashion to mc32_rx_ring. We iterate
+ *	over the transmit ring. For each descriptor which has been
+ *	processed by the card, we free its associated buffer and note
+ *	any errors. This continues until the transmit ring is emptied
+ *	or we reach a descriptor that hasn't yet been processed by the
+ *	card.
+ * 
+ */
+
 static void mc32_tx_ring(struct device *dev) {
 
   struct mc32_local *lp=(struct mc32_local *)dev->priv;
@@ -1085,7 +1276,7 @@
   {   
 	  u16 t; 
 
-	  t=(lp->tx_ring_tail+1)&(TX_RING_LEN-1); 
+	  t=next_tx(lp->tx_ring_tail); 
 	  np=lp->tx_ring[t].p; 
 
 	  if(!(np->status & (1<<7))) { /* Not COMPLETED */ 
@@ -1097,9 +1288,20 @@
 	  if(!(np->status & (1<<6))) /* Not COMPLETED_OK */
 	  {
 		  lp->net_stats.tx_errors++;   
-		  
-                  /* Error stats are stored on-card to be picked up by
-	             mc32_update_stats() - RP */
+
+		  switch(np->status&0x0F)
+		  {
+		  case 1:
+			  lp->net_stats.tx_aborted_errors++;break; /* Max collisions */ 
+		  case 2:
+			  lp->net_stats.tx_fifo_errors++;break;
+		  case 3:
+			  lp->net_stats.tx_carrier_errors++;break;
+		  case 4:
+			  lp->net_stats.tx_window_errors++;break;  /* CTS Lost */ 
+		  case 5:
+			  lp->net_stats.tx_aborted_errors++;break; /* Transmit timeout */ 
+		  }
 	  }
 	  
 	  
@@ -1115,12 +1317,32 @@
 
 	  lp->tx_ring_tail=t; 
   }
+
 } 
 
-/*
- * The typical workload of the driver:
- *   Handle the network interface interrupts.
+
+/**
+ *	mc32_interrupt:
+ *	@irq: Interrupt number
+ *	@dev_id: 3c527 that requires servicing
+ *	@regs: Registers (unused)
+ *
+ *
+ *	An interrupt is raised whenever the 3c527 writes to the command
+ *	register. This register contains the message it wishes to send us
+ *	packed into a single byte field. We keep reading status entries
+ *	until we have processed all the control items, but simply count
+ *	transmit and receive reports. When all reports are in we empty the
+ *	transceiver rings as appropriate. This saves the overhead of
+ *	multiple command requests.
+ *
+ *	Because MCA is level-triggered, we shouldn't miss indications.
+ *	Therefore, we needn't ask the card to suspend interrupts within
+ *	this handler. The card receives an implicit acknowledgment of the
+ *	current interrupt when we read the command register.
+ *
  */
+
 static void mc32_interrupt(int irq, void *dev_id, struct pt_regs * regs)
 {
 	struct device *dev = dev_id;
@@ -1128,12 +1350,12 @@
 	int ioaddr, status, boguscount = 0;
 	int rx_event = 0;
 	int tx_event = 0; 
-	int must_restart = 0;
 	
 	if (dev == NULL) {
 		printk(KERN_WARNING "%s: irq %d for unknown device.\n", cardname, irq);
 		return;
 	}
+
 	dev->interrupt = 1;
  
 	ioaddr = dev->base_addr;
@@ -1161,11 +1383,7 @@
 				break;
 			case 3: /* Halt */
 			case 4: /* Abort */
-				lp->tx_halted=1;
-				wake_up(&lp->event);
-				break;
-			case 5:
-				lp->tx_halted=0;
+				lp->xceiver_state |= TX_HALTED; 
 				wake_up(&lp->event);
 				break;
 			default:
@@ -1179,22 +1397,17 @@
 			case 2:	/* RX */
 				rx_event=1; 
 				break;
-			case 3:
-			case 4:
-				lp->rx_halted=1;
-				wake_up(&lp->event);
-				break;
-			case 5:
-				lp->rx_halted=0;
+			case 3: /* Halt */
+			case 4: /* Abort */
+				lp->xceiver_state |= RX_HALTED;
 				wake_up(&lp->event);
 				break;
 			case 6:
 				/* Out of RX buffers stat */
-				/* Must restart */
+				/* Must restart rx */
 				lp->net_stats.rx_dropped++;
-				must_restart = 1; 	/* To restart */
-				rx_event = 1; 
-
+				mc32_rx_ring(dev); 
+				mc32_start_transceiver(dev); 
 				break;
 			default:
 				printk("%s: strange rx ack %d\n", 
@@ -1203,60 +1416,48 @@
 		status>>=3;
 		if(status&1)
 		{
-			
+
 			/* 0=no 1=yes 2=replied, get cmd, 3 = wait reply & dump it */
 			
-			if(lp->exec_pending!=3) 
-			{
+			if(lp->exec_pending!=3) {
 				lp->exec_pending=2;
 				wake_up(&lp->event);
 			}
 			else 
-			{
-				lp->exec_pending=0;
-				wake_up(&lp->event);
+			{				
+			  	lp->exec_pending=0;
+
+				/* A new multicast set may have been
+				   blocked while the old one was
+				   running. If so, do it now. */
+				   
+				if (lp->mc_reload_wait) 
+					mc32_reset_multicast_list(dev);
+				else 
+					wake_up(&lp->event);			       
 			}
 		}
 		if(status&2)
 		{
 			/*
-			 *	Update the stats as soon as
-			 *	we have it flagged and can 
-			 *	send an immediate reply (CRR set)
+			 *	We get interrupted once per
+			 *	counter that is about to overflow. 
 			 */
-	
-			if(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)
-			{
-			 	mc32_update_stats(dev);
-			        outb(0, ioaddr+HOST_CMD);
-			}
-			
+
+			mc32_update_stats(dev);			
 		}
 	}
 
 
-	if(tx_event) { 
-		mc32_tx_ring(dev);
-	}
-
 	/*
-	 *	Process the receive ring and restart if the card 
-	 *      stopped due to a shortage of free buffers.
+	 *	Process the transmit and receive rings 
          */
+
+	if(tx_event) 
+		mc32_tx_ring(dev);
 	 
-	if(rx_event) {
+	if(rx_event) 
 		mc32_rx_ring(dev);
-		if (must_restart) { 
-			u16 rx_prev_tail=(lp->rx_ring_tail-1)&(RX_RING_LEN-1);
-
-			/* Restart at the current rx_ring_tail */ 
-			lp->rx_box->data[0]=lp->rx_ring[rx_prev_tail].p->next; 
-			lp->rx_box->mbox=0; 
-
-			while(!(inb(ioaddr+HOST_STATUS)&HOST_STATUS_CRR)); 
-			outb(HOST_CMD_START_RX, ioaddr+HOST_CMD); /* Re-enable receives */
-		}
-	}
 
 	dev->interrupt = 0;	
 
@@ -1264,54 +1465,80 @@
 }
 
 
-/* The inverse routine to mc32_open(). */
+/**
+ *	mc32_close:
+ *	@dev: 3c527 card to shut down
+ *
+ *	The 3c527 is a bus mastering device. We must be careful how we
+ *	shut it down. It may also be running shared interrupt so we have
+ *	to be sure to silence it properly
+ *
+ *	We indicate that the card is closing to the rest of the
+ *	driver.  Otherwise, it is possible that the card may run out
+ *	of receive buffers and restart the transceiver while we're
+ *	trying to close it.
+ * 
+ *	We abort any receive and transmits going on and then wait until
+ *	any pending exec commands have completed in other code threads.
+ *	In theory we can't get here while that is true, in practice I am
+ *	paranoid
+ *
+ *	We turn off the interrupt enable for the board to be sure it can't
+ *	intefere with other devices.
+ */
 
 static int mc32_close(struct device *dev)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
+
 	int ioaddr = dev->base_addr;
 	u8 regs;
 	u16 one=1;
 
+	dev->tbusy = 1;
+	dev->start = 0;
+
+	lp->desired_state = HALTED;
+
 	/*
 	 *	Send the indications on command (handy debug check)
 	 */
 
 	mc32_command(dev, 4, &one, 2);
 
-	/* Abort RX and Abort TX */
-	
-	mc32_rx_abort(dev);	
-	mc32_tx_abort(dev);
+	/* Shut down the transceiver */
+
+	mc32_halt_transceiver(dev); 
 	
 	/* Catch any waiting commands */
 	
 	while(lp->exec_pending==1)
 		sleep_on(&lp->event);
-		
+	       
 	/* Ok the card is now stopping */	
 	
 	regs=inb(ioaddr+HOST_CTRL);
 	regs&=~HOST_CTRL_INTE;
 	outb(regs, ioaddr+HOST_CTRL);
 
-	mc32_flush_rx_ring(lp);
-	mc32_flush_tx_ring(lp);
-	
-	dev->tbusy = 1;
-	dev->start = 0;
-
-	/* Update the statistics here. */
+	mc32_flush_rx_ring(dev);
+	mc32_flush_tx_ring(dev);
+		
+	mc32_update_stats(dev); 
 
 	MOD_DEC_USE_COUNT;
 
 	return 0;
-
 }
 
-/*
- * Get the current statistics.
- * This may be called with the card open or closed.
+
+/**
+ *	mc32_get_stats:
+ *	@dev: The 3c527 card to handle
+ *
+ *	We've collected all the stats we can in software already. Now
+ *	it's time to update those kept on-card and return the lot. 
+ * 
  */
 
 static struct net_device_stats *mc32_get_stats(struct device *dev)
@@ -1325,25 +1552,42 @@
 	return &lp->net_stats;
 }
 
-/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1	Promiscuous mode, receive all packets
- * num_addrs == 0	Normal mode, clear multicast list
- * num_addrs > 0	Multicast mode, receive normal and MC packets,
- *			and do best-effort filtering.
+
+/**
+ *	do_mc32_set_multicast_list:
+ *	@dev: 3c527 device to load the list on
+ *	@retry: indicates this is not the first call. 
+ *
+ *
+ * 	Actually set or clear the multicast filter for this adaptor. The
+ *	locking issues are handled by this routine. We have to track
+ *	state as it may take multiple calls to get the command sequence
+ *	completed. We just keep trying to schedule the loads until we
+ *	manage to process them all.
+ * 
+ *	num_addrs == -1	Promiscuous mode, receive all packets
+ * 
+ *	num_addrs == 0	Normal mode, clear multicast list
+ * 
+ *	num_addrs > 0	Multicast mode, receive normal and MC packets, 
+ *			and do best-effort filtering. 
+ *
+ *	See mc32_update_stats() regards setting the SAV BP bit. 
+ *
  */
+
 static void do_mc32_set_multicast_list(struct device *dev, int retry)
 {
 	struct mc32_local *lp = (struct mc32_local *)dev->priv;
-	u16 filt;
+	u16 filt = (1<<2); /* Save Bad Packets, for stats purposes */ 
 
 	if (dev->flags&IFF_PROMISC)
 		/* Enable promiscuous mode */
-		filt = 1;
+		filt |= 1;
 	else if((dev->flags&IFF_ALLMULTI) || dev->mc_count > 10)
 	{
 		dev->flags|=IFF_PROMISC;
-		filt = 1;
+		filt |= 1;
 	}
 	else if(dev->mc_count)
 	{
@@ -1352,9 +1596,7 @@
 		struct dev_mc_list *dmc=dev->mc_list;
 		
 		int i;
-		
-		filt = 0;
-		
+	       
 		if(retry==0)
 			lp->mc_list_valid = 0;
 		if(!lp->mc_list_valid)
@@ -1377,21 +1619,41 @@
 			lp->mc_list_valid=1;
 		}
 	}
-	else 
-	{
-		filt = 0;
-	}
-	if(mc32_command_nowait(dev, 0, &filt, 2)==-1)
+	
+	if(mc32_command_nowait(dev, 0, &filt, 2)==-1) 
 	{
 		lp->mc_reload_wait = 1;
+	} 
+	else { 
+		lp->mc_reload_wait = 0;
 	}
 }
 
+
+/**
+ *	mc32_set_multicast_list:
+ *	@dev: The 3c527 to use
+ *
+ *	Commence loading the multicast list. This is called when the kernel
+ *	changes the lists. It will override any pending list we are trying to
+ *	load.
+ */
+
 static void mc32_set_multicast_list(struct device *dev)
 {
 	do_mc32_set_multicast_list(dev,0);
 }
 
+
+/**
+ *	mc32_reset_multicast_list:
+ *	@dev: The 3c527 to use
+ *
+ *	Attempt the next step in loading the multicast lists. If this attempt
+ *	fails to complete then it will be scheduled and this function called
+ *	again later from elsewhere.
+ */
+
 static void mc32_reset_multicast_list(struct device *dev)
 {
 	do_mc32_set_multicast_list(dev,1);
@@ -1406,6 +1668,14 @@
 	0, 0,  /* I/O address, IRQ */
 	0, 0, 0, NULL, mc32_probe };
 
+/**
+ *	init_module:
+ *
+ *	Probe and locate a 3c527 card. This really should probe and locate
+ *	all the 3c527 cards in the machine not just one of them. Yes you can
+ *	insmod multiple modules for now but it's a hack.
+ */
+
 int init_module(void)
 {
 	int result;
@@ -1416,6 +1686,17 @@
 	return 0;
 }
 
+/**
+ *	cleanup_module:
+ *
+ *	Unloading time. We release the MCA bus resources and the interrupt
+ *	at which point everything is ready to unload. The card must be stopped
+ *	at this point or we would not have been called. When we unload we
+ *	leave the card stopped but not totally shut down. When the card is
+ *	initialized it must be rebooted or the rings reloaded before any
+ *	transmit operations are allowed to start scribbling into memory.
+ */
+
 void cleanup_module(void)
 {
 	int slot;
@@ -1425,8 +1706,6 @@
 
 	/*
 	 * If we don't do this, we can't re-insmod it later.
-	 * Release irq/dma here, when you have jumpered versions and
-	 * allocate them in mc32_probe1().
 	 */
 	 
 	if (this_device.priv)
@@ -1438,6 +1717,7 @@
 		kfree_s(this_device.priv, sizeof(struct mc32_local));
 	}
 	free_irq(this_device.irq, &this_device);
+	release_region(this_device.base_addr, MC32_IO_EXTENT);
 }
 
 #endif /* MODULE */
diff -urN linux-2.2.19-pre16/drivers/net/3c527.h linux/drivers/net/3c527.h
--- linux-2.2.19-pre16/drivers/net/3c527.h	Mon Dec  3 22:16:35 2001
+++ linux/drivers/net/3c527.h	Mon Dec  3 22:16:42 2001
@@ -27,6 +27,10 @@
 
 #define HOST_RAMPAGE		8
 
+#define RX_HALTED (1<<0)
+#define TX_HALTED (1<<1)  
+#define HALTED (RX_HALTED | TX_HALTED)
+#define RUNNING 0
 
 struct mc32_mailbox
 {
@@ -53,7 +57,7 @@
 	u32     rx_toolong_errors   __attribute((packed));
 	u32     rx_outofresource_errors  __attribute((packed)); 
 
-	u32     rx_discarded   __attribute((packed));  // via card pattern match filter
+	u32     rx_discarded   __attribute((packed));  /* via card pattern match filter */ 
 
 	/* TX Errors */
 	u32     tx_max_collisions __attribute((packed)); 
diff -urN linux-2.2.19-pre16/drivers/net/irda/irtty.c linux/drivers/net/irda/irtty.c
--- linux-2.2.19-pre16/drivers/net/irda/irtty.c	Wed Jun  7 14:26:43 2000
+++ linux/drivers/net/irda/irtty.c	Mon Dec  3 22:16:42 2001
@@ -282,6 +282,11 @@
 	tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
 	tty->disc_data = 0;
 	
+	/* We are not using any dongle anymore! */
+	if (self->dongle)
+		irda_device_dongle_cleanup(self->dongle);
+	self->dongle = NULL;
+
 	/* Remove netdevice */
 	if (self->netdev) {
 		rtnl_lock();
@@ -291,11 +296,6 @@
 		kfree(self->netdev);
 	}
 	
-	/* We are not using any dongle anymore! */
-	if (self->dongle)
-		irda_device_dongle_cleanup(self->dongle);
-	self->dongle = NULL;
-
 	/* Remove speed changing task if any */
 	if (self->task)
 		irda_task_delete(self->task);
diff -urN linux-2.2.19-pre16/drivers/net/starfire.c linux/drivers/net/starfire.c
--- linux-2.2.19-pre16/drivers/net/starfire.c	Mon Dec  3 22:16:35 2001
+++ linux/drivers/net/starfire.c	Mon Dec  3 22:16:42 2001
@@ -59,6 +59,10 @@
 	- Removed unused code
 	- Made more functions static and __init
 
+	LK1.2.8 (Ion Badulescu)
+	- Quell bogus error messages, inform about the Tx threshold
+	- Removed #ifdef CONFIG_PCI, this driver is PCI only
+
 TODO:
 	- implement tx_timeout() properly
 	- support ethtool
@@ -71,7 +75,7 @@
 " Updates and info at http://www.scyld.com/network/starfire.html\n";
 
 static const char version3[] =
-" (unofficial 2.2.x kernel port, version 1.2.7, February 26, 2001)\n";
+" (unofficial 2.2.x kernel port, version 1.2.8, March 7, 2001)\n";
 
 /* The user-configurable values.
    These may be modified when a driver module is loaded.*/
@@ -420,7 +424,6 @@
 {
 	struct pci_dev *dev;
 	int count = 0, found, i;
-#ifdef CONFIG_PCI
 	list_add_tail(&drv->node, &pci_drivers);
 	for (dev = pci_devices; dev; dev = dev->next) {
 		found = 0;
@@ -430,7 +433,6 @@
 		if (!found)
 			count += pci_announce_device(drv, dev);
 	}
-#endif
 	return count;
 }
 
@@ -439,7 +441,6 @@
 {
 	struct pci_dev *dev;
 	int i, found;
-#ifdef CONFIG_PCI
 	list_del(&drv->node);
 	for (dev = pci_devices; dev; dev = dev->next) {
 		found = 0;
@@ -454,7 +455,6 @@
 			drvmap[i].dev = NULL;
 		}
 	}
-#endif
 }
 
 static inline int pci_module_init(struct pci_driver *drv)
@@ -579,6 +579,7 @@
 	/* not quite bits */
 	IntrRxDone=IntrRxQ2Done | IntrRxQ1Done,
 	IntrRxEmpty=IntrRxDescQ1Low | IntrRxDescQ2Low,
+	IntrNormalMask=0xf0, IntrAbnormalMask=0x3f0e,
 };
 
 /* Bits in the RxFilterMode register. */
@@ -1557,9 +1558,12 @@
 		get_stats(dev);
 	}
 	/* Came close to underrunning the Tx FIFO, increase threshold. */
-	if (intr_status & IntrTxDataLow)
+	if (intr_status & IntrTxDataLow) {
 		writel(++np->tx_threshold, dev->base_addr + TxThreshold);
-	if ((intr_status & ~(IntrAbnormalSummary|IntrLinkChange|IntrStatsMax|IntrTxDataLow|1)) && debug)
+		printk(KERN_NOTICE "%s: Increasing Tx FIFO threshold to %d bytes\n",
+		       np->tx_threshold * 16);
+	}
+	if ((intr_status & ~(IntrNormalMask | IntrAbnormalSummary | IntrLinkChange | IntrStatsMax | IntrTxDataLow | IntrPCIPad)) && debug)
 		printk(KERN_ERR "%s: Something Wicked happened! %4.4x.\n",
 		       dev->name, intr_status);
 	/* Hmmmmm, it's not clear how to recover from DMA faults. */
diff -urN linux-2.2.19-pre16/drivers/scsi/3w-xxxx.c linux/drivers/scsi/3w-xxxx.c
--- linux-2.2.19-pre16/drivers/scsi/3w-xxxx.c	Mon Dec  3 22:16:35 2001
+++ linux/drivers/scsi/3w-xxxx.c	Mon Dec  3 22:16:42 2001
@@ -6,7 +6,7 @@
 		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 
 
-   Copyright (C) 1999-2000 3ware Inc.
+   Copyright (C) 1999-2001 3ware Inc.
 
    Kernel compatablity By: 	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -68,6 +68,15 @@
                  systems.
    12/09/2000  - release previously allocated resources on failure at
 		 tw_allocate_memory (acme)
+   1.02.00.003 - Fix tw_interrupt() to report error to scsi layer when
+                 controller status is non-zero.
+                 Added handling of request_sense opcode.
+                 Fix possible null pointer dereference in
+                 tw_reset_device_extension()
+   1.02.00.004 - Add support for device id of 3ware 7000 series controllers.
+                 Make tw_setfeature() call with interrupts disabled.
+                 Register interrupt handler before enabling interrupts.
+                 Clear attention interrupt before draining aen queue. 
 */
 
 #include <linux/module.h>
@@ -119,7 +128,7 @@
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.002";
+char *tw_driver_version="1.02.00.004";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -589,173 +598,178 @@
 	struct pci_dev *tw_pci_dev = pci_devices;
 	u32 status_reg_value;
 	unsigned char c = 1;
+	int i;
+	u16 device[TW_NUMDEVICES] = { TW_DEVICE_ID, TW_DEVICE_ID2 };
 
 	dprintk(KERN_NOTICE "3w-xxxx: tw_findcards()\n");
-	while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, TW_DEVICE_ID, tw_pci_dev))) {
-		/* Prepare temporary device extension */
-		tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
-		if (tw_dev == NULL) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
-			continue;
-		}
-		memset(tw_dev, 0, sizeof(TW_Device_Extension));
-
-		error = tw_initialize_device_extension(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Calculate the cards register addresses */
-		tw_dev->registers.base_addr = tw_pci_dev->base_address[0];
-		tw_dev->registers.control_reg_addr = (tw_pci_dev->base_address[0] & ~15);
-		tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4);
-		tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8);
-		tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC);
-		/* Save pci_dev struct to device extension */
-		tw_dev->tw_pci_dev = tw_pci_dev;
-
-		/* Poll status register for 60 secs for 'Controller Ready' flag */
-		if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Disable interrupts on the card */
-		tw_disable_interrupts(tw_dev);
-
-		while (tries < TW_MAX_RESET_TRIES) {
-			/* Do soft reset */
-			tw_soft_reset(tw_dev);
-
-			error = tw_aen_drain_queue(tw_dev);
+	
+	for (i=0;i<TW_NUMDEVICES;i++) {
+		while ((tw_pci_dev = pci_find_device(TW_VENDOR_ID, device[i], tw_pci_dev))) {
+			/* Prepare temporary device extension */
+			tw_dev=(TW_Device_Extension *)kmalloc(sizeof(TW_Device_Extension), GFP_ATOMIC);
+			if (tw_dev == NULL) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): kmalloc() failed for card %d.\n", numcards);
+				continue;
+			}
+			memset(tw_dev, 0, sizeof(TW_Device_Extension));
+			
+			error = tw_initialize_device_extension(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
-				tries++;
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
 				continue;
 			}
-
-			/* Check for controller errors */
-			if (tw_check_errors(tw_dev)) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
-				tries++;
+			
+			/* Calculate the cards register addresses */
+			tw_dev->registers.base_addr = tw_pci_dev->base_address[0];
+			tw_dev->registers.control_reg_addr = (tw_pci_dev->base_address[0] & ~15);
+			tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4);
+			tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8);
+			tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC);
+			/* Save pci_dev struct to device extension */
+			tw_dev->tw_pci_dev = tw_pci_dev;
+			
+			/* Poll status register for 60 secs for 'Controller Ready' flag */
+			if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Microcontroller not ready for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
 				continue;
 			}
-
-			/* Empty the response queue */
-			error = tw_empty_response_que(tw_dev);
+			
+			/* Disable interrupts on the card */
+			tw_disable_interrupts(tw_dev);
+			
+			while (tries < TW_MAX_RESET_TRIES) {
+				/* Do soft reset */
+				tw_soft_reset(tw_dev);
+				
+				error = tw_aen_drain_queue(tw_dev);
+				if (error) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): No attention interrupt for card %d.\n", numcards);
+					tries++;
+					continue;
+				}
+				
+				/* Check for controller errors */
+				if (tw_check_errors(tw_dev)) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller errors found, soft resetting card %d.\n", numcards);
+					tries++;
+					continue;
+				}
+				
+				/* Empty the response queue */
+				error = tw_empty_response_que(tw_dev);
+				if (error) {
+					printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
+					tries++;
+					continue;
+				}
+				
+				/* Now the controller is in a good state */
+				break;
+			}
+			
+			if (tries >= TW_MAX_RESET_TRIES) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+			
+			/* Make sure that io region isn't already taken */
+			if (check_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE)) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
+				       (tw_dev->tw_pci_dev->base_address[0]), 
+				       (tw_dev->tw_pci_dev->base_address[0]) + 
+				       TW_IO_ADDRESS_RANGE, numcards);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+			
+			/* Reserve the io address space */
+			request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
+			error = tw_initialize_units(tw_dev);
 			if (error) {
-				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't empty response queue for card %d.\n", numcards);
-				tries++;
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
+				release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
 				continue;
 			}
-
-			/* Now the controller is in a good state */
-			break;
-		}
-
-		if (tries >= TW_MAX_RESET_TRIES) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Controller error or no attention interrupt: giving up for card %d.\n", numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Make sure that io region isn't already taken */
-		if (check_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE)) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't get io range 0x%lx-0x%lx for card %d.\n", 
-				(tw_dev->tw_pci_dev->base_address[0]), 
-				(tw_dev->tw_pci_dev->base_address[0]) + 
-				TW_IO_ADDRESS_RANGE, numcards);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-    
-		/* Reserve the io address space */
-		request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME);
-		error = tw_initialize_units(tw_dev);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards);
-			release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
-			release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-
-		/* Calculate max cmds per lun */
-		if (tw_dev->num_units > 0)
-			tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
-
-		/* Register the card with the kernel SCSI layer */
-		host = scsi_register(tw_host, sizeof(TW_Device_Extension));
-		
-		/* FIXME - check for NULL */
-
-		status_reg_value = inl(tw_dev->registers.status_reg_addr);
-
-		dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no,
+			
+			error = tw_initconnection(tw_dev, TW_INIT_MESSAGE_CREDITS);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initconnection for card %d.\n", numcards);
+				release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+			
+			/* Calculate max cmds per lun */
+			if (tw_dev->num_units > 0)
+				tw_host->cmd_per_lun = (TW_Q_LENGTH-2)/tw_dev->num_units;
+			
+			/* Register the card with the kernel SCSI layer */
+			host = scsi_register(tw_host, sizeof(TW_Device_Extension));
+			
+			/* FIXME - check for NULL */
+			
+			status_reg_value = inl(tw_dev->registers.status_reg_addr);
+			
+			dprintk(KERN_NOTICE "scsi%d : Found a 3ware Storage Controller at 0x%x, IRQ: %d P-chip: %d.%d\n", host->host_no,
 				(u32)(tw_pci_dev->base_address[0]), tw_pci_dev->irq, 
 				(status_reg_value & TW_STATUS_MAJOR_VERSION_MASK) >> 28, 
 				(status_reg_value & TW_STATUS_MINOR_VERSION_MASK) >> 24);
+			
+			if (host->hostdata) {
+				tw_dev2 = (TW_Device_Extension *)host->hostdata;
+				memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
+				tw_device_extension_list[tw_device_extension_count] = tw_dev2;
+				numcards++;
+				tw_device_extension_count = numcards;
+				tw_dev2->host = host;
+			} else { 
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
+				scsi_unregister(host);
+				release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				continue;
+			}
+			
+			/* Tell the firmware we support shutdown notification*/
+			tw_setfeature(tw_dev2, 2, 1, &c);
+			
+			/* Now setup the interrupt handler */
+			error = tw_setup_irq(tw_dev2);
+			if (error) {
+				printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
+				scsi_unregister(host);
+				release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
+				
+				tw_free_device_extension(tw_dev);
+				kfree(tw_dev);
+				numcards--;
+				continue;
+			}
 
-		if (host->hostdata) {
-			tw_dev2 = (TW_Device_Extension *)host->hostdata;
-			memcpy(tw_dev2, tw_dev, sizeof(TW_Device_Extension));
-			tw_device_extension_list[tw_device_extension_count] = tw_dev2;
-			numcards++;
-			tw_device_extension_count = numcards;
-			tw_dev2->host = host;
-		} else { 
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Bad scsi host data for card %d.\n", numcards-1);
-			scsi_unregister(host);
-			release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			continue;
-		}
-    
-		/* Re-enable interrupts on the card */
-		tw_enable_interrupts(tw_dev2);
-
-		/* Now setup the interrupt handler */
-		error = tw_setup_irq(tw_dev2);
-		if (error) {
-			printk(KERN_WARNING "3w-xxxx: tw_findcards(): Error requesting irq for card %d.\n", numcards-1);
-			scsi_unregister(host);
-			release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE);
-
-			tw_free_device_extension(tw_dev);
-			kfree(tw_dev);
-			numcards--;
-			continue;
+			/* Re-enable interrupts on the card */
+			tw_enable_interrupts(tw_dev2);
+			
+			/* Free the temporary device extension */
+			if (tw_dev)
+				kfree(tw_dev);
 		}
-
-		/* Free the temporary device extension */
-		if (tw_dev)
-			kfree(tw_dev);
-		/* Tell the firmware we support shutdown notification*/
-		tw_setfeature(tw_dev2, 2, 1, &c);
 	}
-
 	if (numcards == 0) 
 		printk(KERN_WARNING "3w-xxxx: tw_findcards(): No cards found.\n");
 	else
-	  register_reboot_notifier(&tw_notifier);
-
+		register_reboot_notifier(&tw_notifier);
+	
 	return numcards;
 } /* End tw_findcards() */
 
@@ -1086,15 +1100,14 @@
 		/* Handle attention interrupt */
 		if (do_attention_interrupt) {
 			dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n");
+			dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
+			tw_clear_attention_interrupt(tw_dev);
 			tw_state_request_start(tw_dev, &request_id);
 			error = tw_aen_read_queue(tw_dev, request_id);
 			if (error) {
 				printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Error reading aen queue.\n");
 				tw_dev->state[request_id] = TW_S_COMPLETED;
 				tw_state_request_finish(tw_dev, request_id);
-			} else {
-				dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n");
-				tw_clear_attention_interrupt(tw_dev);
 			}
 		}
 
@@ -1130,13 +1143,15 @@
 				response_que.value = inl(response_que_addr);
 				request_id = response_que.u.response_id;
 				command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id];
+				error = 0;
 				if (command_packet->status != 0) {
-					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags);
+					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit);
+					error = 1;
 				}
 				if (tw_dev->state[request_id] != TW_S_POSTED) {
 					printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", request_id, command_packet->byte0.opcode);
+					error = 1;
 				}
-				error = 0;
 				dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id);
 				/* Check for internal command */
 				if (tw_dev->srb[request_id] == 0) {
@@ -1180,8 +1195,8 @@
 					}
 					if (error) {
 						/* Tell scsi layer there was an error */
-						printk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
-						tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+						dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n");
+						tw_dev->srb[request_id]->result = (DID_RESET << 16);
 					} else {
 						/* Tell scsi layer command was a success */
 						tw_dev->srb[request_id]->result = (DID_OK << 16);
@@ -1463,8 +1478,10 @@
 		    (tw_dev->state[i] != TW_S_INITIAL) &&
 		    (tw_dev->state[i] != TW_S_COMPLETED)) {
 			srb = tw_dev->srb[i];
-			srb->result = (DID_RESET << 16);
-			tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+			if (srb != NULL) {
+				srb->result = (DID_RESET << 16);
+				tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
+			}
 		}
 	}
 
@@ -1809,6 +1826,10 @@
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught READ_CAPACITY.\n");
 			error = tw_scsiop_read_capacity(tw_dev, request_id);
 			break;
+		case REQUEST_SENSE:
+			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught REQUEST_SENSE.\n");
+			error = tw_scsiop_request_sense(tw_dev, request_id);
+			break;
 		case TW_IOCTL:
 			dprintk(KERN_NOTICE "3w-xxxx: tw_scsi_queue(): caught TW_SCSI_IOCTL.\n");
 			error = tw_ioctl(tw_dev, request_id);
@@ -2164,6 +2185,23 @@
 
 	return 0;
 } /* End tw_scsiop_read_write() */
+
+/* This function will handle the request sense scsi command */
+int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id)
+{
+	dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n");
+	
+	/* For now we just zero the sense buffer */
+	memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen);
+	tw_dev->state[request_id] = TW_S_COMPLETED;
+	tw_state_request_finish(tw_dev, request_id);
+	
+	/* If we got a request_sense, we probably want a reset, return error */
+	tw_dev->srb[request_id]->result = (DID_ERROR << 16);
+	tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]);
+
+	return 0;
+} /* End tw_scsiop_request_sense() */
 
 /* This function will handle test unit ready scsi command */
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id)
diff -urN linux-2.2.19-pre16/drivers/scsi/3w-xxxx.h linux/drivers/scsi/3w-xxxx.h
--- linux-2.2.19-pre16/drivers/scsi/3w-xxxx.h	Mon Sep  4 10:39:20 2000
+++ linux/drivers/scsi/3w-xxxx.h	Mon Dec  3 22:16:42 2001
@@ -3,8 +3,9 @@
    
    Written By: Adam Radford <linux@3ware.com>
    Modifications By: Joel Jacobson <linux@3ware.com>
+		     Arnaldo Carvalho de Melo <acme@conectiva.com.br>
 
-   Copyright (C) 1999, 2000 3ware Inc.
+   Copyright (C) 1999-2001 3ware Inc.
 
    Kernel compatablity By:	Andre Hedrick <andre@suse.com>
    Non-Copyright (C) 2000	Andre Hedrick <andre@suse.com>
@@ -97,6 +98,8 @@
 #define TW_DEVICE_NAME			       "3ware Storage Controller"
 #define TW_VENDOR_ID (0x13C1)	/* 3ware */
 #define TW_DEVICE_ID (0x1000)	/* Storage Controller */
+#define TW_DEVICE_ID2 (0x1001)  /* 7000 series controller */
+#define TW_NUMDEVICES 2
 
 /* Command packet opcodes */
 #define TW_OP_NOP	      0x0
@@ -330,6 +333,7 @@
 int tw_scsiop_read_capacity(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_capacity_complete(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id);
+int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id);
 int tw_scsiop_test_unit_ready(TW_Device_Extension *tw_dev, int request_id);
 int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, unsigned char *val);
 int tw_setup_irq(TW_Device_Extension *tw_dev);
diff -urN linux-2.2.19-pre16/drivers/usb/bluetooth.c linux/drivers/usb/bluetooth.c
--- linux-2.2.19-pre16/drivers/usb/bluetooth.c	Sun Dec 10 16:49:43 2000
+++ linux/drivers/usb/bluetooth.c	Mon Dec  3 22:16:43 2001
@@ -1,11 +1,15 @@
 /*
- * bluetooth.c   Version 0.6
+ * bluetooth.c   Version 0.7
  *
  * Copyright (c) 2000 Greg Kroah-Hartman	<greg@kroah.com>
  * Copyright (c) 2000 Mark Douglas Corner	<mcorner@umich.edu>
  *
  * USB Bluetooth driver, based on the Bluetooth Spec version 1.0B
  *
+ * (11/29/2000) Version 0.7 gkh
+ *	Fixed problem with overrunning the tty flip buffer.
+ *	Removed unneeded NULL pointer initialization.
+ *
  * (10/05/2000) Version 0.6 gkh
  *	Fixed bug with urb->dev not being set properly, now that the usb
  *	core needs it.
@@ -73,9 +77,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/devfs_fs_kernel.h>
 
@@ -199,8 +203,7 @@
 static struct tty_struct *	bluetooth_tty[BLUETOOTH_TTY_MINORS];
 static struct termios *		bluetooth_termios[BLUETOOTH_TTY_MINORS];
 static struct termios *		bluetooth_termios_locked[BLUETOOTH_TTY_MINORS];
-static struct usb_bluetooth	*bluetooth_table[BLUETOOTH_TTY_MINORS] = {NULL, };
-
+static struct usb_bluetooth	*bluetooth_table[BLUETOOTH_TTY_MINORS];
 
 
 static inline int bluetooth_paranoia_check (struct usb_bluetooth *bluetooth, const char *function)
@@ -315,6 +318,11 @@
 	tty->driver_data = bluetooth;
 	bluetooth->tty = tty;
 
+	/* force low_latency on so that our tty_push actually forces the data through, 
+	 * otherwise it is scheduled, and with high data rates (like with OHCI) data
+	 * can get lost. */
+	bluetooth->tty->low_latency = 1;
+	
 	bluetooth->active = 1;
 
 	/* Reset the packet position counters */
@@ -774,9 +782,14 @@
 		return;
 	}
 
-	if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos){
-		for (i = 0; i < bluetooth->int_packet_pos; ++i)
+	if (packet_size + EVENT_HDR_SIZE == bluetooth->int_packet_pos) {
+		for (i = 0; i < bluetooth->int_packet_pos; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them */
+			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(bluetooth->tty);
+			}
 			tty_insert_flip_char(bluetooth->tty, bluetooth->int_buffer[i], 0);
+		}
 		tty_flip_buffer_push(bluetooth->tty);
 
 		bluetooth->int_packet_pos = 0;
@@ -888,8 +901,13 @@
 	}
 
 	if (packet_size + ACL_HDR_SIZE == bluetooth->bulk_packet_pos) {
-		for (i = 0; i < bluetooth->bulk_packet_pos; ++i)
+		for (i = 0; i < bluetooth->bulk_packet_pos; ++i) {
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+			if (bluetooth->tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(bluetooth->tty);
+			}
 			tty_insert_flip_char(bluetooth->tty, bluetooth->bulk_buffer[i], 0);
+		}
 		tty_flip_buffer_push(bluetooth->tty);
 		bluetooth->bulk_packet_pos = 0;
 	}	
diff -urN linux-2.2.19-pre16/drivers/usb/dc2xx.c linux/drivers/usb/dc2xx.c
--- linux-2.2.19-pre16/drivers/usb/dc2xx.c	Sun Dec 10 16:49:43 2000
+++ linux/drivers/usb/dc2xx.c	Mon Dec  3 22:16:43 2001
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1999-2000 by David Brownell <david-b@pacbell.net>
+ * Copyright (C) 1999-2000 by David Brownell <dbrownell@users.sourceforge.net>
  *
  * 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
@@ -59,13 +59,17 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/module.h>
-#undef DEBUG
+#ifdef CONFIG_USB_DEBUG
+	#define DEBUG
+#else
+	#undef DEBUG
+#endif
 #include <linux/usb.h>
 
 
 
 /* current USB framework handles max of 16 USB devices per driver */
-#define	MAX_CAMERAS		8
+#define	MAX_CAMERAS		16
 
 /* USB char devs use USB_MAJOR and from USB_CAMERA_MINOR_BASE up */
 #define	USB_CAMERA_MINOR_BASE	80
@@ -90,6 +94,8 @@
 	/* These have the same application level protocol */  
     { 0x040a, 0x0120 },		// Kodak DC-240
     { 0x040a, 0x0130 },		// Kodak DC-280
+    { 0x040a, 0x0131 },		// Kodak DC-5000
+    { 0x040a, 0x0132 },		// Kodak DC-3400
 
 	/* These have a different application level protocol which
 	 * is part of the Flashpoint "DigitaOS".  That supports some
@@ -435,7 +441,8 @@
 		goto error;
 	}
 
-	info ("USB Camera #%d connected", camera->subminor);
+	info ("USB Camera #%d connected, major/minor %d/%d", camera->subminor,
+		USB_MAJOR, USB_CAMERA_MINOR_BASE + camera->subminor);
 
 	camera->dev = dev;
 	usb_inc_dev_use (dev);
@@ -475,12 +482,13 @@
 }
 
 static /* const */ struct usb_driver camera_driver = {
-	"dc2xx",
-	camera_probe,
-	camera_disconnect,
-	{ NULL, NULL },
-	&usb_camera_fops,
-	USB_CAMERA_MINOR_BASE
+	name:		"dc2xx",
+
+	probe:		camera_probe,
+	disconnect:	camera_disconnect,
+
+	fops:		&usb_camera_fops,
+	minor:		USB_CAMERA_MINOR_BASE
 };
 
 
@@ -497,7 +505,7 @@
 }
 
 
-MODULE_AUTHOR("David Brownell, david-b@pacbell.net");
+MODULE_AUTHOR("David Brownell, dbrownell@users.sourceforge.net");
 MODULE_DESCRIPTION("USB Camera Driver for Kodak DC-2xx series cameras");
 
 module_init (usb_dc2xx_init);
diff -urN linux-2.2.19-pre16/drivers/usb/serial/empeg.c linux/drivers/usb/serial/empeg.c
--- linux-2.2.19-pre16/drivers/usb/serial/empeg.c	Mon Dec  3 22:16:35 2001
+++ linux/drivers/usb/serial/empeg.c	Mon Dec  3 22:16:43 2001
@@ -13,6 +13,17 @@
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
  * 
+ * (01/22/2001) gb
+ *	Added write_room() and chars_in_buffer() support. 
+ * 
+ * (12/21/2000) gb
+ *	Moved termio stuff inside the port->active check.
+ *	Moved MOD_DEC_USE_COUNT to end of empeg_close().
+ * 
+ * (12/03/2000) gb
+ *	Added port->tty->ldisc.set_termios(port->tty, NULL) to empeg_open()
+ *	This notifies the tty driver that the termios have changed.
+ * 
  * (11/13/2000) gb
  *	Moved tty->low_latency = 1 from empeg_read_bulk_callback() to empeg_open()
  *	(It only needs to be set once - Doh!)
@@ -39,9 +50,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #ifdef CONFIG_USB_SERIAL_DEBUG
@@ -53,21 +64,29 @@
 
 #include "usb-serial.h"
 
-#define EMPEG_VENDOR_ID                 0x084f
-#define EMPEG_PRODUCT_ID                0x0001
+#define EMPEG_VENDOR_ID			0x084f
+#define EMPEG_PRODUCT_ID		0x0001
 
 #define MIN(a,b)		(((a)<(b))?(a):(b))
 
 /* function prototypes for an empeg-car player */
-static int  empeg_open		(struct usb_serial_port *port, struct file *filp);
-static void empeg_close		(struct usb_serial_port *port, struct file *filp);
-static int  empeg_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
-static void empeg_throttle	(struct usb_serial_port *port);
-static void empeg_unthrottle	(struct usb_serial_port *port);
-static int  empeg_startup	(struct usb_serial *serial);
-static void empeg_shutdown	(struct usb_serial *serial);
-static int  empeg_ioctl		(struct usb_serial_port *port, struct file * file, unsigned int cmd, unsigned long arg);
-static void empeg_set_termios	(struct usb_serial_port *port, struct termios *old_termios);
+static int  empeg_open			(struct usb_serial_port *port, struct file *filp);
+static void empeg_close			(struct usb_serial_port *port, struct file *filp);
+static int  empeg_write			(struct usb_serial_port *port,
+					int from_user,
+					const unsigned char *buf,
+					int count);
+static int  empeg_write_room		(struct usb_serial_port *port);
+static int  empeg_chars_in_buffer	(struct usb_serial_port *port);
+static void empeg_throttle		(struct usb_serial_port *port);
+static void empeg_unthrottle		(struct usb_serial_port *port);
+static int  empeg_startup		(struct usb_serial *serial);
+static void empeg_shutdown		(struct usb_serial *serial);
+static int  empeg_ioctl			(struct usb_serial_port *port,
+					struct file * file,
+					unsigned int cmd,
+					unsigned long arg);
+static void empeg_set_termios		(struct usb_serial_port *port, struct termios *old_termios);
 static void empeg_write_bulk_callback	(struct urb *urb);
 static void empeg_read_bulk_callback	(struct urb *urb);
 
@@ -93,6 +112,8 @@
 	ioctl:			empeg_ioctl,
 	set_termios:		empeg_set_termios,
 	write:			empeg_write,
+	write_room:		empeg_write_room,
+	chars_in_buffer:	empeg_chars_in_buffer,
 	write_bulk_callback:	empeg_write_bulk_callback,
 	read_bulk_callback:	empeg_read_bulk_callback,
 };
@@ -110,6 +131,7 @@
  ******************************************************************************/
 static int empeg_open (struct usb_serial_port *port, struct file *filp)
 {
+	struct usb_serial *serial = port->serial;
 	unsigned long flags;
 	int result;
 
@@ -123,60 +145,73 @@
 	++port->open_count;
 	MOD_INC_USE_COUNT;
 
-	/* gb - 2000/11/05
-	 *
-	 * personally, I think these termios should be set in
-	 * empeg_startup(), but it appears doing so leads to one
-	 * of those chicken/egg problems. :)
-	 *
-	 */
-	port->tty->termios->c_iflag
-		&= ~(IGNBRK
-		| BRKINT
-		| PARMRK
-		| ISTRIP
-		| INLCR
-		| IGNCR
-		| ICRNL
-		| IXON);
-
-	port->tty->termios->c_oflag
-		&= ~OPOST;
-
-	port->tty->termios->c_lflag
-		&= ~(ECHO
-		| ECHONL
-		| ICANON
-		| ISIG
-		| IEXTEN);
-
-	port->tty->termios->c_cflag
-		&= ~(CSIZE
-		| PARENB);
-
-	port->tty->termios->c_cflag
-		|= CS8;
-
-	/* gb - 2000/11/05
-	 *
-	 * force low_latency on
-	 *
-	 * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
-	 * force the data through if low_latency is set.  Otherwise the pushes are
-	 * scheduled; this is bad as it opens up the possibility of dropping bytes
-	 * on the floor.  We are trying to sustain high data transfer rates; and
-	 * don't want to drop bytes on the floor.
-	 * Moral: use low_latency - drop no bytes - life is good. :)
-	 *
-	 */
-	port->tty->low_latency = 1;
-
 	if (!port->active) {
+
+		/* gb - 2000/11/05
+		 * personally, I think these termios should be set in
+		 * empeg_startup(), but it appears doing so leads to one
+		 * of those chicken/egg problems. :)
+		 */
+		port->tty->termios->c_iflag
+			&= ~(IGNBRK
+			| BRKINT
+			| PARMRK
+			| ISTRIP
+			| INLCR
+			| IGNCR
+			| ICRNL
+			| IXON);
+
+		port->tty->termios->c_oflag
+			&= ~OPOST;
+
+		port->tty->termios->c_lflag
+			&= ~(ECHO
+			| ECHONL
+			| ICANON
+			| ISIG
+			| IEXTEN);
+
+		port->tty->termios->c_cflag
+			&= ~(CSIZE
+			| PARENB);
+
+		port->tty->termios->c_cflag
+			|= CS8;
+
+		/* gb - 2000/12/03
+		 * Contributed by Borislav Deianov
+		 * Notify the tty driver that the termios have changed!!
+		 */
+		port->tty->ldisc.set_termios(port->tty, NULL);
+
+		/* gb - 2000/11/05
+		 * force low_latency on
+		 *
+		 * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
+		 * force the data through if low_latency is set.  Otherwise the pushes are
+		 * scheduled; this is bad as it opens up the possibility of dropping bytes
+		 * on the floor.  We are trying to sustain high data transfer rates; and
+		 * don't want to drop bytes on the floor.
+		 * Moral: use low_latency - drop no bytes - life is good. :)
+		 */
+		port->tty->low_latency = 1;
+
 		port->active = 1;
 		bytes_in = 0;
 		bytes_out = 0;
 
 		/* Start reading from the device */
+		FILL_BULK_URB(
+			port->read_urb,
+			serial->dev, 
+			usb_rcvbulkpipe(serial->dev,
+				port->bulk_in_endpointAddress),
+			port->read_urb->transfer_buffer,
+			port->read_urb->transfer_buffer_length,
+			empeg_read_bulk_callback,
+			port);
+
 		port->read_urb->transfer_flags |= USB_QUEUE_BULK;
 
 		result = usb_submit_urb(port->read_urb);
@@ -210,7 +245,6 @@
 	spin_lock_irqsave (&port->port_lock, flags);
 
 	--port->open_count;
-	MOD_DEC_USE_COUNT;
 
 	if (port->open_count <= 0) {
 		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
@@ -232,6 +266,8 @@
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
 
+	MOD_DEC_USE_COUNT;
+
 }
 
 
@@ -287,8 +323,6 @@
 			memcpy (urb->transfer_buffer, current_position, transfer_size);
 		}
 
-		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
 		/* build up our urb */
 		FILL_BULK_URB (
 			urb,
@@ -320,6 +354,58 @@
 } 
 
 
+static int empeg_write_room (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int room = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	/* tally up the number of bytes available */
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status != -EINPROGRESS) {
+			room += URB_TRANSFER_BUFFER_SIZE;
+		}
+	} 
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	dbg(__FUNCTION__ " - returns %d", room);
+
+	return (room);
+
+}
+
+
+static int empeg_chars_in_buffer (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int chars = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	/* tally up the number of bytes waiting */
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+
+	return (chars);
+
+}
+
+
 static void empeg_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -379,9 +465,6 @@
 			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
 				tty_flip_buffer_push(tty);
 				}
-			/* gb - 2000/11/13
-			 * This doesn't push the data through unless tty->low_latency is set.
-			 */
 			tty_insert_flip_char(tty, data[i], 0);
 		}
 		/* gb - 2000/11/13
@@ -392,7 +475,18 @@
 	}
 
 	/* Continue trying to always read  */
+	FILL_BULK_URB(
+		port->read_urb,
+		serial->dev, 
+		usb_rcvbulkpipe(serial->dev,
+			port->bulk_in_endpointAddress),
+		port->read_urb->transfer_buffer,
+		port->read_urb->transfer_buffer_length,
+		empeg_read_bulk_callback,
+		port);
+
 	port->read_urb->transfer_flags |= USB_QUEUE_BULK;
+
 	result = usb_submit_urb(port->read_urb);
 
 	if (result)
diff -urN linux-2.2.19-pre16/drivers/usb/serial/keyspan.c linux/drivers/usb/serial/keyspan.c
--- linux-2.2.19-pre16/drivers/usb/serial/keyspan.c	Mon Dec  3 22:16:35 2001
+++ linux/drivers/usb/serial/keyspan.c	Mon Dec  3 22:16:43 2001
@@ -54,9 +54,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 
@@ -836,9 +836,6 @@
 	p_priv = (struct keyspan_port_private *)(port->private);
 
 	/* Set some sane defaults */
-	p_priv->baud = 9600;
-	p_priv->cflag = CREAD | CLOCAL;
-	p_priv->flow_control = flow_none;
 	p_priv->rts_state = 1;
 	p_priv->dtr_state = 1;
 
@@ -851,16 +848,8 @@
 			dbg(__FUNCTION__ " submit urb %d failed (%d)", i, err);
 		}
 	}
-/*    Now done in startup routine
-	if (atomic_inc_return(&s_priv->active_count) == 1) {
-		s_priv->instat_urb->dev = serial->dev;
-		if ((err = usb_submit_urb(s_priv->instat_urb)) != 0) {
-			dbg(__FUNCTION__ " submit instat urb failed %d", err);
-		}
-	}
-*/
 
-	keyspan_send_setup(port);
+	keyspan_set_termios(port, NULL);
 
 	return (0);
 }
diff -urN linux-2.2.19-pre16/drivers/usb/serial/usbserial.c linux/drivers/usb/serial/usbserial.c
--- linux-2.2.19-pre16/drivers/usb/serial/usbserial.c	Mon Dec  3 22:16:35 2001
+++ linux/drivers/usb/serial/usbserial.c	Mon Dec  3 22:16:43 2001
@@ -14,7 +14,17 @@
  * based on a driver by Brad Keryan)
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
- * 
+ *
+ * 2001_02_05 gkh
+ *	Fixed buffer overflows bug with the generic serial driver.  Thanks to
+ *	Todd Squires <squirest@ct0.com> for fixing this.
+ *
+ * (12/12/2000) gkh
+ *	Removed MOD_INC and MOD_DEC from poll and disconnect functions, and
+ *	moved them to the serial_open and serial_close functions.
+ *	Also fixed bug with there not being a MOD_DEC for the generic driver
+ *	(thanks to Gary Brubaker for finding this.)
+ *
  * (12/29/2000) gkh
  *	Small NULL pointer initialization cleanup which saves a bit of disk image
  *
@@ -246,9 +256,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 #include <linux/list.h>
@@ -456,6 +466,8 @@
 		return -ENODEV;
 	}
 
+	MOD_INC_USE_COUNT;
+	
 	/* set up our port structure making the tty driver remember our port object, and us it */
 	portNumber = MINOR(tty->device) - serial->minor;
 	port = &serial->port[portNumber];
@@ -493,6 +505,8 @@
 	} else {
 		generic_close(port, filp);
 	}
+
+	MOD_DEC_USE_COUNT;
 }	
 
 
@@ -706,16 +720,22 @@
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
 
+	MOD_INC_USE_COUNT;
+
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	spin_lock_irqsave (&port->port_lock, flags);
 	
 	++port->open_count;
-	MOD_INC_USE_COUNT;
 	
 	if (!port->active) {
 		port->active = 1;
 
+		/* force low_latency on so that our tty_push actually forces the data through, 
+		   otherwise it is scheduled, and with high data rates (like with OHCI) data
+		   can get lost. */
+		port->tty->low_latency = 1;
+		
 		/* if we have a bulk interrupt, start reading from it */
 		if (serial->num_bulk_in) {
 			/* Start reading from the device */
@@ -761,6 +781,7 @@
 	}
 
 	spin_unlock_irqrestore (&port->port_lock, flags);
+	MOD_DEC_USE_COUNT;
 }
 
 
@@ -880,8 +901,13 @@
 	tty = port->tty;
 	if (urb->actual_length) {
 		for (i = 0; i < urb->actual_length ; ++i) {
-			 tty_insert_flip_char(tty, data[i], 0);
-	  	}
+			/* if we insert more than TTY_FLIPBUF_SIZE characters, we drop them. */
+			if(tty->flip.count >= TTY_FLIPBUF_SIZE) {
+				tty_flip_buffer_push(tty);
+			}
+			/* this doesn't actually push the data through unless tty->low_latency is set */
+			tty_insert_flip_char(tty, data[i], 0);
+		}
 	  	tty_flip_buffer_push(tty);
 	}
 
@@ -1056,7 +1082,6 @@
 	}
 
 	/* found all that we need */
-	MOD_INC_USE_COUNT;
 	info("%s converter detected", type->name);
 
 #ifdef CONFIG_USB_SERIAL_GENERIC
@@ -1064,7 +1089,6 @@
 		num_ports = num_bulk_out;
 		if (num_ports == 0) {
 			err("Generic device with no bulk out, not allowed.");
-			MOD_DEC_USE_COUNT;
 			return NULL;
 		}
 	} else
@@ -1074,7 +1098,6 @@
 	serial = get_free_serial (num_ports, &minor);
 	if (serial == NULL) {
 		err("No more free serial devices");
-		MOD_DEC_USE_COUNT;
 		return NULL;
 	}
 	
@@ -1220,7 +1243,6 @@
 
 	/* free up any memory that we allocated */
 	kfree (serial);
-	MOD_DEC_USE_COUNT;
 	return NULL;
 }
 
@@ -1287,7 +1309,6 @@
 		info("device disconnected");
 	}
 	
-	MOD_DEC_USE_COUNT;
 }
 
 
diff -urN linux-2.2.19-pre16/drivers/usb/serial/visor.c linux/drivers/usb/serial/visor.c
--- linux-2.2.19-pre16/drivers/usb/serial/visor.c	Sun Dec 10 16:49:43 2000
+++ linux/drivers/usb/serial/visor.c	Mon Dec  3 22:16:43 2001
@@ -10,11 +10,26 @@
  *	(at your option) any later version.
  *
  * See Documentation/usb/usb-serial.txt for more information on using this driver
+ *
+ * (01/21/2000) gkh
+ *	Added write_room and chars_in_buffer, as they were previously using the
+ *	generic driver versions which is all wrong now that we are using an urb
+ *	pool.  Thanks to Wolfgang Grandegger for pointing this out to me.
+ *	Removed count assignment in the write function, which was not needed anymore
+ *	either.  Thanks to Al Borchers for pointing this out.
+ *
+ * (12/12/2000) gkh
+ *	Moved MOD_DEC to end of visor_close to be nicer, as the final write 
+ *	message can sleep.
  * 
  * (11/12/2000) gkh
  *	Fixed bug with data being dropped on the floor by forcing tty->low_latency
  *	to be on.  This fixes the OHCI issue!
  *
+ * (10/05/2000) gkh
+ *	Fixed bug with urb->dev not being set properly, now that the usb
+ *	core needs it.
+ * 
  * (09/11/2000) gkh
  *	Got rid of always calling kmalloc for every urb we wrote out to the
  *	device.
@@ -69,9 +84,9 @@
 #include <linux/init.h>
 #include <linux/malloc.h>
 #include <linux/fcntl.h>
+#include <linux/tty.h>
 #include <linux/tty_driver.h>
 #include <linux/tty_flip.h>
-#include <linux/tty.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
 
@@ -92,6 +107,8 @@
 static int  visor_open		(struct usb_serial_port *port, struct file *filp);
 static void visor_close		(struct usb_serial_port *port, struct file *filp);
 static int  visor_write		(struct usb_serial_port *port, int from_user, const unsigned char *buf, int count);
+static int  visor_write_room		(struct usb_serial_port *port);
+static int  visor_chars_in_buffer	(struct usb_serial_port *port);
 static void visor_throttle	(struct usb_serial_port *port);
 static void visor_unthrottle	(struct usb_serial_port *port);
 static int  visor_startup	(struct usb_serial *serial);
@@ -124,6 +141,8 @@
 	ioctl:			visor_ioctl,
 	set_termios:		visor_set_termios,
 	write:			visor_write,
+	write_room:		visor_write_room,
+	chars_in_buffer:	visor_chars_in_buffer,
 	write_bulk_callback:	visor_write_bulk_callback,
 	read_bulk_callback:	visor_read_bulk_callback,
 };
@@ -142,7 +161,9 @@
  ******************************************************************************/
 static int visor_open (struct usb_serial_port *port, struct file *filp)
 {
+	struct usb_serial *serial = port->serial;
 	unsigned long flags;
+	int result;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return -ENODEV;
@@ -160,13 +181,18 @@
 		bytes_out = 0;
 
 		/* force low_latency on so that our tty_push actually forces the data through, 
-		  otherwise it is scheduled, and with high data rates (like with OHCI) data
-		  can get lost. */
+		   otherwise it is scheduled, and with high data rates (like with OHCI) data
+		   can get lost. */
 		port->tty->low_latency = 1;
-
-		/*Start reading from the device*/
-		if (usb_submit_urb(port->read_urb))
-			dbg(__FUNCTION__  " - usb_submit_urb(read bulk) failed");
+		
+		/* Start reading from the device */
+		FILL_BULK_URB(port->read_urb, serial->dev, 
+			      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+			      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+			      visor_read_bulk_callback, port);
+		result = usb_submit_urb(port->read_urb);
+		if (result)
+			err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 	}
 	
 	spin_unlock_irqrestore (&port->port_lock, flags);
@@ -193,7 +219,6 @@
 	spin_lock_irqsave (&port->port_lock, flags);
 
 	--port->open_count;
-	MOD_DEC_USE_COUNT;
 
 	if (port->open_count <= 0) {
 		transfer_buffer =  kmalloc (0x12, GFP_KERNEL);
@@ -216,6 +241,8 @@
 
 	/* Uncomment the following line if you want to see some statistics in your syslog */
 	/* info ("Bytes In = %d  Bytes Out = %d", bytes_in, bytes_out); */
+
+	MOD_DEC_USE_COUNT;
 }
 
 
@@ -263,8 +290,6 @@
 		else
 			memcpy (urb->transfer_buffer, current_position, transfer_size);
 		
-		count = (count > port->bulk_out_size) ? port->bulk_out_size : count;
-
 		/* build up our urb */
 		FILL_BULK_URB (urb, serial->dev, usb_sndbulkpipe(serial->dev, port->bulk_out_endpointAddress), 
 				urb->transfer_buffer, transfer_size, visor_write_bulk_callback, port);
@@ -286,6 +311,52 @@
 } 
 
 
+static int visor_write_room (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int room = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status != -EINPROGRESS) {
+			room += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+	
+	spin_unlock_irqrestore (&port->port_lock, flags);
+	
+	dbg(__FUNCTION__ " - returns %d", room);
+	return (room);
+}
+
+
+static int visor_chars_in_buffer (struct usb_serial_port *port)
+{
+	unsigned long flags;
+	int i;
+	int chars = 0;
+
+	dbg(__FUNCTION__ " - port %d", port->number);
+	
+	spin_lock_irqsave (&port->port_lock, flags);
+
+	for (i = 0; i < NUM_URBS; ++i) {
+		if (write_urb_pool[i]->status == -EINPROGRESS) {
+			chars += URB_TRANSFER_BUFFER_SIZE;
+		}
+	}
+	
+	spin_unlock_irqrestore (&port->port_lock, flags);
+
+	dbg (__FUNCTION__ " - returns %d", chars);
+	return (chars);
+}
+
+
 static void visor_write_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
@@ -310,15 +381,22 @@
 static void visor_read_bulk_callback (struct urb *urb)
 {
 	struct usb_serial_port *port = (struct usb_serial_port *)urb->context;
+	struct usb_serial *serial = get_usb_serial (port, __FUNCTION__);
 	struct tty_struct *tty;
 	unsigned char *data = urb->transfer_buffer;
 	int i;
+	int result;
 
 	if (port_paranoia_check (port, __FUNCTION__))
 		return;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
+	if (!serial) {
+		dbg(__FUNCTION__ " - bad serial pointer, exiting");
+		return;
+	}
+
 	if (urb->status) {
 		dbg(__FUNCTION__ " - nonzero read bulk status received: %d", urb->status);
 		return;
@@ -341,8 +419,13 @@
 	}
 
 	/* Continue trying to always read  */
-	if (usb_submit_urb(urb))
-		dbg(__FUNCTION__ " - failed resubmitting read urb");
+	FILL_BULK_URB(port->read_urb, serial->dev, 
+		      usb_rcvbulkpipe(serial->dev, port->bulk_in_endpointAddress),
+		      port->read_urb->transfer_buffer, port->read_urb->transfer_buffer_length,
+		      visor_read_bulk_callback, port);
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed resubmitting read urb, error %d", result);
 	return;
 }
 
@@ -366,13 +449,16 @@
 static void visor_unthrottle (struct usb_serial_port *port)
 {
 	unsigned long flags;
+	int result;
 
 	dbg(__FUNCTION__ " - port %d", port->number);
 
 	spin_lock_irqsave (&port->port_lock, flags);
 
-	if (usb_submit_urb (port->read_urb))
-		dbg(__FUNCTION__ " - usb_submit_urb(read bulk) failed");
+	port->read_urb->dev = port->serial->dev;
+	result = usb_submit_urb(port->read_urb);
+	if (result)
+		err(__FUNCTION__ " - failed submitting read urb, error %d", result);
 
 	spin_unlock_irqrestore (&port->port_lock, flags);
 
diff -urN linux-2.2.19-pre16/fs/binfmt_misc.c linux/fs/binfmt_misc.c
--- linux-2.2.19-pre16/fs/binfmt_misc.c	Sun Dec 10 16:49:44 2000
+++ linux/fs/binfmt_misc.c	Mon Dec  3 22:16:43 2001
@@ -41,9 +41,11 @@
 #error You really need /proc support for binfmt_misc. Please reconfigure!
 #endif
 
-#define VERBOSE_STATUS /* undef this to save 400 bytes kernel memory */
+enum {
+	VERBOSE_STATUS = 1 /* define as zero to save 400 bytes kernel memory */
+};
 
-struct binfmt_entry {
+typedef struct binfmt_entry {
 	struct binfmt_entry *next;
 	long id;
 	int flags;			/* type, status, etc. */
@@ -52,16 +54,15 @@
 	char *magic;			/* magic or filename extension */
 	char *mask;			/* mask, NULL for exact match */
 	char *interpreter;		/* filename of interpreter */
-	char *proc_name;
+	char *name;
 	struct proc_dir_entry *proc_dir;
-};
+} Node;
 
-#define ENTRY_ENABLED 1		/* the old binfmt_entry.enabled */
-#define	ENTRY_MAGIC 8		/* not filename detection */
+enum { Enabled, Magic };
 
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs);
-static void entry_proc_cleanup(struct binfmt_entry *e);
-static int entry_proc_setup(struct binfmt_entry *e);
+static void entry_proc_cleanup(Node *e);
+static int entry_proc_setup(Node *e);
 
 static struct linux_binfmt misc_format = {
 #ifndef MODULE
@@ -73,7 +74,7 @@
 
 static struct proc_dir_entry *bm_dir = NULL;
 
-static struct binfmt_entry *entries = NULL;
+static Node *entries = NULL;
 static int free_id = 1;
 static int enabled = 1;
 
@@ -85,7 +86,7 @@
  */
 static void clear_entry(int id)
 {
-	struct binfmt_entry **ep, *e;
+	Node **ep, *e;
 
 	write_lock(&entries_lock);
 	ep = &entries;
@@ -106,7 +107,7 @@
  */
 static void clear_entries(void)
 {
-	struct binfmt_entry *e, *n;
+	Node *e, *n;
 
 	write_lock(&entries_lock);
 	n = entries;
@@ -123,9 +124,9 @@
 /*
  * Find entry through id and lock it
  */
-static struct binfmt_entry *get_entry(int id)
+static Node *get_entry(int id)
 {
-	struct binfmt_entry *e;
+	Node *e;
 
 	read_lock(&entries_lock);
 	e = entries;
@@ -139,7 +140,7 @@
 /*
  * unlock entry
  */
-static inline void put_entry(struct binfmt_entry *e)
+static inline void put_entry(Node *e)
 {
 	if (e)
 		read_unlock(&entries_lock);
@@ -148,19 +149,19 @@
 
 /* 
  * Check if we support the binfmt
- * if we do, return the binfmt_entry, else NULL
+ * if we do, return the node, else NULL
  * locking is done in load_misc_binary
  */
-static struct binfmt_entry *check_file(struct linux_binprm *bprm)
+static Node *check_file(struct linux_binprm *bprm)
 {
-	struct binfmt_entry *e;
+	Node *e;
 	char *p = strrchr(bprm->filename, '.');
 	int j;
 
 	e = entries;
 	while (e) {
-		if (e->flags & ENTRY_ENABLED) {
-			if (!(e->flags & ENTRY_MAGIC)) {
+		if (test_bit(Enabled, &e->flags)) {
+			if (!test_bit(Magic, &e->flags)) {
 				if (p && !strcmp(e->magic, p + 1))
 					return e;
 			} else {
@@ -183,7 +184,7 @@
  */
 static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
 {
-	struct binfmt_entry *fmt;
+	Node *fmt;
 	struct dentry * dentry;
 	char iname[128];
 	char *iname_addr = iname;
@@ -233,46 +234,44 @@
 	return retval;
 }
 
-
-
-/*
- * /proc handling routines
- */
-
 /*
  * parses and copies one argument enclosed in del from *sp to *dp,
  * recognising the \x special.
  * returns pointer to the copied argument or NULL in case of an
  * error (and sets err) or null argument length.
  */
-static char *copyarg(char **dp, const char **sp, int *count,
-		     char del, int special, int *err)
+static char *scanarg(char *s, char del)
 {
-	char c = 0, *res = *dp;
+	char c;
 
-	while (!*err && ((c = *((*sp)++)), (*count)--) && (c != del)) {
-		switch (c) {
-		case '\\':
-			if (special && (**sp == 'x')) {
-				if (!isxdigit(c = toupper(*(++*sp))))
-					*err = -EINVAL;
-				**dp = (c - (isdigit(c) ? '0' : 'A' - 10)) * 16;
-				if (!isxdigit(c = toupper(*(++*sp))))
-					*err = -EINVAL;
-				*((*dp)++) += c - (isdigit(c) ? '0' : 'A' - 10);
-				++*sp;
-				*count -= 3;
-				break;
-			}
-		default:
-			*((*dp)++) = c;
+	while ((c = *s++) != del) {
+		if (c == '\\' && *s == 'x') {
+			s++;
+			if (!isxdigit(*s++))
+				return NULL;
+			if (!isxdigit(*s++))
+				return NULL;
+		}
+	}
+	return s;
+}
+
+static int unquote(char *from)
+{
+	char c = 0, *s = from, *p = from;
+
+	while ((c = *s++) != '\0') {
+		if (c == '\\' && *s == 'x') {
+			s++;
+			c = toupper(*s++);
+			*p = (c - (isdigit(c) ? '0' : 'A' - 10)) << 4;
+			c = toupper(*s++);
+			*p++ |= c - (isdigit(c) ? '0' : 'A' - 10);
+			continue;
 		}
+		*p++ = c;
 	}
-	if (*err || (c != del) || (res == *dp))
-		res = NULL;
-	else if (!special)
-		*((*dp)++) = '\0';
-	return res;
+	return p - from;
 }
 
 /*
@@ -280,59 +279,197 @@
  * ':name:type:offset:magic:mask:interpreter:'
  * where the ':' is the IFS, that can be chosen with the first char
  */
-static int proc_write_register(struct file *file, const char *buffer,
-			       unsigned long count, void *data)
+static Node *create_entry(const char *buffer, size_t count)
 {
-	const char *sp;
-	char del, *dp;
-	struct binfmt_entry *e;
-	int memsize, cnt = count - 1, err;
+	Node *e;
+	int memsize, err;
+	char *buf, *p;
+	char del;
 
 	/* some sanity checks */
 	err = -EINVAL;
 	if ((count < 11) || (count > 256))
-		goto _err;
+		goto out;
 
 	err = -ENOMEM;
-	memsize = sizeof(struct binfmt_entry) + count;
-	if (!(e = (struct binfmt_entry *) kmalloc(memsize, GFP_USER)))
-		goto _err;
-
-	err = 0;
-	sp = buffer + 1;
-	del = buffer[0];
-	dp = (char *)e + sizeof(struct binfmt_entry);
-
-	e->proc_name = copyarg(&dp, &sp, &cnt, del, 0, &err);
-
-	/* we can use bit 3 of type for ext/magic
-	   flag due to the nice encoding of E and M */
-	if ((*sp & ~('E' | 'M')) || (sp[1] != del))
-		err = -EINVAL;
-	else
-		e->flags = (*sp++ & (ENTRY_MAGIC | ENTRY_ENABLED));
-	cnt -= 2; sp++;
+	memsize = sizeof(Node) + count + 8;
+	e = (Node *) kmalloc(memsize, GFP_USER);
+	if (!e)
+		goto out;
 
-	e->offset = 0;
-	while (cnt-- && isdigit(*sp))
-		e->offset = e->offset * 10 + *sp++ - '0';
-	if (*sp++ != del)
-		err = -EINVAL;
-
-	e->magic = copyarg(&dp, &sp, &cnt, del, (e->flags & ENTRY_MAGIC), &err);
-	e->size = dp - e->magic;
-	e->mask = copyarg(&dp, &sp, &cnt, del, 1, &err);
-	if (e->mask && ((dp - e->mask) != e->size))
-		err = -EINVAL;
-	e->interpreter = copyarg(&dp, &sp, &cnt, del, 0, &err);
-	e->id = free_id++;
+	p = buf = (char *)e + sizeof(Node);
+
+	memset(e, 0, sizeof(Node));
+	if (copy_from_user(buf, buffer, count))
+		goto Efault;
+
+	del = *p++;	/* delimeter */
+
+	memset(buf+count, del, 8);
+
+	e->name = p;
+	p = strchr(p, del);
+	if (!p)
+		goto Einval;
+	*p++ = '\0';
+	if (!e->name[0] ||
+	    !strcmp(e->name, ".") ||
+	    !strcmp(e->name, "..") ||
+	    strchr(e->name, '/'))
+		goto Einval;
+	switch (*p++) {
+		case 'E': e->flags = 1<<Enabled; break;
+		case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
+		default: goto Einval;
+	}
+	if (*p++ != del)
+		goto Einval;
+	if (test_bit(Magic, &e->flags)) {
+		char *s = strchr(p, del);
+		if (!s)
+			goto Einval;
+		*s++ = '\0';
+		e->offset = simple_strtoul(p, &p, 10);
+		if (*p++)
+			goto Einval;
+		e->magic = p;
+		p = scanarg(p, del);
+		if (!p)
+			goto Einval;
+		p[-1] = '\0';
+		if (!e->magic[0])
+			goto Einval;
+		e->mask = p;
+		p = scanarg(p, del);
+		if (!p)
+			goto Einval;
+		p[-1] = '\0';
+		if (!e->mask[0])
+			e->mask = NULL;
+		e->size = unquote(e->magic);
+		if (e->mask && unquote(e->mask) != e->size)
+			goto Einval;
+		if (e->size + e->offset > 128)
+			goto Einval;
+	} else {
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+		e->magic = p;
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+		if (!e->magic[0] || strchr(e->magic, '/'))
+			goto Einval;
+		p = strchr(p, del);
+		if (!p)
+			goto Einval;
+		*p++ = '\0';
+	}
+	e->interpreter = p;
+	p = strchr(p, del);
+	if (!p)
+		goto Einval;
+	*p++ = '\0';
+	if (!e->interpreter[0])
+		goto Einval;
+
+	if (*p == '\n')
+		p++;
+	if (p != buf + count)
+		goto Einval;
+	return e;
+
+out:
+	return ERR_PTR(err);
+
+Efault:
+	kfree(e);
+	return ERR_PTR(-EFAULT);
+Einval:
+	kfree(e);
+	return ERR_PTR(-EINVAL);
+}
+
+/*
+ * Set status of entry/binfmt_misc:
+ * '1' enables, '0' disables and '-1' clears entry/binfmt_misc
+ */
+static int parse_command(const char *buffer, size_t count)
+{
+	char s[4];
+
+	if (!count)
+		return 0;
+	if (count > 3)
+		return -EINVAL;
+	if (copy_from_user(s, buffer, count))
+		return -EFAULT;
+	if (s[count-1] == '\n')
+		count--;
+	if (count == 1 && s[0] == '0')
+		return 1;
+	if (count == 1 && s[0] == '1')
+		return 2;
+	if (count == 2 && s[0] == '-' && s[1] == '1')
+		return 3;
+	return -EINVAL;
+}
+
+static void entry_status(Node *e, char *page)
+{
+	char *dp;
+	char *status = "disabled";
 
-	/* more sanity checks */
-	if (err || !(!cnt || (!(--cnt) && (*sp == '\n'))) ||
-	    (e->size < 1) || ((e->size + e->offset) > 127) ||
-	    !(e->proc_name) || !(e->interpreter) || entry_proc_setup(e))
+	if (test_bit(Enabled, &e->flags))
+		status = "enabled";
+
+	if (!VERBOSE_STATUS) {
+		sprintf(page, "%s\n", status);
+		return;
+	}
+
+	sprintf(page, "%s\ninterpreter %s\n", status, e->interpreter);
+	dp = page + strlen(page);
+	if (!test_bit(Magic, &e->flags)) {
+		sprintf(dp, "extension .%s\n", e->magic);
+	} else {
+		int i;
+
+		sprintf(dp, "offset %i\nmagic ", e->offset);
+		dp = page + strlen(page);
+		for (i = 0; i < e->size; i++) {
+			sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
+			dp += 2;
+		}
+		if (e->mask) {
+			sprintf(dp, "\nmask ");
+			dp += 6;
+			for (i = 0; i < e->size; i++) {
+				sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
+				dp += 2;
+			}
+		}
+		*dp++ = '\n';
+		*dp = '\0';
+	}
+}
+
+static int proc_write_register(struct file *file, const char *buffer,
+			       unsigned long count, void *data)
+{
+	Node *e = create_entry(buffer, count);
+	int err;
+
+	if (IS_ERR(e))
+		return PTR_ERR(e);
+	
+	if (entry_proc_setup(e))
 		goto free_err;
 
+	e->id = free_id++;
 	write_lock(&entries_lock);
 	e->next = entries;
 	entries = e;
@@ -355,68 +492,24 @@
 static int proc_read_status(char *page, char **start, off_t off,
 			    int count, int *eof, void *data)
 {
-	struct binfmt_entry *e;
-	char *dp;
-	int elen, i, err;
+	Node *e;
+	int elen;
 
-#ifndef VERBOSE_STATUS
-	if (data) {
-		if (!(e = get_entry((int) data))) {
-			err = -ENOENT;
-			goto _err;
-		}
-		i = e->flags & ENTRY_ENABLED;
-		put_entry(e);
-	} else {
-		i = enabled;
-	} 
-	sprintf(page, "%s\n", (i ? "enabled" : "disabled"));
-#else
-	if (!data)
+	if (!data) {
 		sprintf(page, "%s\n", (enabled ? "enabled" : "disabled"));
-	else {
-		if (!(e = get_entry((long) data))) {
-			err = -ENOENT;
-			goto _err;
-		}
-		sprintf(page, "%s\ninterpreter %s\n",
-		        (e->flags & ENTRY_ENABLED ? "enabled" : "disabled"),
-			e->interpreter);
-		dp = page + strlen(page);
-		if (!(e->flags & ENTRY_MAGIC)) {
-			sprintf(dp, "extension .%s\n", e->magic);
-			dp = page + strlen(page);
-		} else {
-			sprintf(dp, "offset %i\nmagic ", e->offset);
-			dp = page + strlen(page);
-			for (i = 0; i < e->size; i++) {
-				sprintf(dp, "%02x", 0xff & (int) (e->magic[i]));
-				dp += 2;
-			}
-			if (e->mask) {
-				sprintf(dp, "\nmask ");
-				dp += 6;
-				for (i = 0; i < e->size; i++) {
-					sprintf(dp, "%02x", 0xff & (int) (e->mask[i]));
-					dp += 2;
-				}
-			}
-			*dp++ = '\n';
-			*dp = '\0';
-		}
+	} else {
+		if (!(e = get_entry((long) data)))
+			return -ENOENT;
+		entry_status(e, page);
 		put_entry(e);
 	}
-#endif
 
 	elen = strlen(page) - off;
 	if (elen < 0)
 		elen = 0;
 	*eof = (elen <= count) ? 1 : 0;
 	*start = page + off;
-	err = elen;
-
-_err:
-	return err;
+	return elen;
 }
 
 /*
@@ -426,45 +519,50 @@
 static int proc_write_status(struct file *file, const char *buffer,
 			     unsigned long count, void *data)
 {
-	struct binfmt_entry *e;
-	int res = count;
+	Node *e;
+	int res = parse_command(buffer, count);
 
-	if (buffer[count-1] == '\n')
-		count--;
-	if ((count == 1) && !(buffer[0] & ~('0' | '1'))) {
-		if (data) {
-			if ((e = get_entry((long) data)))
-				e->flags = (e->flags & ~ENTRY_ENABLED)
-					    | (int)(buffer[0] - '0');
-			put_entry(e);
-		} else {
-			enabled = buffer[0] - '0';
-		}
-	} else if ((count == 2) && (buffer[0] == '-') && (buffer[1] == '1')) {
-		if (data)
-			clear_entry((long) data);
-		else
-			clear_entries();
-	} else {
-		res = -EINVAL;
+	switch(res) {
+		case 1: if (data) {
+				if ((e = get_entry((long) data)))
+					clear_bit(Enabled, &e->flags);
+				put_entry(e);
+			} else {
+				enabled = 0;
+			}
+			break;
+		case 2: if (data) {
+				if ((e = get_entry((long) data)))
+					set_bit(Enabled, &e->flags);
+				put_entry(e);
+			} else {
+				enabled = 1;
+			}
+			break;
+		case 3: if (data)
+				clear_entry((long) data);
+			else
+				clear_entries();
+			break;
+		default: return res;
 	}
-	return res;
+	return count;
 }
 
 /*
  * Remove the /proc-dir entries of one binfmt
  */
-static void entry_proc_cleanup(struct binfmt_entry *e)
+static void entry_proc_cleanup(Node *e)
 {
-	remove_proc_entry(e->proc_name, bm_dir);
+	remove_proc_entry(e->name, bm_dir);
 }
 
 /*
  * Create the /proc-dir entry for binfmt
  */
-static int entry_proc_setup(struct binfmt_entry *e)
+static int entry_proc_setup(Node *e)
 {
-	if (!(e->proc_dir = create_proc_entry(e->proc_name,
+	if (!(e->proc_dir = create_proc_entry(e->name,
 			 	S_IFREG | S_IRUGO | S_IWUSR, bm_dir)))
 	{
 		printk(KERN_WARNING "Unable to create /proc entry.\n");
@@ -545,4 +643,3 @@
 	remove_proc_entry("sys/fs/binfmt_misc", NULL);
 }
 #endif
-#undef VERBOSE_STATUS
diff -urN linux-2.2.19-pre16/fs/exec.c linux/fs/exec.c
--- linux-2.2.19-pre16/fs/exec.c	Mon Dec  3 22:16:36 2001
+++ linux/fs/exec.c	Mon Dec  3 22:16:43 2001
@@ -20,9 +20,6 @@
  * table to check for several different types  of binary formats.  We keep
  * trying until we recognize the file or we run out of supported binary
  * formats. 
- *
- * (current->executable doesn't exist anymore, procfs searches for the vma
- * that corresponds to the executable and uses its dentry.)
  */
 
 #include <linux/config.h>
@@ -520,7 +517,6 @@
 
 	current->sas_ss_sp = current->sas_ss_size = 0;
 
-	current->dumpable = 0;
 	bprm->dumpable = 0;
 	if (current->euid == current->uid && current->egid == current->gid)
 		bprm->dumpable = !bprm->priv_change;
@@ -829,6 +825,7 @@
 {
 	struct linux_binprm bprm;
 	struct dentry * dentry;
+	int was_dumpable;
 	int retval;
 	int i;
 
@@ -857,6 +854,9 @@
 		return bprm.envc;
 	}
 
+	was_dumpable = current->dumpable;
+	current->dumpable = 0;
+
 	retval = prepare_binprm(&bprm);
 	
 	if (retval >= 0) {
@@ -871,11 +871,11 @@
 	if (retval >= 0)
 		retval = search_binary_handler(&bprm,regs);
 
-	current->dumpable = bprm.dumpable;
-
-	if (retval >= 0)
+	if (retval >= 0) {
 		/* execve success */
+		current->dumpable = bprm.dumpable;
 		return retval;
+	}
 
 	/* Something went wrong, return the inode and free the argument pages*/
 	if (bprm.dentry)
@@ -883,6 +883,8 @@
 
 	for (i=0 ; i<MAX_ARG_PAGES ; i++)
 		free_page(bprm.page[i]);
+
+	current->dumpable = was_dumpable;
 
 	return retval;
 }
diff -urN linux-2.2.19-pre16/include/linux/cdrom.h linux/include/linux/cdrom.h
--- linux-2.2.19-pre16/include/linux/cdrom.h	Mon Sep  4 10:39:28 2000
+++ linux/include/linux/cdrom.h	Mon Dec  3 22:16:43 2001
@@ -528,10 +528,12 @@
 	__u32 end_sector_l0;
 };
 
+#define DVD_LAYERS	4
+
 struct dvd_physical {
 	__u8 type;
 	__u8 layer_num;
-	struct dvd_layer layer[4];
+	struct dvd_layer layer[DVD_LAYERS];
 };
 
 struct dvd_copyright {
diff -urN linux-2.2.19-pre16/net/ipv4/tcp_input.c linux/net/ipv4/tcp_input.c
--- linux-2.2.19-pre16/net/ipv4/tcp_input.c	Mon Dec  3 22:16:36 2001
+++ linux/net/ipv4/tcp_input.c	Mon Dec  3 22:16:43 2001
@@ -5,7 +5,7 @@
  *
  *		Implementation of the Transmission Control Protocol(TCP).
  *
- * Version:	$Id: tcp_input.c,v 1.164.2.20 2001/02/23 20:20:22 davem Exp $
+ * Version:	$Id: tcp_input.c,v 1.164.2.21 2001/03/06 05:39:39 davem Exp $
  *
  * Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
  *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
@@ -2215,6 +2215,7 @@
 			tp->snd_wnd = htons(th->window);
 			tp->snd_wl1 = TCP_SKB_CB(skb)->seq;
 			tp->snd_wl2 = TCP_SKB_CB(skb)->ack_seq;
+			tp->syn_seq = TCP_SKB_CB(skb)->seq;
 			tp->fin_seq = TCP_SKB_CB(skb)->seq;
 
 			tcp_set_state(sk, TCP_ESTABLISHED);
