patch-2.3.99-pre3 linux/drivers/usb/usb-ohci.c
Next file: linux/drivers/usb/usb-ohci.h
Previous file: linux/drivers/usb/uhci.c
Back to the patch index
Back to the overall index
- Lines: 190
- Date:
Thu Mar 23 15:02:18 2000
- Orig file:
v2.3.99-pre2/linux/drivers/usb/usb-ohci.c
- Orig date:
Sun Mar 19 18:35:31 2000
diff -u --recursive --new-file v2.3.99-pre2/linux/drivers/usb/usb-ohci.c linux/drivers/usb/usb-ohci.c
@@ -262,8 +262,14 @@
urb_print (urb, "SUB", usb_pipein (pipe));
#endif
+ /* a request to the virtual root hub */
if (usb_pipedevice (pipe) == ohci->rh.devnum)
- return rh_submit_urb (urb); /* a request to the virtual root hub */
+ return rh_submit_urb (urb);
+
+ /* when controller's hung, permit only hub cleanup attempts
+ * such as powering down ports */
+ if (ohci->disabled)
+ return -ESHUTDOWN;
/* every endpoint has a ed, locate and fill it */
if (!(ed = ep_add_ed (urb->dev, pipe, urb->interval, 1))) {
@@ -333,10 +339,11 @@
(le16_to_cpu (ohci->hcca.frame_no) + 10)) & 0xffff;
}
- td_submit_urb (urb); /* fill the TDs and link it to the ed */
-
if (ed->state != ED_OPER) /* link the ed into a chain if is not already */
ep_link (ohci, ed);
+
+ td_submit_urb (urb); /* fill the TDs and link it to the ed */
+
spin_unlock_irqrestore (&usb_ed_lock, flags);
urb->status = USB_ST_URB_PENDING;
@@ -1122,8 +1129,8 @@
0x00, /* __u16 bcdDevice; */
0x00,
0x00, /* __u8 iManufacturer; */
- 0x00, /* __u8 iProduct; */
- 0x00, /* __u8 iSerialNumber; */
+ 0x02, /* __u8 iProduct; */
+ 0x01, /* __u8 iSerialNumber; */
0x01 /* __u8 bNumConfigurations; */
};
@@ -1222,13 +1229,16 @@
urb_t * urb = (urb_t *) ptr;
ohci_t * ohci = urb->dev->bus->hcpriv;
+
+ if (ohci->disabled)
+ return;
if(ohci->rh.send) {
len = rh_send_irq (ohci, urb->transfer_buffer, urb->transfer_buffer_length);
if (len > 0) {
urb->actual_length = len;
#ifdef DEBUG
- urb_print (urb, "RET(rh)", usb_pipeout (urb->pipe));
+ urb_print (urb, "RET-t(rh)", usb_pipeout (urb->pipe));
#endif
if (urb->complete) urb->complete (urb);
}
@@ -1379,27 +1389,49 @@
len = min (leni, min (sizeof (root_hub_config_des), wLength));
data_buf = root_hub_config_des; OK(len);
case (0x03): /* string descriptors */
+ len = usb_root_hub_string (wValue & 0xff,
+ (int) ohci->regs, "OHCI",
+ data, wLength);
+ if (len > 0) {
+ data_buf = data;
+ OK (min (leni, len));
+ }
+ // else fallthrough
default:
status = TD_CC_STALL;
}
break;
case RH_GET_DESCRIPTOR | RH_CLASS:
- *(__u8 *) (data_buf+1) = 0x29;
- put_unaligned(cpu_to_le32 (readl (&ohci->regs->roothub.a)),
- (__u32 *) (data_buf + 2));
- *(__u8 *) data_buf = (*(__u8 *) (data_buf + 2) / 8) * 2 + 9; /* length of descriptor */
-
- len = min (leni, min(*(__u8 *) data_buf, wLength));
- *(__u8 *) (data_buf+6) = 0; /* Root Hub needs no current from bus */
- if (*(__u8 *) (data_buf+2) < 8) { /* less than 8 Ports */
- *(__u8 *) (data_buf+7) = readl (&ohci->regs->roothub.b) & 0xff;
- *(__u8 *) (data_buf+8) = (readl (&ohci->regs->roothub.b) & 0xff0000) >> 16;
- } else {
- put_unaligned(cpu_to_le32 (readl(&ohci->regs->roothub.b)),
- (__u32 *) (data_buf + 7));
+ {
+ __u32 temp = readl (&ohci->regs->roothub.a);
+
+ data_buf [0] = 9; // min length;
+ data_buf [1] = 0x29;
+ data_buf [2] = temp & RH_A_NDP;
+ data_buf [3] = 0;
+ if (temp & RH_A_PSM) /* per-port power switching? */
+ data_buf [3] |= 0x1;
+ if (temp & RH_A_NOCP) /* no overcurrent reporting? */
+ data_buf [3] |= 0x10;
+ else if (temp & RH_A_OCPM) /* per-port overcurrent reporting? */
+ data_buf [3] |= 0x8;
+
+ datab [1] = 0;
+ data_buf [5] = (temp & RH_A_POTPGT) >> 24;
+ temp = readl (&ohci->regs->roothub.b);
+ data_buf [7] = temp & RH_B_DR;
+ if (data_buf [2] < 7) {
+ data_buf [8] = 0xff;
+ } else {
+ data_buf [0] += 2;
+ data_buf [8] = (temp & RH_B_DR) >> 8;
+ data_buf [10] = data_buf [9] = 0xff;
+ }
+
+ len = min (leni, min (data_buf [0], wLength));
+ OK (len);
}
- OK (len);
case RH_GET_CONFIGURATION: *(__u8 *) data_buf = 0x01; OK (1);
@@ -1413,7 +1445,8 @@
dbg("USB HC roothubstat2: %x", readl ( &(ohci->regs->roothub.portstatus[1]) ));
len = min(len, leni);
- memcpy (data, data_buf, len);
+ if (data != data_buf)
+ memcpy (data, data_buf, len);
urb->actual_length = len;
urb->status = cc_to_error [status];
@@ -1472,6 +1505,7 @@
}
udelay (1);
}
+ ohci->disabled = 0;
}
/*-------------------------------------------------------------------------*/
@@ -1502,7 +1536,7 @@
writel (0x628, &ohci->regs->lsthresh);
/* Choose the interrupts we care about now, others later on demand */
- mask = OHCI_INTR_MIE | OHCI_INTR_WDH | OHCI_INTR_SO;
+ mask = OHCI_INTR_MIE | OHCI_INTR_UE | OHCI_INTR_WDH | OHCI_INTR_SO;
writel (ohci->hc_control = 0xBF, &ohci->regs->control); /* USB Operational */
writel (mask, &ohci->regs->intrenable);
@@ -1550,6 +1584,11 @@
dbg("Interrupt: %x frame: %x", ints, le16_to_cpu (ohci->hcca.frame_no));
+ if (ints & OHCI_INTR_UE) {
+ ohci->disabled++;
+ err ("OHCI Unrecoverable Error, controller disabled");
+ }
+
if (ints & OHCI_INTR_WDH) {
writel (OHCI_INTR_WDH, ®s->intrdisable);
dl_done_list (ohci, dl_reverse_done_list (ohci));
@@ -1650,16 +1689,24 @@
static int hc_found_ohci (struct pci_dev *dev, int irq, void * mem_base)
{
ohci_t * ohci;
- dbg("USB HC found: irq= %d membase= %lx", irq, (unsigned long) mem_base);
+ char buf[8], *bufp = buf;
+
+#ifndef __sparc__
+ sprintf(buf, "%d", irq);
+#else
+ bufp = __irq_itoa(irq);
+#endif
+ printk(KERN_INFO __FILE__ ": USB OHCI at membase 0x%lx, IRQ %s\n",
+ (unsigned long) mem_base, bufp);
ohci = hc_alloc_ohci (mem_base);
if (!ohci) {
return -ENOMEM;
}
-
+
INIT_LIST_HEAD (&ohci->ohci_hcd_list);
list_add (&ohci->ohci_hcd_list, &ohci_hcd_list);
-
+
hc_reset (ohci);
writel (ohci->hc_control = OHCI_USB_RESET, &ohci->regs->control);
wait_ms (10);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)