summaryrefslogtreecommitdiffstats
path: root/drivers/usb/ohci-hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/ohci-hcd.c')
-rw-r--r--drivers/usb/ohci-hcd.c93
1 files changed, 62 insertions, 31 deletions
diff --git a/drivers/usb/ohci-hcd.c b/drivers/usb/ohci-hcd.c
index 3dc6d74ca..3345e12be 100644
--- a/drivers/usb/ohci-hcd.c
+++ b/drivers/usb/ohci-hcd.c
@@ -14,9 +14,8 @@
* [ Open Host Controller Interface driver for USB. ]
* [ (C) Copyright 1999 Linus Torvalds (uhci.c) ]
* [ (C) Copyright 1999 Gregory P. Smith <greg@electricrain.com> ]
- * [ _Log: ohci-hcd.c,v _
- * [ Revision 1.1 1999/04/05 08:32:30 greg ]
*
+ * v4.3 1999/10/27 multiple HCs, bulk_request
* v4.2 1999/09/05 ISO API alpha, new dev alloc, neg Error-codes
* v4.1 1999/08/27 Randy Dunlap's - ISO API first impl.
* v4.0 1999/08/18
@@ -48,6 +47,7 @@
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
+#include <linux/list.h>
#include <asm/io.h>
#include <asm/irq.h>
@@ -61,6 +61,7 @@
static int handle_apm_event(apm_event_t event);
static int apm_resume = 0;
#endif
+static LIST_HEAD(ohci_hcd_list);
static int ohci_link_ed(struct ohci * ohci, struct usb_ohci_ed *ed);
static int sohci_kill_isoc (struct usb_isoc_desc *id);
@@ -85,10 +86,11 @@ OHCI_DEBUG(printk("******* dev: devnum: %4x, slow: %4x, maxpacketsize: %4x\n",us
**** Interface functions
***********************************************/
-static int sohci_blocking_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
+static int sohci_blocking_handler(void * ohci_in, struct usb_ohci_td *td, void * data, int data_len, int dlen, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
{
+ struct usb_ohci_ed *ed = td->ed;
if(lw0 != NULL) {
- if(USB_ST_CRC < 0 && (status == USB_ST_DATAUNDERRUN || status == USB_ST_NOERROR))
+ if(0 < 0 && (status == USB_ST_DATAUNDERRUN || status == USB_ST_NOERROR))
((struct ohci_state * )lw0)->status = data_len;
else
((struct ohci_state * )lw0)->status = status;
@@ -107,9 +109,9 @@ static int sohci_blocking_handler(void * ohci_in, struct usb_ohci_ed *ed, void *
return 0;
}
-static int sohci_int_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
+static int sohci_int_handler(void * ohci_in, struct usb_ohci_td *td, void * data, int data_len, int dlen, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
{
-
+ struct usb_ohci_ed *ed = td->ed;
struct ohci * ohci = ohci_in;
usb_device_irq handler=(void *) lw0;
void *dev_id = (void *) lw1;
@@ -127,9 +129,30 @@ static int sohci_int_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data
return 0;
}
-static int sohci_iso_handler(void * ohci_in, struct usb_ohci_ed *ed, void * data, int data_len, int status, __OHCI_BAG lw0, __OHCI_BAG lw1) {
+static int sohci_ret_handler(void * ohci_in, struct usb_ohci_td *td, void * data, int data_len, int dlen, int status, __OHCI_BAG lw0, __OHCI_BAG lw1)
+{
+ struct usb_ohci_ed *ed = td->ed;
+ struct ohci * ohci = ohci_in;
+ usb_device_irq handler=(void *) lw0;
+ void *dev_id = (void *) lw1;
+ int ret;
+
+ OHCI_DEBUG({ int i; printk("USB HC RET <<<: %x: data(%d):", ed->hwINFO, data_len);)
+ OHCI_DEBUG( for(i=0; i < data_len; i++ ) printk(" %02x", ((__u8 *) data)[i]);)
+ OHCI_DEBUG( printk(" ret_status: %x\n", status); })
+
+ ret = handler(status, data, data_len, dev_id);
+ if(ret == 0) return 0; /* 0 .. do not requeue */
+ if(status > 0) return -1; /* error occured do not requeue ? */
+ ohci_trans_req(ohci, ed, 0, NULL, data, dlen, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id, td->type & 0x7, sohci_ret_handler); /* requeue int request */
+
+ return 0;
+}
+
+static int sohci_iso_handler(void * ohci_in, struct usb_ohci_td *td, void * data, int data_len, int dlen, int status, __OHCI_BAG lw0, __OHCI_BAG lw1) {
// struct ohci * ohci = ohci_in;
+ struct usb_ohci_ed *ed = td->ed;
unsigned int ix = (unsigned int) lw0;
struct usb_isoc_desc * id = (struct usb_isoc_desc *) lw1;
struct usb_ohci_td **tdp = id->td;
@@ -311,7 +334,7 @@ static void * sohci_request_bulk(struct usb_device *usb_dev, unsigned int pipe,
OHCI_DEBUG( printk("USB HC BULK_RQ>>>: %x \n", ed->hwINFO);)
- ohci_trans_req(ohci, ed, 0, NULL, data, len, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id, (usb_pipeout(pipe))?BULK_OUT:BULK_IN, sohci_int_handler);
+ ohci_trans_req(ohci, ed, 0, NULL, data, len, (__OHCI_BAG) handler, (__OHCI_BAG) dev_id, (usb_pipeout(pipe))?BULK_OUT:BULK_IN, sohci_ret_handler);
if (ED_STATE(ed) != ED_OPER) ohci_link_ed(ohci, ed);
return ed;
@@ -482,7 +505,7 @@ static int sohci_kill_isoc(struct usb_isoc_desc *id) {
struct usb_ohci_ed *ed = NULL;
struct usb_ohci_td **td = id->td;
int i;
-printk("KILL_ISOC***:\n");
+
for (i = 0; i < id->frame_count; i++) {
if(td[i]) {
td[i]->type |= DEL;
@@ -490,22 +513,17 @@ printk("KILL_ISOC***:\n");
}
}
if(ed) usb_ohci_rm_ep(id->usb_dev, ed, NULL, NULL, NULL, TD_RM);
-printk(": end KILL_ISOC***: %p\n", ed);
+
id->start_frame = -1;
return 0;
}
static void sohci_free_isoc(struct usb_isoc_desc *id) {
-printk("FREE_ISOC***\n");
-wait_ms(2000);
+
if(id->start_frame >= 0) sohci_kill_isoc(id);
-printk("FREE_ISOC2***\n");
-wait_ms(2000);
kfree(id->td);
kfree(id);
-printk("FREE_ISOC3***\n");
-wait_ms(2000);
}
struct usb_operations sohci_device_operations = {
@@ -772,17 +790,14 @@ struct usb_ohci_ed *usb_ohci_add_ep(struct usb_device * usb_dev, struct usb_hcd_
// struct ohci * ohci = usb_dev->bus->hcpriv;
struct usb_ohci_td * td;
- struct usb_ohci_ed * ed, *ed1;
+ struct usb_ohci_ed * ed;
- int ed_state, ed_state1;
+ int ed_state;
spin_lock(&usb_ed_lock);
ed = ohci_find_ep(usb_dev, hcd_ed);
-
- ed1 = ((void *) ed) + 0x40; ed_state1 = ED_STATE(ed1);
-OHCI_DEBUG(printk("++++ USB HC add 60 ed1 %x: %x :state: %x\n", ed1->hwINFO, (unsigned int ) ed1, ed_state1); )
ed_state = ED_STATE(ed); /* store state of ed */
OHCI_DEBUG(printk("USB HC add ed %x: %x :state: %x\n", ed->hwINFO, (unsigned int ) ed, ed_state); )
if (ed_state == ED_NEW) {
@@ -1139,7 +1154,8 @@ static int usb_ohci_done_list(struct ohci * ohci, struct usb_ohci_td * td_list)
struct usb_ohci_td * td_list_next = NULL;
int cc;
- int i;
+ int i;
+ int dlen = 0;
while(td_list) {
td_list_next = td_list->next_dl_td;
@@ -1156,8 +1172,9 @@ static int usb_ohci_done_list(struct ohci * ohci, struct usb_ohci_td * td_list)
}
else {
if(td_list->hwBE != 0) {
+ dlen = (bus_to_virt(td_list->hwBE) - td_list->buffer_start + 1);
if(td_list->hwCBP == 0)
- td_list->ed->len += (bus_to_virt(td_list->hwBE) - td_list->buffer_start + 1);
+ td_list->ed->len += dlen;
else
td_list->ed->len += (bus_to_virt(td_list->hwCBP) - td_list->buffer_start);
}
@@ -1170,9 +1187,10 @@ static int usb_ohci_done_list(struct ohci * ohci, struct usb_ohci_td * td_list)
if((td_list->type & SEND) && (ED_STATE(td_list->ed) != ED_STOP) && (td_list->handler)) { /* send the reply */
td_list->handler((void *) ohci,
- td_list->ed,
+ td_list,
td_list->ed->buffer_start,
td_list->ed->len,
+ dlen,
cc,
td_list->lw0,
td_list->lw1);
@@ -1227,7 +1245,7 @@ void reset_hc(struct ohci *ohci) {
udelay(1);
}
}
-static struct ohci *__ohci;
+
/*
* Start an OHCI controller, set the BUS operational
@@ -1353,7 +1371,7 @@ static struct ohci *alloc_ohci(void* mem_base)
ohci->irq = -1;
ohci->regs = mem_base;
ohci->hc_area = hc_area;
- __ohci = ohci;
+
/*
* for load ballancing of the interrupt branches
*/
@@ -1395,7 +1413,7 @@ static void release_ohci(struct ohci *ohci)
/* disconnect all devices */
if(ohci->bus->root_hub) usb_disconnect(&ohci->bus->root_hub);
- reset_hc(__ohci);
+ reset_hc(ohci);
writel(OHCI_USB_RESET, &ohci->regs->control);
wait_ms(10);
@@ -1428,6 +1446,9 @@ static int found_ohci(int irq, void* mem_base)
return -ENOMEM;
}
+ INIT_LIST_HEAD(&ohci->ohci_hcd_list);
+ list_add(&ohci->ohci_hcd_list, &ohci_hcd_list);
+
reset_hc(ohci);
writel(OHCI_USB_RESET, &ohci->regs->control);
wait_ms(10);
@@ -1438,6 +1459,7 @@ static int found_ohci(int irq, void* mem_base)
start_hc(ohci);
return 0;
}
+ printk(KERN_ERR "USB HC (ohci-hcd): request interrupt %d failed\n", irq);
release_ohci(ohci);
return -EBUSY;
}
@@ -1445,7 +1467,8 @@ static int found_ohci(int irq, void* mem_base)
static int start_ohci(struct pci_dev *dev)
{
unsigned int mem_base = dev->resource[0].start;
-
+
+ pci_set_master(dev);
mem_base = (unsigned int) ioremap_nocache(mem_base, 4096);
if (!mem_base) {
@@ -1488,17 +1511,18 @@ static int handle_apm_event(apm_event_t event)
int ohci_hcd_init(void)
{
+ int ret = -ENODEV;
struct pci_dev *dev = NULL;
while((dev = pci_find_class(PCI_CLASS_SERIAL_USB_OHCI, dev))) {
- if (start_ohci(dev) < 0) return -ENODEV;
+ if (start_ohci(dev) >= 0) ret = 0;
}
#ifdef CONFIG_APM
apm_register_callback(&handle_apm_event);
#endif
- return 0;
+ return ret;
}
#ifdef MODULE
@@ -1509,10 +1533,17 @@ int init_module(void)
void cleanup_module(void)
{
+ struct ohci *ohci;
+
# ifdef CONFIG_APM
apm_unregister_callback(&handle_apm_event);
# endif
- release_ohci(__ohci);
+ while(!list_empty(&ohci_hcd_list)) {
+ ohci = list_entry(ohci_hcd_list.next, struct ohci, ohci_hcd_list);
+ list_del(ohci->ohci_hcd_list);
+ INIT_LIST_HEAD(ohci->ohci_hcd_list);
+ release_ohci(ohci);
+ }
}
#endif //MODULE