aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-05-10 15:34:16 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 17:43:59 -0400
commit391eca9d8892a940ff8dbfee2ca78942e05c2d37 (patch)
tree09459bed19e34676108da3ebf8f41c6d5d575143
parentcc095b0b5b653dca3e106710a72ba28b5bb7456b (diff)
[PATCH] USB: dummy_hcd: add suspend/resume support
This patch adds support to dummy_hcd for suspending and resuming the root hub and the emulated platform devices. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r--drivers/usb/gadget/dummy_hcd.c179
1 files changed, 162 insertions, 17 deletions
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index c78c64ae87af..4d692670f288 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -65,7 +65,7 @@
65 65
66 66
67#define DRIVER_DESC "USB Host+Gadget Emulator" 67#define DRIVER_DESC "USB Host+Gadget Emulator"
68#define DRIVER_VERSION "17 Dec 2004" 68#define DRIVER_VERSION "02 May 2005"
69 69
70static const char driver_name [] = "dummy_hcd"; 70static const char driver_name [] = "dummy_hcd";
71static const char driver_desc [] = "USB Host+Gadget Emulator"; 71static const char driver_desc [] = "USB Host+Gadget Emulator";
@@ -150,6 +150,13 @@ struct urbp {
150 struct list_head urbp_list; 150 struct list_head urbp_list;
151}; 151};
152 152
153
154enum dummy_rh_state {
155 DUMMY_RH_RESET,
156 DUMMY_RH_SUSPENDED,
157 DUMMY_RH_RUNNING
158};
159
153struct dummy { 160struct dummy {
154 spinlock_t lock; 161 spinlock_t lock;
155 162
@@ -163,6 +170,7 @@ struct dummy {
163 struct dummy_request fifo_req; 170 struct dummy_request fifo_req;
164 u8 fifo_buf [FIFO_SIZE]; 171 u8 fifo_buf [FIFO_SIZE];
165 u16 devstatus; 172 u16 devstatus;
173 unsigned udc_suspended:1;
166 unsigned pullup:1; 174 unsigned pullup:1;
167 unsigned active:1; 175 unsigned active:1;
168 unsigned old_active:1; 176 unsigned old_active:1;
@@ -170,6 +178,7 @@ struct dummy {
170 /* 178 /*
171 * MASTER/HOST side support 179 * MASTER/HOST side support
172 */ 180 */
181 enum dummy_rh_state rh_state;
173 struct timer_list timer; 182 struct timer_list timer;
174 u32 port_status; 183 u32 port_status;
175 u32 old_status; 184 u32 old_status;
@@ -262,7 +271,9 @@ set_link_state (struct dummy *dum)
262 dum->active = 0; 271 dum->active = 0;
263 if ((dum->port_status & USB_PORT_STAT_POWER) == 0) 272 if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
264 dum->port_status = 0; 273 dum->port_status = 0;
265 else if (!dum->pullup) { 274
275 /* UDC suspend must cause a disconnect */
276 else if (!dum->pullup || dum->udc_suspended) {
266 dum->port_status &= ~(USB_PORT_STAT_CONNECTION | 277 dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
267 USB_PORT_STAT_ENABLE | 278 USB_PORT_STAT_ENABLE |
268 USB_PORT_STAT_LOW_SPEED | 279 USB_PORT_STAT_LOW_SPEED |
@@ -276,7 +287,8 @@ set_link_state (struct dummy *dum)
276 dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); 287 dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
277 if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) 288 if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
278 dum->port_status &= ~USB_PORT_STAT_SUSPEND; 289 dum->port_status &= ~USB_PORT_STAT_SUSPEND;
279 else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0) 290 else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
291 dum->rh_state != DUMMY_RH_SUSPENDED)
280 dum->active = 1; 292 dum->active = 1;
281 } 293 }
282 294
@@ -675,11 +687,16 @@ static int dummy_wakeup (struct usb_gadget *_gadget)
675 struct dummy *dum; 687 struct dummy *dum;
676 688
677 dum = gadget_to_dummy (_gadget); 689 dum = gadget_to_dummy (_gadget);
678 if (!(dum->port_status & USB_PORT_STAT_SUSPEND) 690 if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE)
679 || !(dum->devstatus &
680 ( (1 << USB_DEVICE_B_HNP_ENABLE)
681 | (1 << USB_DEVICE_REMOTE_WAKEUP)))) 691 | (1 << USB_DEVICE_REMOTE_WAKEUP))))
682 return -EINVAL; 692 return -EINVAL;
693 if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0)
694 return -ENOLINK;
695 if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
696 dum->rh_state != DUMMY_RH_SUSPENDED)
697 return -EIO;
698
699 /* FIXME: What if the root hub is suspended but the port isn't? */
683 700
684 /* hub notices our request, issues downstream resume, etc */ 701 /* hub notices our request, issues downstream resume, etc */
685 dum->resuming = 1; 702 dum->resuming = 1;
@@ -917,11 +934,50 @@ static int dummy_udc_remove (struct device *dev)
917 return 0; 934 return 0;
918} 935}
919 936
937static int dummy_udc_suspend (struct device *dev, pm_message_t state,
938 u32 level)
939{
940 struct dummy *dum = dev_get_drvdata(dev);
941
942 if (level != SUSPEND_DISABLE)
943 return 0;
944
945 dev_dbg (dev, "%s\n", __FUNCTION__);
946 spin_lock_irq (&dum->lock);
947 dum->udc_suspended = 1;
948 set_link_state (dum);
949 spin_unlock_irq (&dum->lock);
950
951 dev->power.power_state = state;
952 usb_hcd_poll_rh_status (dummy_to_hcd (dum));
953 return 0;
954}
955
956static int dummy_udc_resume (struct device *dev, u32 level)
957{
958 struct dummy *dum = dev_get_drvdata(dev);
959
960 if (level != RESUME_ENABLE)
961 return 0;
962
963 dev_dbg (dev, "%s\n", __FUNCTION__);
964 spin_lock_irq (&dum->lock);
965 dum->udc_suspended = 0;
966 set_link_state (dum);
967 spin_unlock_irq (&dum->lock);
968
969 dev->power.power_state = PMSG_ON;
970 usb_hcd_poll_rh_status (dummy_to_hcd (dum));
971 return 0;
972}
973
920static struct device_driver dummy_udc_driver = { 974static struct device_driver dummy_udc_driver = {
921 .name = (char *) gadget_name, 975 .name = (char *) gadget_name,
922 .bus = &platform_bus_type, 976 .bus = &platform_bus_type,
923 .probe = dummy_udc_probe, 977 .probe = dummy_udc_probe,
924 .remove = dummy_udc_remove, 978 .remove = dummy_udc_remove,
979 .suspend = dummy_udc_suspend,
980 .resume = dummy_udc_resume,
925}; 981};
926 982
927/*-------------------------------------------------------------------------*/ 983/*-------------------------------------------------------------------------*/
@@ -980,7 +1036,16 @@ static int dummy_urb_enqueue (
980 1036
981static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) 1037static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb)
982{ 1038{
983 /* giveback happens automatically in timer callback */ 1039 struct dummy *dum;
1040 unsigned long flags;
1041
1042 /* giveback happens automatically in timer callback,
1043 * so make sure the callback happens */
1044 dum = hcd_to_dummy (hcd);
1045 spin_lock_irqsave (&dum->lock, flags);
1046 if (dum->rh_state != DUMMY_RH_RUNNING && !list_empty(&dum->urbp_list))
1047 mod_timer (&dum->timer, jiffies);
1048 spin_unlock_irqrestore (&dum->lock, flags);
984 return 0; 1049 return 0;
985} 1050}
986 1051
@@ -1222,7 +1287,8 @@ restart:
1222 if (urb->status != -EINPROGRESS) { 1287 if (urb->status != -EINPROGRESS) {
1223 /* likely it was just unlinked */ 1288 /* likely it was just unlinked */
1224 goto return_urb; 1289 goto return_urb;
1225 } 1290 } else if (dum->rh_state != DUMMY_RH_RUNNING)
1291 continue;
1226 type = usb_pipetype (urb->pipe); 1292 type = usb_pipetype (urb->pipe);
1227 1293
1228 /* used up this frame's non-periodic bandwidth? 1294 /* used up this frame's non-periodic bandwidth?
@@ -1486,12 +1552,12 @@ return_urb:
1486 goto restart; 1552 goto restart;
1487 } 1553 }
1488 1554
1489 /* want a 1 msec delay here */ 1555 if (list_empty (&dum->urbp_list)) {
1490 if (!list_empty (&dum->urbp_list))
1491 mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
1492 else {
1493 usb_put_dev (dum->udev); 1556 usb_put_dev (dum->udev);
1494 dum->udev = NULL; 1557 dum->udev = NULL;
1558 } else if (dum->rh_state == DUMMY_RH_RUNNING) {
1559 /* want a 1 msec delay here */
1560 mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1));
1495 } 1561 }
1496 1562
1497 spin_unlock_irqrestore (&dum->lock, flags); 1563 spin_unlock_irqrestore (&dum->lock, flags);
@@ -1510,11 +1576,13 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
1510{ 1576{
1511 struct dummy *dum; 1577 struct dummy *dum;
1512 unsigned long flags; 1578 unsigned long flags;
1513 int retval; 1579 int retval = 0;
1514 1580
1515 dum = hcd_to_dummy (hcd); 1581 dum = hcd_to_dummy (hcd);
1516 1582
1517 spin_lock_irqsave (&dum->lock, flags); 1583 spin_lock_irqsave (&dum->lock, flags);
1584 if (hcd->state != HC_STATE_RUNNING)
1585 goto done;
1518 1586
1519 if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { 1587 if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
1520 dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 1588 dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
@@ -1522,14 +1590,15 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
1522 set_link_state (dum); 1590 set_link_state (dum);
1523 } 1591 }
1524 1592
1525 if (!(dum->port_status & PORT_C_MASK)) 1593 if ((dum->port_status & PORT_C_MASK) != 0) {
1526 retval = 0;
1527 else {
1528 *buf = (1 << 1); 1594 *buf = (1 << 1);
1529 dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n", 1595 dev_dbg (dummy_dev(dum), "port status 0x%08x has changes\n",
1530 dum->port_status); 1596 dum->port_status);
1531 retval = 1; 1597 retval = 1;
1598 if (dum->rh_state == DUMMY_RH_SUSPENDED)
1599 usb_hcd_resume_root_hub (hcd);
1532 } 1600 }
1601done:
1533 spin_unlock_irqrestore (&dum->lock, flags); 1602 spin_unlock_irqrestore (&dum->lock, flags);
1534 return retval; 1603 return retval;
1535} 1604}
@@ -1559,6 +1628,9 @@ static int dummy_hub_control (
1559 int retval = 0; 1628 int retval = 0;
1560 unsigned long flags; 1629 unsigned long flags;
1561 1630
1631 if (hcd->state != HC_STATE_RUNNING)
1632 return -ETIMEDOUT;
1633
1562 dum = hcd_to_dummy (hcd); 1634 dum = hcd_to_dummy (hcd);
1563 spin_lock_irqsave (&dum->lock, flags); 1635 spin_lock_irqsave (&dum->lock, flags);
1564 switch (typeReq) { 1636 switch (typeReq) {
@@ -1658,6 +1730,7 @@ static int dummy_hub_control (
1658 dum->port_status &= ~(USB_PORT_STAT_ENABLE 1730 dum->port_status &= ~(USB_PORT_STAT_ENABLE
1659 | USB_PORT_STAT_LOW_SPEED 1731 | USB_PORT_STAT_LOW_SPEED
1660 | USB_PORT_STAT_HIGH_SPEED); 1732 | USB_PORT_STAT_HIGH_SPEED);
1733 dum->devstatus = 0;
1661 /* 50msec reset signaling */ 1734 /* 50msec reset signaling */
1662 dum->re_timeout = jiffies + msecs_to_jiffies(50); 1735 dum->re_timeout = jiffies + msecs_to_jiffies(50);
1663 /* FALLS THROUGH */ 1736 /* FALLS THROUGH */
@@ -1684,6 +1757,29 @@ static int dummy_hub_control (
1684 return retval; 1757 return retval;
1685} 1758}
1686 1759
1760static int dummy_hub_suspend (struct usb_hcd *hcd)
1761{
1762 struct dummy *dum = hcd_to_dummy (hcd);
1763
1764 spin_lock_irq (&dum->lock);
1765 dum->rh_state = DUMMY_RH_SUSPENDED;
1766 set_link_state (dum);
1767 spin_unlock_irq (&dum->lock);
1768 return 0;
1769}
1770
1771static int dummy_hub_resume (struct usb_hcd *hcd)
1772{
1773 struct dummy *dum = hcd_to_dummy (hcd);
1774
1775 spin_lock_irq (&dum->lock);
1776 dum->rh_state = DUMMY_RH_RUNNING;
1777 set_link_state (dum);
1778 if (!list_empty(&dum->urbp_list))
1779 mod_timer (&dum->timer, jiffies);
1780 spin_unlock_irq (&dum->lock);
1781 return 0;
1782}
1687 1783
1688/*-------------------------------------------------------------------------*/ 1784/*-------------------------------------------------------------------------*/
1689 1785
@@ -1751,6 +1847,7 @@ static int dummy_start (struct usb_hcd *hcd)
1751 init_timer (&dum->timer); 1847 init_timer (&dum->timer);
1752 dum->timer.function = dummy_timer; 1848 dum->timer.function = dummy_timer;
1753 dum->timer.data = (unsigned long) dum; 1849 dum->timer.data = (unsigned long) dum;
1850 dum->rh_state = DUMMY_RH_RUNNING;
1754 1851
1755 INIT_LIST_HEAD (&dum->urbp_list); 1852 INIT_LIST_HEAD (&dum->urbp_list);
1756 1853
@@ -1803,6 +1900,8 @@ static const struct hc_driver dummy_hcd = {
1803 1900
1804 .hub_status_data = dummy_hub_status, 1901 .hub_status_data = dummy_hub_status,
1805 .hub_control = dummy_hub_control, 1902 .hub_control = dummy_hub_control,
1903 .hub_suspend = dummy_hub_suspend,
1904 .hub_resume = dummy_hub_resume,
1806}; 1905};
1807 1906
1808static int dummy_hcd_probe (struct device *dev) 1907static int dummy_hcd_probe (struct device *dev)
@@ -1836,11 +1935,57 @@ static int dummy_hcd_remove (struct device *dev)
1836 return 0; 1935 return 0;
1837} 1936}
1838 1937
1938static int dummy_hcd_suspend (struct device *dev, pm_message_t state,
1939 u32 level)
1940{
1941 struct usb_hcd *hcd;
1942
1943 if (level != SUSPEND_DISABLE)
1944 return 0;
1945
1946 dev_dbg (dev, "%s\n", __FUNCTION__);
1947 hcd = dev_get_drvdata (dev);
1948
1949#ifndef CONFIG_USB_SUSPEND
1950 /* Otherwise this would never happen */
1951 usb_lock_device (hcd->self.root_hub);
1952 dummy_hub_suspend (hcd);
1953 usb_unlock_device (hcd->self.root_hub);
1954#endif
1955
1956 hcd->state = HC_STATE_SUSPENDED;
1957 return 0;
1958}
1959
1960static int dummy_hcd_resume (struct device *dev, u32 level)
1961{
1962 struct usb_hcd *hcd;
1963
1964 if (level != RESUME_ENABLE)
1965 return 0;
1966
1967 dev_dbg (dev, "%s\n", __FUNCTION__);
1968 hcd = dev_get_drvdata (dev);
1969 hcd->state = HC_STATE_RUNNING;
1970
1971#ifndef CONFIG_USB_SUSPEND
1972 /* Otherwise this would never happen */
1973 usb_lock_device (hcd->self.root_hub);
1974 dummy_hub_resume (hcd);
1975 usb_unlock_device (hcd->self.root_hub);
1976#endif
1977
1978 usb_hcd_poll_rh_status (hcd);
1979 return 0;
1980}
1981
1839static struct device_driver dummy_hcd_driver = { 1982static struct device_driver dummy_hcd_driver = {
1840 .name = (char *) driver_name, 1983 .name = (char *) driver_name,
1841 .bus = &platform_bus_type, 1984 .bus = &platform_bus_type,
1842 .probe = dummy_hcd_probe, 1985 .probe = dummy_hcd_probe,
1843 .remove = dummy_hcd_remove, 1986 .remove = dummy_hcd_remove,
1987 .suspend = dummy_hcd_suspend,
1988 .resume = dummy_hcd_resume,
1844}; 1989};
1845 1990
1846/*-------------------------------------------------------------------------*/ 1991/*-------------------------------------------------------------------------*/