patch-2.3.35 linux/drivers/usb/uhci.c
Next file: linux/drivers/usb/usb-core.c
Previous file: linux/drivers/usb/scanner.c
Back to the patch index
Back to the overall index
- Lines: 307
- Date:
Tue Dec 28 10:24:11 1999
- Orig file:
v2.3.34/linux/drivers/usb/uhci.c
- Orig date:
Mon Dec 20 18:48:22 1999
diff -u --recursive --new-file v2.3.34/linux/drivers/usb/uhci.c linux/drivers/usb/uhci.c
@@ -12,7 +12,7 @@
* (C) Copyright 1999 Johannes Erdfelt
* (C) Copyright 1999 Randy Dunlap
*
- * $Id: uhci.c,v 1.139 1999/12/17 17:50:59 fliegl Exp $
+ * $Id: uhci.c,v 1.149 1999/12/26 20:57:14 acher Exp $
*/
@@ -646,7 +646,7 @@
/* Build the TDs for the bulk request */
len = purb->transfer_buffer_length;
data = purb->transfer_buffer;
- dbg (KERN_DEBUG MODSTR "uhci_submit_bulk_urb: len %d\n", len);
+ dbg (KERN_DEBUG MODSTR "uhci_submit_bulk_urb: pipe %x, len %d\n", pipe, len);
while (len > 0) {
int pktsze = len;
@@ -675,7 +675,7 @@
//dbg("insert td %p, len %i\n",td,pktsze);
insert_td (s, qh, td, UHCI_PTR_DEPTH);
-
+
/* Alternate Data0/1 (start with Data0) */
usb_dotoggle (purb->dev, usb_pipeendpoint (pipe), usb_pipeout (pipe));
}
@@ -701,8 +701,7 @@
unsigned long flags=0;
struct list_head *p;
- if (!purb) // you never know...
-
+ if (!purb) // you never know...
return -1;
s = (puhci_t) purb->dev->bus->hcpriv; // get pointer to uhci struct
@@ -720,6 +719,8 @@
// URB probably still in work
purb_priv = purb->hcpriv;
dequeue_urb (s, &purb->urb_list,1);
+ purb->status = USB_ST_URB_KILLED; // mark urb as killed
+
if(!in_interrupt()) {
spin_unlock_irqrestore (&s->unlink_urb_lock, flags); // allow interrupts from here
}
@@ -757,8 +758,7 @@
delete_qh (s, qh); // remove it physically
}
- purb->status = USB_ST_URB_KILLED; // mark urb as killed
-
+
#ifdef _UHCI_SLAB
kmem_cache_free(urb_priv_kmem, purb->hcpriv);
#else
@@ -872,11 +872,13 @@
now, purb->start_frame, purb->number_of_packets, purb->pipe);
{
puhci_t s = (puhci_t) purb->dev->bus->hcpriv;
- struct list_head *p = s->urb_list.next;
+ struct list_head *p;
purb_t u;
int a = -1, b = -1;
unsigned long flags;
+
spin_lock_irqsave (&s->urb_list_lock, flags);
+ p=s->urb_list.next;
for (; p != &s->urb_list; p = p->next) {
u = list_entry (p, urb_t, urb_list);
@@ -1093,9 +1095,10 @@
// we can accept this urb if it is not queued at this time
// or if non-iso transfer requests should be scheduled for the same device and pipe
if ((usb_pipetype (purb->pipe) != PIPE_ISOCHRONOUS &&
- tmp->dev == purb->dev && tmp->pipe == purb->pipe) || (purb == tmp))
+ tmp->dev == purb->dev && tmp->pipe == purb->pipe) || (purb == tmp)) {
+ spin_unlock_irqrestore (&s->urb_list_lock, flags);
return 1; // found another urb already queued for processing
-
+ }
}
spin_unlock_irqrestore (&s->urb_list_lock, flags);
@@ -1122,7 +1125,7 @@
if (search_dev_ep (s, purb)) {
usb_dec_dev_use (purb->dev);
- return -ENXIO; // no such address
+ return -ENXIO; // urb already queued
}
@@ -1379,7 +1382,7 @@
for (i = 0; i < 8; i++)
uhci->rh.c_p_r[i] = 0;
- dbg (KERN_DEBUG MODSTR "Root-Hub: adr: %2x cmd(%1x): %04 %04 %04 %04\n",
+ dbg(KERN_DEBUG MODSTR "Root-Hub: adr: %2x cmd(%1x): %04x %04x %04x %04x\n",
uhci->rh.devnum, 8, bmRType_bReq, wValue, wIndex, wLength);
switch (bmRType_bReq) {
@@ -1519,7 +1522,7 @@
}
- dbg (KERN_DEBUG MODSTR "Root-Hub stat port1: %x port2: %x \n",
+ printk (KERN_DEBUG MODSTR "Root-Hub stat port1: %x port2: %x \n",
inw (io_addr + USBPORTSC1), inw (io_addr + USBPORTSC2));
purb->actual_length = len;
@@ -1681,27 +1684,32 @@
uhci_show_td (desc); // show first TD of each transfer
#endif
- // go into error condition to keep data_toggle unchanged if short packet occurs
- if ((purb->transfer_flags & USB_DISABLE_SPD) && (actual_length < maxlength)) {
- ret = USB_ST_SHORT_PACKET;
- printk (KERN_DEBUG MODSTR "process_transfer: SPD!!\n");
- break; // exit after this TD because SP was detected
+ // got less data than requested
+ if ( (actual_length < maxlength)) {
+ if (purb->transfer_flags & USB_DISABLE_SPD) {
+ ret = USB_ST_SHORT_PACKET; // treat as real error
+ printk (KERN_DEBUG MODSTR "process_transfer: SPD!!\n");
+ break; // exit after this TD because SP was detected
+ }
+ // short read during control-IN: re-start status stage
+ if ((usb_pipetype (purb->pipe) == PIPE_CONTROL)) {
+ if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) {
+ uhci_show_td (last_desc);
+ qh->hw.qh.element = virt_to_bus (last_desc); // re-trigger status stage
+ printk("uhci: short packet during control transfer, retrigger status stage @ %p\n",last_desc);
+ purb_priv->short_control_packet=1;
+ return 0;
+ }
+ }
+ // all other cases: short read is OK
+ data_toggle = uhci_toggle (desc->hw.td.info);
+ break;
}
data_toggle = uhci_toggle (desc->hw.td.info);
//printk(KERN_DEBUG MODSTR"process_transfer: len:%d status:%x mapped:%x toggle:%d\n", actual_length, desc->hw.td.status,status, data_toggle);
-#if 1
- if ((usb_pipetype (purb->pipe) == PIPE_CONTROL) && (actual_length < maxlength)) {
- if (uhci_packetid(last_desc->hw.td.info) == USB_PID_OUT) {
- uhci_show_td (last_desc);
- qh->hw.qh.element = virt_to_bus (last_desc); // re-trigger status stage
- printk("uhci: short packet during control transfer, retrigger status stage\n");
- purb_priv->short_control_packet=1;
- return 0;
- }
- }
-#endif
+
}
usb_settoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe), !data_toggle);
transfer_finished:
@@ -1714,15 +1722,14 @@
status & TD_CTRL_NAK )
{
ret=0;
- purb->status=0;
+ status=0;
}
unlink_qh (s, qh);
delete_qh (s, qh);
purb->status = status;
-
-
+
dbg(KERN_DEBUG MODSTR"process_transfer: urb %p, wanted len %d, len %d status %x err %d\n",
purb,purb->transfer_buffer_length,purb->actual_length, purb->status, purb->error_count);
//dbg(KERN_DEBUG MODSTR"process_transfer: exit\n");
@@ -1748,21 +1755,15 @@
{
desc = list_entry (p, uhci_desc_t, desc_list);
- if (desc->hw.td.status & TD_CTRL_NAK) {
- // NAKed transfer
- //printk("TD NAK Status @%p %08x\n",desc,desc->hw.td.status);
- goto err;
- }
-
if (desc->hw.td.status & TD_CTRL_ACTIVE) {
// do not process active TDs
//printk("TD ACT Status @%p %08x\n",desc,desc->hw.td.status);
- goto err;
+ break;
}
if (!desc->hw.td.status & TD_CTRL_IOC) {
- // do not process one-shot TDs
- goto err;
+ // do not process one-shot TDs, no recycling
+ break;
}
// extract transfer parameters from TD
@@ -1778,7 +1779,7 @@
// if any error occured: ignore this td, and continue
if (status != USB_ST_NOERROR) {
purb->error_count++;
- goto err;
+ goto recycle;
}
else
purb->actual_length = actual_length;
@@ -1794,7 +1795,7 @@
purb->complete ((struct urb *) purb);
purb->status = USB_ST_URB_PENDING;
}
-
+ recycle:
// Recycle INT-TD if interval!=0, else mark TD as one-shot
if (purb->interval) {
desc->hw.td.status |= TD_CTRL_ACTIVE;
@@ -1804,10 +1805,9 @@
usb_dotoggle (purb->dev, usb_pipeendpoint (purb->pipe), usb_pipeout (purb->pipe));
}
else {
- desc->hw.td.status &= ~TD_CTRL_IOC;
+ desc->hw.td.status &= ~TD_CTRL_IOC; // inactivate TD
}
-
- err:
+ err:
}
return ret;
@@ -1882,10 +1882,12 @@
_static int process_urb (puhci_t s, struct list_head *p)
{
int ret = USB_ST_NOERROR;
- purb_t purb = list_entry (p, urb_t, urb_list);
- spin_lock(&s->urb_list_lock);
+ purb_t purb;
+ spin_lock(&s->urb_list_lock);
+ purb=list_entry (p, urb_t, urb_list);
dbg ( /*KERN_DEBUG */ MODSTR "found queued urb: %p\n", purb);
+
switch (usb_pipetype (purb->pipe)) {
case PIPE_CONTROL:
case PIPE_BULK:
@@ -1933,7 +1935,7 @@
if (purb->complete && (!proceed || (purb->transfer_flags & USB_URB_EARLY_COMPLETE))) {
dbg (KERN_DEBUG MODSTR "process_transfer: calling early completion\n");
purb->complete ((struct urb *) purb);
- if (!proceed && is_ring)
+ if (!proceed && is_ring && (purb->status != USB_ST_URB_KILLED))
uhci_submit_urb (purb);
}
@@ -1942,7 +1944,7 @@
tmp = purb->next; // pointer to first urb
do {
- if ((tmp->status != USB_ST_URB_PENDING) && uhci_submit_urb (tmp) != USB_ST_NOERROR)
+ if ((tmp->status != USB_ST_URB_PENDING) && (tmp->status != USB_ST_URB_KILLED) && uhci_submit_urb (tmp) != USB_ST_NOERROR)
break;
tmp = tmp->next;
}
@@ -2160,6 +2162,7 @@
start_hc (s);
if (request_irq (irq, uhci_interrupt, SA_SHIRQ, MODNAME, s)) {
+ printk(MODSTR KERN_ERR"request_irq %d failed!\n",irq);
usb_free_bus (bus);
reset_hc (s);
release_region (s->io_addr, s->io_size);
@@ -2204,9 +2207,6 @@
/* Is it already in use? */
if (check_region (io_addr, io_size))
break;
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
- pci_enable_device (dev);
-#endif
/* disable legacy emulation */
pci_write_config_word (dev, USBLEGSUP, USBLEGSUP_DEFAULT);
@@ -2297,10 +2297,21 @@
if (type != 0)
continue;
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2,3,8)
+ pci_enable_device (dev);
+#endif
+ if(!dev->irq)
+ {
+ printk(KERN_ERR MODSTR"Found UHCI device with no IRQ assigned. Check BIOS settings!\n");
+ continue;
+ }
+
/* Ok set it up */
retval = start_uhci (dev);
+
if (!retval)
i++;
+
}
#ifdef CONFIG_APM
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)