aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/sl811-hcd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/sl811-hcd.c')
-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);