static int uhci_pci_init(struct usb_hcd *hcd) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); uhci->io_addr = (unsigned long) hcd->rsrc_start; uhci->rh_numports = uhci_count_ports(hcd); /* Intel controllers report the OverCurrent bit active on. * VIA controllers report it active off, so we'll adjust the * bit value. (It's not standardized in the UHCI spec.) */ if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_VIA) uhci->oc_low = 1; /* HP's server management chip requires a longer port reset delay. */ if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_HP) uhci->wait_for_hp = 1; /* Intel controllers use non-PME wakeup signalling */ if (to_pci_dev(uhci_dev(uhci))->vendor == PCI_VENDOR_ID_INTEL) device_set_wakeup_capable(uhci_dev(uhci), true); /* Set up pointers to PCI-specific functions */ uhci->reset_hc = uhci_pci_reset_hc; uhci->check_and_reset_hc = uhci_pci_check_and_reset_hc; uhci->configure_hc = uhci_pci_configure_hc; uhci->resume_detect_interrupts_are_broken = uhci_pci_resume_detect_interrupts_are_broken; uhci->global_suspend_mode_is_broken = uhci_pci_global_suspend_mode_is_broken; /* Kick BIOS off this hardware and reset if the controller * isn't already safely quiescent. */ check_and_reset_hc(uhci); return 0; }
static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); int rc = 0; dev_dbg(uhci_dev(uhci), "%s\n", __func__); spin_lock_irq(&uhci->lock); if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead) goto done_okay; /* Already suspended or dead */ /* All PCI host controllers are required to disable IRQ generation * at the source, so we must turn off PIRQ. */ pci_write_config_word(pdev, USBLEGSUP, 0); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); /* Enable platform-specific non-PME# wakeup */ if (do_wakeup) { if (pdev->vendor == PCI_VENDOR_ID_INTEL) pci_write_config_byte(pdev, USBRES_INTEL, USBPORT1EN | USBPORT2EN); } done_okay: clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); spin_unlock_irq(&uhci->lock); synchronize_irq(hcd->irq); /* Check for race with a wakeup request */ if (do_wakeup && HCD_WAKEUP_PENDING(hcd)) { uhci_pci_resume(hcd, false); rc = -EBUSY; } return rc; }
static int uhci_pci_suspend(struct usb_hcd *hcd, bool do_wakeup) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); struct pci_dev *pdev = to_pci_dev(uhci_dev(uhci)); int rc = 0; dev_dbg(uhci_dev(uhci), "%s\n", __func__); spin_lock_irq(&uhci->lock); if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead) goto done_okay; /* Already suspended or dead */ if (uhci->rh_state > UHCI_RH_SUSPENDED) { dev_warn(uhci_dev(uhci), "Root hub isn't suspended!\n"); rc = -EBUSY; goto done; }; /* All PCI host controllers are required to disable IRQ generation * at the source, so we must turn off PIRQ. */ pci_write_config_word(pdev, USBLEGSUP, 0); clear_bit(HCD_FLAG_POLL_RH, &hcd->flags); /* Enable platform-specific non-PME# wakeup */ if (do_wakeup) { if (pdev->vendor == PCI_VENDOR_ID_INTEL) pci_write_config_byte(pdev, USBRES_INTEL, USBPORT1EN | USBPORT2EN); } done_okay: clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); done: spin_unlock_irq(&uhci->lock); return rc; }
/* Make sure the controller is quiescent and that we're not using it * any more. This is mainly for the benefit of programs which, like kexec, * expect the hardware to be idle: not doing DMA or generating IRQs. * * This routine may be called in a damaged or failing kernel. Hence we * do not acquire the spinlock before shutting down the controller. */ static void uhci_shutdown(struct pci_dev *pdev) { struct usb_hcd *hcd = pci_get_drvdata(pdev); uhci_hc_died(hcd_to_uhci(hcd)); }
/* size of returned buffer is part of USB spec */ static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); int status, lstatus, retval = 0, len = 0; unsigned int port = wIndex - 1; unsigned long port_addr = uhci->io_addr + USBPORTSC1 + 2 * port; u16 wPortChange, wPortStatus; unsigned long flags; if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags) || uhci->dead) return -ETIMEDOUT; spin_lock_irqsave(&uhci->lock, flags); switch (typeReq) { case GetHubStatus: *(__le32 *)buf = cpu_to_le32(0); OK(4); /* hub power */ case GetPortStatus: if (port >= uhci->rh_numports) goto err; uhci_check_ports(uhci); status = inw(port_addr); /* Intel controllers report the OverCurrent bit active on. * VIA controllers report it active off, so we'll adjust the * bit value. (It's not standardized in the UHCI spec.) */ if (to_pci_dev(hcd->self.controller)->vendor == PCI_VENDOR_ID_VIA) status ^= USBPORTSC_OC; /* UHCI doesn't support C_RESET (always false) */ wPortChange = lstatus = 0; if (status & USBPORTSC_CSC) wPortChange |= USB_PORT_STAT_C_CONNECTION; if (status & USBPORTSC_PEC) wPortChange |= USB_PORT_STAT_C_ENABLE; if ((status & USBPORTSC_OCC) && !ignore_oc) wPortChange |= USB_PORT_STAT_C_OVERCURRENT; if (test_bit(port, &uhci->port_c_suspend)) { wPortChange |= USB_PORT_STAT_C_SUSPEND; lstatus |= 1; } if (test_bit(port, &uhci->resuming_ports)) lstatus |= 4; /* UHCI has no power switching (always on) */ wPortStatus = USB_PORT_STAT_POWER; if (status & USBPORTSC_CCS) wPortStatus |= USB_PORT_STAT_CONNECTION; if (status & USBPORTSC_PE) { wPortStatus |= USB_PORT_STAT_ENABLE; if (status & SUSPEND_BITS) wPortStatus |= USB_PORT_STAT_SUSPEND; } if (status & USBPORTSC_OC) wPortStatus |= USB_PORT_STAT_OVERCURRENT; if (status & USBPORTSC_PR) wPortStatus |= USB_PORT_STAT_RESET; if (status & USBPORTSC_LSDA) wPortStatus |= USB_PORT_STAT_LOW_SPEED; if (wPortChange) dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n", wIndex, status, lstatus); *(__le16 *)buf = cpu_to_le16(wPortStatus); *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange); OK(4); case SetHubFeature: /* We don't implement these */ case ClearHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: OK(0); default: goto err; } break; case SetPortFeature: if (port >= uhci->rh_numports) goto err; switch (wValue) { case USB_PORT_FEAT_SUSPEND: SET_RH_PORTSTAT(USBPORTSC_SUSP); OK(0); case USB_PORT_FEAT_RESET: SET_RH_PORTSTAT(USBPORTSC_PR); /* Reset terminates Resume signalling */ uhci_finish_suspend(uhci, port, port_addr); /* USB v2.0 7.1.7.5 */ uhci->ports_timeout = jiffies + msecs_to_jiffies(50); OK(0); case USB_PORT_FEAT_POWER: /* UHCI has no power switching */ OK(0); default: goto err; } break; case ClearPortFeature: if (port >= uhci->rh_numports) goto err; switch (wValue) { case USB_PORT_FEAT_ENABLE: CLR_RH_PORTSTAT(USBPORTSC_PE); /* Disable terminates Resume signalling */ uhci_finish_suspend(uhci, port, port_addr); OK(0); case USB_PORT_FEAT_C_ENABLE: CLR_RH_PORTSTAT(USBPORTSC_PEC); OK(0); case USB_PORT_FEAT_SUSPEND: if (!(inw(port_addr) & USBPORTSC_SUSP)) { /* Make certain the port isn't suspended */ uhci_finish_suspend(uhci, port, port_addr); } else if (!test_and_set_bit(port, &uhci->resuming_ports)) { SET_RH_PORTSTAT(USBPORTSC_RD); /* The controller won't allow RD to be set * if the port is disabled. When this happens * just skip the Resume signalling. */ if (!(inw(port_addr) & USBPORTSC_RD)) uhci_finish_suspend(uhci, port, port_addr); else /* USB v2.0 7.1.7.7 */ uhci->ports_timeout = jiffies + msecs_to_jiffies(20); } OK(0); case USB_PORT_FEAT_C_SUSPEND: clear_bit(port, &uhci->port_c_suspend); OK(0); case USB_PORT_FEAT_POWER: /* UHCI has no power switching */ goto err; case USB_PORT_FEAT_C_CONNECTION: CLR_RH_PORTSTAT(USBPORTSC_CSC); OK(0); case USB_PORT_FEAT_C_OVER_CURRENT: CLR_RH_PORTSTAT(USBPORTSC_OCC); OK(0); case USB_PORT_FEAT_C_RESET: /* this driver won't report these */ OK(0); default: goto err; } break; case GetHubDescriptor: len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); memcpy(buf, root_hub_hub_des, len); if (len > 2) buf[2] = uhci->rh_numports; OK(len); default: err: retval = -EPIPE; } spin_unlock_irqrestore(&uhci->lock, flags); return retval; }
static int __devinit uhci_hcd_grlib_probe(struct platform_device *op) { struct device_node *dn = op->dev.of_node; struct usb_hcd *hcd; struct uhci_hcd *uhci = NULL; struct resource res; int irq; int rv; if (usb_disabled()) return -ENODEV; dev_dbg(&op->dev, "initializing GRUSBHC UHCI USB Controller\n"); rv = of_address_to_resource(dn, 0, &res); if (rv) return rv; /* usb_create_hcd requires dma_mask != NULL */ op->dev.dma_mask = &op->dev.coherent_dma_mask; hcd = usb_create_hcd(&uhci_grlib_hc_driver, &op->dev, "GRUSBHC UHCI USB"); if (!hcd) return -ENOMEM; hcd->rsrc_start = res.start; hcd->rsrc_len = res.end - res.start + 1; if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { ; rv = -EBUSY; goto err_rmr; } irq = irq_of_parse_and_map(dn, 0); if (irq == NO_IRQ) { ; rv = -EBUSY; goto err_irq; } hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len); if (!hcd->regs) { ; rv = -ENOMEM; goto err_ioremap; } uhci = hcd_to_uhci(hcd); uhci->regs = hcd->regs; rv = usb_add_hcd(hcd, irq, 0); if (rv) goto err_uhci; return 0; err_uhci: iounmap(hcd->regs); err_ioremap: irq_dispose_mapping(irq); err_irq: release_mem_region(hcd->rsrc_start, hcd->rsrc_len); err_rmr: usb_put_hcd(hcd); return rv; }
/* Make sure the controller is quiescent and that we're not using it * any more. This is mainly for the benefit of programs which, like kexec, * expect the hardware to be idle: not doing DMA or generating IRQs. * * This routine may be called in a damaged or failing kernel. Hence we * do not acquire the spinlock before shutting down the controller. */ static void uhci_hcd_grlib_shutdown(struct platform_device *op) { struct usb_hcd *hcd = dev_get_drvdata(&op->dev); uhci_hc_died(hcd_to_uhci(hcd)); }
/* Make sure the controller is quiescent and that we're not using it * any more. This is mainly for the benefit of programs which, like kexec, * expect the hardware to be idle: not doing DMA or generating IRQs. * * This routine may be called in a damaged or failing kernel. Hence we * do not acquire the spinlock before shutting down the controller. */ static void uhci_hcd_platform_shutdown(struct platform_device *op) { struct usb_hcd *hcd = platform_get_drvdata(op); uhci_hc_died(hcd_to_uhci(hcd)); }
static int uhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct uhci_hcd *uhci = hcd_to_uhci(hcd); int status, lstatus, retval = 0, len = 0; unsigned int port = wIndex - 1; unsigned long port_addr = USBPORTSC1 + 2 * port; u16 wPortChange, wPortStatus; unsigned long flags; if (!HCD_HW_ACCESSIBLE(hcd) || uhci->dead) return -ETIMEDOUT; spin_lock_irqsave(&uhci->lock, flags); switch (typeReq) { case GetHubStatus: *(__le32 *)buf = cpu_to_le32(0); OK(4); case GetPortStatus: if (port >= uhci->rh_numports) goto err; uhci_check_ports(uhci); status = uhci_readw(uhci, port_addr); if (uhci->oc_low) status ^= USBPORTSC_OC; wPortChange = lstatus = 0; if (status & USBPORTSC_CSC) wPortChange |= USB_PORT_STAT_C_CONNECTION; if (status & USBPORTSC_PEC) wPortChange |= USB_PORT_STAT_C_ENABLE; if ((status & USBPORTSC_OCC) && !ignore_oc) wPortChange |= USB_PORT_STAT_C_OVERCURRENT; if (test_bit(port, &uhci->port_c_suspend)) { wPortChange |= USB_PORT_STAT_C_SUSPEND; lstatus |= 1; } if (test_bit(port, &uhci->resuming_ports)) lstatus |= 4; wPortStatus = USB_PORT_STAT_POWER; if (status & USBPORTSC_CCS) wPortStatus |= USB_PORT_STAT_CONNECTION; if (status & USBPORTSC_PE) { wPortStatus |= USB_PORT_STAT_ENABLE; if (status & SUSPEND_BITS) wPortStatus |= USB_PORT_STAT_SUSPEND; } if (status & USBPORTSC_OC) wPortStatus |= USB_PORT_STAT_OVERCURRENT; if (status & USBPORTSC_PR) wPortStatus |= USB_PORT_STAT_RESET; if (status & USBPORTSC_LSDA) wPortStatus |= USB_PORT_STAT_LOW_SPEED; if (wPortChange) dev_dbg(uhci_dev(uhci), "port %d portsc %04x,%02x\n", wIndex, status, lstatus); *(__le16 *)buf = cpu_to_le16(wPortStatus); *(__le16 *)(buf + 2) = cpu_to_le16(wPortChange); OK(4); case SetHubFeature: case ClearHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: OK(0); default: goto err; } break; case SetPortFeature: if (port >= uhci->rh_numports) goto err; switch (wValue) { case USB_PORT_FEAT_SUSPEND: SET_RH_PORTSTAT(USBPORTSC_SUSP); OK(0); case USB_PORT_FEAT_RESET: SET_RH_PORTSTAT(USBPORTSC_PR); uhci_finish_suspend(uhci, port, port_addr); uhci->ports_timeout = jiffies + msecs_to_jiffies(50); OK(0); case USB_PORT_FEAT_POWER: OK(0); default: goto err; } break; case ClearPortFeature: if (port >= uhci->rh_numports) goto err; switch (wValue) { case USB_PORT_FEAT_ENABLE: CLR_RH_PORTSTAT(USBPORTSC_PE); uhci_finish_suspend(uhci, port, port_addr); OK(0); case USB_PORT_FEAT_C_ENABLE: CLR_RH_PORTSTAT(USBPORTSC_PEC); OK(0); case USB_PORT_FEAT_SUSPEND: if (!(uhci_readw(uhci, port_addr) & USBPORTSC_SUSP)) { uhci_finish_suspend(uhci, port, port_addr); } else if (!test_and_set_bit(port, &uhci->resuming_ports)) { SET_RH_PORTSTAT(USBPORTSC_RD); if (!(uhci_readw(uhci, port_addr) & USBPORTSC_RD)) uhci_finish_suspend(uhci, port, port_addr); else uhci->ports_timeout = jiffies + msecs_to_jiffies(20); } OK(0); case USB_PORT_FEAT_C_SUSPEND: clear_bit(port, &uhci->port_c_suspend); OK(0); case USB_PORT_FEAT_POWER: goto err; case USB_PORT_FEAT_C_CONNECTION: CLR_RH_PORTSTAT(USBPORTSC_CSC); OK(0); case USB_PORT_FEAT_C_OVER_CURRENT: CLR_RH_PORTSTAT(USBPORTSC_OCC); OK(0); case USB_PORT_FEAT_C_RESET: OK(0); default: goto err; } break; case GetHubDescriptor: len = min_t(unsigned int, sizeof(root_hub_hub_des), wLength); memcpy(buf, root_hub_hub_des, len); if (len > 2) buf[2] = uhci->rh_numports; OK(len); default: err: retval = -EPIPE; } spin_unlock_irqrestore(&uhci->lock, flags); return retval; }