Commit 7176b206 authored by Linus Torvalds's avatar Linus Torvalds

Import 2.3.12pre4

parent 77725b26
...@@ -188,7 +188,7 @@ tristate 'Kernel support for a.out (ECOFF) binaries' CONFIG_BINFMT_AOUT ...@@ -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 ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86 tristate 'Kernel support for Linux/Intel ELF binaries' CONFIG_BINFMT_EM86
source drivers/parpor/Config.in source drivers/parport/Config.in
endmenu endmenu
source drivers/pnp/Config.in source drivers/pnp/Config.in
......
...@@ -322,14 +322,9 @@ void machine_restart(char * __unused) ...@@ -322,14 +322,9 @@ void machine_restart(char * __unused)
pg0[0] = _PAGE_RW | _PAGE_PRESENT; pg0[0] = _PAGE_RW | _PAGE_PRESENT;
/* /*
* Use `swapper_pg_dir' as our page directory. We bother with * Use `swapper_pg_dir' as our page directory.
* `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 ;)
*/ */
current->mm->pgd = swapper_pg_dir; asm volatile("movl %0,%%cr3": :"r" (__pa(swapper_pg_dir)));
current->active_mm->pgd = swapper_pg_dir;
activate_context();
/* Write 0x1234 to absolute memory location 0x472. The BIOS reads /* Write 0x1234 to absolute memory location 0x472. The BIOS reads
this on booting to tell it to "Bypass memory test (also warm this on booting to tell it to "Bypass memory test (also warm
...@@ -490,16 +485,7 @@ void release_segments(struct mm_struct *mm) ...@@ -490,16 +485,7 @@ void release_segments(struct mm_struct *mm)
*/ */
if (ldt) { if (ldt) {
mm->segments = NULL; mm->segments = NULL;
/* clear_LDT();
* 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:
*/
vfree(ldt); vfree(ldt);
} }
} }
...@@ -581,12 +567,8 @@ void release_thread(struct task_struct *dead_task) ...@@ -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 * 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) 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) ...@@ -597,22 +579,19 @@ void copy_segments(struct task_struct *p, struct mm_struct *new_mm)
/* /*
* default LDT - use the one from init_task * default LDT - use the one from init_task
*/ */
if (new_mm) new_mm->segments = NULL;
new_mm->segments = NULL;
return; return;
} }
if (new_mm) { /*
/* * Completely new LDT, we initialize it from the parent:
* Completely new LDT, we initialize it from the parent: */
*/ ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
ldt = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); if (!ldt)
if (!ldt) printk(KERN_WARNING "ldt allocation failed\n");
printk(KERN_WARNING "ldt allocation failed\n"); else
else memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); new_mm->segments = ldt;
new_mm->segments = ldt;
}
return; return;
} }
......
...@@ -336,15 +336,15 @@ int usb_mouse_init(void) ...@@ -336,15 +336,15 @@ int usb_mouse_init(void)
{ {
struct mouse_state *mouse = &static_mouse_state; struct mouse_state *mouse = &static_mouse_state;
misc_register(&usb_mouse);
mouse->present = mouse->active = 0; mouse->present = mouse->active = 0;
mouse->irq_handle = NULL; mouse->irq_handle = NULL;
init_waitqueue_head(&mouse->wait); init_waitqueue_head(&mouse->wait);
mouse->fasync = NULL; mouse->fasync = NULL;
misc_register(&usb_mouse);
usb_register(&mouse_driver); 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; return 0;
} }
......
...@@ -131,7 +131,18 @@ void show_ohci_td(struct ohci_td *td) ...@@ -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 " 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 " buf_end = 0x%x\n", le32_to_cpup(&td->buf_end));
printk(KERN_DEBUG " ohci TD driver fields:\n"); 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 " 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 " dev_id = %p\n", td->dev_id);
printk(KERN_DEBUG " ed = %p\n", td->ed); printk(KERN_DEBUG " ed = %p\n", td->ed);
if (td->data != NULL) { if (td->data != NULL) {
......
...@@ -111,8 +111,8 @@ static const char *cc_names[16] = { ...@@ -111,8 +111,8 @@ static const char *cc_names[16] = {
* *
* This function can be called by the interrupt handler. * This function can be called by the interrupt handler.
*/ */
static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td, static struct ohci_td *ohci_add_tds_to_ed(struct ohci_td *td,
struct ohci_td *last_td, struct ohci_ed *ed) struct ohci_ed *ed)
{ {
struct ohci_td *t, *dummy_td; struct ohci_td *t, *dummy_td;
u32 new_dummy; u32 new_dummy;
...@@ -127,14 +127,14 @@ static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td, ...@@ -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))) { for (t = td; ; t = bus_to_virt(le32_to_cpup(&t->next_td))) {
t->ed = ed; t->ed = ed;
if (t == last_td) if (t->next_td == 0)
break; break;
} }
/* Make the last TD point back to the first, since it /* Make the last TD point back to the first, since it
* will become the new dummy TD. */ * will become the new dummy TD. */
new_dummy = cpu_to_le32(virt_to_bus(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 */ /* Copy the contents of the first TD into the dummy */
*dummy_td = *td; *dummy_td = *td;
...@@ -146,34 +146,7 @@ static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td, ...@@ -146,34 +146,7 @@ static struct ohci_td *ohci_add_td_to_ed(struct ohci_td *td,
ed->tail_td = new_dummy; ed->tail_td = new_dummy;
return dummy_td; /* replacement head of chain */ return dummy_td; /* replacement head of chain */
} /* ohci_add_td_to_ed() */ } /* ohci_add_tds_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() */
/* .......... */ /* .......... */
...@@ -261,6 +234,7 @@ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period) ...@@ -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)]; int_ed = &root_hub->ed[ms_to_ed_int(period)];
#ifdef OHCI_DEBUG #ifdef OHCI_DEBUG
if (MegaDebug)
printk(KERN_DEBUG "usb-ohci: Using INT ED queue %d for %dms period\n", printk(KERN_DEBUG "usb-ohci: Using INT ED queue %d for %dms period\n",
ms_to_ed_int(period), period); ms_to_ed_int(period), period);
#endif #endif
...@@ -277,6 +251,42 @@ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period) ...@@ -277,6 +251,42 @@ void ohci_add_periodic_ed(struct ohci *ohci, struct ohci_ed *ed, int period)
ohci_start_periodic(ohci); ohci_start_periodic(ohci);
} /* ohci_add_periodic_ed() */ } /* 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 * Put an isochronous ED on the controller's list
*/ */
...@@ -507,6 +517,7 @@ static int ohci_remove_device_list(__u32 *headp, int devnum) ...@@ -507,6 +517,7 @@ static int ohci_remove_device_list(__u32 *headp, int devnum)
/* set the controller to skip this one /* set the controller to skip this one
and remove it from the list */ and remove it from the list */
ed->status |= cpu_to_le32(OHCI_ED_SKIP); ed->status |= cpu_to_le32(OHCI_ED_SKIP);
/* XXX should call td->completed for each td */
*prevp = ed->next_ed; *prevp = ed->next_ed;
removed = 1; removed = 1;
} else { } else {
...@@ -670,6 +681,7 @@ static struct ohci_ed *ohci_get_free_ed(struct ohci_device *dev) ...@@ -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); new_ed->status |= cpu_to_le32(OHCI_ED_SKIP);
/* mark it as allocated */ /* mark it as allocated */
allocate_ed(new_ed); allocate_ed(new_ed);
new_ed->ohci_dev = dev;
return new_ed; return new_ed;
} }
} }
...@@ -722,7 +734,7 @@ struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32 ...@@ -722,7 +734,7 @@ struct ohci_td *ohci_fill_new_td(struct ohci_td *td, int dir, int toggle, __u32
flags); flags);
td->cur_buf = (data == NULL) ? 0 : cpu_to_le32(virt_to_bus(data)); td->cur_buf = (data == NULL) ? 0 : cpu_to_le32(virt_to_bus(data));
td->buf_end = (len == 0) ? 0 : 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 */ /* driver fields */
td->data = data; td->data = data;
...@@ -789,31 +801,24 @@ struct ohci_ed *ohci_fill_ed(struct ohci_device *dev, struct ohci_ed *ed, ...@@ -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. * 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; struct ohci_td *head, *cur_td;
__u32 bus_data_start, bus_data_end; unsigned max_len;
unsigned short max_page0_len;
if (!data || (len == 0)) if (!data || (len == 0))
return NULL; return NULL;
/* Setup the first TD, leaving buf_end = 0 */ /* Get the first TD */
head = ohci_get_free_td(dev); head = ohci_get_free_td(dev);
if (head == NULL) { if (head == NULL) {
printk(KERN_ERR "usb-ohci: out of TDs\n"); printk(KERN_ERR "usb-ohci: out of TDs\n");
return NULL; 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; cur_td = head;
/* AFICT, that the OHCI controller takes care of the innards of /* 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 ...@@ -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 * packets as necessary if the transfer falls on an even packet
* size boundary, we don't need a special TD for that. */ * size boundary, we don't need a special TD for that. */
while (len > 0) { /* check the 4096 byte alignment of the start of the data */
bus_data_start = virt_to_bus(data); max_len = 0x2000 - ((unsigned long)data & 0xfff);
bus_data_end = virt_to_bus(data+(len-1));
/* check if the remaining data occupies more than two pages */
/* check the 4096 byte alignment of the start of the data */ while (len > max_len) {
max_page0_len = 0x1000 - (bus_data_start & 0xfff); struct ohci_td *new_td;
/* check if the remaining data occupies more than two pages */ /* TODO lookup effect of rounding bit on
if ((max_page0_len < len) && (len - max_page0_len > 0x1000)) { * individual TDs vs. whole TD chain transfers;
struct ohci_td *new_td; * disable cur_td's rounding bit here if needed. */
/* Point this TD to data up through the end of ohci_fill_new_td(cur_td,
* the second page */ td_set_dir_out(dir),
cur_td->buf_end = bus_data_start + toggle & OHCI_TD_DT,
(max_page0_len + 0xfff); (round ? OHCI_TD_ROUND : 0),
data, max_len - 1,
/* adjust the data pointer & remaining length */ dev_id, handler);
data += (max_page0_len + 0x1000); if (!auto_free)
len -= (max_page0_len + 0x1000); noauto_free_td(head);
/* TODO lookup effect of rounding bit on /* adjust the data pointer & remaining length */
* individual TDs vs. whole TD chain transfers; data += max_len;
* disable cur_td's rounding bit here if needed. */ 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... */ /* Link the new TD to the chain & advance */
clear_td_endofchain(cur_td); cur_td->next_td = cpu_to_le32(virt_to_bus(new_td));
cur_td = new_td;
/* allocate another td */ /* address is page-aligned now */
new_td = ohci_get_free_td(dev); max_len = 0x2000;
if (new_td == NULL) { toggle = TOGGLE_AUTO; /* toggle Data0/1 via the ED */
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);
len = 0; ohci_fill_new_td(cur_td,
break; td_set_dir_out(dir),
} toggle & OHCI_TD_DT,
} /* while */ (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 */ /* 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; return head;
} /* ohci_build_td_chain() */ } /* ohci_build_td_chain() */
...@@ -902,10 +901,10 @@ static __u16 ohci_td_bytes_done(struct ohci_td *td) ...@@ -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 cur_buf is 0, all data has been transferred */
if (!td->cur_buf) { 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? */ /* is it on the same page? */
if ((bus_data_start & ~0xfff) == (bus_data_end & ~0xfff)) { 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, ...@@ -945,13 +944,36 @@ static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
struct ohci_td *td; struct ohci_td *td;
struct ohci_ed *interrupt_ed; /* endpoint descriptor for this irq */ struct ohci_ed *interrupt_ed; /* endpoint descriptor for this irq */
int maxps = usb_maxpacket(usb, pipe); int maxps = usb_maxpacket(usb, pipe);
unsigned long flags;
/* Get an ED and TD */ /* Get an ED and TD */
interrupt_ed = ohci_get_free_ed(dev); interrupt_ed = ohci_get_periodic_ed(dev, period, pipe, 0);
if (!interrupt_ed) { if (interrupt_ed == 0) {
printk(KERN_ERR "Out of EDs on device %p in ohci_request_irq\n", dev); interrupt_ed = ohci_get_free_ed(dev);
return NULL; 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); td = ohci_get_free_td(dev);
if (!td) { if (!td) {
...@@ -960,13 +982,6 @@ static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe, ...@@ -960,13 +982,6 @@ static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
return NULL; 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 */ /* Fill in the TD */
if (maxps > sizeof(dev->data)) if (maxps > sizeof(dev->data))
maxps = sizeof(dev->data); maxps = sizeof(dev->data);
...@@ -975,20 +990,15 @@ static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe, ...@@ -975,20 +990,15 @@ static void* ohci_request_irq(struct usb_device *usb, unsigned int pipe,
OHCI_TD_ROUND, OHCI_TD_ROUND,
dev->data, maxps, dev->data, maxps,
dev_id, handler); dev_id, handler);
set_td_endofchain(td);
/* /*
* Put the TD onto our ED and make sure its ready to run * Put the TD onto our ED and make sure its ready to run
*/ */
td = ohci_add_td_to_ed(td, td, interrupt_ed); td->next_td = 0;
interrupt_ed->status &= cpu_to_le32(~OHCI_ED_SKIP); spin_lock_irqsave(&ohci_edtd_lock, flags);
ohci_unhalt_ed(interrupt_ed); td = ohci_add_tds_to_ed(td, interrupt_ed);
spin_unlock_irqrestore(&ohci_edtd_lock, flags);
/* 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);
return (void*)td; return (void*)td;
} /* ohci_request_irq() */ } /* ohci_request_irq() */
...@@ -1148,6 +1158,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, ...@@ -1148,6 +1158,7 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
0 /* flags */, 0 /* flags */,
NULL /* data */, 0 /* data len */, NULL /* data */, 0 /* data len */,
&completion_status, ohci_control_completed); &completion_status, ohci_control_completed);
set_td_endofchain(status_td);
status_td->next_td = 0; /* end of TDs */ status_td->next_td = 0; /* end of TDs */
/* If there is data to transfer, create the chain of data 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, ...@@ -1167,18 +1178,18 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
} }
/* link the to the data & status TDs */ /* 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 { } else {
/* no data TDs, link to the status TD */ /* 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) * 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); setup_td = ohci_add_tds_to_ed(setup_td, control_ed);
control_ed->status &= ~OHCI_ED_SKIP; control_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
ohci_unhalt_ed(control_ed); /* ohci_unhalt_ed(control_ed); */
#ifdef OHCI_DEBUG #ifdef OHCI_DEBUG
if (MegaDebug) { if (MegaDebug) {
...@@ -1201,35 +1212,34 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, ...@@ -1201,35 +1212,34 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
/* Give the ED to the HC */ /* Give the ED to the HC */
ohci_add_control_ed(dev->ohci, control_ed); ohci_add_control_ed(dev->ohci, control_ed);
schedule_timeout(HZ/10); schedule_timeout(HZ);
remove_wait_queue(&control_wakeup, &wait); 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 #ifdef OHCI_DEBUG
if (completion_status != 0) { if (completion_status != 0) {
const char *what = (completion_status < 0)? "timed out": const char *what = (completion_status < 0)? "timed out":
cc_names[completion_status & 0xf]; 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, what, pipe, cmd->requesttype, cmd->request,
cmd->value, cmd->index, cmd->length); 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)) { } else if (!usb_pipeout(pipe)) {
unsigned char *q = data; unsigned char *q = data;
int i; int i;
...@@ -1243,7 +1253,26 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe, ...@@ -1243,7 +1253,26 @@ static int ohci_control_msg(struct usb_device *usb, unsigned int pipe,
} }
printk("\n"); 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 #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; return completion_status;
} /* ohci_control_msg() */ } /* ohci_control_msg() */
...@@ -1278,6 +1307,7 @@ static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id) ...@@ -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; req = (struct ohci_bulk_request_state *) dev_id;
#ifdef OHCI_DEBUG #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); printk(KERN_DEBUG "ohci_bulk_td_handler stats %x, buffer %p, len %d, req %p\n", stats, buffer, len, req);
#endif #endif
...@@ -1285,11 +1315,24 @@ static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id) ...@@ -1285,11 +1315,24 @@ static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id)
if (stats == USB_ST_NOERROR) if (stats == USB_ST_NOERROR)
req->_bytes_done += len; 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 */ /* call the real completion handler when done or on an error */
if ((stats != USB_ST_NOERROR) || if ((stats != USB_ST_NOERROR) ||
(req->_bytes_done >= req->length && req->completion != NULL)) { (req->_bytes_done >= req->length && req->completion != NULL)) {
*req->bytes_transferred_p += req->_bytes_done; *req->bytes_transferred_p += req->_bytes_done;
#ifdef OHCI_DEBUG #ifdef OHCI_DEBUG
if (MegaDebug)
printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req); printk(KERN_DEBUG "usb-ohci: bulk request %p ending\n", req);
#endif #endif
req->completion(stats, buffer, req->_bytes_done, req->dev_id); 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) ...@@ -1305,7 +1348,7 @@ static int ohci_bulk_td_handler(int stats, void *buffer, int len, void *dev_id)
* to an error. * to an error.
* *
* bytes_transferred_p is a pointer to an integer that will be * 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 * transferred. The interrupt handler will update it after each
* internal TD completes successfully. * internal TD completes successfully.
* *
...@@ -1329,6 +1372,7 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re ...@@ -1329,6 +1372,7 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re
unsigned long flags; unsigned long flags;
#ifdef OHCI_DEBUG #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); 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 #endif
...@@ -1358,6 +1402,10 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re ...@@ -1358,6 +1402,10 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re
usb_pipeslow(pipe), usb_pipeslow(pipe),
usb_pipe_endpdev(pipe), 0 /* bulk uses normal TDs */); 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 */ /* initialize the internal counter */
bulk_request->_bytes_done = 0; bulk_request->_bytes_done = 0;
...@@ -1365,13 +1413,11 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re ...@@ -1365,13 +1413,11 @@ static struct ohci_ed* ohci_request_bulk(struct ohci_bulk_request_state *bulk_re
* Add the TDs to the ED * Add the TDs to the ED
*/ */
spin_lock_irqsave(&ohci_edtd_lock, flags); spin_lock_irqsave(&ohci_edtd_lock, flags);
bulk_ed->status |= OHCI_ED_SKIP; head_td = ohci_add_tds_to_ed(head_td, bulk_ed);
head_td = ohci_add_td_chain_to_ed(head_td, bulk_ed); bulk_ed->status &= cpu_to_le32(~OHCI_ED_SKIP);
bulk_ed->status &= ~OHCI_ED_SKIP; /* ohci_unhalt_ed(bulk_ed); */
ohci_unhalt_ed(bulk_ed);
spin_unlock_irqrestore(&ohci_edtd_lock, flags); spin_unlock_irqrestore(&ohci_edtd_lock, flags);
#ifdef OHCI_DEBUG #ifdef OHCI_DEBUG
if (MegaDebug) { if (MegaDebug) {
/* complete request debugging output (before) */ /* complete request debugging output (before) */
...@@ -1414,7 +1460,8 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da ...@@ -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_bulk_request_state req;
struct ohci_ed *req_ed; 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); 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 #endif
...@@ -1430,6 +1477,12 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da ...@@ -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.bytes_transferred_p = bytes_transferred_p;
req.dev_id = &completion_status; req.dev_id = &completion_status;
req.completion = ohci_bulk_msg_completed; 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.. * Start the transaction..
...@@ -1442,7 +1495,8 @@ static int ohci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da ...@@ -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... */ /* FIXME this should to wait for a caller specified time... */
schedule_timeout(HZ*5); 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) { if (completion_status == USB_ST_INTERNALERROR) {
struct ohci_device *dev = usb_to_ohci(usb_dev); struct ohci_device *dev = usb_to_ohci(usb_dev);
struct ohci_regs *regs = dev->ohci->regs; 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 ...@@ -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 */ /* remove the ED from the HC */
ohci_remove_bulk_ed(usb_to_ohci(usb_dev)->ohci, req_ed); 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 */ ohci_free_ed(req_ed); /* return it to the pool */
#ifdef OHCI_DEBUG #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); printk(KERN_DEBUG "ohci_bulk_msg done, status %x (bytes_transferred = %ld).\n", completion_status, *bytes_transferred_p);
#endif #endif
...@@ -1659,7 +1719,6 @@ static int start_hc(struct ohci *ohci) ...@@ -1659,7 +1719,6 @@ static int start_hc(struct ohci *ohci)
struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub); struct ohci_device *root_hub=usb_to_ohci(ohci->bus->root_hub);
fminterval = readl(&ohci->regs->fminterval) & 0x3fff;
#if 0 #if 0
printk(KERN_DEBUG "entering start_hc %p\n", ohci); printk(KERN_DEBUG "entering start_hc %p\n", ohci);
#endif #endif
...@@ -1671,16 +1730,22 @@ static int start_hc(struct ohci *ohci) ...@@ -1671,16 +1730,22 @@ static int start_hc(struct ohci *ohci)
writel(virt_to_bus(root_hub->hcca), &ohci->regs->hcca); writel(virt_to_bus(root_hub->hcca), &ohci->regs->hcca);
/* /*
* XXX Should fminterval also be set here? * fminterval has to be 11999 (it can be adjusted +/- 1
* The spec suggests 0x2edf [11,999]. (FIXME: make this a constant) * to sync with other things if necessary).
*/ */
/* fminterval |= (0x2edf << 16); */ fminterval = 11999;
fminterval = (10240 << 16) | 11999;
writel(fminterval, &ohci->regs->fminterval);
/* Start periodic transfers at 90% of fminterval (fmremaining /* Start periodic transfers at 90% of fminterval (fmremaining
* counts down; this will put them in the first 10% of the * counts down; this will put them in the first 10% of the
* frame). */ * 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 * FNO (frame number overflow) could be enabled... they
...@@ -1926,7 +1991,8 @@ static void ohci_reap_donelist(struct ohci *ohci) ...@@ -1926,7 +1991,8 @@ static void ohci_reap_donelist(struct ohci *ohci)
struct ohci_td *td; /* used for walking the list */ struct ohci_td *td; /* used for walking the list */
/* um... isn't this dangerous to do in an interrupt handler? -greg */ /* 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 */ /* create the FIFO ordered donelist */
td = ohci_reverse_donelist(ohci); td = ohci_reverse_donelist(ohci);
...@@ -1934,18 +2000,33 @@ static void ohci_reap_donelist(struct ohci *ohci) ...@@ -1934,18 +2000,33 @@ static void ohci_reap_donelist(struct ohci *ohci)
while (td != NULL) { while (td != NULL) {
struct ohci_td *next_td = td->next_dl_td; struct ohci_td *next_td = td->next_dl_td;
int cc = OHCI_TD_CC_GET(le32_to_cpup(&td->info)); int cc = OHCI_TD_CC_GET(le32_to_cpup(&td->info));
struct ohci_ed *ed = td->ed;
if (td_dummy(*td)) if (td_dummy(*td))
printk(KERN_ERR "yikes! reaping a dummy TD\n"); 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 * There was an error on this TD and the ED
* is halted, and this was not the last TD * is halted, and this was not the last TD
* of the transaction, so there will be TDs * of the transaction, so there will be TDs
* to clean off the ED. * 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 *tail_td = bus_to_virt(ed_tail_td(ed));
struct ohci_td *ntd; struct ohci_td *ntd;
...@@ -1953,24 +2034,17 @@ static void ohci_reap_donelist(struct ohci *ohci) ...@@ -1953,24 +2034,17 @@ static void ohci_reap_donelist(struct ohci *ohci)
td = ntd = bus_to_virt(ed_head_td(ed)); td = ntd = bus_to_virt(ed_head_td(ed));
while (td != tail_td) { while (td != tail_td) {
ntd = bus_to_virt(le32_to_cpup(&td->next_td)); ntd = bus_to_virt(le32_to_cpup(&td->next_td));
if (td_endofchain(*td))
break;
/* only deal with TDs from this ED, printk(KERN_DEBUG "skipping TD %p\n", td);
* the host controller could have ohci_free_td(td);
* 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);
}
td = ntd; td = ntd;
} }
/* Set the ED head past the ones we cleaned /* Set the ED head past the ones we cleaned
off, and clear the halted flag */ 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)); set_ed_head_td(ed, virt_to_bus(ntd));
ohci_unhalt_ed(ed); ohci_unhalt_ed(ed);
/* If we didn't find an endofchain TD, give up */ /* If we didn't find an endofchain TD, give up */
...@@ -1996,8 +2070,9 @@ static void ohci_reap_donelist(struct ohci *ohci) ...@@ -1996,8 +2070,9 @@ static void ohci_reap_donelist(struct ohci *ohci)
td->cur_buf = cpu_to_le32(virt_to_bus(td->data)); td->cur_buf = cpu_to_le32(virt_to_bus(td->data));
/* insert it back on its ED */ /* insert it back on its ED */
ohci_add_td_to_ed(td, td, td->ed); td->next_td = 0;
ohci_unhalt_ed(td->ed); ohci_add_tds_to_ed(td, ed);
/* ohci_unhalt_ed(td->ed); */
} else { } else {
/* return it to the pool of free TDs */ /* return it to the pool of free TDs */
if (can_auto_free(*td)) if (can_auto_free(*td))
...@@ -2007,7 +2082,7 @@ static void ohci_reap_donelist(struct ohci *ohci) ...@@ -2007,7 +2082,7 @@ static void ohci_reap_donelist(struct ohci *ohci)
td = next_td; td = next_td;
} }
// spin_unlock(&ohci_edtd_lock); spin_unlock(&ohci_edtd_lock);
} /* ohci_reap_donelist() */ } /* ohci_reap_donelist() */
...@@ -2259,8 +2334,10 @@ static struct ohci *alloc_ohci(void* mem_base) ...@@ -2259,8 +2334,10 @@ static struct ohci *alloc_ohci(void* mem_base)
writel(0, &ohci->regs->ed_bulkhead); writel(0, &ohci->regs->ed_bulkhead);
#ifdef OHCI_DEBUG #ifdef OHCI_DEBUG
if (MegaDebug) {
printk(KERN_DEBUG "alloc_ohci(): controller\n"); printk(KERN_DEBUG "alloc_ohci(): controller\n");
show_ohci_status(ohci); show_ohci_status(ohci);
}
#endif #endif
#if 0 #if 0
...@@ -2333,7 +2410,7 @@ static int ohci_control_thread(void * __ohci) ...@@ -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); printk(KERN_DEBUG "ohci-control thread code for 0x%p code at 0x%p\n", __ohci, &ohci_control_thread);
exit_mm(current); exit_mm(current);
exit_files(current); exit_files(current);
exit_fs(current); /*exit_fs(current);*/ /* can't do kernel_thread if we do this */
strcpy(current->comm, "ohci-control"); strcpy(current->comm, "ohci-control");
...@@ -2398,6 +2475,7 @@ static int ohci_control_thread(void * __ohci) ...@@ -2398,6 +2475,7 @@ static int ohci_control_thread(void * __ohci)
#endif #endif
} else { } else {
/* unknown signal, exit the thread */ /* unknown signal, exit the thread */
printk(KERN_DEBUG "usb-ohci: control thread for %p exiting on signal %ld\n", __ohci, signr);
break; break;
} }
} }
...@@ -2406,7 +2484,6 @@ static int ohci_control_thread(void * __ohci) ...@@ -2406,7 +2484,6 @@ static int ohci_control_thread(void * __ohci)
reset_hc(ohci); reset_hc(ohci);
release_ohci(ohci); release_ohci(ohci);
usb_deregister_bus(ohci->bus); usb_deregister_bus(ohci->bus);
printk(KERN_DEBUG "ohci-control thread for 0x%p exiting\n", __ohci);
return 0; return 0;
} /* ohci_control_thread() */ } /* ohci_control_thread() */
......
...@@ -41,8 +41,7 @@ struct ohci_td { ...@@ -41,8 +41,7 @@ struct ohci_td {
/* bit0: Is this TD allocated? */ /* bit0: Is this TD allocated? */
/* bit1: Is this a dummy (end of list) TD? */ /* bit1: Is this a dummy (end of list) TD? */
/* bit2: do NOT automatically free this TD on completion */ /* bit2: do NOT automatically free this TD on completion */
/* bit3: this is NOT the last TD in a contiguious TD chain /* bit3: this is the last TD in a contiguious TD chain */
* on the indicated ED. (0 means it is the last) */
struct usb_device *usb_dev; /* the owning device */ struct usb_device *usb_dev; /* the owning device */
...@@ -86,9 +85,9 @@ struct ohci_td { ...@@ -86,9 +85,9 @@ struct ohci_td {
#define make_dumb_td(td) ((td)->hcd_flags |= 2) #define make_dumb_td(td) ((td)->hcd_flags |= 2)
#define clear_dumb_td(td) ((td)->hcd_flags &= ~(__u32)2) #define clear_dumb_td(td) ((td)->hcd_flags &= ~(__u32)2)
#define td_endofchain(td) (!((td).hcd_flags & (1 << 3))) #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 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 * These control if the IRQ will call ohci_free_td after taking the TDs
...@@ -109,6 +108,10 @@ struct ohci_ed { ...@@ -109,6 +108,10 @@ struct ohci_ed {
__u32 tail_td; /* TD Queue tail pointer */ __u32 tail_td; /* TD Queue tail pointer */
__u32 _head_td; /* TD Queue head pointer, toggle carry & halted bits */ __u32 _head_td; /* TD Queue head pointer, toggle carry & halted bits */
__u32 next_ed; /* Next ED */ __u32 next_ed; /* Next ED */
/* driver fields */
struct ohci_device *ohci_dev;
struct ohci_ed *ed_chain;
} __attribute((aligned(16))); } __attribute((aligned(16)));
/* get the head_td */ /* get the head_td */
...@@ -119,10 +122,13 @@ struct ohci_ed { ...@@ -119,10 +122,13 @@ struct ohci_ed {
#define set_ed_head_td(ed, td) ((ed)->_head_td = cpu_to_le32((td)) \ #define set_ed_head_td(ed, td) ((ed)->_head_td = cpu_to_le32((td)) \
| ((ed)->_head_td & cpu_to_le32(3))) | ((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_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_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_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_SKIP (1 << 14)
#define OHCI_ED_MPS (0x7ff << 16) #define OHCI_ED_MPS (0x7ff << 16)
...@@ -142,6 +148,8 @@ struct ohci_ed { ...@@ -142,6 +148,8 @@ struct ohci_ed {
#define OHCI_ED_EN (0xf << 7) #define OHCI_ED_EN (0xf << 7)
#define OHCI_ED_FA (0x7f) #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 */ /* NOTE: bits 27-31 of the status dword are reserved for the HCD */
/* /*
......
...@@ -139,10 +139,20 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length) ...@@ -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; this_xfer = length > max_size ? max_size : length;
length -= this_xfer; length -= this_xfer;
do { 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, result = us->pusb_dev->bus->op->bulk_msg(us->pusb_dev, pipe, buf,
this_xfer, &partial); 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 */ /* we want to retry if the device reported NAK */
if (result == USB_ST_TIMEOUT) { if (result == USB_ST_TIMEOUT) {
if (partial != this_xfer) { if (partial != this_xfer) {
...@@ -171,28 +181,31 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length) ...@@ -171,28 +181,31 @@ static int us_one_transfer(struct us_data *us, int pipe, char *buf, int length)
return 0; return 0;
} }
static int us_transfer(Scsi_Cmnd *srb, int dir_in) static int us_transfer(Scsi_Cmnd *srb, int dir_in)
{ {
struct us_data *us = (struct us_data *)srb->host_scribble; struct us_data *us = (struct us_data *)srb->host_scribble;
int i; int i;
int result = -1; 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) { if (srb->use_sg) {
struct scatterlist *sg = (struct scatterlist *) srb->request_buffer; struct scatterlist *sg = (struct scatterlist *) srb->request_buffer;
for (i = 0; i < srb->use_sg; i++) { for (i = 0; i < srb->use_sg; i++) {
result = us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : result = us_one_transfer(us, pipe, sg[i].address, sg[i].length);
usb_sndbulkpipe(us->pusb_dev, us->ep_out),
sg[i].address, sg[i].length);
if (result) if (result)
break; break;
} }
return result;
} }
else else
return us_one_transfer(us, dir_in ? usb_rcvbulkpipe(us->pusb_dev, us->ep_in) : result = us_one_transfer(us, pipe,
usb_sndbulkpipe(us->pusb_dev, us->ep_out), srb->request_buffer, srb->request_bufflen);
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) 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) ...@@ -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; struct us_data *us = (struct us_data *)dev_id;
if (state != USB_ST_REMOVED) { if (state != USB_ST_REMOVED) {
us->ip_data = *(__u16 *)buffer; us->ip_data = le16_to_cpup((__u16 *)buffer);
US_DEBUGP("Interrupt Status %x\n", us->ip_data); /* 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); wake_up(&us->ip_waitq);
us->ip_wanted = 0; }
/* we dont want another interrupt */ /* we dont want another interrupt */
...@@ -250,6 +264,7 @@ static int pop_CB_reset(struct us_data *us) ...@@ -250,6 +264,7 @@ static int pop_CB_reset(struct us_data *us)
devrequest dr; devrequest dr;
int result; int result;
US_DEBUGP("pop_CB_reset\n");
dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE; dr.requesttype = USB_TYPE_CLASS | USB_RT_INTERFACE;
dr.request = US_CBI_ADSC; dr.request = US_CBI_ADSC;
dr.value = 0; dr.value = 0;
...@@ -262,12 +277,15 @@ static int pop_CB_reset(struct us_data *us) ...@@ -262,12 +277,15 @@ static int pop_CB_reset(struct us_data *us)
usb_sndctrlpipe(us->pusb_dev,0), usb_sndctrlpipe(us->pusb_dev,0),
&dr, cmd, 12); &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 */ /* long wait for reset */
schedule_timeout(HZ*5); 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; return 0;
} }
...@@ -325,6 +343,7 @@ static int pop_CB_command(Scsi_Cmnd *srb) ...@@ -325,6 +343,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
/* as per spec try a start command, wait and retry */ /* as per spec try a start command, wait and retry */
done_start++; done_start++;
memset(cmd, 0, sizeof(cmd));
cmd[0] = START_STOP; cmd[0] = START_STOP;
cmd[4] = 1; /* start */ cmd[4] = 1; /* start */
result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, result = us->pusb_dev->bus->op->control_msg(us->pusb_dev,
...@@ -338,7 +357,7 @@ static int pop_CB_command(Scsi_Cmnd *srb) ...@@ -338,7 +357,7 @@ static int pop_CB_command(Scsi_Cmnd *srb)
result = us->pusb_dev->bus->op->control_msg(us->pusb_dev, result = us->pusb_dev->bus->op->control_msg(us->pusb_dev,
usb_sndctrlpipe(us->pusb_dev,0), usb_sndctrlpipe(us->pusb_dev,0),
&dr, srb->cmnd, srb->cmd_len); &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;
} }
return result; return result;
...@@ -356,6 +375,7 @@ static int pop_CB_status(Scsi_Cmnd *srb) ...@@ -356,6 +375,7 @@ static int pop_CB_status(Scsi_Cmnd *srb)
devrequest dr; devrequest dr;
int retry = 5; int retry = 5;
US_DEBUGP("pop_CB_status, proto=%x\n", us->protocol);
switch (us->protocol) { switch (us->protocol) {
case US_PR_CB: case US_PR_CB:
/* get from control */ /* get from control */
...@@ -439,23 +459,26 @@ static int pop_CBI(Scsi_Cmnd *srb) ...@@ -439,23 +459,26 @@ static int pop_CBI(Scsi_Cmnd *srb)
if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) { if (result == USB_ST_STALL || result == USB_ST_TIMEOUT) {
return (DID_OK << 16) | 2; return (DID_OK << 16) | 2;
} }
return DID_ABORT << 16; return DID_ERROR << 16;
} }
/* transfer the data */ /* transfer the data */
if (us_transfer_length(srb)) { if (us_transfer_length(srb)) {
result = us_transfer(srb, US_DIRECTION(srb->cmnd[0])); 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); US_DEBUGP("CBI transfer %x\n", result);
return DID_ABORT << 16; return DID_ERROR << 16;
} else if (result == USB_ST_DATAUNDERRUN) { }
#if 0
else if (result == USB_ST_DATAUNDERRUN) {
return DID_OK << 16; return DID_OK << 16;
} }
} else { } else {
if (!result) { if (!result) {
return DID_OK << 16; return DID_OK << 16;
} }
#endif
} }
/* get status */ /* get status */
...@@ -947,6 +970,7 @@ static int usbscsi_control_thread(void * __us) ...@@ -947,6 +970,7 @@ static int usbscsi_control_thread(void * __us)
US_DEBUGP("Old/New length = %d/%d\n", savelen, length); US_DEBUGP("Old/New length = %d/%d\n", savelen, length);
if (us->srb->request_bufflen != length) { if (us->srb->request_bufflen != length) {
US_DEBUGP("redoing cmd with len=%d\n", length);
us->srb->request_bufflen = length; us->srb->request_bufflen = length;
us->srb->result = us->pop(us->srb); us->srb->result = us->pop(us->srb);
} }
...@@ -957,6 +981,15 @@ static int usbscsi_control_thread(void * __us) ...@@ -957,6 +981,15 @@ static int usbscsi_control_thread(void * __us)
case REQUEST_SENSE: case REQUEST_SENSE:
case INQUIRY: case INQUIRY:
case MODE_SENSE: 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; us->srb->cmnd[4] = saveallocation;
break; break;
...@@ -969,6 +1002,7 @@ static int usbscsi_control_thread(void * __us) ...@@ -969,6 +1002,7 @@ static int usbscsi_control_thread(void * __us)
} }
/* force attention on first command */ /* force attention on first command */
if (!us->attention_done) { if (!us->attention_done) {
US_DEBUGP("forcing unit attention\n");
if (us->srb->cmnd[0] == REQUEST_SENSE) { if (us->srb->cmnd[0] == REQUEST_SENSE) {
if (us->srb->result == (DID_OK << 16)) { if (us->srb->result == (DID_OK << 16)) {
unsigned char *p = (unsigned char *)us->srb->request_buffer; unsigned char *p = (unsigned char *)us->srb->request_buffer;
...@@ -987,6 +1021,7 @@ static int usbscsi_control_thread(void * __us) ...@@ -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->scsi_done(us->srb);
us->srb = NULL; us->srb = NULL;
break; break;
......
...@@ -1972,7 +1972,7 @@ void end_lazy_tlb(struct mm_struct *mm) ...@@ -1972,7 +1972,7 @@ void end_lazy_tlb(struct mm_struct *mm)
current->mm = mm; current->mm = mm;
if (mm != active_mm) { if (mm != active_mm) {
current->active_mm = mm; current->active_mm = mm;
activate_context(); switch_mm(active_mm, mm);
} }
mmdrop(active_mm); mmdrop(active_mm);
} }
......
...@@ -384,7 +384,7 @@ static int exec_mmap(void) ...@@ -384,7 +384,7 @@ static int exec_mmap(void)
mm->cpu_vm_mask = (1UL << smp_processor_id()); mm->cpu_vm_mask = (1UL << smp_processor_id());
current->mm = mm; current->mm = mm;
current->active_mm = mm; current->active_mm = mm;
activate_context(); switch_mm(active_mm, mm);
mm_release(); mm_release();
if (old_mm) { if (old_mm) {
if (active_mm != old_mm) BUG(); if (active_mm != old_mm) BUG();
......
...@@ -69,17 +69,28 @@ extern void set_intr_gate(unsigned int irq, void * addr); ...@@ -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_ldt_desc(unsigned int n, void *addr, unsigned int size);
extern void set_tss_desc(unsigned int n, void *addr); 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 * load one particular LDT into the current CPU
*/ */
extern inline void load_LDT (struct mm_struct *mm) extern inline void load_LDT (struct mm_struct *mm)
{ {
int cpu = smp_processor_id(); int cpu = smp_processor_id();
void *segments = mm->segments;
int count = LDT_ENTRIES;
if (mm->segments) if (!segments) {
set_ldt_desc(cpu, mm->segments, LDT_ENTRIES); segments = &default_ldt;
else count = 1;
set_ldt_desc(cpu, &default_ldt, 1); }
set_ldt_desc(cpu, segments, count);
__load_LDT(cpu); __load_LDT(cpu);
} }
......
...@@ -9,15 +9,6 @@ ...@@ -9,15 +9,6 @@
#define destroy_context(mm) do { } while(0) #define destroy_context(mm) do { } while(0)
#define init_new_context(tsk,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) static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next)
{ {
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment