static void hc_state_transitions(struct uhci_hcd *uhci);
/* If a transfer is still active after this much time, turn off FSBR */
-#define IDLE_TIMEOUT (HZ / 20) /* 50 ms */
-#define FSBR_DELAY (HZ / 20) /* 50 ms */
+#define IDLE_TIMEOUT msecs_to_jiffies(50)
+#define FSBR_DELAY msecs_to_jiffies(50)
/* When we timeout an idle transfer for FSBR, we'll switch it over to */
/* depth first traversal. We'll do it in groups of this number of TD's */
urbp->short_control_packet = 1;
td = list_entry(urbp->td_list.prev, struct uhci_td, list);
- urbp->qh->element = td->dma_handle;
+ urbp->qh->element = cpu_to_le32(td->dma_handle);
return -EINPROGRESS;
}
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
struct list_head list, *tmp, *head;
unsigned long flags;
+ int called_uhci_finish_completion = 0;
INIT_LIST_HEAD(&list);
uhci_get_current_frame_number(uhci) != uhci->urb_remove_age) {
uhci_remove_pending_urbps(uhci);
uhci_finish_completion(hcd, NULL);
+ called_uhci_finish_completion = 1;
}
head = &uhci->urb_list;
}
spin_unlock_irqrestore(&uhci->schedule_lock, flags);
+ /* Wake up anyone waiting for an URB to complete */
+ if (called_uhci_finish_completion)
+ wake_up_all(&uhci->waitqh);
+
head = &list;
tmp = head->next;
while (tmp != head) {
init_timer(&uhci->stall_timer);
uhci->stall_timer.function = stall_callback;
uhci->stall_timer.data = (unsigned long)hcd;
- uhci->stall_timer.expires = jiffies + (HZ / 10);
+ uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100);
add_timer(&uhci->stall_timer);
return 0;
static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs)
{
struct uhci_hcd *uhci = hcd_to_uhci(hcd);
- unsigned int io_addr = uhci->io_addr;
+ unsigned long io_addr = uhci->io_addr;
unsigned short status;
struct list_head *tmp, *head;
unsigned int age;
static void reset_hc(struct uhci_hcd *uhci)
{
- unsigned int io_addr = uhci->io_addr;
+ unsigned long io_addr = uhci->io_addr;
+
+ /* Turn off PIRQ, SMI, and all interrupts. This also turns off
+ * the BIOS's USB Legacy Support.
+ */
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP, 0);
+ outw(0, uhci->io_addr + USBINTR);
/* Global reset for 50ms */
uhci->state = UHCI_RESET;
outw(USBCMD_GRESET, io_addr + USBCMD);
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((HZ*50+999) / 1000);
+ msleep(50);
outw(0, io_addr + USBCMD);
/* Another 10ms delay */
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout((HZ*10+999) / 1000);
+ msleep(10);
uhci->resume_detect = 0;
}
static void suspend_hc(struct uhci_hcd *uhci)
{
- unsigned int io_addr = uhci->io_addr;
+ unsigned long io_addr = uhci->io_addr;
dev_dbg(uhci_dev(uhci), "%s\n", __FUNCTION__);
uhci->state = UHCI_SUSPENDED;
static void wakeup_hc(struct uhci_hcd *uhci)
{
- unsigned int io_addr = uhci->io_addr;
+ unsigned long io_addr = uhci->io_addr;
switch (uhci->state) {
case UHCI_SUSPENDED: /* Start the resume */
/* Global resume for >= 20ms */
outw(USBCMD_FGR | USBCMD_EGSM, io_addr + USBCMD);
uhci->state = UHCI_RESUMING_1;
- uhci->state_end = jiffies + (20*HZ+999) / 1000;
+ uhci->state_end = jiffies + msecs_to_jiffies(20);
break;
case UHCI_RESUMING_1: /* End global resume */
static int ports_active(struct uhci_hcd *uhci)
{
- unsigned int io_addr = uhci->io_addr;
+ unsigned long io_addr = uhci->io_addr;
int connection = 0;
int i;
static int suspend_allowed(struct uhci_hcd *uhci)
{
- unsigned int io_addr = uhci->io_addr;
+ unsigned long io_addr = uhci->io_addr;
int i;
if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL)
static void start_hc(struct uhci_hcd *uhci)
{
- unsigned int io_addr = uhci->io_addr;
+ unsigned long io_addr = uhci->io_addr;
int timeout = 1000;
/*
}
}
- /* Turn on all interrupts */
+ /* Turn on PIRQ and all interrupts */
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+ USBLEGSUP_DEFAULT);
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC | USBINTR_SP,
io_addr + USBINTR);
uhci->io_addr = (unsigned long) hcd->regs;
- /* Turn off all interrupts */
- outw(0, uhci->io_addr + USBINTR);
-
- /* Maybe kick BIOS off this hardware. Then reset, so we won't get
+ /* Kick BIOS off this hardware and reset, so we won't get
* interrupts from any previous setup.
*/
reset_hc(uhci);
- pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
- USBLEGSUP_DEFAULT);
return 0;
}
uhci->rh_numports = port;
- hcd->self.root_hub = udev = usb_alloc_dev(NULL, &hcd->self, 0);
+ udev = usb_alloc_dev(NULL, &hcd->self, 0);
if (!udev) {
dev_err(uhci_dev(uhci), "unable to allocate root hub\n");
goto err_alloc_root_hub;
uhci->fl->frame[i] = cpu_to_le32(uhci->skelqh[irq]->dma_handle);
}
+ /*
+ * Some architectures require a full mb() to enforce completion of
+ * the memory writes above before the I/O transfers in start_hc().
+ */
+ mb();
start_hc(uhci);
init_stall_timer(hcd);
udev->speed = USB_SPEED_FULL;
- if (usb_register_root_hub(udev, uhci_dev(uhci)) != 0) {
+ if (hcd_register_root(udev, &uhci->hcd) != 0) {
dev_err(uhci_dev(uhci), "unable to start root hub\n");
retval = -ENOMEM;
goto err_start_root_hub;
err_alloc_term_td:
usb_put_dev(udev);
- hcd->self.root_hub = NULL;
err_alloc_root_hub:
dma_pool_destroy(uhci->qh_pool);
/*
* Some systems don't maintain the UHCI register values
* during a PM suspend/resume cycle, so reinitialize
- * the Frame Number, the Framelist Base Address, and the
- * Interrupt Enable registers.
+ * the Frame Number, Framelist Base Address, Interrupt
+ * Enable, and Legacy Support registers.
*/
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+ 0);
outw(uhci->saved_framenumber, uhci->io_addr + USBFRNUM);
outl(uhci->fl->dma_handle, uhci->io_addr + USBFLBASEADD);
outw(USBINTR_TIMEOUT | USBINTR_RESUME | USBINTR_IOC |
USBINTR_SP, uhci->io_addr + USBINTR);
uhci->resume_detect = 1;
+ pci_write_config_word(to_pci_dev(uhci_dev(uhci)), USBLEGSUP,
+ USBLEGSUP_DEFAULT);
} else {
reset_hc(uhci);
start_hc(uhci);
}
#ifdef CONFIG_PROC_FS
- uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, 0);
+ uhci_proc_root = create_proc_entry("driver/uhci", S_IFDIR, NULL);
if (!uhci_proc_root)
goto proc_failed;
#endif
up_failed:
#ifdef CONFIG_PROC_FS
- remove_proc_entry("driver/uhci", 0);
+ remove_proc_entry("driver/uhci", NULL);
proc_failed:
#endif
warn("not all urb_priv's were freed!");
#ifdef CONFIG_PROC_FS
- remove_proc_entry("driver/uhci", 0);
+ remove_proc_entry("driver/uhci", NULL);
#endif
if (errbuf)