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

diff -urN linux-2.4.13-pre4/Makefile linux/Makefile
--- linux-2.4.13-pre4/Makefile	Mon Dec  3 23:18:45 2001
+++ linux/Makefile	Mon Dec  3 23:18:54 2001
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 4
 SUBLEVEL = 13
-EXTRAVERSION =-pre4
+EXTRAVERSION =-pre5
 
 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
 
diff -urN linux-2.4.13-pre4/drivers/char/joystick/analog.c linux/drivers/char/joystick/analog.c
--- linux-2.4.13-pre4/drivers/char/joystick/analog.c	Fri Sep 14 14:40:00 2001
+++ linux/drivers/char/joystick/analog.c	Mon Dec  3 23:18:54 2001
@@ -138,7 +138,7 @@
 
 #ifdef __i386__
 #define TSC_PRESENT	(test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
-#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define GET_TIME(x)	do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
 #define DELTA(x,y)	(TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
 #define TIME_NAME	(TSC_PRESENT?"TSC":"PIT")
 #elif __x86_64__
@@ -499,7 +499,9 @@
 	else
 		printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
 		port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
-		port->speed > 10000 ? "M" : "k", (port->loop * 1000000) / port->speed);
+		port->speed > 10000 ? "M" : "k",
+		port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
+				    : (port->loop * 1000000) / port->speed);
 }
 
 /*
diff -urN linux-2.4.13-pre4/drivers/usb/uhci.c linux/drivers/usb/uhci.c
--- linux-2.4.13-pre4/drivers/usb/uhci.c	Mon Dec  3 23:18:46 2001
+++ linux/drivers/usb/uhci.c	Mon Dec  3 23:18:55 2001
@@ -113,44 +113,6 @@
 
 static int uhci_free_dev(struct usb_device *dev)
 {
-	struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-	struct list_head list, *tmp, *head;
-	unsigned long flags;
-
-	/* Walk through the entire URB list and forcefully remove any */
-	/*  URBs that are still active for that device */
-
-	/* Two stage unlink so we don't deadlock on urb_list_lock */
-	INIT_LIST_HEAD(&list);
-
-	spin_lock_irqsave(&uhci->urb_list_lock, flags);
-	head = &uhci->urb_list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-
-		tmp = tmp->next;
-
-		if (urb->dev == dev) {
-			list_del(&urb->urb_list);
-			list_add(&urb->urb_list, &list);
-		}
-	}
-	spin_unlock_irqrestore(&uhci->urb_list_lock, flags);
-
-	head = &list;
-	tmp = head->next;
-	while (tmp != head) {
-		struct urb *urb = list_entry(tmp, struct urb, urb_list);
-		tmp = tmp->next;
-
-		/* Make sure we block waiting on these to die */
-		urb->transfer_flags &= ~USB_ASYNC_UNLINK;
-
-		/* uhci_unlink_urb will unlink from the temp list */
-		uhci_unlink_urb(urb);
-	}
-
 	return 0;
 }
 
@@ -396,50 +358,96 @@
 	pci_pool_free(uhci->qh_pool, qh, qh->dma_handle);
 }
 
-static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct uhci_qh *qh)
+static void _uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
 {
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+	struct list_head *head, *tmp;
 	struct uhci_qh *lqh;
-	unsigned long flags;
-
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
 	/* Grab the last QH */
 	lqh = list_entry(skelqh->list.prev, struct uhci_qh, list);
 
-	qh->link = lqh->link;
+	if (lqh->urbp) {
+		head = &lqh->urbp->queue_list;
+		tmp = head->next;
+		while (head != tmp) {
+			struct urb_priv *turbp =
+				list_entry(tmp, struct urb_priv, queue_list);
+
+			tmp = tmp->next;
+
+			turbp->qh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
+		}
+	}
+
+	head = &urbp->queue_list;
+	tmp = head->next;
+	while (head != tmp) {
+		struct urb_priv *turbp =
+			list_entry(tmp, struct urb_priv, queue_list);
+
+		tmp = tmp->next;
+
+		turbp->qh->link = lqh->link;
+	}
+
+	urbp->qh->link = lqh->link;
 	mb();				/* Ordering is important */
-	lqh->link = qh->dma_handle | UHCI_PTR_QH;
+	lqh->link = urbp->qh->dma_handle | UHCI_PTR_QH;
 
-	list_add_tail(&qh->list, &skelqh->list);
+	list_add_tail(&urbp->qh->list, &skelqh->list);
+}
+
+static void uhci_insert_qh(struct uhci *uhci, struct uhci_qh *skelqh, struct urb *urb)
+{
+	unsigned long flags;
 
+	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+	_uhci_insert_qh(uhci, skelqh, urb);
 	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
 }
 
-static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
+static void uhci_remove_qh(struct uhci *uhci, struct urb *urb)
 {
+	struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 	unsigned long flags;
-	struct uhci_qh *prevqh;
+	struct uhci_qh *qh = urbp->qh, *pqh;
+
+	if (!qh)
+		return;
 
 	/* Only go through the hoops if it's actually linked in */
-	if (list_empty(&qh->list)) {
-		goto list;
-	}
+	if (!list_empty(&qh->list)) {
+		qh->urbp = NULL;
 
-	qh->urbp = NULL;
+		spin_lock_irqsave(&uhci->frame_list_lock, flags);
 
-	spin_lock_irqsave(&uhci->frame_list_lock, flags);
+		pqh = list_entry(qh->list.prev, struct uhci_qh, list);
 
-	prevqh = list_entry(qh->list.prev, struct uhci_qh, list);
+		if (pqh->urbp) {
+			struct list_head *head, *tmp;
 
-	prevqh->link = qh->link;
-	mb();
-	qh->element = qh->link = UHCI_PTR_TERM;
+			head = &pqh->urbp->queue_list;
+			tmp = head->next;
+			while (head != tmp) {
+				struct urb_priv *turbp =
+					list_entry(tmp, struct urb_priv, queue_list);
 
-	list_del_init(&qh->list);
+				tmp = tmp->next;
 
-	spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+				turbp->qh->link = qh->link;
+			}
+		}
+
+		pqh->link = qh->link;
+		mb();
+		qh->element = qh->link = UHCI_PTR_TERM;
+
+		list_del_init(&qh->list);
+
+		spin_unlock_irqrestore(&uhci->frame_list_lock, flags);
+	}
 
-list:
 	spin_lock_irqsave(&uhci->qh_remove_list_lock, flags);
 
 	/* Check to see if the remove list is empty. Set the IOC bit */
@@ -464,9 +472,10 @@
 
 		tmp = tmp->next;
 
-		td->info &= ~(1 << TD_TOKEN_TOGGLE);
 		if (toggle)
-			td->info |= (1 << TD_TOKEN_TOGGLE);
+			set_bit(TD_TOKEN_TOGGLE, &td->info);
+		else
+			clear_bit(TD_TOKEN_TOGGLE, &td->info);
 
 		toggle ^= 1;
 	}
@@ -481,7 +490,7 @@
 {
 	struct urb_priv *eurbp, *urbp, *furbp, *lurbp;
 	struct list_head *tmp;
-	struct uhci_td *ftd, *lltd;
+	struct uhci_td *lltd;
 	unsigned long flags;
 
 	eurbp = eurb->hcpriv;
@@ -510,13 +519,15 @@
 	lurbp = list_entry(furbp->queue_list.prev, struct urb_priv, queue_list);
 
 	lltd = list_entry(lurbp->td_list.prev, struct uhci_td, list);
-	ftd = list_entry(urbp->td_list.next, struct uhci_td, list);
 
 	uhci_fixup_toggle(urb, uhci_toggle(lltd->info) ^ 1);
 
+	/* All qh's in the queue need to link to the next queue */
+	urbp->qh->link = eurbp->qh->link;
+
 	mb();			/* Make sure we flush everything */
 	/* Only support bulk right now, so no depth */
-	lltd->link = ftd->dma_handle;
+	lltd->link = urbp->qh->dma_handle | UHCI_PTR_QH;
 
 	list_add_tail(&urbp->queue_list, &furbp->queue_list);
 
@@ -576,30 +587,9 @@
 		usb_pipeout(urb->pipe), toggle);
 
 	if (!urbp->queued) {
-		int status;
-
-		/*  The HC may continue using the current QH if it finished */
-		/* all of the TD's in this URB and may have started on the */
-		/* next URB's TD's already, so we'll take over ownership */
-		/* of this QH and use it instead. Don't forget to delete */
-		/* the old QH first */
-		uhci_free_qh(uhci, nurbp->qh);
-
-		nurbp->qh = urbp->qh;
-		nurbp->qh->urbp = nurbp;
-		urbp->qh = NULL;
-
-		/* If the last TD from the first (this) urb didn't */
-		/*  complete, reset qh->element to the first TD in the */
-		/*  next urb */
-		pltd = list_entry(urbp->td_list.prev, struct uhci_td, list);
-		status = uhci_status_bits(pltd->status);
-		if ((status & TD_CTRL_ACTIVE) || uhci_actual_length(pltd->status) < uhci_expected_length(pltd->info)) {
-			struct uhci_td *ftd = list_entry(nurbp->td_list.next, struct uhci_td, list);
-			nurbp->qh->element = ftd->dma_handle;
-		}
-
 		nurbp->queued = 0;
+
+		_uhci_insert_qh(uhci, uhci->skel_bulk_qh, nurbp->urb);
 	} else {
 		/* We're somewhere in the middle (or end). A bit trickier */
 		/*  than the head scenario */
@@ -607,15 +597,10 @@
 				queue_list);
 
 		pltd = list_entry(purbp->td_list.prev, struct uhci_td, list);
-		if (nurbp->queued) {
-			struct uhci_td *nftd;
-
-			/* Close the gap between the two */
-			nftd = list_entry(nurbp->td_list.next, struct uhci_td,
-					list);
-			pltd->link = nftd->dma_handle;
-		} else
-			/* The next URB happens to be the beggining, so */
+		if (nurbp->queued)
+			pltd->link = nurbp->qh->dma_handle | UHCI_PTR_QH;
+		else
+			/* The next URB happens to be the beginning, so */
 			/*  we're the last, end the chain */
 			pltd->link = UHCI_PTR_TERM;
 	}
@@ -639,6 +624,7 @@
 	memset((void *)urbp, 0, sizeof(*urbp));
 
 	urbp->inserttime = jiffies;
+	urbp->fsbrtime = jiffies;
 	urbp->urb = urb;
 	urbp->dev = urb->dev;
 	
@@ -900,19 +886,19 @@
 	if (!qh)
 		return -ENOMEM;
 
+	urbp->qh = qh;
+	qh->urbp = urbp;
+
 	/* Low speed or small transfers gets a different queue and treatment */
 	if (urb->pipe & TD_CTRL_LS) {
 		uhci_insert_tds_in_qh(qh, urb, 0);
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, qh);
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	} else {
 		uhci_insert_tds_in_qh(qh, urb, 1);
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, qh);
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
 		uhci_inc_fsbr(uhci, urb);
 	}
 
-	urbp->qh = qh;
-	qh->urbp = urbp;
-
 	return -EINPROGRESS;
 }
 
@@ -961,6 +947,7 @@
 		    !(td->status & TD_CTRL_ACTIVE)) {
 			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
 			urbp->fsbr_timeout = 0;
+			urbp->fsbrtime = jiffies;
 			clear_bit(TD_CTRL_IOC_BIT, &td->status);
 		}
 
@@ -1043,7 +1030,7 @@
 	urbp->short_control_packet = 1;
 
 	/* Create a new QH to avoid pointer overwriting problems */
-	uhci_remove_qh(uhci, urbp->qh);
+	uhci_remove_qh(uhci, urb);
 
 	/* Delete all of the TD's except for the status TD at the end */
 	head = &urbp->td_list;
@@ -1071,9 +1058,9 @@
 
 	/* Low speed or small transfers gets a different queue and treatment */
 	if (urb->pipe & TD_CTRL_LS)
-		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urbp->qh);
+		uhci_insert_qh(uhci, uhci->skel_ls_control_qh, urb);
 	else
-		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urbp->qh);
+		uhci_insert_qh(uhci, uhci->skel_hs_control_qh, urb);
 
 	return -EINPROGRESS;
 }
@@ -1134,6 +1121,7 @@
 		    !(td->status & TD_CTRL_ACTIVE)) {
 			uhci_inc_fsbr(urb->dev->bus->hcpriv, urb);
 			urbp->fsbr_timeout = 0;
+			urbp->fsbrtime = jiffies;
 			clear_bit(TD_CTRL_IOC_BIT, &td->status);
 		}
 
@@ -1147,10 +1135,6 @@
 			goto td_error;
 
 		if (uhci_actual_length(td->status) < uhci_expected_length(td->info)) {
-			usb_settoggle(urb->dev, uhci_endpoint(td->info),
-				uhci_packetout(td->info),
-				uhci_toggle(td->info) ^ 1);
-
 			if (urb->transfer_flags & USB_DISABLE_SPD) {
 				ret = -EREMOTEIO;
 				goto err;
@@ -1303,7 +1287,7 @@
 	if (urb->transfer_flags & USB_QUEUE_BULK && eurb)
 		uhci_append_queued_urb(uhci, eurb, urb);
 	else
-		uhci_insert_qh(uhci, uhci->skel_bulk_qh, qh);
+		uhci_insert_qh(uhci, uhci->skel_bulk_qh, urb);
 
 	uhci_inc_fsbr(uhci, urb);
 
@@ -1681,6 +1665,7 @@
 
 static void uhci_unlink_generic(struct uhci *uhci, struct urb *urb)
 {
+	struct list_head *head, *tmp;
 	struct urb_priv *urbp = urb->hcpriv;
 
 	/* We can get called when urbp allocation fails, so check */
@@ -1689,15 +1674,30 @@
 
 	uhci_dec_fsbr(uhci, urb);	/* Safe since it checks */
 
+	head = &urbp->td_list;
+	tmp = head->next;
+	while (tmp != head) {
+		struct uhci_td *td = list_entry(tmp, struct uhci_td, list);
+
+		tmp = tmp->next;
+
+		/* Control and Isochronous ignore the toggle, so this */
+		/* is safe for all types */
+		if (!(td->status & TD_CTRL_ACTIVE) &&
+		    uhci_actual_length(td->status) < uhci_expected_length(td->info) ||
+		    tmp == head) {
+			usb_settoggle(urb->dev, uhci_endpoint(td->info),
+				uhci_packetout(td->info),
+				uhci_toggle(td->info) ^ 1);
+		}
+	}
+
 	uhci_delete_queued_urb(uhci, urb);
 
-	if (urbp->qh)
-		/* The interrupt loop will reclaim the QH's */
-		uhci_remove_qh(uhci, urbp->qh);
+	/* The interrupt loop will reclaim the QH's */
+	uhci_remove_qh(uhci, urb);
 }
 
-/* FIXME: If we forcefully unlink an urb, we should reset the toggle for */
-/*  that pipe to match what actually completed */
 static int uhci_unlink_urb(struct urb *urb)
 {
 	struct uhci *uhci;
@@ -1951,11 +1951,11 @@
 		tmp = tmp->next;
 
 		/* Check if the FSBR timed out */
-		if (urbp->fsbr && time_after_eq(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+		if (urbp->fsbr && !urbp->fsbr_timeout && time_after_eq(jiffies, urbp->fsbrtime + IDLE_TIMEOUT))
 			uhci_fsbr_timeout(uhci, u);
 
 		/* Check if the URB timed out */
-		if (u->timeout && time_after_eq(jiffies, u->timeout)) {
+		if (u->timeout && time_after_eq(jiffies, urbp->inserttime + u->timeout)) {
 			list_del(&u->urb_list);
 			list_add_tail(&u->urb_list, &list);
 		}
diff -urN linux-2.4.13-pre4/drivers/usb/uhci.h linux/drivers/usb/uhci.h
--- linux-2.4.13-pre4/drivers/usb/uhci.h	Mon Dec  3 23:18:46 2001
+++ linux/drivers/usb/uhci.h	Mon Dec  3 23:18:55 2001
@@ -345,6 +345,7 @@
 	int status;			/* Final status */
 
 	unsigned long inserttime;	/* In jiffies */
+	unsigned long fsbrtime;	/* In jiffies */
 
 	struct list_head queue_list;
 	struct list_head complete_list;
diff -urN linux-2.4.13-pre4/drivers/usb/usbnet.c linux/drivers/usb/usbnet.c
--- linux-2.4.13-pre4/drivers/usb/usbnet.c	Fri Sep 14 14:04:07 2001
+++ linux/drivers/usb/usbnet.c	Mon Dec  3 23:18:55 2001
@@ -15,7 +15,7 @@
  * support as appropriate.  Devices currently supported include:
  *
  *	- AnchorChip 2720
- *	- Belkin F5U104 (custom)
+ *	- Belkin, eTEK (interops with Win32 drivers)
  *	- "Linux Devices" (like iPaq and similar SA-1100 based PDAs)
  *	- NetChip 1080 (interoperates with NetChip Win32 drivers)
  *	- Prolific PL-2301/2302 (replaces "plusb" driver)
@@ -73,6 +73,9 @@
  *		Win32 Belkin driver; other cleanups (db).
  * 16-jul-2001	Bugfixes for uhci oops-on-unplug, Belkin support, various
  *		cleanups for problems not yet seen in the field. (db)
+ * 17-oct-2001	Handle "Advance USBNET" product, like Belkin/eTEK devices,
+ *		from Ioannis Mavroukakis <i.mavroukakis@btinternet.com>;
+ *		rx unlinks somehow weren't async; minor cleanup.
  *
  *-------------------------------------------------------------------------*/
 
@@ -97,7 +100,7 @@
 
 
 #define	CONFIG_USB_AN2720
-#define	CONFIG_USB_BELKIN_F5U104
+#define	CONFIG_USB_BELKIN
 #define	CONFIG_USB_LINUXDEV
 #define	CONFIG_USB_NET1080
 #define	CONFIG_USB_PL2301
@@ -119,7 +122,7 @@
 #endif
 
 // packets are always ethernet inside
-// ... except they can be bigger (up to 64K with this framing)
+// ... except they can be bigger (limit of 64K with NetChip framing)
 #define MIN_PACKET	sizeof(struct ethhdr)
 #define MAX_PACKET	32768
 
@@ -161,7 +164,7 @@
 	struct sk_buff_head	txq;
 	struct sk_buff_head	done;
 	struct tasklet_struct	bh;
-	struct tq_struct ctrl_task;
+	struct tq_struct	ctrl_task;
 };
 
 // device-specific info used by the driver
@@ -169,7 +172,8 @@
 	char		*description;
 
 	int		flags;
-#define FLAG_FRAMING	0x0001		/* guard against device dropouts */ 
+#define FLAG_FRAMING_NC	0x0001		/* guard against device dropouts */ 
+#define FLAG_NO_SETINT	0x0010		/* device can't set_interface() */
 
 	/* reset device ... can sleep */
 	int	(*reset)(struct usbnet *);
@@ -251,7 +255,7 @@
 	u16	packet_id;
 } __attribute__((__packed__));
 
-// packets may use FLAG_FRAMING and optional pad
+// packets may use FLAG_FRAMING_NC and optional pad
 #define FRAMED_SIZE(mtu) (sizeof (struct nc_header) \
 				+ sizeof (struct ethhdr) \
 				+ (mtu) \
@@ -288,22 +292,24 @@
 
 
 
-#ifdef	CONFIG_USB_BELKIN_F5U104
+#ifdef	CONFIG_USB_BELKIN
 
 /*-------------------------------------------------------------------------
  *
  * Belkin F5U104 ... two NetChip 2280 devices + Atmel microcontroller
  *
+ * ... also two eTEK designs, including one sold as "Advance USBNET"
+ *
  *-------------------------------------------------------------------------*/
 
 static const struct driver_info	belkin_info = {
-	description:	"Belkin USB Direct Connect (F5U104)",
+	description:	"Belkin, eTEK, or compatible",
 
 	in: 1, out: 1,		// direction distinguishes these
 	epsize:	64,
 };
 
-#endif	/* CONFIG_USB_BELKIN_F5U104 */
+#endif	/* CONFIG_USB_BELKIN */
 
 
 
@@ -632,7 +638,7 @@
 
 static const struct driver_info	net1080_info = {
 	description:	"NetChip TurboCONNECT",
-	flags:		FLAG_FRAMING,
+	flags:		FLAG_FRAMING_NC,
 	reset:		net1080_reset,
 	check_connect:	net1080_check_connect,
 
@@ -729,9 +735,9 @@
 {
 	struct usbnet	*dev = (struct usbnet *) net->priv;
 
-	if (new_mtu <= sizeof (struct ethhdr) || new_mtu > MAX_PACKET)
+	if (new_mtu <= MIN_PACKET || new_mtu > MAX_PACKET)
 		return -EINVAL;
-	if (((dev->driver_info->flags) & FLAG_FRAMING)) {
+	if (((dev->driver_info->flags) & FLAG_FRAMING_NC)) {
 		if (FRAMED_SIZE (new_mtu) > MAX_PACKET)
 			return -EINVAL;
 	// no second zero-length packet read wanted after mtu-sized packets
@@ -779,9 +785,11 @@
 	unsigned long		lockflags;
 	size_t			size;
 
-	size = (dev->driver_info->flags & FLAG_FRAMING)
-			? FRAMED_SIZE (dev->net.mtu)
-			: (sizeof (struct ethhdr) + dev->net.mtu);
+	if (dev->driver_info->flags & FLAG_FRAMING_NC)
+		size = FRAMED_SIZE (dev->net.mtu);
+	else
+		size = (sizeof (struct ethhdr) + dev->net.mtu);
+
 	if ((skb = alloc_skb (size, flags)) == 0) {
 		dbg ("no rx skb");
 		tasklet_schedule (&dev->bh);
@@ -798,9 +806,15 @@
 	FILL_BULK_URB (urb, dev->udev,
 		usb_rcvbulkpipe (dev->udev, dev->driver_info->in),
 		skb->data, size, rx_complete, skb);
+	urb->transfer_flags |= USB_ASYNC_UNLINK;
 #ifdef	REALLY_QUEUE
 	urb->transfer_flags |= USB_QUEUE_BULK;
 #endif
+#if 0
+	// Idle-but-posted reads with UHCI really chew up
+	// PCI bandwidth unless FSBR is disabled
+	urb->transfer_flags |= USB_NO_FSBR;
+#endif
 
 	spin_lock_irqsave (&dev->rxq.lock, lockflags);
 
@@ -827,7 +841,7 @@
 
 static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
 {
-	if (dev->driver_info->flags & FLAG_FRAMING) {
+	if (dev->driver_info->flags & FLAG_FRAMING_NC) {
 		struct nc_header	*header;
 		struct nc_trailer	*trailer;
 
@@ -1083,9 +1097,11 @@
 	}
 
 	netif_start_queue (net);
-	devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %sframed",
+	devdbg (dev, "open: enable queueing (rx %d, tx %d) mtu %d %s framing",
 		RX_QLEN, TX_QLEN, dev->net.mtu,
-		(info->flags & FLAG_FRAMING) ? "" : "un"
+		(info->flags & FLAG_FRAMING_NC)
+		    ? "NetChip"
+		    : "raw"
 		);
 
 	// delay posting reads until we're fully open
@@ -1194,7 +1210,7 @@
 
 	flags = in_interrupt () ? GFP_ATOMIC : GFP_KERNEL;
 
-	if (info->flags & FLAG_FRAMING) {
+	if (info->flags & FLAG_FRAMING_NC) {
 		struct sk_buff	*skb2;
 		skb2 = fixup_skb (skb, flags);
 		if (!skb2) {
@@ -1215,7 +1231,7 @@
 	entry->state = tx_start;
 	entry->length = length;
 
-	if (info->flags & FLAG_FRAMING) {
+	if (info->flags & FLAG_FRAMING_NC) {
 		header = (struct nc_header *) skb_push (skb, sizeof *header);
 		header->hdr_len = cpu_to_le16 (sizeof (*header));
 		header->packet_len = cpu_to_le16 (length);
@@ -1223,31 +1239,31 @@
 			*skb_put (skb, 1) = PAD_BYTE;
 		trailer = (struct nc_trailer *) skb_put (skb, sizeof *trailer);
 	} else if ((length % EP_SIZE (dev)) == 0) {
-			if (skb_shared (skb)) {
-				struct sk_buff *skb2;
-				skb2 = skb_unshare (skb, flags);
-				if (!skb2) {
-					dbg ("can't unshare skb");
-					goto drop;
-				}
-				skb = skb2;
+		// not all hardware behaves with USB_ZERO_PACKET,
+		// so we add an extra one-byte packet
+		if (skb_shared (skb)) {
+			struct sk_buff *skb2;
+			skb2 = skb_unshare (skb, flags);
+			if (!skb2) {
+				dbg ("can't unshare skb");
+				goto drop;
 			}
-			skb->len++;
+			skb = skb2;
 		}
+		skb->len++;
+	}
 
 	FILL_BULK_URB (urb, dev->udev,
 			usb_sndbulkpipe (dev->udev, info->out),
 			skb->data, skb->len, tx_complete, skb);
-	// Idle-but-posted reads with UHCI really chew up
-	// PCI bandwidth unless FSBR is disabled
-	urb->transfer_flags |= USB_ASYNC_UNLINK | USB_NO_FSBR;
+	urb->transfer_flags |= USB_ASYNC_UNLINK;
 #ifdef	REALLY_QUEUE
 	urb->transfer_flags |= USB_QUEUE_BULK;
 #endif
 	// FIXME urb->timeout = ... jiffies ... ;
 
 	spin_lock_irqsave (&dev->txq.lock, flags);
-	if (info->flags & FLAG_FRAMING) {
+	if (info->flags & FLAG_FRAMING_NC) {
 		header->packet_id = cpu_to_le16 (dev->packet_id++);
 		put_unaligned (header->packet_id, &trailer->packet_id);
 #if 0
@@ -1408,9 +1424,12 @@
 		return 0;
 	}
 
-	if (usb_set_interface (udev, ifnum, altnum) < 0) {
-		err ("set_interface failed");
-		return 0;
+	// more sanity (unless the device is broken)
+	if (!(info->flags & FLAG_NO_SETINT)) {
+		if (usb_set_interface (udev, ifnum, altnum) < 0) {
+			err ("set_interface failed");
+			return 0;
+		}
 	}
 
 	// set up our own records
@@ -1484,6 +1503,18 @@
 },
 #endif
 
+#ifdef	CONFIG_USB_BELKIN
+{
+	USB_DEVICE (0x050d, 0x0004),	// Belkin
+	driver_info:	(unsigned long) &belkin_info,
+}, {
+	USB_DEVICE (0x056c, 0x8100),	// eTEK
+	driver_info:	(unsigned long) &belkin_info,
+}, {
+	USB_DEVICE (0x0525, 0x9901),	// Advance USBNET (eTEK)
+	driver_info:	(unsigned long) &belkin_info,
+},
+#endif
 
 // GeneSys GL620USB (www.genesyslogic.com.tw)
 // (patch exists against an older driver version)
@@ -1508,16 +1539,6 @@
 },
 #endif
 
-#ifdef	CONFIG_USB_BELKIN_F5U104
-{
-	USB_DEVICE (0x050d, 0x0004),	// Belkin
-	driver_info:	(unsigned long) &belkin_info,
-}, {
-	USB_DEVICE (0x056c, 0x8100),	// eTEK
-	driver_info:	(unsigned long) &belkin_info,
-},
-#endif
-
 #ifdef CONFIG_USB_PL2301
 {
 	USB_DEVICE (0x067b, 0x0000),	// PL-2301
@@ -1563,6 +1584,7 @@
 }
 module_exit (usbnet_exit);
 
+EXPORT_NO_SYMBOLS;
 MODULE_AUTHOR ("David Brownell <dbrownell@users.sourceforge.net>");
-MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (Belkin, Linux, NetChip, Prolific, ...)");
-MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION ("USB Host-to-Host Link Drivers (numerous vendors)");
+MODULE_LICENSE ("GPL");
diff -urN linux-2.4.13-pre4/fs/buffer.c linux/fs/buffer.c
--- linux-2.4.13-pre4/fs/buffer.c	Mon Dec  3 23:18:46 2001
+++ linux/fs/buffer.c	Mon Dec  3 23:18:55 2001
@@ -1131,31 +1131,13 @@
 }
 
 /*
- * bforget() is like brelse(), except it might discard any
+ * bforget() is like brelse(), except it discards any
  * potentially dirty data.
  */
 void __bforget(struct buffer_head * buf)
 {
-	/* grab the lru lock here so that "b_count" is stable */
-	spin_lock(&lru_list_lock);
-	write_lock(&hash_table_lock);
-	if (!atomic_dec_and_test(&buf->b_count) || buffer_locked(buf))
-		goto in_use;
-
-	/* Mark it clean */
-	clear_bit(BH_Dirty, &buf->b_state);
-	write_unlock(&hash_table_lock);
-
-	/* After which we can remove it from all queues */
-	remove_inode_queue(buf);
-	__remove_from_lru_list(buf);
-	buf->b_list = BUF_CLEAN;
-	spin_unlock(&lru_list_lock);
-	return;
-
-in_use:
-	write_unlock(&hash_table_lock);
-	spin_unlock(&lru_list_lock);
+	mark_buffer_clean(buf);
+	__brelse(buf);
 }
 
 /**
diff -urN linux-2.4.13-pre4/mm/page_alloc.c linux/mm/page_alloc.c
--- linux-2.4.13-pre4/mm/page_alloc.c	Mon Dec  3 23:18:46 2001
+++ linux/mm/page_alloc.c	Mon Dec  3 23:18:55 2001
@@ -394,7 +394,7 @@
 	}
 
 	/* Don't let big-order allocations loop */
-	if (order)
+	if (order > 1)
 		return NULL;
 
 	/* Yield for kswapd, and try again */
diff -urN linux-2.4.13-pre4/mm/vmscan.c linux/mm/vmscan.c
--- linux-2.4.13-pre4/mm/vmscan.c	Mon Dec  3 23:18:46 2001
+++ linux/mm/vmscan.c	Mon Dec  3 23:18:55 2001
@@ -346,11 +346,7 @@
 
 		page = list_entry(entry, struct page, lru);
 
-		if (unlikely(!PageInactive(page) && !PageActive(page)))
-			BUG();
-
-		/* Mapping-less page on LRU-list? */
-		if (unlikely(!page->mapping))
+		if (unlikely(!PageInactive(page)))
 			BUG();
 
 		list_del(entry);
@@ -363,31 +359,17 @@
 			continue;
 
 		/* Racy check to avoid trylocking when not worthwhile */
-		if (!is_page_cache_freeable(page))
+		if (!page->buffers && page_count(page) != 1)
 			continue;
 
-		if (unlikely(TryLockPage(page))) {
-			if (gfp_mask & __GFP_FS) {
-				page_cache_get(page);
-				spin_unlock(&pagemap_lru_lock);
-				wait_on_page(page);
-				page_cache_release(page);
-				spin_lock(&pagemap_lru_lock);
-			}
-			continue;
-		}
-
 		/*
-		 * Still strictly racy - we don't own the pagecache lock,
-		 * so somebody might look up the page while we do this.
-		 * It's just a heuristic, though.
+		 * The page is locked. IO in progress?
+		 * Move it to the back of the list.
 		 */
-		if (!is_page_cache_freeable(page)) {
-			UnlockPage(page);
+		if (unlikely(TryLockPage(page)))
 			continue;
-		}
 
-		if (PageDirty(page)) {
+		if (PageDirty(page) && is_page_cache_freeable(page) && page->mapping) {
 			/*
 			 * It is not critical here to write it only if
 			 * the page is unmapped beause any direct writer
@@ -460,6 +442,9 @@
 				continue;
 			}
 		}
+
+		if (unlikely(!page->mapping))
+			BUG();
 
 		if (unlikely(!spin_trylock(&pagecache_lock))) {
 			/* we hold the page lock so the page cannot go away from under us */
