]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.51pre2 2.3.51pre2
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:32:38 +0000 (15:32 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:32:38 +0000 (15:32 -0500)
17 files changed:
arch/i386/kernel/apm.c
arch/i386/kernel/process.c
drivers/block/ide-disk.c
drivers/block/ide-geometry.c
drivers/block/ide-proc.c
drivers/net/3c509.c
drivers/net/ppp_generic.c
drivers/usb/uhci.c
drivers/usb/uhci.h
drivers/usb/usb-ohci.c
drivers/usb/usb-uhci.c
drivers/usb/usb.c
drivers/usb/usb.h
include/asm-i386/system.h
include/linux/fb.h
include/linux/pci_ids.h
ipc/shm.c

index 3d403b93cf633b2e92e7ecbdc545d9b2ea6e49e1..99e2587565ad7b14e29a2532a71b72f5e1cb3e83 100644 (file)
@@ -590,11 +590,11 @@ static void apm_cpu_idle(void)
                                        continue;
                                if (hlt_counter)
                                        continue;
-                               asm volatile("cli" : : : "memory");
+                               __cli();
                                if (!current->need_resched)
-                                       asm volatile("sti ; hlt" : : : "memory");
+                                       safe_halt();
                                else
-                                       asm volatile("sti" : : : "memory");
+                                       __sti();
                                continue;
                        }
 
index a043b4cfe0a2713b7c543c483f871bbd841b0a2d..3ba1d8257f63bf1907d6d2f3a2db9011546782f5 100644 (file)
@@ -75,11 +75,11 @@ void enable_hlt(void)
 static void default_idle(void)
 {
        if (current_cpu_data.hlt_works_ok && !hlt_counter) {
-               asm volatile("cli" : : : "memory");
+               __cli();
                if (!current->need_resched)
-                       asm volatile("sti ; hlt" : : : "memory");
+                       safe_halt();
                else
-                       asm volatile("sti" : : : "memory");
+                       __sti();
        }
 }
 
index f766605bcde93c60e4f649acc6977fa6cf05d77a..2ef50f2851eaf4d4114389efc3b3fdeb7b132dcd 100644 (file)
@@ -105,8 +105,11 @@ static int lba_capacity_is_ok (struct hd_driveid *id)
         * The ATA spec tells large drives to return
         * C/H/S = 16383/16/63 independent of their size.
         * Some drives can be jumpered to use 15 heads instead of 16.
+        * Some drives can be jumpered to use 4092 cyls instead of 16383.
         */
-       if (id->cyls == 16383 && id->sectors == 63 &&
+       if ((id->cyls == 16383
+            || (id->cyls == 4092 && id->cur_cyls == 16383)) &&
+           id->sectors == 63 &&
            (id->heads == 15 || id->heads == 16) &&
            id->lba_capacity >= 16383*63*id->heads)
                return 1;
index 0f24b0ac3ac379812b26f7e76cb752bf4620b6e4..6ebf20fe11331dea18b7b6af15ca4260ab81fe19 100644 (file)
@@ -2,6 +2,8 @@
  * linux/drivers/block/ide-geometry.c
  */
 #include <linux/config.h>
+
+#ifdef CONFIG_BLK_DEV_IDE
 #include <linux/ide.h>
 
 #include <asm/io.h>
@@ -60,15 +62,7 @@ void probe_cmos_for_drives (ide_hwif_t *hwif)
        /* Extract drive geometry from CMOS+BIOS if not already setup */
        for (unit = 0; unit < MAX_DRIVES; ++unit) {
                ide_drive_t *drive = &hwif->drives[unit];
-#if 0
-               if ((cmos_disks & (0xf0 >> (unit*4))) &&
-                   !drive->present && !drive->nobios) {
-                       drive->cyl   = drive->bios_cyl  = *(unsigned short *)BIOS;
-                       drive->head  = drive->bios_head = *(BIOS+2);
-                       drive->sect  = drive->bios_sect = *(BIOS+14);
-                       drive->ctl   = *(BIOS+8);
-               }
-#else
+
                if ((cmos_disks & (0xf0 >> (unit*4)))
                   && !drive->present && !drive->nobios) {
                        unsigned short cyl = *(unsigned short *)BIOS;
@@ -83,7 +77,7 @@ void probe_cmos_for_drives (ide_hwif_t *hwif)
                                printk("hd%d: C/H/S=%d/%d/%d from BIOS ignored\n", unit, cyl, head, sect);
                        }
                }
-#endif
+
                BIOS += 16;
        }
 #endif
@@ -98,13 +92,15 @@ static void
 ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
        static const byte dm_head_vals[] = {4, 8, 16, 32, 64, 128, 255, 0};
        const byte *headp = dm_head_vals;
-       unsigned long total, tracks;
+       unsigned long total;
 
        /*
         * The specs say: take geometry as obtained from Identify,
         * compute total capacity C*H*S from that, and truncate to
         * 1024*255*63. Now take S=63, H the first in the sequence
         * 4, 8, 16, 32, 64, 128, 255 such that 63*H*1024 >= total.
+        * [Please tell aeb@cwi.nl in case this computes a
+        * geometry different from what OnTrack uses.]
         */
        total = DRIVER(drive)->capacity(drive);
 
@@ -116,32 +112,10 @@ ontrack(ide_drive_t *drive, int heads, unsigned int *c, int *h, int *s) {
                return;
        }
 
-#if 0
        while (63 * headp[0] * 1024 < total && headp[1] != 0)
                 headp++;
        *h = headp[0];
        *c = total / (63 * headp[0]);
-#else
-       /* The code below differs in two aspects:
-          (i) It will not produce geometries like C/H/S = 1024/64/63
-               because of the `>='. This follows OnTracks text (which
-               claims that 512 <= C <= 1023), but not OnTracks code.
-          (ii) It starts dividing by 63, so that a rounding down occurs.
-               For example, with C=11159, H=10, S=37 we find total=4128830
-               and DM would make C=512, H=128, S=63, but we make 1024/64/63
-               if `>=' is replaced by `>'.
-          The reason we use this code is mainly that we have done so for
-          a long time without getting complaints.
-       */
-
-       tracks = total / 63;
-       while (*c >= 1024) {
-               *h = *headp;
-               *c = tracks / *h;
-               if (*++headp == 0)
-                       break;
-       }
-#endif
 }
 
 /*
@@ -237,3 +211,4 @@ int ide_xlate_1024 (kdev_t i_rdev, int xparm, int ptheads, const char *msg)
                       drive->bios_cyl, drive->bios_head, drive->bios_sect);
        return ret;
 }
+#endif /* CONFIG_BLK_DEV_IDE */
index debba3207c19da1c64dbd656b8edaf0718a7c897..753597e9cf19f7b3a3d701866d10af0e03f285e3 100644 (file)
@@ -51,7 +51,7 @@
  * be updated someday soon to use this mechanism.
  *
  * Feel free to develop and distribute fancy GUI configuration
- * utilities for you favorite PCI chipsets.  I'll be working on
+ * utilities for your favorite PCI chipsets.  I'll be working on
  * one for the Promise 20246 someday soon.  -ml
  *
  */
@@ -798,7 +798,7 @@ void proc_ide_create(void)
 
        create_proc_ide_interfaces();
 
-       create_proc_read_entry("drivers",0,proc_ide_root,
+       create_proc_read_entry("drivers", 0, proc_ide_root,
                                proc_ide_read_drivers, NULL);
 
 #ifdef CONFIG_BLK_DEV_AEC6210
@@ -823,11 +823,11 @@ void proc_ide_create(void)
 #endif /* CONFIG_BLK_DEV_CS5530 */
 #ifdef CONFIG_BLK_DEV_HPT34X
        if ((hpt34x_display_info) && (hpt34x_proc))
-               create_proc_info_entry("", 0, proc_ide_root, hpt34x_display_info);
+               create_proc_info_entry("hpt34x", 0, proc_ide_root, hpt34x_display_info);
 #endif /* CONFIG_BLK_DEV_HPT34X */
 #ifdef CONFIG_BLK_DEV_HPT366
        if ((hpt366_display_info) && (hpt366_proc))
-               create_proc_info_entry("", 0, proc_ide_root, hpt366_display_info);
+               create_proc_info_entry("hpt366", 0, proc_ide_root, hpt366_display_info);
 #endif /* CONFIG_BLK_DEV_HPT366 */
 #ifdef CONFIG_BLK_DEV_PDC202XX
        if ((pdc202xx_display_info) && (pdc202xx_proc))
index 06a616592c513b1bb6afa0172e9ea083d748f31e..08c92ace9d02be89bab3d84fb6551276338146d7 100644 (file)
@@ -186,8 +186,10 @@ u16 el3_isapnp_phys_addr[8][3] = {
        {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0},
        {0, 0, 0}, {0, 0, 0}, {0, 0, 0}, {0, 0, 0}
 };
-#endif
+#endif /* CONFIG_ISAPNP */
+#if defined(CONFIG_ISAPNP) || defined(MODULE)
 static int nopnp = 0;
+#endif
 
 int el3_probe(struct net_device *dev)
 {
@@ -195,8 +197,10 @@ int el3_probe(struct net_device *dev)
        int ioaddr, irq, if_port;
        u16 phys_addr[3];
        static int current_tag = 0;
-       static int pnp_cards = 0;
        int mca_slot = -1;
+#ifdef CONFIG_ISAPNP
+       static int pnp_cards = 0;
+#endif
 
        /* First check all slots of the EISA bus.  The next slot address to
           probe is kept in 'eisa_addr' to support multiple probe() calls. */
index ddfed868e8c5c26e27149135b678060ea3333afc..0b3aeff4bc6339c621107f8fcaa0b6f5d16c4b89 100644 (file)
@@ -558,7 +558,9 @@ int __init ppp_init(void)
 {
        int err;
 #ifndef MODULE
+#ifdef CONFIG_PPP_DEFLATE
        extern struct compressor ppp_deflate, ppp_deflate_draft;
+#endif
        extern int ppp_async_init(void);
        extern int ppp_sync_init(void);
 #endif
index ec4cad49199e91acae57f869131a003309373de7..bf6fe6571d19d39a6e8d96d9e5559ebf9fadbaac 100644 (file)
@@ -54,18 +54,21 @@ MODULE_PARM(debug, "i");
 
 static kmem_cache_t *uhci_td_cachep;
 static kmem_cache_t *uhci_qh_cachep;
+static kmem_cache_t *uhci_up_cachep;   /* urb_priv */
 
 static LIST_HEAD(uhci_list);
 
 static int rh_submit_urb(urb_t *urb);
 static int rh_unlink_urb(urb_t *urb);
 static int uhci_get_current_frame_number(struct usb_device *dev);
-static void uhci_stop_hc_schedule(struct uhci *uhci);
-static void uhci_start_hc_schedule(struct uhci *uhci);
+static int uhci_unlink_generic(urb_t *urb);
 static int uhci_unlink_urb(urb_t *urb);
 
 #define min(a,b) (((a)<(b))?(a):(b))
 
+/* If a transfer is still active after this much time, turn off FSBR */
+#define IDLE_TIMEOUT   (HZ / 20)       /* 50 ms */
+
 /*
  * Only the USB core should call uhci_alloc_dev and uhci_free_dev
  */
@@ -78,7 +81,7 @@ static int uhci_free_dev(struct usb_device *dev)
 {
        urb_t *u;
        struct uhci *uhci = (struct uhci *)dev->bus->hcpriv;
-       struct list_head *tmp, *head = &uhci->urb_list;
+       struct list_head *tmp, *next, *head = &uhci->urb_list;
        unsigned long flags;
 
        /* Walk through the entire URB list and forcefully remove any */
@@ -88,38 +91,18 @@ static int uhci_free_dev(struct usb_device *dev)
        while (tmp != head) {
                u = list_entry(tmp, urb_t, urb_list);
 
+               next = tmp->next;
+
                if (u->dev == dev)
                        uhci_unlink_urb(u);
+
+               tmp = next;
        }
        nested_unlock(&uhci->urblist_lock, flags);
 
        return 0;
 }
 
-/*
- * UHCI interrupt list operations..
- */
-static void uhci_add_irq_list(struct uhci *uhci, struct uhci_td *td)
-{
-       unsigned long flags;
-
-       nested_lock(&uhci->irqlist_lock, flags);
-       list_add(&td->irq_list, &uhci->interrupt_list);
-       nested_unlock(&uhci->irqlist_lock, flags);
-}
-
-static void uhci_remove_irq_list(struct uhci *uhci, struct uhci_td *td)
-{
-       unsigned long flags;
-
-       nested_lock(&uhci->irqlist_lock, flags);
-       if (td->irq_list.next != &td->irq_list) {
-               list_del(&td->irq_list);
-               INIT_LIST_HEAD(&td->irq_list);
-       }
-       nested_unlock(&uhci->irqlist_lock, flags);
-}
-
 static void uhci_add_urb_list(struct uhci *uhci, struct urb *urb)
 {
        unsigned long flags;
@@ -141,6 +124,54 @@ static void uhci_remove_urb_list(struct uhci *uhci, struct urb *urb)
        nested_unlock(&uhci->urblist_lock, flags);
 }
 
+static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
+{
+       struct uhci_td *td;
+
+       td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+       if (!td)
+               return NULL;
+
+       td->link = UHCI_PTR_TERM;
+       td->buffer = 0;
+
+       td->frameptr = NULL;
+       td->nexttd = td->prevtd = NULL;
+       td->list.next = td->list.prev = NULL;
+       td->dev = dev;
+
+       usb_inc_dev_use(dev);
+
+       return td;
+}
+
+static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
+               __u32 info, __u32 buffer)
+{
+       td->status = status;
+       td->info = info;
+       td->buffer = buffer;
+}
+
+static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&uhci->framelist_lock, flags);
+
+       /* Fix the linked list pointers */
+       td->nexttd = skeltd->nexttd;
+       td->prevtd = skeltd;
+       if (skeltd->nexttd)
+               skeltd->nexttd->prevtd = td;
+       skeltd->nexttd = td;
+
+       td->link = skeltd->link;
+       skeltd->link = virt_to_bus(td);
+
+       spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+}
+
 /*
  * We insert Isochronous transfers directly into the frame list at the
  * beginning
@@ -157,6 +188,7 @@ static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, uns
        framenum %= UHCI_NUMFRAMES;
 
        spin_lock_irqsave(&uhci->framelist_lock, flags);
+
        td->frameptr = &uhci->fl->frame[framenum];
        td->link = uhci->fl->frame[framenum];
        if (!(td->link & (UHCI_PTR_TERM | UHCI_PTR_QH))) {
@@ -166,6 +198,7 @@ static void uhci_insert_td_frame_list(struct uhci *uhci, struct uhci_td *td, uns
                nexttd->frameptr = NULL;
        }
        uhci->fl->frame[framenum] = virt_to_bus(td);
+
        spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
 
@@ -173,6 +206,10 @@ static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
 {
        unsigned long flags;
 
+       /* If it's not inserted, don't remove it */
+       if (!td->frameptr && !td->prevtd && !td->nexttd)
+               return;
+
        spin_lock_irqsave(&uhci->framelist_lock, flags);
        if (td->frameptr) {
                *(td->frameptr) = td->link;
@@ -195,77 +232,41 @@ static void uhci_remove_td(struct uhci *uhci, struct uhci_td *td)
        spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
 
-static void uhci_insert_td(struct uhci *uhci, struct uhci_td *skeltd, struct uhci_td *td)
-{
-       unsigned long flags;
-
-       spin_lock_irqsave(&uhci->framelist_lock, flags);
-
-       /* Fix the linked list pointers */
-       td->nexttd = skeltd->nexttd;
-       td->prevtd = skeltd;
-       if (skeltd->nexttd)
-               skeltd->nexttd->prevtd = td;
-       skeltd->nexttd = td;
-
-       td->link = skeltd->link;
-       skeltd->link = virt_to_bus(td);
-
-       spin_unlock_irqrestore(&uhci->framelist_lock, flags);
-}
-
 /*
  * Inserts a td into qh list at the top.
  */
-static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct uhci_td *begin)
+static void uhci_insert_tds_in_qh(struct uhci_qh *qh, struct urb *urb, int breadth)
 {
-       struct uhci_td *td, *prevtd;
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+       struct uhci_td *td, *prevtd = NULL;
 
-       if (!begin)             /* Nothing to do */
+       if (!urbp)
                return;
 
-       /* Grab the first TD and add it to the QH */
-       td = begin;
-       qh->element = virt_to_bus(td) | UHCI_PTR_DEPTH;
+       td = urbp->list.begin;
+       if (!td)
+               return;
+
+       /* Add the first TD to the QH element pointer */
+       qh->element = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
 
-       /* Go through the rest of the TD's, link them together */
        prevtd = td;
-       td = td->next;
-       while (td) {
-               prevtd->link = virt_to_bus(td) | UHCI_PTR_DEPTH;
+
+       /* Then link the rest of the TD's */
+       for (td = td->list.next; td; td = td->list.next) {
+               prevtd->link = virt_to_bus(td) | (breadth ? 0 : UHCI_PTR_DEPTH);
 
                prevtd = td;
-               td = td->next;
        }
 
        prevtd->link = UHCI_PTR_TERM;
 }
 
-static struct uhci_td *uhci_alloc_td(struct usb_device *dev)
-{
-       struct uhci_td *td;
-
-       td = kmem_cache_alloc(uhci_td_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
-       if (!td)
-               return NULL;
-
-       td->link = UHCI_PTR_TERM;
-       td->buffer = 0;
-
-       td->frameptr = NULL;
-       td->nexttd = td->prevtd = NULL;
-       td->next = NULL;
-       td->dev = dev;
-       INIT_LIST_HEAD(&td->irq_list);
-       INIT_LIST_HEAD(&td->list);
-
-       usb_inc_dev_use(dev);
-
-       return td;
-}
-
 static void uhci_free_td(struct uhci_td *td)
 {
+       if (td->list.next || td->list.prev)
+               dbg("td is still in URB list!");
+
        kmem_cache_free(uhci_td_cachep, td);
 
        if (td->dev)
@@ -286,7 +287,7 @@ static struct uhci_qh *uhci_alloc_qh(struct usb_device *dev)
        qh->dev = dev;
        qh->prevqh = qh->nextqh = NULL;
 
-       INIT_LIST_HEAD(&qh->list);
+       INIT_LIST_HEAD(&qh->remove_list);
 
        usb_inc_dev_use(dev);
 
@@ -333,14 +334,31 @@ static void uhci_remove_qh(struct uhci *uhci, struct uhci_qh *qh)
                qh->nextqh->prevqh = qh->prevqh;
        qh->prevqh = qh->nextqh = NULL;
        spin_unlock_irqrestore(&uhci->framelist_lock, flags);
+
+       spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+       list_add(&qh->remove_list, &uhci->qh_remove_list);
+       spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
 }
 
-static void inline uhci_fill_td(struct uhci_td *td, __u32 status,
-               __u32 info, __u32 buffer)
+struct urb_priv *uhci_alloc_urb_priv(struct urb *urb)
 {
-       td->status = status;
-       td->info = info;
-       td->buffer = buffer;
+       struct urb_priv *urbp;
+
+       urbp = kmem_cache_alloc(uhci_up_cachep, in_interrupt() ? SLAB_ATOMIC : SLAB_KERNEL);
+       if (!urbp)
+               return NULL;
+
+       memset((void *)urbp, 0, sizeof(*urbp));
+
+       urbp->list.begin = urbp->list.end = NULL;
+
+       urb->hcpriv = urbp;
+
+       urbp->inserttime = jiffies;
+
+       usb_inc_dev_use(urb->dev);
+
+       return urbp;
 }
 
 static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
@@ -349,35 +367,110 @@ static void uhci_add_td_to_urb(urb_t *urb, struct uhci_td *td)
 
        td->urb = urb;
 
-       if (urbp->end)
-               urbp->end->next = td;
+       if (!urbp->list.begin)
+               urbp->list.begin = td;
+
+       if (urbp->list.end) {
+               urbp->list.end->list.next = td;
+               td->list.prev = urbp->list.end;
+       }
+       urbp->list.end = td;
+}
+
+static void uhci_remove_td_from_urb(urb_t *urb, struct uhci_td *td)
+{
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+       if (!urbp->list.begin && !urbp->list.end)
+               return;
+
+       if (td->list.prev)
+               td->list.prev->list.next = td->list.next;
+       else
+               urbp->list.begin = td->list.next;
+
+       if (td->list.next)
+               td->list.next->list.prev = td->list.prev;
+       else
+               urbp->list.end = td->list.prev;
+
+       td->list.next = td->list.prev = NULL;
+       td->urb = NULL;
+}
+
+static void uhci_destroy_urb_priv(urb_t *urb)
+{
+       struct urb_priv *urbp;
+       struct uhci *uhci;
+       struct uhci_td *td, *nexttd;
+       unsigned long flags;
+
+       spin_lock_irqsave(&urb->lock, flags);
+
+       urbp = (struct urb_priv *)urb->hcpriv;
+       if (!urbp)
+               return;
+
+       if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
+               return;
+
+       uhci = urb->dev->bus->hcpriv;
+
+       td = urbp->list.begin;
+       while (td) {
+               nexttd = td->list.next;
+
+               uhci_remove_td_from_urb(urb, td);
+
+               uhci_remove_td(uhci, td);
+
+               uhci_free_td(td);
+               
+               td = nexttd;
+       }
+
+       urb->hcpriv = NULL;
+       kmem_cache_free(uhci_up_cachep, urbp);
 
-       urbp->end = td;
+       spin_unlock_irqrestore(&urb->lock, flags);
 
-       if (!urbp->begin)
-               urbp->begin = td;
+       usb_dec_dev_use(urb->dev);
 }
 
-void uhci_inc_fsbr(struct uhci *uhci)
+static void uhci_inc_fsbr(struct uhci *uhci, struct urb *urb)
 {
        unsigned long flags;
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+       if (!urbp)
+               return;
 
        spin_lock_irqsave(&uhci->framelist_lock, flags);
 
-       if (!uhci->fsbr++)
-               uhci->skel_term_qh.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+       if (!urbp->fsbr) {
+               urbp->fsbr = 1;
+               if (!uhci->fsbr++)
+                       uhci->skel_term_td.link = virt_to_bus(&uhci->skel_hs_control_qh) | UHCI_PTR_QH;
+       }
 
        spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
 
-void uhci_dec_fsbr(struct uhci *uhci)
+static void uhci_dec_fsbr(struct uhci *uhci, struct urb *urb)
 {
        unsigned long flags;
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+
+       if (!urbp)
+               return;
 
        spin_lock_irqsave(&uhci->framelist_lock, flags);
 
-       if (!--uhci->fsbr)
-               uhci->skel_term_qh.link = UHCI_PTR_TERM;
+       if (urbp->fsbr) {
+               urbp->fsbr = 0;
+               if (!--uhci->fsbr)
+                       uhci->skel_term_td.link = UHCI_PTR_TERM;
+       }
 
        spin_unlock_irqrestore(&uhci->framelist_lock, flags);
 }
@@ -419,14 +512,14 @@ static int uhci_map_status(int status, int dir_out)
  */
 static int uhci_submit_control(urb_t *urb)
 {
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
+       struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
        struct uhci_td *td;
        struct uhci_qh *qh;
        unsigned long destination, status;
-       struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
        int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
        int len = urb->transfer_buffer_length;
        unsigned char *data = urb->transfer_buffer;
-       struct urb_priv *urbp;
 
        /* The "pipe" thing contains the destination in bits 8--18 */
        destination = (urb->pipe & PIPE_DEVEP_MASK) | USB_PID_SETUP;
@@ -434,14 +527,6 @@ static int uhci_submit_control(urb_t *urb)
        /* 3 errors */
        status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
 
-       urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-       if (!urbp)
-               return -ENOMEM;
-
-       urbp->begin = urbp->end = NULL;
-
-       urb->hcpriv = urbp;
-
        /*
         * Build the TD for the control request
         */
@@ -465,18 +550,16 @@ static int uhci_submit_control(urb_t *urb)
        /*
         * Build the DATA TD's
         */
-       td = uhci_alloc_td(urb->dev);
-       if (!td) {
-               /* FIXME: Free the TD's */
-               return -ENOMEM;
-       }
-
        while (len > 0) {
                int pktsze = len;
 
                if (pktsze > maxsze)
                        pktsze = maxsze;
 
+               td = uhci_alloc_td(urb->dev);
+               if (!td)
+                       return -ENOMEM;
+
                /* Alternate Data0/1 (start with Data1) */
                destination ^= 1 << TD_TOKEN_TOGGLE;
        
@@ -486,16 +569,16 @@ static int uhci_submit_control(urb_t *urb)
 
                data += pktsze;
                len -= pktsze;
-
-               td = uhci_alloc_td(urb->dev);
-               if (!td)
-                       /* FIXME: Free all of the previously allocated td's */
-                       return -ENOMEM;
        }
 
        /*
         * Build the final TD for control status 
-        *
+        */
+       td = uhci_alloc_td(urb->dev);
+       if (!td)
+               return -ENOMEM;
+
+       /*
         * It's IN if the pipe is an output pipe or we're not expecting
         * data back.
         */
@@ -513,20 +596,19 @@ static int uhci_submit_control(urb_t *urb)
        uhci_fill_td(td, status | TD_CTRL_IOC,
                destination | (UHCI_NULL_DATA_SIZE << 21), 0);
 
-       uhci_add_irq_list(uhci, td);
-
        qh = uhci_alloc_qh(urb->dev);
-       if (!qh) {
-               /* FIXME: Free all of the TD's */
+       if (!qh)
                return -ENOMEM;
-       }
-       uhci_insert_tds_in_qh(qh, urbp->begin);
 
-       if (!(urb->pipe & TD_CTRL_LS)) {
-               uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
-               uhci_inc_fsbr(uhci);
-       } else
+       /* 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);
+       } else {
+               uhci_insert_tds_in_qh(qh, urb, 1);
+               uhci_insert_qh(uhci, &uhci->skel_hs_control_qh, qh);
+               uhci_inc_fsbr(uhci, urb);
+       }
 
        urbp->qh = qh;
 
@@ -537,66 +619,22 @@ static int uhci_submit_control(urb_t *urb)
        return -EINPROGRESS;
 }
 
-/* This is also the uhci_unlink_bulk function */
-static int uhci_unlink_control(urb_t *urb)
+static int uhci_result_control(urb_t *urb)
 {
        struct urb_priv *urbp = urb->hcpriv;
        struct uhci_td *td;
-       struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-       int notfinished;
+       unsigned int status;
 
        if (!urbp)
                return -EINVAL;
 
-       notfinished = (urb->status == -EINPROGRESS);
-
-       if (notfinished)
-               uhci_stop_hc_schedule(uhci);
-
-       if (!(urb->pipe & TD_CTRL_LS))
-               uhci_dec_fsbr(uhci);
-
-       uhci_remove_qh(uhci, urbp->qh);
-       uhci_free_qh(urbp->qh);
-
-       /* Go through the rest of the TD's, deleting them, then scheduling */
-       /*  their deletion */
-       td = urbp->begin;
-       while (td) {
-               struct uhci_td *next = td->next;
-
-               if (td->status & TD_CTRL_IOC)
-                       uhci_remove_irq_list(uhci, td);
-
-               uhci_free_td(td);
-
-               td = next;
-       }
-
-       if (notfinished)
-               uhci_start_hc_schedule(uhci);
-
-       kfree(urbp);
-       urb->hcpriv = NULL;
-
-       uhci_remove_urb_list(uhci, urb);
-
-       return 0;
-}
-
-static int uhci_result_control(urb_t *urb)
-{
-       struct urb_priv *urbp = urb->hcpriv;
-       struct uhci_td *td;
-       unsigned int status;
-
-       td = urbp->begin;
-       if (!td)                /* Nothing to do */
+       td = urbp->list.begin;
+       if (!td)
                return -EINVAL;
 
        /* The first TD is the SETUP phase, check the status, but skip */
        /*  the count */
-       status =  uhci_status_bits(td->status);
+       status = uhci_status_bits(td->status);
        if (status & TD_CTRL_ACTIVE)
                return -EINPROGRESS;
 
@@ -605,9 +643,10 @@ static int uhci_result_control(urb_t *urb)
 
        urb->actual_length = 0;
 
+       td = td->list.next;
+
        /* The rest of the TD's (but the last) are data */
-       td = td->next;
-       while (td && td->next) {
+       while (td && td->list.next) {
                status = uhci_status_bits(td->status);
                if (status & TD_CTRL_ACTIVE)
                        return -EINPROGRESS;
@@ -617,13 +656,14 @@ static int uhci_result_control(urb_t *urb)
                /* If SPD is set then we received a short packet */
                /*  There will be no status phase at the end */
                /* FIXME: Re-setup the queue to run the STATUS phase? */
-               if (td->status & TD_CTRL_SPD && (uhci_actual_length(td->status) < uhci_expected_length(td->info)))
+               if ((td->status & TD_CTRL_SPD) &&
+                   (uhci_actual_length(td->status) < uhci_expected_length(td->info)))
                        return 0;
 
                if (status)
                        goto td_error;
 
-               td = td->next;
+               td = td->list.next;
        }
 
        /* Control status phase */
@@ -648,18 +688,16 @@ static int uhci_result_control(urb_t *urb)
 td_error:
        /* Some debugging code */
        if (debug) {
-               dbg("uhci_result_control() failed with status %x",
-                       status);
+               dbg("uhci_result_control() failed with status %x", status);
 
                /* Print the chain for debugging purposes */
                uhci_show_queue(urbp->qh);
        }
 
-       if (status & TD_CTRL_STALLED) {
+       if (status & TD_CTRL_STALLED)
                /* endpoint has stalled - mark it halted */
                usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
                                uhci_packetout(td->info));
-       }
 
        return uhci_map_status(status, uhci_packetout(td->info));
 }
@@ -672,7 +710,6 @@ static int uhci_submit_interrupt(urb_t *urb)
        struct uhci_td *td;
        unsigned long destination, status;
        struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-       struct urb_priv *urbp;
 
        if (urb->transfer_buffer_length > usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe)))
                return -EINVAL;
@@ -680,16 +717,7 @@ static int uhci_submit_interrupt(urb_t *urb)
        /* The "pipe" thing contains the destination in bits 8--18 */
        destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
-       status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_SPD |
-                       TD_CTRL_IOC;
-
-       urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-       if (!urbp)
-               return -ENOMEM;
-
-       urbp->begin = urbp->end = NULL;
-
-       urb->hcpriv = urbp;
+       status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
 
        td = uhci_alloc_td(urb->dev);
        if (!td)
@@ -698,72 +726,70 @@ static int uhci_submit_interrupt(urb_t *urb)
        destination |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
        destination |= ((urb->transfer_buffer_length - 1) << 21);
 
+       usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
+
        uhci_add_td_to_urb(urb, td);
        uhci_fill_td(td, status, destination,
                virt_to_bus(urb->transfer_buffer));
 
-       uhci_add_irq_list(uhci, td);
-
        uhci_insert_td(uhci, &uhci->skeltd[__interval_to_skel(urb->interval)], td);
 
        uhci_add_urb_list(uhci, urb);
 
-       usb_inc_dev_use(urb->dev);
-
        return -EINPROGRESS;
 }
 
-static int uhci_unlink_interrupt(urb_t *urb)
+static int uhci_result_interrupt(urb_t *urb)
 {
        struct urb_priv *urbp = urb->hcpriv;
        struct uhci_td *td;
-       struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-       int notfinished;
+       unsigned int status;
 
        if (!urbp)
                return -EINVAL;
 
-       notfinished = (urb->status == -EINPROGRESS);
+       urb->actual_length = 0;
 
-       if (notfinished)
-               uhci_stop_hc_schedule(uhci);
+       for (td = urbp->list.begin; td; td = td->list.next) {
+               status = uhci_status_bits(td->status);
+               if (status & TD_CTRL_ACTIVE)
+                       return -EINPROGRESS;
 
-       td = urbp->begin;
-       uhci_remove_td(uhci, td);
-       if (td->status & TD_CTRL_IOC)
-               uhci_remove_irq_list(uhci, td);
-       uhci_free_td(td);
+               urb->actual_length += uhci_actual_length(td->status);
 
-       if (notfinished)
-               uhci_start_hc_schedule(uhci);
+               /* If SPD is set then we received a short packet */
+               if ((td->status & TD_CTRL_SPD) &&
+                   (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);
 
-       kfree(urbp);
-       urb->hcpriv = NULL;
+                       return 0;
+               }
 
-       uhci_remove_urb_list(uhci, urb);
+               if (status)
+                       goto td_error;
+       }
 
        return 0;
-}
-
-static int uhci_result_interrupt(urb_t *urb)
-{
-       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
-       struct uhci_td *td;
-       int status;
-
-       if (!urbp)
-               return -EINVAL;
 
-       td = urbp->begin;
-       if (!td)
-               return -EINVAL;
+td_error:
+       /* Some debugging code */
+       if (debug) {
+               dbg("uhci_result_interrupt/bulk() failed with status %x",
+                       status);
 
-       status =  uhci_status_bits(td->status);
-       if (status & TD_CTRL_ACTIVE)
-               return -EINPROGRESS;
+               /* Print the chain for debugging purposes */
+               if (urbp->qh)
+                       uhci_show_queue(urbp->qh);
+               else
+                       uhci_show_td(td);
+       }
 
-       if (!status)
-               urb->actual_length = uhci_actual_length(td->status);
+       if (status & TD_CTRL_STALLED)
+               /* endpoint has stalled - mark it halted */
+               usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
+                               uhci_packetout(td->info));
 
        return uhci_map_status(status, uhci_packetout(td->info));
 }
@@ -773,12 +799,17 @@ static void uhci_reset_interrupt(urb_t *urb)
        struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
        struct uhci_td *td;
 
-       td = urbp->begin;
+       if (!urbp)
+               return;
+
+       td = urbp->list.begin;
+       if (!td)
+               return;
 
-       usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
        td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
        td->info &= ~(1 << TD_TOKEN_TOGGLE);
        td->info |= (usb_gettoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe)) << TD_TOKEN_TOGGLE);
+       usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe), usb_pipeout(urb->pipe));
 
        urb->status = -EINPROGRESS;
 }
@@ -795,27 +826,23 @@ static int uhci_submit_bulk(urb_t *urb)
        int maxsze = usb_maxpacket(urb->dev, urb->pipe, usb_pipeout(urb->pipe));
        int len = urb->transfer_buffer_length;
        unsigned char *data = urb->transfer_buffer;
-       struct urb_priv *urbp;
+       struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
 
        if (len < 0)
                return -EINVAL;
 
+       /* Can't have low speed bulk transfers */
+       if (urb->pipe & TD_CTRL_LS)
+               return -EINVAL;
+
        /* The "pipe" thing contains the destination in bits 8--18 */
        destination = (urb->pipe & PIPE_DEVEP_MASK) | usb_packetid(urb->pipe);
 
        /* 3 errors */
-       status = (urb->pipe & TD_CTRL_LS) | TD_CTRL_ACTIVE | (3 << 27);
+       status = TD_CTRL_ACTIVE | (3 << 27);
        if (!(urb->transfer_flags & USB_DISABLE_SPD))
                status |= TD_CTRL_SPD;
 
-       urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-       if (!urbp)
-               return -ENOMEM;
-
-       urbp->begin = urbp->end = NULL;
-
-       urb->hcpriv = urbp;
-
        /*
         * Build the DATA TD's
         */
@@ -826,10 +853,8 @@ static int uhci_submit_bulk(urb_t *urb)
                        pktsze = maxsze;
 
                td = uhci_alloc_td(urb->dev);
-               if (!td) {
-                       /* FIXME: Free the TD's */
+               if (!td)
                        return -ENOMEM;
-               }
 
                uhci_add_td_to_urb(urb, td);
                uhci_fill_td(td, status, destination | ((pktsze - 1) << 21) |
@@ -840,86 +865,31 @@ static int uhci_submit_bulk(urb_t *urb)
                data += pktsze;
                len -= maxsze;
 
-               if (len <= 0) {
+               if (len <= 0)
                        td->status |= TD_CTRL_IOC;
-                       uhci_add_irq_list(uhci, td);
-               }
 
                usb_dotoggle(urb->dev, usb_pipeendpoint(urb->pipe),
                        usb_pipeout(urb->pipe));
        }
 
        qh = uhci_alloc_qh(urb->dev);
-       if (!qh) {
-               /* FIXME: Free all of the TD's */
+       if (!qh)
                return -ENOMEM;
-       }
-       uhci_insert_tds_in_qh(qh, urbp->begin);
+
+       uhci_insert_tds_in_qh(qh, urb, 1);
 
        uhci_insert_qh(uhci, &uhci->skel_bulk_qh, qh);
        urbp->qh = qh;
 
        uhci_add_urb_list(uhci, urb);
 
-       usb_inc_dev_use(urb->dev);
-
-       uhci_inc_fsbr(uhci);
+       uhci_inc_fsbr(uhci, urb);
 
        return -EINPROGRESS;
 }
 
-/* We can use the control unlink since they're identical */
-#define uhci_unlink_bulk uhci_unlink_control
-
-static int uhci_result_bulk(urb_t *urb)
-{
-       struct urb_priv *urbp = urb->hcpriv;
-       struct uhci_td *td;
-       unsigned int status;
-
-       urb->actual_length = 0;
-
-       /* The rest of the TD's (but the last) are data */
-       for (td = urbp->begin; td; td = td->next) {
-               status = uhci_status_bits(td->status);
-               if (status & TD_CTRL_ACTIVE)
-                       return -EINPROGRESS;
-
-               urb->actual_length += uhci_actual_length(td->status);
-
-               /* If SPD is set then we received a short packet */
-               if (td->status & TD_CTRL_SPD && (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);
-
-                       return 0;
-               }
-
-               if (status)
-                       goto td_error;
-       }
-
-       return 0;
-
-td_error:
-       /* Some debugging code */
-       if (debug) {
-               dbg("uhci_result_bulk() failed with status %x",
-                       status);
-
-               /* Print the chain for debugging purposes */
-               uhci_show_queue(urbp->qh);
-       }
-
-       if (status & TD_CTRL_STALLED) {
-               /* endpoint has stalled - mark it halted */
-               usb_endpoint_halt(urb->dev, uhci_endpoint(td->info),
-                               uhci_packetout(td->info));
-       }
-
-       return uhci_map_status(status, uhci_packetout(td->info));
-}
+/* We can use the result interrupt since they're identical */
+#define uhci_result_bulk uhci_result_interrupt
 
 /*
  * Isochronous transfers
@@ -929,6 +899,7 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int
        urb_t *u, *last_urb = NULL;
        struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
        struct list_head *tmp, *head = &uhci->urb_list;
+       int ret = 0;
        unsigned long flags;
 
        nested_lock(&uhci->urblist_lock, flags);
@@ -945,14 +916,16 @@ static int isochronous_find_limits(urb_t *urb, unsigned int *start, unsigned int
                }
                tmp = tmp->next;
        }
-       nested_unlock(&uhci->urblist_lock, flags);
 
        if (last_urb) {
                *end = (last_urb->start_frame + last_urb->number_of_packets) & 1023;
-               return 0;
+               ret = 0;
        } else
-               return -1;      // no previous urb found
+               ret = -1;       /* no previous urb found */
+
+       nested_unlock(&uhci->urblist_lock, flags);
 
+       return ret;
 }
 
 static int isochronous_find_start(urb_t *urb)
@@ -985,7 +958,6 @@ static int uhci_submit_isochronous(urb_t *urb)
 {
        struct uhci_td *td;
        struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-       struct urb_priv *urbp;
        int i, ret, framenum;
        int status, destination;
 
@@ -996,85 +968,30 @@ static int uhci_submit_isochronous(urb_t *urb)
        if (ret)
                return ret;
 
-       urbp = kmalloc(sizeof(*urbp), in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-       if (!urbp)
-               return -ENOMEM;
-
-       urbp->begin = urbp->end = NULL;
-
-       urb->hcpriv = urbp;
-
        framenum = urb->start_frame;
        for (i = 0; i < urb->number_of_packets; i++, framenum++) {
                if (!urb->iso_frame_desc[i].length)
                        continue;
 
                td = uhci_alloc_td(urb->dev);
-               if (!td) {
-                       /* FIXME: Free the TD's */
+               if (!td)
                        return -ENOMEM;
-               }
 
                uhci_add_td_to_urb(urb, td);
                uhci_fill_td(td, status, destination | ((urb->iso_frame_desc[i].length - 1) << 21),
                        virt_to_bus(urb->transfer_buffer + urb->iso_frame_desc[i].offset));
 
-               if (i + 1 >= urb->number_of_packets) {
+               if (i + 1 >= urb->number_of_packets)
                        td->status |= TD_CTRL_IOC;
-                       uhci_add_irq_list(uhci, td);
-               }
 
                uhci_insert_td_frame_list(uhci, td, framenum);
        }
 
        uhci_add_urb_list(uhci, urb);
 
-       usb_inc_dev_use(urb->dev);
-
        return -EINPROGRESS;
 }
 
-static int uhci_unlink_isochronous(urb_t *urb)
-{
-       struct urb_priv *urbp = urb->hcpriv;
-       struct uhci_td *td;
-       struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
-       int notfinished;
-
-       if (!urbp)
-               return -EINVAL;
-
-       notfinished = (urb->status == -EINPROGRESS);
-
-       if (notfinished)
-               uhci_stop_hc_schedule(uhci);
-
-       /* Go through the rest of the TD's, deleting them, then scheduling */
-       /*  their deletion */
-       td = urbp->begin;
-       while (td) {
-               struct uhci_td *next = td->next;
-
-               uhci_remove_td(uhci, td);
-
-               if (td->status & TD_CTRL_IOC)
-                       uhci_remove_irq_list(uhci, td);
-               uhci_free_td(td);
-
-               td = next;
-       }
-
-       if (notfinished)
-               uhci_start_hc_schedule(uhci);
-
-       kfree(urbp);
-       urb->hcpriv = NULL;
-
-       uhci_remove_urb_list(uhci, urb);
-
-       return 0;
-}
-
 static int uhci_result_isochronous(urb_t *urb)
 {
        struct urb_priv *urbp = (struct urb_priv *)urb->hcpriv;
@@ -1082,19 +999,17 @@ static int uhci_result_isochronous(urb_t *urb)
        int status;
        int i, ret = 0;
 
-       td = urbp->end;
-       if (!td)                /* Nothing to do */
+       if (!urbp)
                return -EINVAL;
 
-       status = uhci_status_bits(td->status);
-       if (status & TD_CTRL_ACTIVE)
-               return -EINPROGRESS;
-
        urb->actual_length = 0;
 
-       for (i = 0, td = urbp->begin; td; i++, td = td->next) {
+       for (i = 0, td = urbp->list.begin; td; i++, td = td->list.next) {
                int actlength;
 
+               if (td->status & TD_CTRL_ACTIVE)
+                       return -EINPROGRESS;
+
                actlength = uhci_actual_length(td->status);
                urb->iso_frame_desc[i].actual_length = actlength;
                urb->actual_length += actlength;
@@ -1114,17 +1029,26 @@ static int uhci_submit_urb(urb_t *urb)
 {
        int ret = -EINVAL;
        struct uhci *uhci;
+       unsigned long flags;
 
        if (!urb)
                return -EINVAL;
 
-       if (!urb->dev || !urb->dev->bus)
+       if (!urb->dev || !urb->dev->bus || !urb->dev->bus->hcpriv)
                return -ENODEV;
 
        uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
+       /* Short circuit the virtual root hub */
        if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
-               return rh_submit_urb(urb);      /* Virtual root hub */
+               return rh_submit_urb(urb);
+
+       spin_lock_irqsave(&urb->lock, flags);
+
+       if (!uhci_alloc_urb_priv(urb)) {
+               spin_unlock_irqrestore(&urb->lock, flags);
+               return -ENOMEM;
+       }
 
        switch (usb_pipetype(urb->pipe)) {
        case PIPE_CONTROL:
@@ -1142,20 +1066,30 @@ static int uhci_submit_urb(urb_t *urb)
        }
 
        urb->status = ret;
+
+       spin_unlock_irqrestore(&urb->lock, flags);
+
        if (ret == -EINPROGRESS)
-               return 0;
+               ret = 0;
+       else
+               uhci_unlink_generic(urb);
 
        return ret;
 }
 
 /*
  * Return the result of a transfer
+ *
+ * Must be called with urblist_lock acquired
  */
 static void uhci_transfer_result(urb_t *urb)
 {
        urb_t *turb;
        int proceed = 0, is_ring = 0;
        int ret = -EINVAL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&urb->lock, flags);
 
        switch (usb_pipetype(urb->pipe)) {
        case PIPE_CONTROL:
@@ -1173,12 +1107,17 @@ static void uhci_transfer_result(urb_t *urb)
        }
 
        urb->status = ret;
-       if (urb->status == -EINPROGRESS)
+
+       spin_unlock_irqrestore(&urb->lock, flags);
+
+       if (ret == -EINPROGRESS)
                return;
 
        switch (usb_pipetype(urb->pipe)) {
        case PIPE_CONTROL:
-               uhci_unlink_control(urb);
+       case PIPE_BULK:
+       case PIPE_ISOCHRONOUS:
+               uhci_unlink_generic(urb);
                break;
        case PIPE_INTERRUPT:
                /* Interrupts are an exception */
@@ -1186,14 +1125,8 @@ static void uhci_transfer_result(urb_t *urb)
                if (urb->interval)
                        uhci_reset_interrupt(urb);
                else
-                       uhci_unlink_interrupt(urb);
-               return;
-       case PIPE_BULK:
-               uhci_unlink_bulk(urb);
-               break;
-       case PIPE_ISOCHRONOUS:
-               uhci_unlink_isochronous(urb);
-               break;
+                       uhci_unlink_generic(urb);
+               return;         /* <-- Note the return */
        }
 
        if (urb->next) {
@@ -1231,10 +1164,32 @@ static void uhci_transfer_result(urb_t *urb)
        }
 }
 
+static int uhci_unlink_generic(urb_t *urb)
+{
+       struct urb_priv *urbp = urb->hcpriv;
+       struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+
+       if (!urbp)
+               return -EINVAL;
+
+       uhci_dec_fsbr(uhci, urb);       /* Safe since it checks */
+
+       uhci_remove_urb_list(uhci, urb);
+
+       if (urbp->qh)
+               /* The interrupt loop will reclaim the QH's */
+               uhci_remove_qh(uhci, urbp->qh);
+
+       uhci_destroy_urb_priv(urb);
+
+       return 0;
+}
+
 static int uhci_unlink_urb(urb_t *urb)
 {
        struct uhci *uhci;
        int ret = 0;
+       unsigned long flags;
 
        if (!urb)
                return -EINVAL;
@@ -1244,40 +1199,34 @@ static int uhci_unlink_urb(urb_t *urb)
 
        uhci = (struct uhci *)urb->dev->bus->hcpriv;
 
+       /* Short circuit the virtual root hub */
        if (usb_pipedevice(urb->pipe) == uhci->rh.devnum)
                return rh_unlink_urb(urb);
 
        if (urb->status == -EINPROGRESS) {
-               switch (usb_pipetype(urb->pipe)) {
-               case PIPE_CONTROL:
-                       ret = uhci_unlink_control(urb);
-                       break;
-               case PIPE_INTERRUPT:
-                       ret = uhci_unlink_interrupt(urb);
-                       break;
-               case PIPE_BULK:
-                       ret = uhci_unlink_bulk(urb);
-                       break;
-               case PIPE_ISOCHRONOUS:
-                       ret = uhci_unlink_isochronous(urb);
-                       break;
-               }
+               uhci_unlink_generic(urb);
 
-               if (urb->complete)
-                       urb->complete(urb);
+               if (urb->transfer_flags & USB_ASYNC_UNLINK) {
+                       spin_lock_irqsave(&uhci->urb_remove_lock, flags);
+                       list_add(&urb->urb_list, &uhci->urb_remove_list);
+                       spin_unlock_irqrestore(&uhci->urb_remove_lock, flags);
 
-#ifndef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
-               if (in_interrupt()) {           /* wait at least 1 frame */
-                       int errorcount = 10;
+                       urb->status = -ECONNABORTED;
+               } else {
+                       if (in_interrupt()) {   /* wait at least 1 frame */
+                               static int errorcount = 10;
 
-                       if (errorcount--)
-                               dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
-                       udelay(1000);
-               } else
-                       schedule_timeout(1+1*HZ/1000); 
-#endif
+                               if (errorcount--)
+                                       dbg("uhci_unlink_urb called from interrupt for urb %p", urb);
+                               udelay(1000);
+                       } else
+                               schedule_timeout(1+1*HZ/1000); 
 
-               urb->status = -ENOENT;
+                       if (urb->complete)
+                               urb->complete(urb);
+
+                       urb->status = -ENOENT;
+               }
        }
 
        return ret;
@@ -1412,9 +1361,12 @@ static int rh_init_int_timer(urb_t *urb);
 
 static void rh_int_timer_do(unsigned long ptr)
 {
-       int len;
-       urb_t *urb = (urb_t *)ptr;
+       urb_t *urb = (urb_t *)ptr, *u;
        struct uhci *uhci = (struct uhci *)urb->dev->bus->hcpriv;
+       struct list_head *tmp, *head = &uhci->urb_list;
+       struct urb_priv *urbp;
+       int len;
+       unsigned long flags;
 
        if (uhci->rh.send) {
                len = rh_send_irq(urb);
@@ -1425,6 +1377,21 @@ static void rh_int_timer_do(unsigned long ptr)
                }
        }
 
+       nested_lock(&uhci->urblist_lock, flags);
+       tmp = head->next;
+       while (tmp != head) {
+               u = list_entry(tmp, urb_t, urb_list);
+
+               urbp = (struct urb_priv *)u->hcpriv;
+               if (urbp) {
+                       if (urbp->fsbr && time_after(jiffies, urbp->inserttime + IDLE_TIMEOUT))
+                               uhci_dec_fsbr(uhci, u);
+               }
+
+               tmp = tmp->next;
+       }
+       nested_unlock(&uhci->urblist_lock, flags);
+
        rh_init_int_timer(urb);
 }
 
@@ -1645,6 +1612,27 @@ static int rh_unlink_urb(urb_t *urb)
 }
 /*-------------------------------------------------------------------*/
 
+void uhci_free_pending_qhs(struct uhci *uhci)
+{
+       struct list_head *tmp, *head;
+       unsigned long flags;
+
+       /* Free any pending QH's */
+       spin_lock_irqsave(&uhci->qh_remove_lock, flags);
+       head = &uhci->qh_remove_list;
+       tmp = head->next;
+       while (tmp != head) {
+               struct uhci_qh *qh = list_entry(tmp, struct uhci_qh, remove_list);
+
+               tmp = tmp->next;
+
+               list_del(&qh->remove_list);
+
+               uhci_free_qh(qh);
+       }
+       spin_unlock_irqrestore(&uhci->qh_remove_lock, flags);
+}
+
 static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
 {
        struct uhci *uhci = __uhci;
@@ -1652,7 +1640,6 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
        unsigned short status;
        unsigned long flags;
        struct list_head *tmp, *head;
-       urb_t *urb;
 
        /*
         * Read the interrupt status, and write it back to clear the
@@ -1676,55 +1663,36 @@ static void uhci_interrupt(int irq, void *__uhci, struct pt_regs *regs)
                }
        }
 
-       /* Walk the list of pending TD's to see which ones completed.. */
-       nested_lock(&uhci->irqlist_lock, flags);
-       head = &uhci->interrupt_list;
+       uhci_free_pending_qhs(uhci);
+
+       spin_lock(&uhci->urb_remove_lock);
+       head = &uhci->urb_remove_list;
        tmp = head->next;
        while (tmp != head) {
-               struct uhci_td *td = list_entry(tmp, struct uhci_td, irq_list);
-
-               urb = td->urb;
+               struct urb *urb = list_entry(tmp, struct urb, urb_list);
 
                tmp = tmp->next;
 
-               /* Checks the status and does all of the magic necessary */
-               uhci_transfer_result(urb);
-       }
-       nested_unlock(&uhci->irqlist_lock, flags);
-}
-
-static void uhci_stop_hc_schedule(struct uhci *uhci)
-{
-#ifdef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
-       unsigned int cmdreg, timeout = 1000;
-
-       cmdreg = inw(uhci->io_addr + USBCMD);
-       outw(cmdreg & ~USBCMD_RS, uhci->io_addr + USBCMD);
+               list_del(&urb->urb_list);
 
-       while (!(inw(uhci->io_addr + USBSTS) & USBSTS_HCH)) {
-               if (!--timeout) {
-                       printk(KERN_ERR "uhci: stop_hc_schedule failed, HC still running\n");
-                       break;
-               }
+               if (urb->complete)
+                       urb->complete(urb);
        }
-#endif
-}
+       spin_unlock(&uhci->urb_remove_lock);
 
-static void uhci_start_hc_schedule(struct uhci *uhci)
-{
-#ifdef CONFIG_USB_UHCI_ALT_UNLINK_OPTIMIZE
-       unsigned int cmdreg, timeout = 1000;
+       /* Walk the list of pending TD's to see which ones completed */
+       nested_lock(&uhci->urblist_lock, flags);
+       head = &uhci->urb_list;
+       tmp = head->next;
+       while (tmp != head) {
+               struct urb *urb = list_entry(tmp, struct urb, urb_list);
 
-       cmdreg = inw(uhci->io_addr + USBCMD);
-       outw(cmdreg | USBCMD_RS, uhci->io_addr + USBCMD);
+               tmp = tmp->next;
 
-       while (inw(uhci->io_addr + USBSTS) & USBSTS_HCH) {
-               if (!--timeout) {
-                       printk(KERN_ERR "uhci: start_hc_schedule failed, HC still halted\n");
-                       break;
-               }
+               /* Checks the status and does all of the magic necessary */
+               uhci_transfer_result(urb);
        }
-#endif
+       nested_unlock(&uhci->urblist_lock, flags);
 }
 
 static void reset_hc(struct uhci *uhci)
@@ -1780,7 +1748,7 @@ static void start_hc(struct uhci *uhci)
  *    of the queues. We don't do that here, because
  *    we'll create the actual TD entries on demand.
  *  - The first queue is the "interrupt queue".
- *  - The second queue is the "control queue".
+ *  - The second queue is the "control queue", split into low and high speed
  *  - The third queue is "bulk data".
  */
 static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
@@ -1799,14 +1767,16 @@ static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
        uhci->io_addr = io_addr;
        uhci->io_size = io_size;
 
-       INIT_LIST_HEAD(&uhci->interrupt_list);
-       INIT_LIST_HEAD(&uhci->urb_list);
+       spin_lock_init(&uhci->qh_remove_lock);
+       INIT_LIST_HEAD(&uhci->qh_remove_list);
+
+       spin_lock_init(&uhci->urb_remove_lock);
+       INIT_LIST_HEAD(&uhci->urb_remove_list);
 
-       spin_lock_init(&uhci->framelist_lock);
        nested_init(&uhci->urblist_lock);
-       nested_init(&uhci->irqlist_lock);
+       INIT_LIST_HEAD(&uhci->urb_list);
 
-       uhci->fsbr = 0;
+       spin_lock_init(&uhci->framelist_lock);
 
        /* We need exactly one page (per UHCI specs), how convenient */
        /* We assume that one page is atleast 4k (1024 frames * 4 bytes) */
@@ -1870,8 +1840,12 @@ static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
        uhci->skel_bulk_qh.link = virt_to_bus(&uhci->skel_term_qh) | UHCI_PTR_QH;
        uhci->skel_bulk_qh.element = UHCI_PTR_TERM;
 
+       /* This dummy TD is to work around a bug in Intel PIIX controllers */
+       uhci_fill_td(&uhci->skel_term_td, 0, (UHCI_NULL_DATA_SIZE << 21) | (0x7f << 8) | USB_PID_IN, 0);
+       uhci->skel_term_td.link = UHCI_PTR_TERM;
+
        uhci->skel_term_qh.link = UHCI_PTR_TERM;
-       uhci->skel_term_qh.element = UHCI_PTR_TERM;
+       uhci->skel_term_qh.element = virt_to_bus(&uhci->skel_term_td);
 
        /*
         * Fill the frame list: make all entries point to
@@ -2022,23 +1996,24 @@ static int found_uhci(struct pci_dev *dev)
                        dev->resource[i].end - dev->resource[i].start + 1;
 
                /* IO address? */
-               if (!(dev->resource[i].flags & 1))
+               if (!(dev->resource[i].flags & IORESOURCE_IO))
                        continue;
 
                /* Is it already in use? */
                if (check_region(io_addr, io_size))
                        break;
 
-               /* disable legacy emulation */
-               pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
-
-               pci_enable_device(dev);
-
                if (!dev->irq) {
                        err("found UHCI device with no IRQ assigned. check BIOS settings!");
                        continue;
                }
 
+               /* disable legacy emulation */
+               pci_write_config_word(dev, USBLEGSUP, USBLEGSUP_DEFAULT);
+
+               if (pci_enable_device(dev) < 0)
+                       continue;
+
                return setup_uhci(dev, dev->irq, io_addr, io_size);
        }
 
@@ -2081,6 +2056,12 @@ int uhci_init(void)
        if (!uhci_qh_cachep)
                goto qh_failed;
 
+       uhci_up_cachep = kmem_cache_create("uhci_urb_priv",
+               sizeof(struct urb_priv), 0, 0, NULL, NULL);
+
+       if (!uhci_up_cachep)
+               goto up_failed;
+
        retval = -ENODEV;
        dev = NULL;
        for (;;) {
@@ -2105,6 +2086,10 @@ int uhci_init(void)
        return 0;
 
 init_failed:
+       if (kmem_cache_destroy(uhci_up_cachep))
+               printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
+up_failed:
        if (kmem_cache_destroy(uhci_qh_cachep))
                printk(KERN_INFO "uhci: not all QH's were freed\n");
 
@@ -2118,13 +2103,13 @@ td_failed:
 
 void uhci_cleanup(void)
 {
-       struct list_head *next, *tmp, *head = &uhci_list;
+       struct list_head *tmp, *head = &uhci_list;
 
        tmp = head->next;
        while (tmp != head) {
                struct uhci *uhci = list_entry(tmp, struct uhci, uhci_list);
 
-               next = tmp->next;
+               tmp = tmp->next;
 
                list_del(&uhci->uhci_list);
                INIT_LIST_HEAD(&uhci->uhci_list);
@@ -2137,11 +2122,14 @@ void uhci_cleanup(void)
                reset_hc(uhci);
                release_region(uhci->io_addr, uhci->io_size);
 
-               release_uhci(uhci);
+               uhci_free_pending_qhs(uhci);
 
-               tmp = next;
+               release_uhci(uhci);
        }
 
+       if (kmem_cache_destroy(uhci_up_cachep))
+               printk(KERN_INFO "uhci: not all urb_priv's were freed\n");
+
        if (kmem_cache_destroy(uhci_qh_cachep))
                printk(KERN_INFO "uhci: not all QH's were freed\n");
 
index 88891ea895d8e0be76a8a25e66b7de5ce9b5707e..e7b5a7aac9175c6b7370ff95ed0371fe44033fd3 100644 (file)
@@ -106,11 +106,12 @@ struct uhci_qh {
        __u32 element;                          /* Queue element pointer */
 
        /* Software fields */
-       struct uhci_qh *prevqh, *nextqh;        /* Previous and next TD in queue */
+       /* Can't use list_head since we want a specific order */
+       struct uhci_qh *prevqh, *nextqh;
 
        struct usb_device *dev;                 /* The owning device */
 
-       struct list_head list;
+       struct list_head remove_list;
 } __attribute__((aligned(16)));
 
 struct uhci_framelist {
@@ -184,10 +185,10 @@ struct uhci_td {
 
        struct usb_device *dev;
        struct urb *urb;                /* URB this TD belongs to */
-       struct uhci_td *next;           /* List of chained TD's for an URB */
-
-       struct list_head irq_list;      /* Active interrupt list.. */
-       struct list_head list;
+       /* We can't use list_head since we need a specific order */
+       struct ut_list {
+               struct uhci_td *prev, *next;
+       } list;
 } __attribute__((aligned(16)));
 
 /*
@@ -233,7 +234,7 @@ struct uhci_td {
  * labels (below) are only signficant to the root hub's QH's
  */
 
-#define UHCI_NUM_SKELTD                9
+#define UHCI_NUM_SKELTD                10
 #define skel_int1_td           skeltd[0]
 #define skel_int2_td           skeltd[1]
 #define skel_int4_td           skeltd[2]
@@ -243,6 +244,7 @@ struct uhci_td {
 #define skel_int64_td          skeltd[6]
 #define skel_int128_td         skeltd[7]
 #define skel_int256_td         skeltd[8]
+#define skel_term_td           skeltd[9]       /* To work around PIIX UHCI bug */
 
 #define UHCI_NUM_SKELQH                4
 #define skel_ls_control_qh     skelqh[0]
@@ -306,6 +308,7 @@ struct virt_root_hub {
  * a subset of what the full implementation needs.
  */
 struct uhci {
+       /* Grabbed from PCI */
        int irq;
        unsigned int io_addr;
        unsigned int io_size;
@@ -317,25 +320,32 @@ struct uhci {
        struct uhci_td skeltd[UHCI_NUM_SKELTD]; /* Skeleton TD's */
        struct uhci_qh skelqh[UHCI_NUM_SKELQH]; /* Skeleton QH's */
 
+       spinlock_t framelist_lock;
        struct uhci_framelist *fl;              /* Frame list */
+       int fsbr;                               /* Full speed bandwidth reclamation */
+
+       spinlock_t qh_remove_lock;
+       struct list_head qh_remove_list;
 
-       struct s_nested_lock irqlist_lock;
-       struct list_head interrupt_list;        /* List of interrupt-active TD's for this uhci */
+       spinlock_t urb_remove_lock;
+       struct list_head urb_remove_list;
 
        struct s_nested_lock urblist_lock;
        struct list_head urb_list;
 
-       spinlock_t framelist_lock;
-
-       int fsbr;                       /* Full speed bandwidth reclamation */
-
        struct virt_root_hub rh;        /* private data of the virtual root hub */
 };
 
 struct urb_priv {
        struct uhci_qh *qh;             /* QH for this URB */
-       struct uhci_td *begin;
-       struct uhci_td *end;
+
+       int fsbr;
+
+       unsigned long inserttime;       /* In jiffies */
+
+       struct up_list {
+               struct uhci_td *begin, *end;
+       } list;
 };
 
 /* -------------------------------------------------------------------------
index 9bc13642063ee23e342db702fbf8c980f70e90ec..bc6a842e574fb81fe3e1ab298a49660a8f6aa003 100644 (file)
@@ -1675,20 +1675,24 @@ static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
  
 static int hc_start_ohci (struct pci_dev * dev)
 {
-       u32 cmd;
+       unsigned long mem_base;
+
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0)
-       unsigned long mem_base = dev->resource[0].start;
+       mem_base = dev->resource[0].start;
+       if (pci_enable_device(dev) < 0)
+               return -ENODEV;
 #else
-       unsigned long mem_base = dev->base_address[0];
+       u16 cmd;
+
+       mem_base = dev->base_address[0];
        if (mem_base & PCI_BASE_ADDRESS_SPACE_IO) return -ENODEV;
        mem_base &= PCI_BASE_ADDRESS_MEM_MASK;
+
+       /* Some Mac firmware will switch memory response off */
+       pci_read_config_word(dev, PCI_COMMAND, &cmd);
+       pci_write_config_word(dev, PCI_COMMAND, cmd | PCI_COMMAND_MEMORY);
 #endif
        
-       /* Some Mac firmware will switch memory response off */
-       pci_read_config_dword(dev, PCI_COMMAND, &cmd);
-       cmd = (cmd | PCI_COMMAND_MEMORY);
-       pci_write_config_dword(dev, PCI_COMMAND, cmd);
-
        pci_set_master (dev);
        mem_base = (unsigned long) ioremap_nocache (mem_base, 4096);
 
index 1b72efd9262134ca702d38278c62e7276845fb10..51b58ea72a24de8364eefd18cdff66c9dd2aa876 100644 (file)
@@ -2408,7 +2408,7 @@ _static int __init start_uhci (struct pci_dev *dev)
                unsigned int io_addr = dev->resource[i].start;
                unsigned int io_size =
                dev->resource[i].end - dev->resource[i].start + 1;
-               if (!(dev->resource[i].flags & 1))
+               if (!(dev->resource[i].flags & IORESOURCE_IO))
                        continue;
 #else
                unsigned int io_addr = dev->base_address[i];
@@ -2464,7 +2464,8 @@ int __init uhci_init (void)
                        continue;
 
 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
-               pci_enable_device (dev);
+               if (pci_enable_device (dev) < 0)
+                       continue;
 #endif
                if(!dev->irq)
                {
index 6b9eba17a5d2e2b916cb3ac40309233f358e197b..4197650b4e23a0124bf1a19ce14cbd29cc04fa9c 100644 (file)
@@ -475,30 +475,34 @@ void usb_inc_dev_use(struct usb_device *dev)
  * New USB Core Functions
  * -------------------------------------------------------------------------------------*/
 
-urb_tusb_alloc_urb(int iso_packets)
+urb_t *usb_alloc_urb(int iso_packets)
 {
        urb_t *urb;
-       urb=(urb_t*)kmalloc(sizeof(urb_t) + iso_packets*sizeof(iso_packet_descriptor_t),
+
+       urb = (urb_t *)kmalloc(sizeof(urb_t) + iso_packets * sizeof(iso_packet_descriptor_t),
              in_interrupt() ? GFP_ATOMIC : GFP_KERNEL);
-       if (!urb)
-       {
+       if (!urb) {
                err("alloc_urb: kmalloc failed");
-               return 0;
+               return NULL;
        }
-       memset(urb,0,sizeof(urb_t));
+
+       memset(urb, 0, sizeof(*urb));
+
+       spin_lock_init(&urb->lock);
+
        return urb;
 }
 
 /*-------------------------------------------------------------------*/
 void usb_free_urb(urb_t* urb)
 {
-       if(urb)
+       if (urb)
                kfree(urb);
 }
 /*-------------------------------------------------------------------*/
 int usb_submit_urb(urb_t *urb)
 {
-       if(urb && urb->dev)
+       if (urb && urb->dev)
                return urb->dev->bus->op->submit_urb(urb);
        else
                return -1;
@@ -507,7 +511,7 @@ int usb_submit_urb(urb_t *urb)
 /*-------------------------------------------------------------------*/
 int usb_unlink_urb(urb_t *urb)
 {
-       if(urb && urb->dev)
+       if (urb && urb->dev)
                return urb->dev->bus->op->unlink_urb(urb);
        else
                return -1;
@@ -537,10 +541,10 @@ static void usb_api_blocking_completion(urb_t *urb)
  *-------------------------------------------------------------------*/
 static void usb_api_async_completion(urb_t *urb)
 {
-       api_wrapper_data *awd=(api_wrapper_data*)urb->context;
+       api_wrapper_data *awd = (api_wrapper_data *)urb->context;
 
        if (awd->handler)
-               awd->handler(urb->status,urb->transfer_buffer,urb->actual_length,awd->stuff);
+               awd->handler(urb->status, urb->transfer_buffer, urb->actual_length, awd->stuff);
  }
 
 /*-------------------------------------------------------------------*
@@ -555,13 +559,13 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
        api_wrapper_data awd;
        int status;
   
-       awd.wakeup=&wqh;
-       awd.handler=0;
+       awd.wakeup = &wqh;
+       awd.handler = 0;
        init_waitqueue_head(&wqh);      
        current->state = TASK_INTERRUPTIBLE;
        add_wait_queue(&wqh, &wait);
-       urb->context=&awd;
-       status=usb_submit_urb(urb);
+       urb->context = &awd;
+       status = usb_submit_urb(urb);
        if (status) {
                // something went wrong
                usb_free_urb(urb);
@@ -581,13 +585,12 @@ static int usb_start_wait_urb(urb_t *urb, int timeout, int* actual_length)
                // timeout
                printk("usb_control/bulk_msg: timeout\n");
                usb_unlink_urb(urb);  // remove urb safely
-               status=-ETIMEDOUT;
-       }
-       else
-               status=urb->status;
+               status = -ETIMEDOUT;
+       } else
+               status = urb->status;
 
        if (actual_length)
-               *actual_length=urb->actual_length;
+               *actual_length = urb->actual_length;
 
        usb_free_urb(urb);
        return status;
@@ -602,20 +605,21 @@ int usb_internal_control_msg(struct usb_device *usb_dev, unsigned int pipe,
        int retv;
        int length;
 
-       urb=usb_alloc_urb(0);
+       urb = usb_alloc_urb(0);
        if (!urb)
                return -ENOMEM;
   
        FILL_CONTROL_URB(urb, usb_dev, pipe, (unsigned char*)cmd, data, len,    /* build urb */  
                   (usb_complete_t)usb_api_blocking_completion,0);
 
-       retv=usb_start_wait_urb(urb,timeout, &length);
+       retv = usb_start_wait_urb(urb, timeout, &length);
        if (retv < 0)
                return retv;
        else
                return length;
        
 }
+
 /*-------------------------------------------------------------------*/
 int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u8 requesttype,
                         __u16 value, __u16 index, void *data, __u16 size, int timeout)
@@ -623,7 +627,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
        devrequest *dr = kmalloc(sizeof(devrequest), GFP_KERNEL);
        int ret;
        
-       if(!dr)
+       if (!dr)
                return -ENOMEM;
 
        dr->requesttype = requesttype;
@@ -634,7 +638,7 @@ int usb_control_msg(struct usb_device *dev, unsigned int pipe, __u8 request, __u
 
        //dbg("usb_control_msg");       
 
-       ret=usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
+       ret = usb_internal_control_msg(dev, pipe, dr, data, size, timeout);
 
        kfree(dr);
 
index d1381c10743c3fb104b7e056fb364d06e61055bd..69f0189aa4a6de21a98113fe51d71ff027023332 100644 (file)
@@ -364,17 +364,16 @@ struct usb_driver {
  */
 typedef int (*usb_device_irq)(int, void *, int, void *);
 
-/* -------------------------------------------------------------------------------------
- * New USB Structures                                                                   *
- * -------------------------------------------------------------------------------------*/
+/* --------------------------------------------------------------------------* 
+ * New USB Structures                                                        *
+ * --------------------------------------------------------------------------*/
 
+#define USB_DISABLE_SPD                1
+#define USB_ISO_ASAP           2
+#define USB_URB_EARLY_COMPLETE 4
+#define USB_ASYNC_UNLINK       8
 
-#define USB_DISABLE_SPD           1
-#define USB_ISO_ASAP              2
-#define USB_URB_EARLY_COMPLETE    4
-
-typedef struct
-{
+typedef struct {
        unsigned int offset;
        unsigned int length;            // expected length
        unsigned int actual_length;
@@ -386,9 +385,10 @@ typedef void (*usb_complete_t)(struct urb *);
 
 typedef struct urb
 {
+       spinlock_t lock;                // lock for the URB
        void *hcpriv;                   // private data for host controller
        struct list_head urb_list;      // list pointer to all active urbs 
-       struct urbnext;               // pointer to next URB  
+       struct urb *next;               // pointer to next URB  
        struct usb_device *dev;         // pointer to associated USB device
        unsigned int pipe;              // pipe information
        int status;                     // returned status
@@ -396,7 +396,7 @@ typedef struct urb
        void *transfer_buffer;          // associated data buffer
        int transfer_buffer_length;     // data buffer length
        int actual_length;              // actual data buffer length    
-       unsigned charsetup_packet;    // setup packet (control only)
+       unsigned char *setup_packet;    // setup packet (control only)
        //
        int start_frame;                // start frame (iso/irq only)
        int number_of_packets;          // number of packets in this request (iso/irq only)
@@ -411,6 +411,7 @@ typedef struct urb
 
 #define FILL_CONTROL_URB(a,aa,b,c,d,e,f,g) \
     do {\
+       spin_lock_init(&(a)->lock);\
        (a)->dev=aa;\
        (a)->pipe=b;\
        (a)->setup_packet=c;\
@@ -422,6 +423,7 @@ typedef struct urb
 
 #define FILL_BULK_URB(a,aa,b,c,d,e,f) \
     do {\
+       spin_lock_init(&(a)->lock);\
        (a)->dev=aa;\
        (a)->pipe=b;\
        (a)->transfer_buffer=c;\
@@ -432,6 +434,7 @@ typedef struct urb
     
 #define FILL_INT_URB(a,aa,b,c,d,e,f,g) \
     do {\
+       spin_lock_init(&(a)->lock);\
        (a)->dev=aa;\
        (a)->pipe=b;\
        (a)->transfer_buffer=c;\
index ac0ff6e1e53950f839ccd2e06238c4a7ab0c6eab..36f2c8855d6295ee9fc8bc75bb4b409aad9bf1f9 100644 (file)
@@ -279,6 +279,8 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
 #define __restore_flags(x)     __asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"g" (x):"memory")
 #define __cli()                __asm__ __volatile__("cli": : :"memory")
 #define __sti()                        __asm__ __volatile__("sti": : :"memory")
+/* used in the idle loop; sti takes one instruction cycle to complete */
+#define safe_halt()            __asm__ __volatile__("sti; hlt": : :"memory")
 
 /* For spinlocks etc */
 #define local_irq_save(x)      __asm__ __volatile__("pushfl ; popl %0 ; cli":"=g" (x): /* no input */ :"memory")
index 4a345df690b63a8f7dee912eeb612bb9a1b3af49..43bf69f866e50d24eb14982a4f045cde08ef59af 100644 (file)
@@ -295,6 +295,7 @@ struct fb_info {
    struct fb_var_screeninfo var;        /* Current var */
    struct fb_fix_screeninfo fix;        /* Current fix */
    struct fb_monspecs monspecs;         /* Current Monitor specs */
+   struct fb_cmap cmap;                 /* Current cmap */
    struct fb_ops *fbops;
    char *screen_base;                   /* Virtual address */
    struct display *disp;               /* initial display variable */
index ebe4d6865ce8411bb4b4c64cb23624122c1878e1..5435fd57d2cf8cb4cd2aa4dddb495ebfd0cac25f 100644 (file)
 #define PCI_DEVICE_ID_PANACOM_QUADMODEM        0x0400
 #define PCI_DEVICE_ID_PANACOM_DUALMODEM        0x0402
 
+#define PCI_VENDOR_ID_AFAVLAB          0x14db
+#define PCI_DEVICE_ID_AFAVLAB_TK9902   0x2120
+
 #define PCI_VENDOR_ID_SYMPHONY         0x1c1c
 #define PCI_DEVICE_ID_SYMPHONY_101     0x0001
 
index 21d4257b5931b2b5329cca57c5a582990b5ffb84..a36abec5ad94f1a1bccd318e759353c67e63f1cb 100644 (file)
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -216,6 +216,7 @@ void __init shm_init (void)
 #endif
        zero_id = ipc_addid(&shm_ids, &zshmid_kernel.shm_perm, 1);
        shm_unlock(zero_id);
+       INIT_LIST_HEAD(&zshmid_kernel.zero_list);
        zdent = d_alloc_root(get_empty_inode());
        return;
 }
@@ -1531,10 +1532,9 @@ done:
 
 #define VMA_TO_SHP(vma)                ((vma)->vm_file->private_data)
 
-static LIST_HEAD(zmap_list);
 static spinlock_t zmap_list_lock = SPIN_LOCK_UNLOCKED;
 static unsigned long zswap_idx = 0; /* next to swap */
-static struct shmid_kernel *zswap_shp = (struct shmid_kernel *)&zmap_list;
+static struct shmid_kernel *zswap_shp = &zshmid_kernel;
 static int zshm_rss;
 
 static struct vm_operations_struct shmzero_vm_ops = {
@@ -1607,7 +1607,7 @@ int map_zero_setup(struct vm_area_struct *vma)
        vma->vm_ops = &shmzero_vm_ops;
        shmzero_open(vma);
        spin_lock(&zmap_list_lock);
-       list_add(&shp->zero_list, &zmap_list);
+       list_add(&shp->zero_list, &zshmid_kernel.zero_list);
        spin_unlock(&zmap_list_lock);
        return 0;
 }
@@ -1668,8 +1668,8 @@ static void zmap_unuse(swp_entry_t entry, struct page *page)
 
        spin_lock(&zmap_list_lock);
        shm_lock(zero_id);
-       for (shp = list_entry(zmap_list.next, struct shmid_kernel, zero_list);
-                       shp != (struct shmid_kernel *)&zmap_list;
+       for (shp = list_entry(zshmid_kernel.zero_list.next, struct shmid_kernel, 
+                       zero_list); shp != &zshmid_kernel;
                        shp = list_entry(shp->zero_list.next, struct shmid_kernel,
                                                                zero_list)) {
                if (shm_unuse_core(shp, entry, page))
@@ -1697,10 +1697,10 @@ next:
 
        spin_lock(&zmap_list_lock);
        shm_lock(zero_id);
-       if (zmap_list.next == 0)
+       if (zshmid_kernel.zero_list.next == 0)
                goto failed;
 next_id:
-       if (zswap_shp == (struct shmid_kernel *)&zmap_list) {
+       if (zswap_shp == &zshmid_kernel) {
                if (loop) {
 failed:
                        shm_unlock(zero_id);
@@ -1708,8 +1708,8 @@ failed:
                        __swap_free(swap_entry, 2);
                        return;
                }
-               zswap_shp = list_entry(zmap_list.next, struct shmid_kernel
-                                                               zero_list);
+               zswap_shp = list_entry(zshmid_kernel.zero_list.next
+                                       struct shmid_kernel, zero_list);
                zswap_idx = 0;
                loop = 1;
        }