aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Brownell <david-b@pacbell.net>2005-05-26 08:55:55 -0400
committerGreg KH <gregkh@suse.de>2005-05-31 17:13:58 -0400
commit1e9a47b62f7daf5a94fdd74a94dd4e076f44909a (patch)
tree3c279e2c896ea0b56d6d5694e643f19be88c8740
parent2e3e80c2b75e3815a0160cbd23d4fdb767d66b35 (diff)
[PATCH] USB: sl811-hcd fixes
Various fixes to the sl811-hcd driver: * Fix small glitches that crept in during recent evolution of usbcore's hcd glue layer, coupling endpoint state records to usbcore and active urbs. (As noted by folk whose boards weren't stuck on 2.6.9 kernels...) * Cope with various system-specific issues: - Some configurations (e.g. a CF-card uses this chip) have iospace addresses for the two registers, rather than memory mapped ones. - Some configurations do interesting things with IRQs; maybe the line is shared, or it doesn't support level triggering. - Not all boards can drive the chip reset line in software. * Address a potential race during unlinking. * Tweak probe/remove section info to handle the case where this segment of a platform bus is hotpluggable (e.g. CF card). (The basic problem is that CONFIG_HOTPLUG is global, which is wrong since not all busses can hotplug even on hotplug-friendly systems...) Also export the driver, so that the CF driver can depend on it. Also removed some annoying end-of-line whitespace. Signed-off-by: David Brownell <dbrownell@users.sourceforge.net> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/host/sl811-hcd.c146
1 files changed, 81 insertions, 65 deletions
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index a374b7692073..99d43f758ad0 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -2,8 +2,8 @@
2 * SL811HS HCD (Host Controller Driver) for USB. 2 * SL811HS HCD (Host Controller Driver) for USB.
3 * 3 *
4 * Copyright (C) 2004 Psion Teklogix (for NetBook PRO) 4 * Copyright (C) 2004 Psion Teklogix (for NetBook PRO)
5 * Copyright (C) 2004 David Brownell 5 * Copyright (C) 2004-2005 David Brownell
6 * 6 *
7 * Periodic scheduling is based on Roman's OHCI code 7 * Periodic scheduling is based on Roman's OHCI code
8 * Copyright (C) 1999 Roman Weissgaerber 8 * Copyright (C) 1999 Roman Weissgaerber
9 * 9 *
@@ -15,7 +15,7 @@
15 * For documentation, see the SL811HS spec and the "SL811HS Embedded Host" 15 * For documentation, see the SL811HS spec and the "SL811HS Embedded Host"
16 * document (providing significant pieces missing from that spec); plus 16 * document (providing significant pieces missing from that spec); plus
17 * the SL811S spec if you want peripheral side info. 17 * the SL811S spec if you want peripheral side info.
18 */ 18 */
19 19
20/* 20/*
21 * Status: Passed basic stress testing, works with hubs, mice, keyboards, 21 * Status: Passed basic stress testing, works with hubs, mice, keyboards,
@@ -67,7 +67,7 @@
67MODULE_DESCRIPTION("SL811HS USB Host Controller Driver"); 67MODULE_DESCRIPTION("SL811HS USB Host Controller Driver");
68MODULE_LICENSE("GPL"); 68MODULE_LICENSE("GPL");
69 69
70#define DRIVER_VERSION "15 Dec 2004" 70#define DRIVER_VERSION "19 May 2005"
71 71
72 72
73#ifndef DEBUG 73#ifndef DEBUG
@@ -121,6 +121,10 @@ static void port_power(struct sl811 *sl811, int is_on)
121 /* reset as thoroughly as we can */ 121 /* reset as thoroughly as we can */
122 if (sl811->board && sl811->board->reset) 122 if (sl811->board && sl811->board->reset)
123 sl811->board->reset(hcd->self.controller); 123 sl811->board->reset(hcd->self.controller);
124 else {
125 sl811_write(sl811, SL11H_CTLREG1, SL11H_CTL1MASK_SE0);
126 mdelay(20);
127 }
124 128
125 sl811_write(sl811, SL11H_IRQ_ENABLE, 0); 129 sl811_write(sl811, SL11H_IRQ_ENABLE, 0);
126 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1); 130 sl811_write(sl811, SL11H_CTLREG1, sl811->ctrl1);
@@ -443,6 +447,7 @@ static void finish_request(
443 spin_lock(&urb->lock); 447 spin_lock(&urb->lock);
444 if (urb->status == -EINPROGRESS) 448 if (urb->status == -EINPROGRESS)
445 urb->status = status; 449 urb->status = status;
450 urb->hcpriv = NULL;
446 spin_unlock(&urb->lock); 451 spin_unlock(&urb->lock);
447 452
448 spin_unlock(&sl811->lock); 453 spin_unlock(&sl811->lock);
@@ -472,7 +477,7 @@ static void finish_request(
472 if (*prev) 477 if (*prev)
473 *prev = ep->next; 478 *prev = ep->next;
474 sl811->load[i] -= ep->load; 479 sl811->load[i] -= ep->load;
475 } 480 }
476 ep->branch = PERIODIC_SIZE; 481 ep->branch = PERIODIC_SIZE;
477 sl811->periodic_count--; 482 sl811->periodic_count--;
478 sl811_to_hcd(sl811)->self.bandwidth_allocated 483 sl811_to_hcd(sl811)->self.bandwidth_allocated
@@ -661,9 +666,9 @@ retry:
661 666
662#ifdef QUIRK2 667#ifdef QUIRK2
663 /* this may no longer be necessary ... */ 668 /* this may no longer be necessary ... */
664 if (irqstat == 0 && ret == IRQ_NONE) { 669 if (irqstat == 0) {
665 irqstat = checkdone(sl811); 670 irqstat = checkdone(sl811);
666 if (irqstat /* && irq != ~0 */ ) 671 if (irqstat)
667 sl811->stat_lost++; 672 sl811->stat_lost++;
668 } 673 }
669#endif 674#endif
@@ -722,7 +727,8 @@ retry:
722 if (sl811->active_a) { 727 if (sl811->active_a) {
723 sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0); 728 sl811_write(sl811, SL811_EP_A(SL11H_HOSTCTLREG), 0);
724 finish_request(sl811, sl811->active_a, 729 finish_request(sl811, sl811->active_a,
725 container_of(sl811->active_a->hep->urb_list.next, 730 container_of(sl811->active_a
731 ->hep->urb_list.next,
726 struct urb, urb_list), 732 struct urb, urb_list),
727 NULL, -ESHUTDOWN); 733 NULL, -ESHUTDOWN);
728 sl811->active_a = NULL; 734 sl811->active_a = NULL;
@@ -731,7 +737,8 @@ retry:
731 if (sl811->active_b) { 737 if (sl811->active_b) {
732 sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0); 738 sl811_write(sl811, SL811_EP_B(SL11H_HOSTCTLREG), 0);
733 finish_request(sl811, sl811->active_b, 739 finish_request(sl811, sl811->active_b,
734 container_of(sl811->active_b->hep->urb_list.next, 740 container_of(sl811->active_b
741 ->hep->urb_list.next,
735 struct urb, urb_list), 742 struct urb, urb_list),
736 NULL, -ESHUTDOWN); 743 NULL, -ESHUTDOWN);
737 sl811->active_b = NULL; 744 sl811->active_b = NULL;
@@ -761,7 +768,7 @@ retry:
761 goto retry; 768 goto retry;
762 } 769 }
763 770
764 if (sl811->periodic_count == 0 && list_empty(&sl811->async)) 771 if (sl811->periodic_count == 0 && list_empty(&sl811->async))
765 sofirq_off(sl811); 772 sofirq_off(sl811);
766 sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable); 773 sl811_write(sl811, SL11H_IRQ_ENABLE, sl811->irq_enable);
767 774
@@ -796,7 +803,7 @@ static int balance(struct sl811 *sl811, u16 period, u16 load)
796 } 803 }
797 if (j < PERIODIC_SIZE) 804 if (j < PERIODIC_SIZE)
798 continue; 805 continue;
799 branch = i; 806 branch = i;
800 } 807 }
801 } 808 }
802 return branch; 809 return branch;
@@ -890,6 +897,7 @@ static int sl811h_urb_enqueue(
890 break; 897 break;
891 } 898 }
892 899
900 ep->hep = hep;
893 hep->hcpriv = ep; 901 hep->hcpriv = ep;
894 } 902 }
895 903
@@ -961,15 +969,16 @@ fail:
961static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb) 969static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
962{ 970{
963 struct sl811 *sl811 = hcd_to_sl811(hcd); 971 struct sl811 *sl811 = hcd_to_sl811(hcd);
964 struct usb_host_endpoint *hep = urb->hcpriv; 972 struct usb_host_endpoint *hep;
965 unsigned long flags; 973 unsigned long flags;
966 struct sl811h_ep *ep; 974 struct sl811h_ep *ep;
967 int retval = 0; 975 int retval = 0;
968 976
977 spin_lock_irqsave(&sl811->lock, flags);
978 hep = urb->hcpriv;
969 if (!hep) 979 if (!hep)
970 return -EINVAL; 980 goto fail;
971 981
972 spin_lock_irqsave(&sl811->lock, flags);
973 ep = hep->hcpriv; 982 ep = hep->hcpriv;
974 if (ep) { 983 if (ep) {
975 /* finish right away if this urb can't be active ... 984 /* finish right away if this urb can't be active ...
@@ -1017,6 +1026,7 @@ static int sl811h_urb_dequeue(struct usb_hcd *hcd, struct urb *urb)
1017 VDBG("dequeue, urb %p active %s; wait4irq\n", urb, 1026 VDBG("dequeue, urb %p active %s; wait4irq\n", urb,
1018 (sl811->active_a == ep) ? "A" : "B"); 1027 (sl811->active_a == ep) ? "A" : "B");
1019 } else 1028 } else
1029fail:
1020 retval = -EINVAL; 1030 retval = -EINVAL;
1021 spin_unlock_irqrestore(&sl811->lock, flags); 1031 spin_unlock_irqrestore(&sl811->lock, flags);
1022 return retval; 1032 return retval;
@@ -1576,6 +1586,9 @@ sl811h_start(struct usb_hcd *hcd)
1576 if (sl811->board && sl811->board->power) 1586 if (sl811->board && sl811->board->power)
1577 hub_set_power_budget(udev, sl811->board->power * 2); 1587 hub_set_power_budget(udev, sl811->board->power * 2);
1578 1588
1589 /* enable power and interupts */
1590 port_power(sl811, 1);
1591
1579 return 0; 1592 return 0;
1580} 1593}
1581 1594
@@ -1618,7 +1631,7 @@ static struct hc_driver sl811h_hc_driver = {
1618 1631
1619/*-------------------------------------------------------------------------*/ 1632/*-------------------------------------------------------------------------*/
1620 1633
1621static int __init_or_module 1634static int __devexit
1622sl811h_remove(struct device *dev) 1635sl811h_remove(struct device *dev)
1623{ 1636{
1624 struct usb_hcd *hcd = dev_get_drvdata(dev); 1637 struct usb_hcd *hcd = dev_get_drvdata(dev);
@@ -1631,21 +1644,20 @@ sl811h_remove(struct device *dev)
1631 remove_debug_file(sl811); 1644 remove_debug_file(sl811);
1632 usb_remove_hcd(hcd); 1645 usb_remove_hcd(hcd);
1633 1646
1634 iounmap(sl811->data_reg); 1647 /* some platforms may use IORESOURCE_IO */
1635 res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 1648 res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1636 release_mem_region(res->start, 1); 1649 if (res)
1650 iounmap(sl811->data_reg);
1637 1651
1638 iounmap(sl811->addr_reg);
1639 res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 1652 res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1640 release_mem_region(res->start, 1); 1653 if (res)
1654 iounmap(sl811->addr_reg);
1641 1655
1642 usb_put_hcd(hcd); 1656 usb_put_hcd(hcd);
1643 return 0; 1657 return 0;
1644} 1658}
1645 1659
1646#define resource_len(r) (((r)->end - (r)->start) + 1) 1660static int __devinit
1647
1648static int __init
1649sl811h_probe(struct device *dev) 1661sl811h_probe(struct device *dev)
1650{ 1662{
1651 struct usb_hcd *hcd; 1663 struct usb_hcd *hcd;
@@ -1656,7 +1668,7 @@ sl811h_probe(struct device *dev)
1656 void __iomem *addr_reg; 1668 void __iomem *addr_reg;
1657 void __iomem *data_reg; 1669 void __iomem *data_reg;
1658 int retval; 1670 int retval;
1659 u8 tmp; 1671 u8 tmp, ioaddr = 0;
1660 1672
1661 /* basic sanity checks first. board-specific init logic should 1673 /* basic sanity checks first. board-specific init logic should
1662 * have initialized these three resources and probably board 1674 * have initialized these three resources and probably board
@@ -1664,13 +1676,8 @@ sl811h_probe(struct device *dev)
1664 * minimal sanity checking. 1676 * minimal sanity checking.
1665 */ 1677 */
1666 pdev = container_of(dev, struct platform_device, dev); 1678 pdev = container_of(dev, struct platform_device, dev);
1667 if (pdev->num_resources < 3)
1668 return -ENODEV;
1669
1670 addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1671 data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1672 irq = platform_get_irq(pdev, 0); 1679 irq = platform_get_irq(pdev, 0);
1673 if (!addr || !data || irq < 0) 1680 if (pdev->num_resources < 3 || irq < 0)
1674 return -ENODEV; 1681 return -ENODEV;
1675 1682
1676 /* refuse to confuse usbcore */ 1683 /* refuse to confuse usbcore */
@@ -1679,24 +1686,31 @@ sl811h_probe(struct device *dev)
1679 return -EINVAL; 1686 return -EINVAL;
1680 } 1687 }
1681 1688
1682 if (!request_mem_region(addr->start, 1, hcd_name)) { 1689 /* the chip may be wired for either kind of addressing */
1683 retval = -EBUSY; 1690 addr = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1684 goto err1; 1691 data = platform_get_resource(pdev, IORESOURCE_MEM, 1);
1685 } 1692 retval = -EBUSY;
1686 addr_reg = ioremap(addr->start, resource_len(addr)); 1693 if (!addr || !data) {
1687 if (addr_reg == NULL) { 1694 addr = platform_get_resource(pdev, IORESOURCE_IO, 0);
1688 retval = -ENOMEM; 1695 data = platform_get_resource(pdev, IORESOURCE_IO, 1);
1689 goto err2; 1696 if (!addr || !data)
1690 } 1697 return -ENODEV;
1698 ioaddr = 1;
1699
1700 addr_reg = (void __iomem *) addr->start;
1701 data_reg = (void __iomem *) data->start;
1702 } else {
1703 addr_reg = ioremap(addr->start, 1);
1704 if (addr_reg == NULL) {
1705 retval = -ENOMEM;
1706 goto err2;
1707 }
1691 1708
1692 if (!request_mem_region(data->start, 1, hcd_name)) { 1709 data_reg = ioremap(data->start, 1);
1693 retval = -EBUSY; 1710 if (data_reg == NULL) {
1694 goto err3; 1711 retval = -ENOMEM;
1695 } 1712 goto err4;
1696 data_reg = ioremap(data->start, resource_len(addr)); 1713 }
1697 if (data_reg == NULL) {
1698 retval = -ENOMEM;
1699 goto err4;
1700 } 1714 }
1701 1715
1702 /* allocate and initialize hcd */ 1716 /* allocate and initialize hcd */
@@ -1737,12 +1751,14 @@ sl811h_probe(struct device *dev)
1737 goto err6; 1751 goto err6;
1738 } 1752 }
1739 1753
1740 /* sl811s would need a different handler for this irq */ 1754 /* The chip's IRQ is level triggered, active high. A requirement
1741#ifdef CONFIG_ARM 1755 * for platform device setup is to cope with things like signal
1742 /* Cypress docs say the IRQ is IRQT_HIGH ... */ 1756 * inverters (e.g. CF is active low) or working only with edge
1743 set_irq_type(irq, IRQT_RISING); 1757 * triggers (e.g. most ARM CPUs). Initial driver stress testing
1744#endif 1758 * was on a system with single edge triggering, so most sorts of
1745 retval = usb_add_hcd(hcd, irq, SA_INTERRUPT); 1759 * triggering arrangement should work.
1760 */
1761 retval = usb_add_hcd(hcd, irq, SA_INTERRUPT | SA_SHIRQ);
1746 if (retval != 0) 1762 if (retval != 0)
1747 goto err6; 1763 goto err6;
1748 1764
@@ -1752,14 +1768,12 @@ sl811h_probe(struct device *dev)
1752 err6: 1768 err6:
1753 usb_put_hcd(hcd); 1769 usb_put_hcd(hcd);
1754 err5: 1770 err5:
1755 iounmap(data_reg); 1771 if (!ioaddr)
1772 iounmap(data_reg);
1756 err4: 1773 err4:
1757 release_mem_region(data->start, 1); 1774 if (!ioaddr)
1758 err3: 1775 iounmap(addr_reg);
1759 iounmap(addr_reg);
1760 err2: 1776 err2:
1761 release_mem_region(addr->start, 1);
1762 err1:
1763 DBG("init error, %d\n", retval); 1777 DBG("init error, %d\n", retval);
1764 return retval; 1778 return retval;
1765} 1779}
@@ -1767,7 +1781,7 @@ sl811h_probe(struct device *dev)
1767#ifdef CONFIG_PM 1781#ifdef CONFIG_PM
1768 1782
1769/* for this device there's no useful distinction between the controller 1783/* for this device there's no useful distinction between the controller
1770 * and its root hub, except that the root hub only gets direct PM calls 1784 * and its root hub, except that the root hub only gets direct PM calls
1771 * when CONFIG_USB_SUSPEND is enabled. 1785 * when CONFIG_USB_SUSPEND is enabled.
1772 */ 1786 */
1773 1787
@@ -1821,20 +1835,22 @@ sl811h_resume(struct device *dev, u32 phase)
1821#endif 1835#endif
1822 1836
1823 1837
1824static struct device_driver sl811h_driver = { 1838/* this driver is exported so sl811_cs can depend on it */
1839struct device_driver sl811h_driver = {
1825 .name = (char *) hcd_name, 1840 .name = (char *) hcd_name,
1826 .bus = &platform_bus_type, 1841 .bus = &platform_bus_type,
1827 1842
1828 .probe = sl811h_probe, 1843 .probe = sl811h_probe,
1829 .remove = sl811h_remove, 1844 .remove = __devexit_p(sl811h_remove),
1830 1845
1831 .suspend = sl811h_suspend, 1846 .suspend = sl811h_suspend,
1832 .resume = sl811h_resume, 1847 .resume = sl811h_resume,
1833}; 1848};
1849EXPORT_SYMBOL(sl811h_driver);
1834 1850
1835/*-------------------------------------------------------------------------*/ 1851/*-------------------------------------------------------------------------*/
1836 1852
1837static int __init sl811h_init(void) 1853static int __init sl811h_init(void)
1838{ 1854{
1839 if (usb_disabled()) 1855 if (usb_disabled())
1840 return -ENODEV; 1856 return -ENODEV;
@@ -1844,8 +1860,8 @@ static int __init sl811h_init(void)
1844} 1860}
1845module_init(sl811h_init); 1861module_init(sl811h_init);
1846 1862
1847static void __exit sl811h_cleanup(void) 1863static void __exit sl811h_cleanup(void)
1848{ 1864{
1849 driver_unregister(&sl811h_driver); 1865 driver_unregister(&sl811h_driver);
1850} 1866}
1851module_exit(sl811h_cleanup); 1867module_exit(sl811h_cleanup);