]> git.neil.brown.name Git - history.git/commitdiff
Import 2.3.12pre4 2.3.12pre4
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:26:25 +0000 (15:26 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:26:25 +0000 (15:26 -0500)
arch/alpha/config.in
arch/i386/kernel/process.c
drivers/usb/mouse.c
drivers/usb/ohci-debug.c
drivers/usb/ohci.c
drivers/usb/ohci.h
drivers/usb/usb_scsi.c
fs/buffer.c
fs/exec.c
include/asm-i386/desc.h
include/asm-i386/mmu_context.h

index 0c00ff22f106a6a5f3777c0f039e72beddad3e06..46c4a470bf462f229d734180fd14b801b327590d 100644 (file)
@@ -188,7 +188,7 @@ tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT
 tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
 tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
 tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
-source drivers/parpor/Config.in
+source drivers/parport/Config.in
 endmenu
 
 source drivers/pnp/Config.in
index d98600fddfb6be4749d908f4b48b11ee803ecd6e..b506facc1c1bcb3bc2f59602e1bbe506285b8fa3 100644 (file)
@@ -322,14 +322,9 @@ void machine_restart(char * __unused)
        pg0[0] = _PAGE_RW | _PAGE_PRESENT;
 
        /*
-        * Use `swapper_pg_dir' as our page directory.  We bother with
-        * `SET_PAGE_DIR' because although might be rebooting, but if we change
-        * the way we set root page dir in the future, then we wont break a
-        * seldom used feature ;)
+        * Use `swapper_pg_dir' as our page directory.
         */
-       current->mm->pgd = swapper_pg_dir;
-       current->active_mm->pgd = swapper_pg_dir;
-       activate_context();
+       asm volatile("movl %0,%%cr3": :"r" (__pa(swapper_pg_dir)));
 
        /* Write 0x1234 to absolute memory location 0x472.  The BIOS reads
           this on booting to tell it to "Bypass memory test (also warm
@@ -490,16 +485,7 @@ void release_segments(struct mm_struct *mm)
         */
        if (ldt) {
                mm->segments = NULL;
-               /*
-                * special case, when we release the LDT from under
-                * the running CPU. Other CPUs cannot possibly use
-                * this LDT as we were getting here through mmput() ...
-                */
-               if (mm == current->mm)
-                       load_LDT(mm);
-               /*
-                * Nobody anymore uses the LDT, we can free it:
-                */
+               clear_LDT();
                vfree(ldt);
        }
 }
@@ -581,12 +567,8 @@ void release_thread(struct task_struct *dead_task)
 }
 
 /*
- * If new_mm is NULL, we're being called to set up the LDT for
- * a clone task: this is easy since the clone is not running yet.
- * otherwise we copy the old segment into a new segment.
- *
  * we do not have to muck with descriptors here, that is
- * done in __switch_to() and get_mmu_context().
+ * done in switch_mm() as needed.
  */
 void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
 {
@@ -597,22 +579,19 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
                /*
                 * default LDT - use the one from init_task
                 */
-               if (new_mm)
-                       new_mm->segments = NULL;
+               new_mm->segments = NULL;
                return;
        }
 
-       if (new_mm) {
-               /*
-                * Completely new LDT, we initialize it from the parent:
-                */
-               ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
-               if (!ldt)
-                       printk(KERN_WARNING "ldt allocation failed\n");
-               else
-                       memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
-               new_mm->segments = ldt;
-       }
+       /*
+        * Completely new LDT, we initialize it from the parent:
+        */
+       ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
+       if (!ldt)
+               printk(KERN_WARNING "ldt allocation failed\n");
+       else
+               memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
+       new_mm->segments = ldt;
        return;
 }
 
index 4b4be164d617b35e4cd4a0bffc30a49186bd3722..44ab909862656c8b3fb1a467dd180e4aa1cfef24 100644 (file)
@@ -336,15 +336,15 @@ int usb_mouse_init(void)
 {
        struct mouse_state *mouse = &static_mouse_state;
 
-       misc_register(&usb_mouse);
-
        mouse->present = mouse->active = 0;
        mouse->irq_handle = NULL;
        init_waitqueue_head(&mouse->wait);
        mouse->fasync = NULL;
 
+       misc_register(&usb_mouse);
+
        usb_register(&mouse_driver);
-       printk(KERN_INFO "USB HID boot protocol mouse registered.\n");
+       printk(KERN_INFO "USB HID boot protocol mouse driver registered.\n");
        return 0;
 }
 
index 8bf2736921bb737e8dc24307f06a830ebe3fd37e..339652d210e5f696057e8ca6cb7a63a71d4b22f0 100644 (file)
@@ -131,7 +131,18 @@ void show_ohci_td(struct ohci_td *td)
        printk(KERN_DEBUG "      next_td  =  0x%x\n", le32_to_cpup(&td->next_td));
        printk(KERN_DEBUG "      buf_end  =  0x%x\n", le32_to_cpup(&td->buf_end));
        printk(KERN_DEBUG "   ohci TD driver fields:\n");
+       printk(KERN_DEBUG "      flags    =  %x {", td->hcd_flags);
+       if (td_allocated(*td))
+               printk(" alloc");
+       if (td_dummy(*td))
+               printk(" dummy");
+       if (td_endofchain(*td))
+               printk(" endofchain");
+       if (!can_auto_free(*td))
+               printk(" noautofree");
+       printk("}\n");
        printk(KERN_DEBUG "      data     =  %p\n", td->data);
+       printk(KERN_DEBUG "      cmpltd   =  %p\n", td->completed);
        printk(KERN_DEBUG "      dev_id   =  %p\n", td->dev_id);
        printk(KERN_DEBUG "      ed       =  %p\n", td->ed);
        if (td->data != NULL) {
index dd54f77e37f54d3a5fd8270bcb5e734b3a7b44df..65798e6d21de48d0af73e9cfabebeff995b460d3 100644 (file)
@@ -111,8 +111,8 @@ static const char *cc_names[16] = {
  *
  * This function can be called by the interrupt handler.
  */
-static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
-                               struct ohci_td *last_td, struct ohci_ed *ed)
+static struct ohci_td *ohci_add_tds_to_ed(struct ohci_td *td,
+                                         struct ohci_ed *ed)
 {
        struct ohci_td *t, *dummy_td;
        u32 new_dummy;
@@ -127,14 +127,14 @@ static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
 
        for (t = td; ; t = bus_to_virt(le32_to_cpup(&t->next_td))) {
                t->ed = ed;
-               if (t == last_td)
+               if (t->next_td == 0)
                        break;
        }
 
        /* Make the last TD point back to the first, since it
         * will become the new dummy TD. */
        new_dummy = cpu_to_le32(virt_to_bus(td));
-       last_td->next_td = new_dummy;
+       t->next_td = new_dummy;
 
        /* Copy the contents of the first TD into the dummy */
        *dummy_td = *td;
@@ -146,34 +146,7 @@ static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
        ed->tail_td = new_dummy;
 
        return dummy_td;        /* replacement head of chain */
-} /* ohci_add_td_to_ed() */
-
-
-/*
- * Add a whole chain of TDs to an ED using the above function.
- * The same restrictions apply.
- *
- * XXX This function is being removed in the future! XXX
- */
-static struct ohci_td *ohci_add_td_chain_to_ed(struct ohci_td *td, struct ohci_ed *ed)
-{
-       struct ohci_td *cur_td;
-       if (!td)
-               return NULL;
-
-       /* Find the last TD in this chain, storing its pointer in cur_td */
-       cur_td = td;
-       for (;;) {
-               __u32 next_td = cur_td->next_td;
-
-               /* advance to the next td, exit if there isn't one */
-               if (!next_td)
-                       break;
-               cur_td = bus_to_virt(le32_to_cpup(&next_td));
-       }
-
-       return td = ohci_add_td_to_ed(td, cur_td, ed);
-} /* ohci_add_td_chain_to_ed() */
+} /* ohci_add_tds_to_ed() */
 
 
 /* .......... */
@@ -261,6 +234,7 @@ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
         */
        int_ed = &root_hub->ed[ms_to_ed_int(period)];
 #ifdef OHCI_DEBUG
+       if (MegaDebug)
        printk(KERN_DEBUG "usb-ohci: Using INT ED queue %d for %dms period\n",
               ms_to_ed_int(period), period);
 #endif
@@ -277,6 +251,42 @@ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
        ohci_start_periodic(ohci);
 } /* ohci_add_periodic_ed() */
 
+/*
+ * Locate the periodic ED for a given interrupt endpoint.
+ */
+struct ohci_ed *ohci_get_periodic_ed(struct ohci_device *dev, int period,
+                                    unsigned int pipe, int isoc)
+{
+       struct ohci_device *root_hub = usb_to_ohci(dev->ohci->bus->root_hub);
+       unsigned long flags;
+       struct ohci_ed *int_ed;
+       unsigned int status, req_status;
+
+       /* get the dummy ED before the EDs for this period */
+       int_ed = &root_hub->ed[ms_to_ed_int(period)];
+
+       /* decide on what the status field should look like */
+       req_status = ed_set_maxpacket(usb_maxpacket(ohci_to_usb(dev), pipe))
+               | ed_set_speed(usb_pipeslow(pipe))
+               | (usb_pipe_endpdev(pipe) & 0x7ff)
+               | ed_set_type_isoc(isoc);
+
+       spin_lock_irqsave(&ohci_edtd_lock, flags);
+       for (;;) {
+               int_ed = bus_to_virt(le32_to_cpup(&int_ed->next_ed));
+               /* stop if we get to the end or to another dummy ED. */
+               if (int_ed == 0)
+                       break;
+               status = le32_to_cpup(&int_ed->status);
+               if ((status & OHCI_ED_FA) == 0)
+                       break;
+               /* check whether all the appropriate fields match */
+               if ((status & 0x7ffa7ff) == req_status)
+                       return int_ed;
+       }
+       return 0;
+}
+
 /*
  *  Put an isochronous ED on the controller's list
  */
@@ -507,6 +517,7 @@ static int ohci_remove_device_list(__u32 *headp, int devnum)
                        /* set the controller to skip this one
                           and remove it from the list */
                        ed->status |= cpu_to_le32(OHCI_ED_SKIP);
+                       /* XXX should call td->completed for each td */
                        *prevp = ed->next_ed;
                        removed = 1;
                } else {
@@ -670,6 +681,7 @@ static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev)
                        new_ed->status |= cpu_to_le32(OHCI_ED_SKIP);
                        /* mark it as allocated */
                        allocate_ed(new_ed);
+                       new_ed->ohci_dev = dev;
                        return new_ed;
                }
        }
@@ -722,7 +734,7 @@ struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32
                               flags);
        td->cur_buf = (data == NULL) ? 0 : cpu_to_le32(virt_to_bus(data));
        td->buf_end = (len == 0) ? 0 :
-               cpu_to_le32(le32_to_cpup(&td->cur_buf) + len - 1);
+               cpu_to_le32(virt_to_bus((char *)data + len - 1));
 
        /* driver fields */
        td->data = data;
@@ -789,31 +801,24 @@ struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed,
  *
  *  Returns the head TD in the chain.
  */
-struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, void *data, unsigned int len, int dir, __u32 toggle, int round, int auto_free, void* dev_id, usb_device_irq handler, __u32 next_td)
+struct ohci_td *ohci_build_td_chain(struct ohci_device *dev,
+               void *data, unsigned int len, int dir, __u32 toggle,
+               int round, int auto_free, void* dev_id,
+               usb_device_irq handler, __u32 next_td)
 {
        struct ohci_td *head, *cur_td;
-       __u32 bus_data_start, bus_data_end;
-       unsigned short max_page0_len;
+       unsigned max_len;
 
        if (!data || (len == 0))
                return NULL;
 
-       /* Setup the first TD, leaving buf_end = 0 */
+       /* Get the first TD */
        head = ohci_get_free_td(dev);
        if (head == NULL) {
                printk(KERN_ERR "usb-ohci: out of TDs\n");
                return NULL;
        }
 
-       ohci_fill_new_td(head,
-               td_set_dir_out(dir),
-               toggle & OHCI_TD_DT,
-               (round ? OHCI_TD_ROUND : 0),
-               data, 0,
-               dev_id, handler);
-       if (!auto_free)
-               noauto_free_td(head);
-
        cur_td = head;
 
        /* AFICT, that the OHCI controller takes care of the innards of
@@ -821,66 +826,60 @@ struct ohci_td *ohci_build_td_chain(struct ohci_device *dev, void *data, unsigne
         * packets as necessary if the transfer falls on an even packet
         * size boundary, we don't need a special TD for that. */
 
-       while (len > 0) {
-               bus_data_start = virt_to_bus(data);
-               bus_data_end = virt_to_bus(data+(len-1));
-
-               /* check the 4096 byte alignment of the start of the data */
-               max_page0_len = 0x1000 - (bus_data_start & 0xfff);
-
-               /* check if the remaining data occupies more than two pages */
-               if ((max_page0_len < len) && (len - max_page0_len > 0x1000)) {
-                       struct ohci_td *new_td;
-
-                       /* Point this TD to data up through the end of
-                        * the second page */
-                       cur_td->buf_end = bus_data_start +
-                               (max_page0_len + 0xfff);
-
-                       /* adjust the data pointer & remaining length */
-                       data += (max_page0_len + 0x1000);
-                       len  -= (max_page0_len + 0x1000);
-
-                       /* TODO lookup effect of rounding bit on
-                        * individual TDs vs. whole TD chain transfers;
-                        * disable cur_td's rounding bit here if needed. */
+       /* check the 4096 byte alignment of the start of the data */
+       max_len = 0x2000 - ((unsigned long)data & 0xfff);
+
+       /* check if the remaining data occupies more than two pages */
+       while (len > max_len) {
+               struct ohci_td *new_td;
+
+               /* TODO lookup effect of rounding bit on
+                * individual TDs vs. whole TD chain transfers;
+                * disable cur_td's rounding bit here if needed. */
+
+               ohci_fill_new_td(cur_td,
+                                td_set_dir_out(dir),
+                                toggle & OHCI_TD_DT,
+                                (round ? OHCI_TD_ROUND : 0),
+                                data, max_len - 1,
+                                dev_id, handler);
+               if (!auto_free)
+                       noauto_free_td(head);
+
+               /* adjust the data pointer & remaining length */
+               data += max_len;
+               len  -= max_len;
+
+               /* allocate another td */
+               new_td = ohci_get_free_td(dev);
+               if (new_td == NULL) {
+                       printk(KERN_ERR "usb-ohci: out of TDs\n");
+                       /* FIXME: free any allocated TDs */
+                       return NULL;
+               }
 
-                       /* mark that this is not the last TD... */
-                       clear_td_endofchain(cur_td);
+               /* Link the new TD to the chain & advance */
+               cur_td->next_td = cpu_to_le32(virt_to_bus(new_td));
+               cur_td = new_td;
 
-                       /* allocate another td */
-                       new_td = ohci_get_free_td(dev);
-                       if (new_td == NULL) {
-                               printk(KERN_ERR "usb-ohci: out of TDs\n");
-                               /* FIXME: free any allocated TDs */
-                               return NULL;
-                       }
-
-                       ohci_fill_new_td(new_td,
-                               td_set_dir_out(dir),
-                               TOGGLE_AUTO,  /* toggle Data0/1 via the ED */
-                               round ? OHCI_TD_ROUND : 0,
-                               data, 0,
-                               dev_id, handler);
-                       if (!auto_free)
-                               noauto_free_td(new_td);
-
-                       /* Link the new TD to the chain & advance */
-                       cur_td->next_td = virt_to_bus(new_td);
-                       cur_td = new_td;
-               } else {
-                       /* Last TD in this chain, normal buf_end is fine */
-                       cur_td->buf_end = bus_data_end;
-
-                       set_td_endofchain(cur_td);
+               /* address is page-aligned now */
+               max_len = 0x2000;
+               toggle = TOGGLE_AUTO;  /* toggle Data0/1 via the ED */
+       }
 
-                       len = 0;
-                       break;
-               }
-       } /* while */
+       ohci_fill_new_td(cur_td,
+               td_set_dir_out(dir),
+               toggle & OHCI_TD_DT,
+               (round ? OHCI_TD_ROUND : 0),
+               data, len,
+               dev_id, handler);
+       if (!auto_free)
+               noauto_free_td(head);
 
        /* link the given next_td to the end of this chain */
-       cur_td->next_td = next_td;
+       cur_td->next_td = cpu_to_le32(next_td);
+       if (next_td == 0)
+               set_td_endofchain(cur_td);
 
        return head;
 } /* ohci_build_td_chain() */
@@ -902,10 +901,10 @@ static __u16 ohci_td_bytes_done(struct ohci_td *td)
 
        /* if cur_buf is 0, all data has been transferred */
        if (!td->cur_buf) {
-               return td->buf_end - bus_data_start + 1;
+               return le32_to_cpup(&td->buf_end) - bus_data_start + 1;
        }
 
-       bus_data_end = td->cur_buf;
+       bus_data_end = le32_to_cpup(&td->cur_buf);
 
        /* is it on the same page? */
        if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) {
@@ -945,13 +944,36 @@ static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
        struct ohci_td *td;
        struct ohci_ed *interrupt_ed;   /* endpoint descriptor for this irq */
        int maxps = usb_maxpacket(usb, pipe);
+       unsigned long flags;
 
        /* Get an ED and TD */
-       interrupt_ed = ohci_get_free_ed(dev);
-       if (!interrupt_ed) {
-               printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
-               return NULL;
+       interrupt_ed = ohci_get_periodic_ed(dev, period, pipe, 0);
+       if (interrupt_ed == 0) {
+               interrupt_ed = ohci_get_free_ed(dev);
+               if (!interrupt_ed) {
+                       printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev);
+                       return NULL;
+               }
+
+               /*
+                * Set the max packet size, device speed, endpoint number, usb
+                * device number (function address), and type of TD.
+                */
+               ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe),
+                            usb_pipe_endpdev(pipe), 0 /* normal TDs */);
+               interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
+
+               /* Assimilate the new ED into the collective */
+               ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
+       }
+#ifdef OHCI_DEBUG
+       if (MegaDebug) {
+       printk(KERN_DEBUG "ohci_request irq: using ED %p [%x %x %x %x]\n",
+              interrupt_ed, FIELDS_OF_ED(interrupt_ed));
+       printk(KERN_DEBUG "  for dev %d pipe %x period %d\n", usb->devnum,
+              pipe, period);
        }
+#endif
 
        td = ohci_get_free_td(dev);
        if (!td) {
@@ -960,13 +982,6 @@ static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
                return NULL;
        }
 
-       /*
-        * Set the max packet size, device speed, endpoint number, usb
-        * device number (function address), and type of TD.
-        */
-       ohci_fill_ed(dev, interrupt_ed, maxps, usb_pipeslow(pipe),
-                    usb_pipe_endpdev(pipe), 0 /* normal TDs */);
-
        /* Fill in the TD */
        if (maxps > sizeof(dev->data))
                maxps = sizeof(dev->data);
@@ -975,20 +990,15 @@ static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
                        OHCI_TD_ROUND,
                        dev->data, maxps,
                        dev_id, handler);
+       set_td_endofchain(td);
 
        /*
         *  Put the TD onto our ED and make sure its ready to run
         */
-       td = ohci_add_td_to_ed(td, td, interrupt_ed);
-       interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
-       ohci_unhalt_ed(interrupt_ed);
-
-       /* Make sure all the stores above get done before
-        * the store which tells the OHCI about the new ed. */
-       wmb();
-
-       /* Assimilate the new ED into the collective */
-       ohci_add_periodic_ed(dev->ohci, interrupt_ed, period);
+       td->next_td = 0;
+       spin_lock_irqsave(&ohci_edtd_lock, flags);
+       td = ohci_add_tds_to_ed(td, interrupt_ed);
+       spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 
        return (void*)td;
 } /* ohci_request_irq() */
@@ -1148,6 +1158,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
                        0 /* flags */,
                        NULL /* data */, 0 /* data len */,
                        &completion_status, ohci_control_completed);
+       set_td_endofchain(status_td);
        status_td->next_td = 0; /* end of TDs */
 
        /* If there is data to transfer, create the chain of data TDs
@@ -1167,18 +1178,18 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
                }
 
                /* link the to the data & status TDs */
-               setup_td->next_td = virt_to_bus(data_td);
+               setup_td->next_td = cpu_to_le32(virt_to_bus(data_td));
        } else {
                /* no data TDs, link to the status TD */
-               setup_td->next_td = virt_to_bus(status_td);
+               setup_td->next_td = cpu_to_le32(virt_to_bus(status_td));
        }
 
        /*
         * Add the control TDs to the control ED (setup_td is the first)
         */
-       setup_td = ohci_add_td_chain_to_ed(setup_td, control_ed);
-       control_ed->status &= ~OHCI_ED_SKIP;
-       ohci_unhalt_ed(control_ed);
+       setup_td = ohci_add_tds_to_ed(setup_td, control_ed);
+       control_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
+       /* ohci_unhalt_ed(control_ed); */
 
 #ifdef OHCI_DEBUG
        if (MegaDebug) {
@@ -1201,35 +1212,34 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
        /* Give the ED to the HC */
        ohci_add_control_ed(dev->ohci, control_ed);
 
-       schedule_timeout(HZ/10);
+       schedule_timeout(HZ);
 
        remove_wait_queue(&control_wakeup, &wait);
 
-#ifdef OHCI_DEBUG
-       if (MegaDebug) {
-       /* complete transaction debugging output (after) */
-       printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed));
-       show_ohci_ed(control_ed);
-       printk(KERN_DEBUG " *after* Control TD chain:\n");
-       show_ohci_td_chain(setup_td);
-       printk(KERN_DEBUG " *after* OHCI Controller Status:\n");
-       show_ohci_status(dev->ohci);
-       }
-#endif
-
-       /* no TD cleanup, the TDs were auto-freed as they finished */
-
-       /* remove the control ED from the HC */
-       ohci_remove_control_ed(dev->ohci, control_ed);
-       ohci_free_ed(control_ed);        /* return it to the pool */
-
 #ifdef OHCI_DEBUG
        if (completion_status != 0) {
                const char *what = (completion_status < 0)? "timed out":
                        cc_names[completion_status & 0xf];
-               printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x\n",
+               printk(KERN_ERR "ohci_control_msg: %s on pipe %x cmd %x %x %x %x %x",
                       what, pipe, cmd->requesttype, cmd->request,
                       cmd->value, cmd->index, cmd->length);
+               if (usb_pipeout(pipe) && len > 0) {
+                       int i;
+                       printk(" data");
+                       for (i = 0; i < 16 && i < len; ++i)
+                               printk(" %.2x", ((unsigned char *)data)[i]);
+                       if (i < len)
+                               printk(" ...");
+               }
+               printk("\n");
+               if (MegaDebug && completion_status < 0) {
+                       printk(KERN_DEBUG "control_ed at %p:\n", control_ed);
+                       show_ohci_ed(control_ed);
+                       if (ed_head_td(control_ed) != ed_tail_td(control_ed))
+                               show_ohci_td_chain(bus_to_virt(ed_head_td(control_ed)));
+                       printk(KERN_DEBUG "setup TD at %p:\n", setup_td);
+                       show_ohci_td(setup_td);
+               }
        } else if (!usb_pipeout(pipe)) {
                unsigned char *q = data;
                int i;
@@ -1243,7 +1253,26 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
                }
                printk("\n");
        }
+
+       if (MegaDebug) {
+       /* complete transaction debugging output (after) */
+       printk(KERN_DEBUG " *after* Control ED %lx:\n", virt_to_bus(control_ed));
+       show_ohci_ed(control_ed);
+       printk(KERN_DEBUG " *after* Control TD chain:\n");
+       show_ohci_td_chain(setup_td);
+       printk(KERN_DEBUG " *after* OHCI Controller Status:\n");
+       show_ohci_status(dev->ohci);
+       }
 #endif
+
+       /* no TD cleanup, the TDs were auto-freed as they finished */
+
+       /* remove the control ED from the HC */
+       ohci_remove_control_ed(dev->ohci, control_ed);
+       ohci_free_ed(control_ed);        /* return it to the pool */
+
+       if (completion_status < 0)
+               completion_status = USB_ST_TIMEOUT;
        return completion_status;
 } /* ohci_control_msg() */
 
@@ -1278,6 +1307,7 @@ static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id)
        req = (struct ohci_bulk_request_state *) dev_id;
 
 #ifdef OHCI_DEBUG
+       if (MegaDebug)
        printk(KERN_DEBUG "ohci_bulk_td_handler stats %x, buffer %p, len %d, req %p\n", stats, buffer, len, req);
 #endif
 
@@ -1285,11 +1315,24 @@ static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id)
        if (stats == USB_ST_NOERROR)
                req->_bytes_done += len;
 
+#ifdef OHCI_DEBUG
+       if (MegaDebug && req->_bytes_done) {
+               int i;
+               printk(KERN_DEBUG " %d bytes, bulk data:", req->_bytes_done);
+               for (i = 0; i < 16 && i < req->_bytes_done; ++i)
+                       printk(" %.2x", ((unsigned char *)buffer)[i]);
+               if (i < req->_bytes_done)
+                       printk(" ...");
+               printk("\n");
+       }
+#endif
+
        /* call the real completion handler when done or on an error */
        if ((stats != USB_ST_NOERROR) ||
            (req->_bytes_done >= req->length && req->completion != NULL)) {
                *req->bytes_transferred_p += req->_bytes_done;
 #ifdef OHCI_DEBUG
+               if (MegaDebug)
                printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req);
 #endif
                req->completion(stats, buffer, req->_bytes_done, req->dev_id);
@@ -1305,7 +1348,7 @@ static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id)
  * to an error.
  *
  * bytes_transferred_p is a pointer to an integer that will be
- * -incremented- by the number of bytes that have been successfully
+ * set to the number of bytes that have been successfully
  * transferred.  The interrupt handler will update it after each
  * internal TD completes successfully.
  *
@@ -1329,6 +1372,7 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re
        unsigned long flags;
 
 #ifdef OHCI_DEBUG 
+       if (MegaDebug)
        printk(KERN_DEBUG "ohci_request_bulk(%p) ohci_dev %p, completion %p, pipe %x, data %p, len %d\n", bulk_request, dev, bulk_request->completion, pipe, data, len);
 #endif
 
@@ -1358,6 +1402,10 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re
                usb_pipeslow(pipe),
                usb_pipe_endpdev(pipe), 0 /* bulk uses normal TDs */);
 
+       /* initialize the toggle carry */
+       if (usb_gettoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe)))
+               ohci_ed_set_carry(bulk_ed);
+
        /* initialize the internal counter */
        bulk_request->_bytes_done = 0;
 
@@ -1365,13 +1413,11 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re
         * Add the TDs to the ED
         */
        spin_lock_irqsave(&ohci_edtd_lock, flags);
-       bulk_ed->status |= OHCI_ED_SKIP;
-       head_td = ohci_add_td_chain_to_ed(head_td, bulk_ed);
-       bulk_ed->status &= ~OHCI_ED_SKIP;
-       ohci_unhalt_ed(bulk_ed);
+       head_td = ohci_add_tds_to_ed(head_td, bulk_ed);
+       bulk_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
+       /* ohci_unhalt_ed(bulk_ed); */
        spin_unlock_irqrestore(&ohci_edtd_lock, flags);
 
-
 #ifdef OHCI_DEBUG
        if (MegaDebug) {
        /* complete request debugging output (before) */
@@ -1414,7 +1460,8 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
        struct ohci_bulk_request_state req;
        struct ohci_ed *req_ed;
 
-#ifdef OHCI_DEBUG 
+#ifdef OHCI_DEBUG
+       if (MegaDebug)
        printk(KERN_DEBUG "ohci_bulk_msg %p pipe %x, data %p, len %d, bytes_transferred %p\n", usb_dev, pipe, data, len, bytes_transferred_p);
 #endif
 
@@ -1430,6 +1477,12 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
        req.bytes_transferred_p = bytes_transferred_p;
        req.dev_id = &completion_status;
        req.completion = ohci_bulk_msg_completed;
+       if (bytes_transferred_p)
+               *bytes_transferred_p = 0;
+
+       if (usb_endpoint_halted(usb_dev, usb_pipeendpoint(pipe))
+           && usb_clear_halt(usb_dev, usb_pipeendpoint(pipe) | (pipe & 0x80)))
+               return USB_ST_STALL;
 
        /*
         * Start the transaction..
@@ -1442,7 +1495,8 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
        /* FIXME this should to wait for a caller specified time... */
        schedule_timeout(HZ*5);
 
-       /* it'll only stay in this state of the request never finished */
+       /* completion_status will only stay in this state of the
+        * request never finished */
        if (completion_status == USB_ST_INTERNALERROR) {
                struct ohci_device *dev = usb_to_ohci(usb_dev);
                struct ohci_regs *regs = dev->ohci->regs;
@@ -1485,9 +1539,15 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
 
        /* remove the ED from the HC */
        ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed);
+
+       /* save the toggle value back into the usb_dev */
+       usb_settoggle(usb_dev, usb_pipeendpoint(pipe), usb_pipeout(pipe),
+                     ohci_ed_carry(req_ed));
+
        ohci_free_ed(req_ed);    /* return it to the pool */
 
 #ifdef OHCI_DEBUG
+       if (completion_status != 0 || MegaDebug)
        printk(KERN_DEBUG "ohci_bulk_msg done, status %x (bytes_transferred = %ld).\n", completion_status, *bytes_transferred_p);
 #endif
 
@@ -1659,7 +1719,6 @@ static int start_hc(struct ohci *ohci)
 
        struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
 
-       fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
 #if 0
        printk(KERN_DEBUG "entering start_hc %p\n", ohci);
 #endif
@@ -1671,16 +1730,22 @@ static int start_hc(struct ohci *ohci)
        writel(virt_to_bus(root_hub->hcca), &ohci->regs->hcca);
 
        /*
-        * XXX Should fminterval also be set here?
-        * The spec suggests 0x2edf [11,999]. (FIXME: make this a constant)
+        * fminterval has to be 11999 (it can be adjusted +/- 1
+        * to sync with other things if necessary).
         */
-       /* fminterval |= (0x2edf << 16); */
-       fminterval = (10240 << 16) | 11999;
-       writel(fminterval, &ohci->regs->fminterval);
+       fminterval = 11999;
+
        /* Start periodic transfers at 90% of fminterval (fmremaining
         * counts down; this will put them in the first 10% of the
         * frame). */
-       writel((0x2edf*9)/10, &ohci->regs->periodicstart);
+       writel((fminterval * 9) / 10, &ohci->regs->periodicstart);
+
+       /* Set largest data packet counter and frame interval. */
+       fminterval |= ((fminterval - 210) * 6 / 7) << 16;
+       writel(fminterval, &ohci->regs->fminterval);
+
+       /* Set low-speed threshold (value from MacOS) */
+       writel(1576, &ohci->regs->lsthresh);
 
        /*
         * FNO (frame number overflow) could be enabled...  they
@@ -1926,7 +1991,8 @@ static void ohci_reap_donelist(struct ohci *ohci)
        struct ohci_td *td;             /* used for walking the list */
 
        /* um... isn't this dangerous to do in an interrupt handler? -greg */
-//     spin_lock(&ohci_edtd_lock);
+       /* nope. -paulus */
+       spin_lock(&ohci_edtd_lock);
 
        /* create the FIFO ordered donelist */
        td = ohci_reverse_donelist(ohci);
@@ -1934,18 +2000,33 @@ static void ohci_reap_donelist(struct ohci *ohci)
        while (td != NULL) {
                struct ohci_td *next_td = td->next_dl_td;
                int cc = OHCI_TD_CC_GET(le32_to_cpup(&td->info));
+               struct ohci_ed *ed = td->ed;
 
                if (td_dummy(*td))
                        printk(KERN_ERR "yikes! reaping a dummy TD\n");
 
-               if (cc != 0 && ohci_ed_halted(td->ed) && !td_endofchain(*td)) {
+#ifdef OHCI_DEBUG
+               if (cc != 0 && MegaDebug) {
+                       printk("cc=%s on td %p (ed %p)\n", cc_names[cc], td, ed);
+                       show_ohci_td(td);
+                       show_ohci_ed(ed);
+                       if (ed_head_td(ed) != ed_tail_td(ed))
+                               show_ohci_td_chain(bus_to_virt(ed_head_td(ed)));
+               }
+#endif
+
+               if (cc == USB_ST_STALL) {
+                       /* mark endpoint as halted */
+                       usb_endpoint_halt(ed->ohci_dev->usb, ed_get_en(ed));
+               }
+
+               if (cc != 0 && ohci_ed_halted(ed) && !td_endofchain(*td)) {
                        /*
                         * There was an error on this TD and the ED
                         * is halted, and this was not the last TD
                         * of the transaction, so there will be TDs
                         * to clean off the ED.
                         */
-                       struct ohci_ed *ed = td->ed;
                        struct ohci_td *tail_td = bus_to_virt(ed_tail_td(ed));
                        struct ohci_td *ntd;
 
@@ -1953,24 +2034,17 @@ static void ohci_reap_donelist(struct ohci *ohci)
                        td = ntd = bus_to_virt(ed_head_td(ed));
                        while (td != tail_td) {
                                ntd = bus_to_virt(le32_to_cpup(&td->next_td));
+                               if (td_endofchain(*td))
+                                       break;
 
-                               /* only deal with TDs from this ED,
-                                * the host controller could have
-                                * processed other endpoints at the
-                                * same time as this one.. */
-                               if (td->ed == ed) {
-                                       if (td_endofchain(*td))
-                                               break;
-
-                                       /* FIXME: unlink this TD from the
-                                        * reverse donelist! */
-                                       ohci_free_td(td);
-                               }
+                               printk(KERN_DEBUG "skipping TD %p\n", td);
+                               ohci_free_td(td);
 
                                td = ntd;
                        }
                        /* Set the ED head past the ones we cleaned
                           off, and clear the halted flag */
+                       printk(KERN_DEBUG "restarting ED %p at TD %p\n", ed, ntd);
                        set_ed_head_td(ed, virt_to_bus(ntd));
                        ohci_unhalt_ed(ed);
                        /* If we didn't find an endofchain TD, give up */
@@ -1996,8 +2070,9 @@ static void ohci_reap_donelist(struct ohci *ohci)
                        td->cur_buf = cpu_to_le32(virt_to_bus(td->data));
 
                        /* insert it back on its ED */
-                       ohci_add_td_to_ed(td, td, td->ed);
-                       ohci_unhalt_ed(td->ed);
+                       td->next_td = 0;
+                       ohci_add_tds_to_ed(td, ed);
+                       /* ohci_unhalt_ed(td->ed); */
                } else {
                        /* return it to the pool of free TDs */
                        if (can_auto_free(*td))
@@ -2007,7 +2082,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
                td = next_td;
        }
 
-//     spin_unlock(&ohci_edtd_lock);
+       spin_unlock(&ohci_edtd_lock);
 } /* ohci_reap_donelist() */
 
 
@@ -2259,8 +2334,10 @@ static struct ohci *alloc_ohci(void* mem_base)
        writel(0, &ohci->regs->ed_bulkhead);
 
 #ifdef OHCI_DEBUG
+       if (MegaDebug) {
        printk(KERN_DEBUG "alloc_ohci(): controller\n");
        show_ohci_status(ohci);
+       }
 #endif
 
 #if 0
@@ -2333,7 +2410,7 @@ static int ohci_control_thread(void * __ohci)
        printk(KERN_DEBUG "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread);
        exit_mm(current);
        exit_files(current);
-       exit_fs(current);
+       /*exit_fs(current);*/   /* can't do kernel_thread if we do this */
 
        strcpy(current->comm, "ohci-control");
 
@@ -2398,6 +2475,7 @@ static int ohci_control_thread(void * __ohci)
 #endif
                        } else {
                                /* unknown signal, exit the thread */
+                               printk(KERN_DEBUG "usb-ohci: control thread for %p exiting on signal %ld\n", __ohci, signr);
                                break;
                        }
                }
@@ -2406,7 +2484,6 @@ static int ohci_control_thread(void * __ohci)
        reset_hc(ohci);
        release_ohci(ohci);
        usb_deregister_bus(ohci->bus);
-       printk(KERN_DEBUG "ohci-control thread for 0x%p exiting\n", __ohci);
 
        return 0;
 } /* ohci_control_thread() */
index 804a7297610c015fd97552d781a3a36dc8ee0776..4bb71c55ce2e8572ccd6f9cfb76d677a0136585b 100644 (file)
@@ -41,8 +41,7 @@ struct ohci_td {
                /* bit0: Is this TD allocated? */
                /* bit1: Is this a dummy (end of list) TD? */
                /* bit2: do NOT automatically free this TD on completion */
-               /* bit3: this is NOT the last TD in a contiguious TD chain
-                *       on the indicated ED.  (0 means it is the last) */
+               /* bit3: this is the last TD in a contiguious TD chain */
 
        struct usb_device *usb_dev;     /* the owning device */
 
@@ -86,9 +85,9 @@ struct ohci_td {
 #define make_dumb_td(td)       ((td)->hcd_flags |= 2)
 #define clear_dumb_td(td)      ((td)->hcd_flags &= ~(__u32)2)
 
-#define td_endofchain(td)      (!((td).hcd_flags & (1 << 3)))
-#define set_td_endofchain(td)  ((td)->hcd_flags &= ~(1 << 3))
-#define clear_td_endofchain(td)        ((td)->hcd_flags |= (1 << 3))
+#define td_endofchain(td)      ((td).hcd_flags & (1 << 3))
+#define clear_td_endofchain(td)        ((td)->hcd_flags &= ~(1 << 3))
+#define set_td_endofchain(td)  ((td)->hcd_flags |= (1 << 3))
 
 /*
  * These control if the IRQ will call ohci_free_td after taking the TDs
@@ -109,6 +108,10 @@ struct ohci_ed {
        __u32 tail_td;  /* TD Queue tail pointer */
        __u32 _head_td; /* TD Queue head pointer, toggle carry & halted bits */
        __u32 next_ed;  /* Next ED */
+
+       /* driver fields */
+       struct ohci_device *ohci_dev;
+       struct ohci_ed  *ed_chain;
 } __attribute((aligned(16)));
 
 /* get the head_td */
@@ -119,10 +122,13 @@ struct ohci_ed {
 #define set_ed_head_td(ed, td) ((ed)->_head_td = cpu_to_le32((td)) \
                                 | ((ed)->_head_td & cpu_to_le32(3)))
 
-/* Control the ED's halted flag */
+/* Control the ED's halted and carry flags */
 #define ohci_halt_ed(ed)       ((ed)->_head_td |= cpu_to_le32(1))
 #define ohci_unhalt_ed(ed)     ((ed)->_head_td &= cpu_to_le32(~(__u32)1))
 #define ohci_ed_halted(ed)     ((ed)->_head_td & cpu_to_le32(1))
+#define ohci_ed_set_carry(ed)  ((ed)->_head_td |= cpu_to_le32(2))
+#define ohci_ed_clr_carry(ed)  ((ed)->_head_td &= ~cpu_to_le32(2))
+#define ohci_ed_carry(ed)      ((le32_to_cpup(&(ed)->_head_td) >> 1) & 1)
 
 #define OHCI_ED_SKIP   (1 << 14)
 #define OHCI_ED_MPS    (0x7ff << 16)
@@ -142,6 +148,8 @@ struct ohci_ed {
 #define OHCI_ED_EN     (0xf << 7)
 #define OHCI_ED_FA     (0x7f)
 
+#define ed_get_en(ed)  ((le32_to_cpup(&(ed)->status) & OHCI_ED_EN) >> 7)
+#define ed_get_fa(ed)  (le32_to_cpup(&(ed)->status) & OHCI_ED_FA)
 
 /* NOTE: bits 27-31 of the status dword are reserved for the HCD */
 /*
index 5701d26710f20599c227523d2cf98be022e8751e..3099c9826e43171ed8ac00e86197002b65cd33b4 100644 (file)
@@ -139,10 +139,20 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
        this_xfer = length > max_size ? max_size : length;
        length -= this_xfer;
        do {
-           US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);
+           /*US_DEBUGP("Bulk xfer %x(%d)\n", (unsigned int)buf, this_xfer);*/
            result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf, 
                                                    this_xfer, &partial);
 
+           if (result != 0 || partial != this_xfer)
+               US_DEBUGP("bulk_msg returned %d xferred %lu/%d\n",
+                         result, partial, this_xfer);
+
+           if (result == USB_ST_STALL) {
+               US_DEBUGP("clearing endpoing halt for pipe %x\n", pipe);
+               usb_clear_halt(us->pusb_dev,
+                              usb_pipeendpoint(pipe) | (pipe & 0x80));
+           }
+
            /* we want to retry if the device reported NAK */
            if (result == USB_ST_TIMEOUT) {
                if (partial != this_xfer) {
@@ -171,28 +181,31 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
     return 0;
 
 }
+
 static int us_transfer(Scsi_Cmnd *srb, int dir_in)
 {
     struct us_data *us = (struct us_data *)srb->host_scribble;
     int i;
     int result = -1;
+    unsigned int pipe = dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
+           usb_sndbulkpipe(us->pusb_dev, us->ep_out);
 
     if (srb->use_sg) {
        struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
 
        for (i = 0; i < srb->use_sg; i++) {
-           result = us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
-                                                 usb_sndbulkpipe(us->pusb_dev, us->ep_out),
-                                    sg[i].address, sg[i].length);
+           result = us_one_transfer(us, pipe, sg[i].address, sg[i].length);
            if (result)
                break;
        }
-       return result;
     }
     else
-       return us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) :
-                                           usb_sndbulkpipe(us->pusb_dev, us->ep_out),
-                              srb->request_buffer, srb->request_bufflen);
+       result = us_one_transfer(us, pipe,
+                                srb->request_buffer, srb->request_bufflen);
+
+    if (result)
+       US_DEBUGP("us_transfer returning error %d\n", result);
+    return result;
 }
 
 static unsigned int us_transfer_length(Scsi_Cmnd *srb)
@@ -232,12 +245,13 @@ static int pop_CBI_irq(int state, void *buffer, int len, void *dev_id)
     struct us_data *us = (struct us_data *)dev_id;
 
     if (state != USB_ST_REMOVED) {
-       us->ip_data = *(__u16 *)buffer;
-       US_DEBUGP("Interrupt Status %x\n", us->ip_data);
+       us->ip_data = le16_to_cpup((__u16 *)buffer);
+       /* US_DEBUGP("Interrupt Status %x\n", us->ip_data); */
     }
-    if (us->ip_wanted)
+    if (us->ip_wanted) {
+       us->ip_wanted = 0;
        wake_up(&us->ip_waitq);
-    us->ip_wanted = 0;
+    }
 
     /* we dont want another interrupt */
 
@@ -250,6 +264,7 @@ static int pop_CB_reset(struct us_data *us)
     devrequest dr;
     int result;
 
+    US_DEBUGP("pop_CB_reset\n");
     dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
     dr.request = US_CBI_ADSC;
     dr.value = 0;
@@ -262,12 +277,15 @@ static int pop_CB_reset(struct us_data *us)
                                        usb_sndctrlpipe(us->pusb_dev,0),
                                        &dr, cmd, 12);
 
-    usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
-    usb_clear_halt(us->pusb_dev, us->ep_out);
-
     /* long wait for reset */
 
     schedule_timeout(HZ*5);
+
+    US_DEBUGP("pop_CB_reset: clearing endpoint halt\n");
+    usb_clear_halt(us->pusb_dev, us->ep_in | 0x80);
+    usb_clear_halt(us->pusb_dev, us->ep_out);
+
+    US_DEBUGP("pop_CB_reset done\n");
     return 0;
 }
 
@@ -325,6 +343,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
                /* as per spec try a start command, wait and retry */
 
                done_start++;
+               memset(cmd, 0, sizeof(cmd));
                cmd[0] = START_STOP;
                cmd[4] = 1;             /* start */
                result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
@@ -338,7 +357,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
            result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, 
                                                  usb_sndctrlpipe(us->pusb_dev,0),
                                                  &dr, srb->cmnd, srb->cmd_len);
-       if (result != USB_ST_STALL && result != USB_ST_TIMEOUT)
+       if (/*result != USB_ST_STALL &&*/ result != USB_ST_TIMEOUT)
            return result;
     }
     return result;
@@ -356,6 +375,7 @@ static int pop_CB_status(Scsi_Cmnd *srb)
     devrequest dr;
     int retry = 5;
 
+    US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol);
     switch (us->protocol) {
     case US_PR_CB:
        /* get from control */
@@ -439,23 +459,26 @@ static int pop_CBI(Scsi_Cmnd *srb)
        if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) {
            return (DID_OK << 16) | 2;
        }
-       return DID_ABORT << 16;
+       return DID_ERROR << 16;
     }
 
     /* transfer the data */
 
     if (us_transfer_length(srb)) {
        result = us_transfer(srb, US_DIRECTION(srb->cmnd[0]));
-       if (result && result != USB_ST_DATAUNDERRUN) {
+       if (result && result != USB_ST_DATAUNDERRUN && result != USB_ST_STALL) {
            US_DEBUGP("CBI  transfer %x\n", result);
-           return DID_ABORT << 16;
-       } else if (result == USB_ST_DATAUNDERRUN) {
+           return DID_ERROR << 16;
+       }
+#if 0
+       else if (result == USB_ST_DATAUNDERRUN) {
            return DID_OK << 16;
        }
     } else {
        if (!result) {
            return DID_OK << 16;
        }
+#endif
     }
 
     /* get status */
@@ -947,6 +970,7 @@ static int usbscsi_control_thread(void * __us)
                            US_DEBUGP("Old/New length = %d/%d\n", savelen, length);
 
                            if (us->srb->request_bufflen != length) {
+                               US_DEBUGP("redoing cmd with len=%d\n", length);
                                us->srb->request_bufflen = length;
                                us->srb->result = us->pop(us->srb);
                            }
@@ -957,6 +981,15 @@ static int usbscsi_control_thread(void * __us)
                            case REQUEST_SENSE:
                            case INQUIRY:
                            case MODE_SENSE:
+                               if (us->srb->use_sg == 0 && length > 0) {
+                                   int i;
+                                   printk(KERN_DEBUG "Data is");
+                                   for (i = 0; i < 32 && i < length; ++i)
+                                       printk(" %.2x", ((unsigned char *)us->srb->request_buffer)[i]);
+                                   if (i < length)
+                                       printk(" ...");
+                                   printk("\n");
+                               }
                                us->srb->cmnd[4] = saveallocation;
                                break;
 
@@ -969,6 +1002,7 @@ static int usbscsi_control_thread(void * __us)
                        }
                        /* force attention on first command */
                        if (!us->attention_done) {
+                           US_DEBUGP("forcing unit attention\n");
                            if (us->srb->cmnd[0] == REQUEST_SENSE) {
                                if (us->srb->result == (DID_OK << 16)) {
                                    unsigned char *p = (unsigned char *)us->srb->request_buffer;
@@ -987,6 +1021,7 @@ static int usbscsi_control_thread(void * __us)
                        }
                    }
                }
+               US_DEBUGP("scsi cmd done, result=%x\n", us->srb->result);
                us->srb->scsi_done(us->srb);
                us->srb = NULL;
                break;
index f578992b3b2f0f37a3fb862c13fcfe0b17c23163..11cfc4145dc837d9d97fb1edf13e611ddea7b4ca 100644 (file)
@@ -1972,7 +1972,7 @@ void end_lazy_tlb(struct mm_struct *mm)
        current->mm = mm;
        if (mm != active_mm) {
                current->active_mm = mm;
-               activate_context();
+               switch_mm(active_mm, mm);
        }
        mmdrop(active_mm);
 }
index 5e614d8cdef72f8d126ffce941b8cd95480215cc..e3d6fa4b7e288b5ddf00b8a93a069bd9d3087d77 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -384,7 +384,7 @@ static int exec_mmap(void)
                mm->cpu_vm_mask = (1UL << smp_processor_id());
                current->mm = mm;
                current->active_mm = mm;
-               activate_context();
+               switch_mm(active_mm, mm);
                mm_release();
                if (old_mm) {
                        if (active_mm != old_mm) BUG();
index 31e267386415be74c4d1af39f5ec8be31d6240c1..3b29aac272074b8120a8d2c7cf7cbd9970a930c2 100644 (file)
@@ -69,17 +69,28 @@ extern void set_intr_gate(unsigned int irq, void * addr);
 extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
 extern void set_tss_desc(unsigned int n, void *addr);
 
+extern inline void clear_LDT(void)
+{
+       int cpu = smp_processor_id();
+       set_ldt_desc(cpu, &default_ldt, 1);
+       __load_LDT(cpu);
+}
+
 /*
  * load one particular LDT into the current CPU
  */
 extern inline void load_LDT (struct mm_struct *mm)
 {
        int cpu = smp_processor_id();
+       void *segments = mm->segments;
+       int count = LDT_ENTRIES;
 
-       if (mm->segments)
-               set_ldt_desc(cpu, mm->segments, LDT_ENTRIES);
-       else
-               set_ldt_desc(cpu, &default_ldt, 1);
+       if (!segments) {
+               segments = &default_ldt;
+               count = 1;
+       }
+               
+       set_ldt_desc(cpu, segments, count);
        __load_LDT(cpu);
 }
 
index 769fad6d4f443c59c95d4c4f6b8e607f0c3c967d..9b48c8b5e199e43c3b35590a266ac5b48a048655 100644 (file)
@@ -9,15 +9,6 @@
 #define destroy_context(mm)            do { } while(0)
 #define init_new_context(tsk,mm)       do { } while (0)
 
-static inline void activate_context(void)
-{
-       struct task_struct *tsk = current;
-       struct mm_struct *mm = tsk->mm;
-
-       load_LDT(mm);
-       __asm__ __volatile__("movl %0,%%cr3": :"r" (__pa(mm->pgd)));
-}
-
 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next)
 {
        /*