Loading drivers/usb/host/uhci-hcd.c +143 −144 Original line number Diff line number Diff line Loading @@ -90,7 +90,6 @@ static char *errbuf; static kmem_cache_t *uhci_up_cachep; /* urb_priv */ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); 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 msecs_to_jiffies(50) Loading @@ -105,96 +104,43 @@ static void hc_state_transitions(struct uhci_hcd *uhci); #include "uhci-debug.c" #include "uhci-q.c" static int init_stall_timer(struct usb_hcd *hcd); static void stall_callback(unsigned long ptr) { struct usb_hcd *hcd = (struct usb_hcd *)ptr; struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct urb_priv *up; unsigned long flags; spin_lock_irqsave(&uhci->lock, flags); uhci_scan_schedule(uhci, NULL); list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; spin_lock(&u->lock); /* Check if the FSBR timed out */ if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); spin_unlock(&u->lock); } /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { uhci->fsbrtimeout = 0; uhci->skel_term_qh->link = UHCI_PTR_TERM; } /* Poll for and perform state transitions */ hc_state_transitions(uhci); if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) uhci_check_ports(uhci); init_stall_timer(hcd); spin_unlock_irqrestore(&uhci->lock, flags); } static int init_stall_timer(struct usb_hcd *hcd) static int ports_active(struct uhci_hcd *uhci) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; int connection = 0; int i; init_timer(&uhci->stall_timer); uhci->stall_timer.function = stall_callback; uhci->stall_timer.data = (unsigned long)hcd; uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100); add_timer(&uhci->stall_timer); for (i = 0; i < uhci->rh_numports; i++) connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS); return 0; return connection; } static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) static int suspend_allowed(struct uhci_hcd *uhci) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; unsigned short status; int i; /* * Read the interrupt status, and write it back to clear the * interrupt cause. Contrary to the UHCI specification, the * "HC Halted" status bit is persistent: it is RO, not R/WC. if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) return 1; /* Some of Intel's USB controllers have a bug that causes false * resume indications if any port has an over current condition. * To prevent problems, we will not allow a global suspend if * any ports are OC. * * Some motherboards using Intel's chipsets (but not using all * the USB ports) appear to hardwire the over current inputs active * to disable the USB ports. */ status = inw(io_addr + USBSTS); if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ return IRQ_NONE; outw(status, io_addr + USBSTS); /* Clear it */ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & USBSTS_HSE) dev_err(uhci_dev(uhci), "host system error, " "PCI problems?\n"); if (status & USBSTS_HCPE) dev_err(uhci_dev(uhci), "host controller process " "error, something bad happened!\n"); if ((status & USBSTS_HCH) && uhci->state > 0) { dev_err(uhci_dev(uhci), "host controller halted, " "very bad!\n"); /* FIXME: Reset the controller, fix the offending TD */ } /* check for over current condition on any port */ for (i = 0; i < uhci->rh_numports; i++) { if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC) return 0; } if (status & USBSTS_RD) uhci->resume_detect = 1; spin_lock(&uhci->lock); uhci_scan_schedule(uhci, regs); spin_unlock(&uhci->lock); return IRQ_HANDLED; return 1; } static void reset_hc(struct uhci_hcd *uhci) Loading Loading @@ -276,43 +222,46 @@ static void wakeup_hc(struct uhci_hcd *uhci) } } static int ports_active(struct uhci_hcd *uhci) static int start_hc(struct uhci_hcd *uhci) { unsigned long io_addr = uhci->io_addr; int connection = 0; int i; for (i = 0; i < uhci->rh_numports; i++) connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS); int timeout = 10; return connection; /* * Reset the HC - this will force us to get a * new notification of any already connected * ports due to the virtual disconnect that it * implies. */ outw(USBCMD_HCRESET, io_addr + USBCMD); while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { if (--timeout < 0) { dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n"); return -ETIMEDOUT; } msleep(1); } static int suspend_allowed(struct uhci_hcd *uhci) { unsigned long io_addr = uhci->io_addr; int i; /* Mark controller as running before we enable interrupts */ uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) return 1; /* 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); /* Some of Intel's USB controllers have a bug that causes false * resume indications if any port has an over current condition. * To prevent problems, we will not allow a global suspend if * any ports are OC. * * Some motherboards using Intel's chipsets (but not using all * the USB ports) appear to hardwire the over current inputs active * to disable the USB ports. */ /* Start at frame 0 */ outw(0, io_addr + USBFRNUM); outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); /* check for over current condition on any port */ for (i = 0; i < uhci->rh_numports; i++) { if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC) return 0; } /* Run and mark it configured with a 64-byte max packet */ uhci->state = UHCI_RUNNING_GRACE; uhci->state_end = jiffies + HZ; outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); uhci->is_stopped = 0; return 1; return 0; } static void hc_state_transitions(struct uhci_hcd *uhci) Loading Loading @@ -353,56 +302,106 @@ static void hc_state_transitions(struct uhci_hcd *uhci) } } /* * Store the current frame number in uhci->frame_number if the controller * is runnning */ static void uhci_get_current_frame_number(struct uhci_hcd *uhci) static int init_stall_timer(struct usb_hcd *hcd); static void stall_callback(unsigned long ptr) { if (!uhci->is_stopped) uhci->frame_number = inw(uhci->io_addr + USBFRNUM); struct usb_hcd *hcd = (struct usb_hcd *)ptr; struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct urb_priv *up; unsigned long flags; spin_lock_irqsave(&uhci->lock, flags); uhci_scan_schedule(uhci, NULL); list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; spin_lock(&u->lock); /* Check if the FSBR timed out */ if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); spin_unlock(&u->lock); } static int start_hc(struct uhci_hcd *uhci) /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { uhci->fsbrtimeout = 0; uhci->skel_term_qh->link = UHCI_PTR_TERM; } /* Poll for and perform state transitions */ hc_state_transitions(uhci); if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) uhci_check_ports(uhci); init_stall_timer(hcd); spin_unlock_irqrestore(&uhci->lock, flags); } static int init_stall_timer(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); init_timer(&uhci->stall_timer); uhci->stall_timer.function = stall_callback; uhci->stall_timer.data = (unsigned long)hcd; 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 long io_addr = uhci->io_addr; int timeout = 10; unsigned short status; /* * Reset the HC - this will force us to get a * new notification of any already connected * ports due to the virtual disconnect that it * implies. * Read the interrupt status, and write it back to clear the * interrupt cause. Contrary to the UHCI specification, the * "HC Halted" status bit is persistent: it is RO, not R/WC. */ outw(USBCMD_HCRESET, io_addr + USBCMD); while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { if (--timeout < 0) { dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n"); return -ETIMEDOUT; status = inw(io_addr + USBSTS); if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ return IRQ_NONE; outw(status, io_addr + USBSTS); /* Clear it */ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & USBSTS_HSE) dev_err(uhci_dev(uhci), "host system error, " "PCI problems?\n"); if (status & USBSTS_HCPE) dev_err(uhci_dev(uhci), "host controller process " "error, something bad happened!\n"); if ((status & USBSTS_HCH) && uhci->state > 0) { dev_err(uhci_dev(uhci), "host controller halted, " "very bad!\n"); /* FIXME: Reset the controller, fix the offending TD */ } msleep(1); } /* Mark controller as running before we enable interrupts */ uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; /* 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); if (status & USBSTS_RD) uhci->resume_detect = 1; /* Start at frame 0 */ outw(0, io_addr + USBFRNUM); outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); spin_lock(&uhci->lock); uhci_scan_schedule(uhci, regs); spin_unlock(&uhci->lock); /* Run and mark it configured with a 64-byte max packet */ uhci->state = UHCI_RUNNING_GRACE; uhci->state_end = jiffies + HZ; outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); uhci->is_stopped = 0; return IRQ_HANDLED; } return 0; /* * Store the current frame number in uhci->frame_number if the controller * is runnning */ static void uhci_get_current_frame_number(struct uhci_hcd *uhci) { if (!uhci->is_stopped) uhci->frame_number = inw(uhci->io_addr + USBFRNUM); } /* Loading Loading
drivers/usb/host/uhci-hcd.c +143 −144 Original line number Diff line number Diff line Loading @@ -90,7 +90,6 @@ static char *errbuf; static kmem_cache_t *uhci_up_cachep; /* urb_priv */ static void uhci_get_current_frame_number(struct uhci_hcd *uhci); 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 msecs_to_jiffies(50) Loading @@ -105,96 +104,43 @@ static void hc_state_transitions(struct uhci_hcd *uhci); #include "uhci-debug.c" #include "uhci-q.c" static int init_stall_timer(struct usb_hcd *hcd); static void stall_callback(unsigned long ptr) { struct usb_hcd *hcd = (struct usb_hcd *)ptr; struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct urb_priv *up; unsigned long flags; spin_lock_irqsave(&uhci->lock, flags); uhci_scan_schedule(uhci, NULL); list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; spin_lock(&u->lock); /* Check if the FSBR timed out */ if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); spin_unlock(&u->lock); } /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { uhci->fsbrtimeout = 0; uhci->skel_term_qh->link = UHCI_PTR_TERM; } /* Poll for and perform state transitions */ hc_state_transitions(uhci); if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) uhci_check_ports(uhci); init_stall_timer(hcd); spin_unlock_irqrestore(&uhci->lock, flags); } static int init_stall_timer(struct usb_hcd *hcd) static int ports_active(struct uhci_hcd *uhci) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; int connection = 0; int i; init_timer(&uhci->stall_timer); uhci->stall_timer.function = stall_callback; uhci->stall_timer.data = (unsigned long)hcd; uhci->stall_timer.expires = jiffies + msecs_to_jiffies(100); add_timer(&uhci->stall_timer); for (i = 0; i < uhci->rh_numports; i++) connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS); return 0; return connection; } static irqreturn_t uhci_irq(struct usb_hcd *hcd, struct pt_regs *regs) static int suspend_allowed(struct uhci_hcd *uhci) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); unsigned long io_addr = uhci->io_addr; unsigned short status; int i; /* * Read the interrupt status, and write it back to clear the * interrupt cause. Contrary to the UHCI specification, the * "HC Halted" status bit is persistent: it is RO, not R/WC. if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) return 1; /* Some of Intel's USB controllers have a bug that causes false * resume indications if any port has an over current condition. * To prevent problems, we will not allow a global suspend if * any ports are OC. * * Some motherboards using Intel's chipsets (but not using all * the USB ports) appear to hardwire the over current inputs active * to disable the USB ports. */ status = inw(io_addr + USBSTS); if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ return IRQ_NONE; outw(status, io_addr + USBSTS); /* Clear it */ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & USBSTS_HSE) dev_err(uhci_dev(uhci), "host system error, " "PCI problems?\n"); if (status & USBSTS_HCPE) dev_err(uhci_dev(uhci), "host controller process " "error, something bad happened!\n"); if ((status & USBSTS_HCH) && uhci->state > 0) { dev_err(uhci_dev(uhci), "host controller halted, " "very bad!\n"); /* FIXME: Reset the controller, fix the offending TD */ } /* check for over current condition on any port */ for (i = 0; i < uhci->rh_numports; i++) { if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC) return 0; } if (status & USBSTS_RD) uhci->resume_detect = 1; spin_lock(&uhci->lock); uhci_scan_schedule(uhci, regs); spin_unlock(&uhci->lock); return IRQ_HANDLED; return 1; } static void reset_hc(struct uhci_hcd *uhci) Loading Loading @@ -276,43 +222,46 @@ static void wakeup_hc(struct uhci_hcd *uhci) } } static int ports_active(struct uhci_hcd *uhci) static int start_hc(struct uhci_hcd *uhci) { unsigned long io_addr = uhci->io_addr; int connection = 0; int i; for (i = 0; i < uhci->rh_numports; i++) connection |= (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_CCS); int timeout = 10; return connection; /* * Reset the HC - this will force us to get a * new notification of any already connected * ports due to the virtual disconnect that it * implies. */ outw(USBCMD_HCRESET, io_addr + USBCMD); while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { if (--timeout < 0) { dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n"); return -ETIMEDOUT; } msleep(1); } static int suspend_allowed(struct uhci_hcd *uhci) { unsigned long io_addr = uhci->io_addr; int i; /* Mark controller as running before we enable interrupts */ uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; if (to_pci_dev(uhci_dev(uhci))->vendor != PCI_VENDOR_ID_INTEL) return 1; /* 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); /* Some of Intel's USB controllers have a bug that causes false * resume indications if any port has an over current condition. * To prevent problems, we will not allow a global suspend if * any ports are OC. * * Some motherboards using Intel's chipsets (but not using all * the USB ports) appear to hardwire the over current inputs active * to disable the USB ports. */ /* Start at frame 0 */ outw(0, io_addr + USBFRNUM); outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); /* check for over current condition on any port */ for (i = 0; i < uhci->rh_numports; i++) { if (inw(io_addr + USBPORTSC1 + i * 2) & USBPORTSC_OC) return 0; } /* Run and mark it configured with a 64-byte max packet */ uhci->state = UHCI_RUNNING_GRACE; uhci->state_end = jiffies + HZ; outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); uhci->is_stopped = 0; return 1; return 0; } static void hc_state_transitions(struct uhci_hcd *uhci) Loading Loading @@ -353,56 +302,106 @@ static void hc_state_transitions(struct uhci_hcd *uhci) } } /* * Store the current frame number in uhci->frame_number if the controller * is runnning */ static void uhci_get_current_frame_number(struct uhci_hcd *uhci) static int init_stall_timer(struct usb_hcd *hcd); static void stall_callback(unsigned long ptr) { if (!uhci->is_stopped) uhci->frame_number = inw(uhci->io_addr + USBFRNUM); struct usb_hcd *hcd = (struct usb_hcd *)ptr; struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct urb_priv *up; unsigned long flags; spin_lock_irqsave(&uhci->lock, flags); uhci_scan_schedule(uhci, NULL); list_for_each_entry(up, &uhci->urb_list, urb_list) { struct urb *u = up->urb; spin_lock(&u->lock); /* Check if the FSBR timed out */ if (up->fsbr && !up->fsbr_timeout && time_after_eq(jiffies, up->fsbrtime + IDLE_TIMEOUT)) uhci_fsbr_timeout(uhci, u); spin_unlock(&u->lock); } static int start_hc(struct uhci_hcd *uhci) /* Really disable FSBR */ if (!uhci->fsbr && uhci->fsbrtimeout && time_after_eq(jiffies, uhci->fsbrtimeout)) { uhci->fsbrtimeout = 0; uhci->skel_term_qh->link = UHCI_PTR_TERM; } /* Poll for and perform state transitions */ hc_state_transitions(uhci); if (unlikely(uhci->suspended_ports && uhci->state != UHCI_SUSPENDED)) uhci_check_ports(uhci); init_stall_timer(hcd); spin_unlock_irqrestore(&uhci->lock, flags); } static int init_stall_timer(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); init_timer(&uhci->stall_timer); uhci->stall_timer.function = stall_callback; uhci->stall_timer.data = (unsigned long)hcd; 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 long io_addr = uhci->io_addr; int timeout = 10; unsigned short status; /* * Reset the HC - this will force us to get a * new notification of any already connected * ports due to the virtual disconnect that it * implies. * Read the interrupt status, and write it back to clear the * interrupt cause. Contrary to the UHCI specification, the * "HC Halted" status bit is persistent: it is RO, not R/WC. */ outw(USBCMD_HCRESET, io_addr + USBCMD); while (inw(io_addr + USBCMD) & USBCMD_HCRESET) { if (--timeout < 0) { dev_err(uhci_dev(uhci), "USBCMD_HCRESET timed out!\n"); return -ETIMEDOUT; status = inw(io_addr + USBSTS); if (!(status & ~USBSTS_HCH)) /* shared interrupt, not mine */ return IRQ_NONE; outw(status, io_addr + USBSTS); /* Clear it */ if (status & ~(USBSTS_USBINT | USBSTS_ERROR | USBSTS_RD)) { if (status & USBSTS_HSE) dev_err(uhci_dev(uhci), "host system error, " "PCI problems?\n"); if (status & USBSTS_HCPE) dev_err(uhci_dev(uhci), "host controller process " "error, something bad happened!\n"); if ((status & USBSTS_HCH) && uhci->state > 0) { dev_err(uhci_dev(uhci), "host controller halted, " "very bad!\n"); /* FIXME: Reset the controller, fix the offending TD */ } msleep(1); } /* Mark controller as running before we enable interrupts */ uhci_to_hcd(uhci)->state = HC_STATE_RUNNING; /* 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); if (status & USBSTS_RD) uhci->resume_detect = 1; /* Start at frame 0 */ outw(0, io_addr + USBFRNUM); outl(uhci->fl->dma_handle, io_addr + USBFLBASEADD); spin_lock(&uhci->lock); uhci_scan_schedule(uhci, regs); spin_unlock(&uhci->lock); /* Run and mark it configured with a 64-byte max packet */ uhci->state = UHCI_RUNNING_GRACE; uhci->state_end = jiffies + HZ; outw(USBCMD_RS | USBCMD_CF | USBCMD_MAXP, io_addr + USBCMD); uhci->is_stopped = 0; return IRQ_HANDLED; } return 0; /* * Store the current frame number in uhci->frame_number if the controller * is runnning */ static void uhci_get_current_frame_number(struct uhci_hcd *uhci) { if (!uhci->is_stopped) uhci->frame_number = inw(uhci->io_addr + USBFRNUM); } /* Loading