summaryrefslogtreecommitdiffstats
path: root/drivers/usb/uhci.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-01-21 22:34:01 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-01-21 22:34:01 +0000
commit9e30c3705aed9fbec4c3304570e4d6e707856bcb (patch)
treeb19e6acb5a67af31a4e7742e05c2166dc3f1444c /drivers/usb/uhci.c
parent72919904796333a20c6a5d5c380091b42e407aa9 (diff)
Merge with Linux 2.3.22.
Diffstat (limited to 'drivers/usb/uhci.c')
-rw-r--r--drivers/usb/uhci.c55
1 files changed, 37 insertions, 18 deletions
diff --git a/drivers/usb/uhci.c b/drivers/usb/uhci.c
index e359d7721..ae2b4ec73 100644
--- a/drivers/usb/uhci.c
+++ b/drivers/usb/uhci.c
@@ -119,6 +119,7 @@ static int uhci_map_status(int status, int dir_out)
return USB_ST_INTERNALERROR;
}
+
/*
* Return the result of a TD..
*/
@@ -189,12 +190,12 @@ static int uhci_td_result(struct uhci_device *dev, struct uhci_td *td, unsigned
if (!status)
return USB_ST_NOERROR;
- /* APC BackUPS Pro kludge */
+ /* XXX FIXME APC BackUPS Pro kludge */
/* It tries to send all of the descriptor instead of */
/* the amount we requested */
if (tmp->status & TD_CTRL_IOC &&
tmp->status & TD_CTRL_ACTIVE &&
- tmp->status & TD_CTRL_NAK)
+ tmp->status & TD_CTRL_NAK /* && its a control TD */)
return USB_ST_NOERROR;
#if 0
@@ -627,9 +628,11 @@ static void uhci_remove_transfer(struct uhci_td *td, char removeirq)
*
* Returns 0 (success) or negative (failure).
* Also returns/sets a "handle pointer" that release_irq can use to stop this
- * interrupt. (It's really a pointer to the TD).
+ * interrupt. (It's really a pointer to the TD.)
*/
-static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_device_irq handler, int period, void *dev_id, void **handle)
+static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe,
+ usb_device_irq handler, int period,
+ void *dev_id, void **handle, long bustime)
{
struct uhci_device *dev = usb_to_uhci(usb_dev);
struct uhci_td *td = uhci_td_alloc(dev);
@@ -658,13 +661,15 @@ static int uhci_request_irq(struct usb_device *usb_dev, unsigned int pipe, usb_d
td->buffer = virt_to_bus(dev->data);
td->qh = qh;
td->dev = dev;
+ td->pipetype = PIPE_INTERRUPT;
+ td->bandwidth_alloc = bustime;
- /* if period 0, insert into fast q */
+ /* if period 0, set _REMOVE flag */
if (period == 0) {
td->flags |= UHCI_TD_REMOVE;
- qh->skel = &dev->uhci->skel_int2_qh;
- } else
- qh->skel = &dev->uhci->skel_int8_qh;
+ }
+
+ qh->skel = &dev->uhci->skelqh[__interval_to_skel(period)];
uhci_add_irq_list(dev->uhci, td, handler, dev_id);
@@ -964,6 +969,7 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
td->info = destination | ((frlen - 1) << 21);
td->buffer = virt_to_bus (bufptr);
td->dev = dev;
+ td->pipetype = PIPE_ISOCHRONOUS;
td->isoc_td_number = ix; /* 0-based; does not wrap/overflow back to 0 */
if (isocdesc->callback_frames &&
@@ -971,7 +977,7 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
td->status |= TD_CTRL_IOC;
td->completed = isocdesc->callback_fn;
cb_frames = 0;
- uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc->context);
+ uhci_add_irq_list (dev->uhci, td, isocdesc->callback_fn, isocdesc);
}
bufptr += fd->frame_length; /* or isocdesc->frame_size; */
@@ -991,7 +997,7 @@ static int uhci_run_isoc (struct usb_isoc_desc *isocdesc,
if (!(td->status & TD_CTRL_IOC)) {
td->status |= TD_CTRL_IOC;
td->completed = isocdesc->callback_fn;
- uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc->context); /* TBD: D.K. ??? */
+ uhci_add_irq_list(dev->uhci, td, isocdesc->callback_fn, isocdesc); /* TBD: D.K. ??? */
}
return 0;
} /* end uhci_run_isoc */
@@ -1158,6 +1164,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
td->status = status; /* Try forever */
td->info = destination | (7 << 21); /* 8 bytes of data */
td->buffer = virt_to_bus(cmd);
+ td->pipetype = PIPE_CONTROL;
/*
* If direction is "send", change the frame from SETUP (0x2D)
@@ -1191,6 +1198,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
td->info = destination | ((pktsze - 1) << 21); /* pktsze bytes of data */
td->buffer = virt_to_bus(data);
td->backptr = &prevtd->link;
+ td->pipetype = PIPE_CONTROL;
data += pktsze;
len -= pktsze;
@@ -1219,6 +1227,7 @@ static int uhci_control_msg(struct usb_device *usb_dev, unsigned int pipe, devre
td->buffer = 0;
td->backptr = &prevtd->link;
td->link = UHCI_PTR_TERM; /* Terminate */
+ td->pipetype = PIPE_CONTROL;
/* Start it up.. */
ret = uhci_run_control(dev, first, td, timeout);
@@ -1349,6 +1358,7 @@ static int uhci_bulk_msg(struct usb_device *usb_dev, unsigned int pipe, void *da
usb_pipeout(pipe)) << TD_TOKEN_TOGGLE); /* pktsze bytes of data */
td->buffer = virt_to_bus(data);
td->backptr = &prevtd->link;
+ td->pipetype = PIPE_BULK;
data += maxsze;
len -= maxsze;
@@ -1429,6 +1439,7 @@ static void * uhci_request_bulk(struct usb_device *usb_dev, unsigned int pipe, u
td->backptr = &prevtd->link;
td->qh = bulk_qh;
td->dev = dev;
+ td->pipetype = PIPE_BULK;
data += pktsze;
len -= pktsze;
@@ -1467,11 +1478,11 @@ static int uhci_terminate_bulk(struct usb_device *dev, void *first)
{
/* none found? there is nothing to remove! */
if (!first)
- return 0;
+ return USB_ST_REMOVED;
uhci_remove_transfer(first, 1);
- return 1;
+ return USB_ST_NOERROR;
}
struct usb_operations uhci_device_operations = {
@@ -1698,7 +1709,7 @@ static void uhci_interrupt_notify(struct uhci *uhci)
uhci_packetout(td->info)) << 19; /* toggle between data0 and data1 */
td->status = (td->status & 0x2F000000) | TD_CTRL_ACTIVE | TD_CTRL_IOC;
/* The HC only removes it when it completed */
- /* successfully, so force remove and readd it */
+ /* successfully, so force remove and re-add it */
uhci_remove_td(td);
uhci_insert_td_in_qh(td->qh, td);
} else if (td->flags & UHCI_TD_REMOVE) {
@@ -1710,6 +1721,8 @@ static void uhci_interrupt_notify(struct uhci *uhci)
uhci_remove_qh(td->qh->skel, td->qh);
uhci_qh_free(td->qh);
uhci_td_free(td);
+ if (td->pipetype == PIPE_INTERRUPT)
+ usb_release_bandwidth(usb_dev, td->bandwidth_alloc);
}
/* If completed does not wants to reactivate, then */
@@ -1790,6 +1803,7 @@ static void uhci_init_ticktd(struct uhci *uhci)
td->info = (15 << 21) | (0x7f << 8) | USB_PID_IN; /* (ignored) input packet, 16 bytes, device 127 */
td->buffer = 0;
td->qh = NULL;
+ td->pipetype = -1;
uhci->fl->frame[0] = virt_to_bus(td);
@@ -1931,16 +1945,21 @@ static struct uhci *alloc_uhci(unsigned int io_addr, unsigned int io_size)
usb->maxchild = port;
usb_init_root_hub(usb);
- /* 8 Interrupt queues */
- for (i = 0; i < 8; i++) {
+ /*
+ * 9 Interrupt queues; link int2 thru int256 to int1 first,
+ * then link int1 to control and control to bulk
+ */
+ for (i = 1; i < 9; i++) {
struct uhci_qh *qh = &uhci->skelqh[i];
- qh->link = virt_to_bus(&uhci->skel_control_qh) | UHCI_PTR_QH;
+ qh->link = virt_to_bus(&uhci->skel_int1_qh) | UHCI_PTR_QH;
qh->element = UHCI_PTR_TERM;
}
- uhci->skel_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) |
- UHCI_PTR_QH;
+ uhci->skel_int1_qh.link = virt_to_bus(&uhci->skel_control_qh) | UHCI_PTR_QH;
+ uhci->skel_int1_qh.element = UHCI_PTR_TERM;
+
+ uhci->skel_control_qh.link = virt_to_bus(&uhci->skel_bulk_qh) | UHCI_PTR_QH;
uhci->skel_control_qh.element = UHCI_PTR_TERM;
uhci->skel_bulk_qh.link = UHCI_PTR_TERM;