aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb
diff options
context:
space:
mode:
authorAlan Stern <stern@rowland.harvard.edu>2005-05-03 16:24:04 -0400
committerGreg Kroah-Hartman <gregkh@suse.de>2005-06-27 17:43:52 -0400
commitf1c39fad7d1bbea31744138cd3a532ff346cd4ab (patch)
tree8925368cf99ad45b92eb9e42a86615a7ba7640b0 /drivers/usb
parentd9b762510c186584a6be0d3ece03e8a4b2ac13a8 (diff)
[PATCH] USB dummy_hcd: Centralize link state computations
This patch adds to the dummy_hcd driver a new routine for keeping track of all changes in the state of the emulated USB link. The logic is now kept in one spot instead of spread around, and it's easier to verify and update the code. The behavior of the port features has been corrected in a few respects as well (for instance, if the POWER feature is clear then none of the other features can be set). Also added is support for the (relatively new) _connect() and _disconnect() calls of the Gadget API. Signed-off-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/usb')
-rw-r--r--drivers/usb/gadget/dummy_hcd.c254
1 files changed, 162 insertions, 92 deletions
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index dc0e3233b0e9..2d6d22951326 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -163,12 +163,16 @@ struct dummy {
163 struct dummy_request fifo_req; 163 struct dummy_request fifo_req;
164 u8 fifo_buf [FIFO_SIZE]; 164 u8 fifo_buf [FIFO_SIZE];
165 u16 devstatus; 165 u16 devstatus;
166 unsigned pullup:1;
167 unsigned active:1;
168 unsigned old_active:1;
166 169
167 /* 170 /*
168 * MASTER/HOST side support 171 * MASTER/HOST side support
169 */ 172 */
170 struct timer_list timer; 173 struct timer_list timer;
171 u32 port_status; 174 u32 port_status;
175 u32 old_status;
172 unsigned resuming:1; 176 unsigned resuming:1;
173 unsigned long re_timeout; 177 unsigned long re_timeout;
174 178
@@ -215,6 +219,98 @@ static struct dummy *the_controller;
215 219
216/*-------------------------------------------------------------------------*/ 220/*-------------------------------------------------------------------------*/
217 221
222/* SLAVE/GADGET SIDE UTILITY ROUTINES */
223
224/* called with spinlock held */
225static void nuke (struct dummy *dum, struct dummy_ep *ep)
226{
227 while (!list_empty (&ep->queue)) {
228 struct dummy_request *req;
229
230 req = list_entry (ep->queue.next, struct dummy_request, queue);
231 list_del_init (&req->queue);
232 req->req.status = -ESHUTDOWN;
233
234 spin_unlock (&dum->lock);
235 req->req.complete (&ep->ep, &req->req);
236 spin_lock (&dum->lock);
237 }
238}
239
240/* caller must hold lock */
241static void
242stop_activity (struct dummy *dum)
243{
244 struct dummy_ep *ep;
245
246 /* prevent any more requests */
247 dum->address = 0;
248
249 /* The timer is left running so that outstanding URBs can fail */
250
251 /* nuke any pending requests first, so driver i/o is quiesced */
252 list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
253 nuke (dum, ep);
254
255 /* driver now does any non-usb quiescing necessary */
256}
257
258/* caller must hold lock */
259static void
260set_link_state (struct dummy *dum)
261{
262 dum->active = 0;
263 if ((dum->port_status & USB_PORT_STAT_POWER) == 0)
264 dum->port_status = 0;
265 else if (!dum->pullup) {
266 dum->port_status &= ~(USB_PORT_STAT_CONNECTION |
267 USB_PORT_STAT_ENABLE |
268 USB_PORT_STAT_LOW_SPEED |
269 USB_PORT_STAT_HIGH_SPEED |
270 USB_PORT_STAT_SUSPEND);
271 if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0)
272 dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
273 } else {
274 dum->port_status |= USB_PORT_STAT_CONNECTION;
275 if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0)
276 dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
277 if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0)
278 dum->port_status &= ~USB_PORT_STAT_SUSPEND;
279 else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0)
280 dum->active = 1;
281 }
282
283 if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active)
284 dum->resuming = 0;
285
286 if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
287 (dum->port_status & USB_PORT_STAT_RESET) != 0) {
288 if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
289 (dum->old_status & USB_PORT_STAT_RESET) == 0 &&
290 dum->driver) {
291 stop_activity (dum);
292 spin_unlock (&dum->lock);
293 dum->driver->disconnect (&dum->gadget);
294 spin_lock (&dum->lock);
295 }
296 } else if (dum->active != dum->old_active) {
297 if (dum->old_active && dum->driver->suspend) {
298 spin_unlock (&dum->lock);
299 dum->driver->suspend (&dum->gadget);
300 spin_lock (&dum->lock);
301 } else if (!dum->old_active && dum->driver->resume) {
302 spin_unlock (&dum->lock);
303 dum->driver->resume (&dum->gadget);
304 spin_lock (&dum->lock);
305 }
306 }
307
308 dum->old_status = dum->port_status;
309 dum->old_active = dum->active;
310}
311
312/*-------------------------------------------------------------------------*/
313
218/* SLAVE/GADGET SIDE DRIVER 314/* SLAVE/GADGET SIDE DRIVER
219 * 315 *
220 * This only tracks gadget state. All the work is done when the host 316 * This only tracks gadget state. All the work is done when the host
@@ -339,22 +435,6 @@ done:
339 return retval; 435 return retval;
340} 436}
341 437
342/* called with spinlock held */
343static void nuke (struct dummy *dum, struct dummy_ep *ep)
344{
345 while (!list_empty (&ep->queue)) {
346 struct dummy_request *req;
347
348 req = list_entry (ep->queue.next, struct dummy_request, queue);
349 list_del_init (&req->queue);
350 req->req.status = -ESHUTDOWN;
351
352 spin_unlock (&dum->lock);
353 req->req.complete (&ep->ep, &req->req);
354 spin_lock (&dum->lock);
355 }
356}
357
358static int dummy_disable (struct usb_ep *_ep) 438static int dummy_disable (struct usb_ep *_ep)
359{ 439{
360 struct dummy_ep *ep; 440 struct dummy_ep *ep;
@@ -603,7 +683,7 @@ static int dummy_wakeup (struct usb_gadget *_gadget)
603 683
604 /* hub notices our request, issues downstream resume, etc */ 684 /* hub notices our request, issues downstream resume, etc */
605 dum->resuming = 1; 685 dum->resuming = 1;
606 dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 686 dum->re_timeout = jiffies + msecs_to_jiffies(20);
607 return 0; 687 return 0;
608} 688}
609 689
@@ -619,10 +699,24 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
619 return 0; 699 return 0;
620} 700}
621 701
702static int dummy_pullup (struct usb_gadget *_gadget, int value)
703{
704 struct dummy *dum;
705 unsigned long flags;
706
707 dum = gadget_to_dummy (_gadget);
708 spin_lock_irqsave (&dum->lock, flags);
709 dum->pullup = (value != 0);
710 set_link_state (dum);
711 spin_unlock_irqrestore (&dum->lock, flags);
712 return 0;
713}
714
622static const struct usb_gadget_ops dummy_ops = { 715static const struct usb_gadget_ops dummy_ops = {
623 .get_frame = dummy_g_get_frame, 716 .get_frame = dummy_g_get_frame,
624 .wakeup = dummy_wakeup, 717 .wakeup = dummy_wakeup,
625 .set_selfpowered = dummy_set_selfpowered, 718 .set_selfpowered = dummy_set_selfpowered,
719 .pullup = dummy_pullup,
626}; 720};
627 721
628/*-------------------------------------------------------------------------*/ 722/*-------------------------------------------------------------------------*/
@@ -675,7 +769,6 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
675 */ 769 */
676 770
677 dum->devstatus = 0; 771 dum->devstatus = 0;
678 dum->resuming = 0;
679 772
680 INIT_LIST_HEAD (&dum->gadget.ep_list); 773 INIT_LIST_HEAD (&dum->gadget.ep_list);
681 for (i = 0; i < DUMMY_ENDPOINTS; i++) { 774 for (i = 0; i < DUMMY_ENDPOINTS; i++) {
@@ -714,35 +807,14 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver)
714 device_bind_driver (&dum->gadget.dev); 807 device_bind_driver (&dum->gadget.dev);
715 808
716 /* khubd will enumerate this in a while */ 809 /* khubd will enumerate this in a while */
717 dum->port_status |= USB_PORT_STAT_CONNECTION 810 spin_lock_irq (&dum->lock);
718 | (USB_PORT_STAT_C_CONNECTION << 16); 811 dum->pullup = 1;
812 set_link_state (dum);
813 spin_unlock_irq (&dum->lock);
719 return 0; 814 return 0;
720} 815}
721EXPORT_SYMBOL (usb_gadget_register_driver); 816EXPORT_SYMBOL (usb_gadget_register_driver);
722 817
723/* caller must hold lock */
724static void
725stop_activity (struct dummy *dum, struct usb_gadget_driver *driver)
726{
727 struct dummy_ep *ep;
728
729 /* prevent any more requests */
730 dum->address = 0;
731
732 /* The timer is left running so that outstanding URBs can fail */
733
734 /* nuke any pending requests first, so driver i/o is quiesced */
735 list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
736 nuke (dum, ep);
737
738 /* driver now does any non-usb quiescing necessary */
739 if (driver) {
740 spin_unlock (&dum->lock);
741 driver->disconnect (&dum->gadget);
742 spin_lock (&dum->lock);
743 }
744}
745
746int 818int
747usb_gadget_unregister_driver (struct usb_gadget_driver *driver) 819usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
748{ 820{
@@ -758,10 +830,8 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
758 driver->driver.name); 830 driver->driver.name);
759 831
760 spin_lock_irqsave (&dum->lock, flags); 832 spin_lock_irqsave (&dum->lock, flags);
761 stop_activity (dum, driver); 833 dum->pullup = 0;
762 dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | 834 set_link_state (dum);
763 USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED);
764 dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16);
765 spin_unlock_irqrestore (&dum->lock, flags); 835 spin_unlock_irqrestore (&dum->lock, flags);
766 836
767 driver->unbind (&dum->gadget); 837 driver->unbind (&dum->gadget);
@@ -770,6 +840,11 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver)
770 device_release_driver (&dum->gadget.dev); 840 device_release_driver (&dum->gadget.dev);
771 driver_unregister (&driver->driver); 841 driver_unregister (&driver->driver);
772 842
843 spin_lock_irqsave (&dum->lock, flags);
844 dum->pullup = 0;
845 set_link_state (dum);
846 spin_unlock_irqrestore (&dum->lock, flags);
847
773 return 0; 848 return 0;
774} 849}
775EXPORT_SYMBOL (usb_gadget_unregister_driver); 850EXPORT_SYMBOL (usb_gadget_unregister_driver);
@@ -1432,6 +1507,13 @@ static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
1432 dum = hcd_to_dummy (hcd); 1507 dum = hcd_to_dummy (hcd);
1433 1508
1434 spin_lock_irqsave (&dum->lock, flags); 1509 spin_lock_irqsave (&dum->lock, flags);
1510
1511 if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) {
1512 dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1513 dum->port_status &= ~USB_PORT_STAT_SUSPEND;
1514 set_link_state (dum);
1515 }
1516
1435 if (!(dum->port_status & PORT_C_MASK)) 1517 if (!(dum->port_status & PORT_C_MASK))
1436 retval = 0; 1518 retval = 0;
1437 else { 1519 else {
@@ -1480,16 +1562,16 @@ static int dummy_hub_control (
1480 /* 20msec resume signaling */ 1562 /* 20msec resume signaling */
1481 dum->resuming = 1; 1563 dum->resuming = 1;
1482 dum->re_timeout = jiffies + 1564 dum->re_timeout = jiffies +
1483 msecs_to_jiffies(20); 1565 msecs_to_jiffies(20);
1484 } 1566 }
1485 break; 1567 break;
1486 case USB_PORT_FEAT_POWER: 1568 case USB_PORT_FEAT_POWER:
1487 dum->port_status = 0; 1569 if (dum->port_status & USB_PORT_STAT_POWER)
1488 dum->resuming = 0; 1570 dev_dbg (dummy_dev(dum), "power-off\n");
1489 stop_activity(dum, dum->driver); 1571 /* FALLS THROUGH */
1490 break;
1491 default: 1572 default:
1492 dum->port_status &= ~(1 << wValue); 1573 dum->port_status &= ~(1 << wValue);
1574 set_link_state (dum);
1493 } 1575 }
1494 break; 1576 break;
1495 case GetHubDescriptor: 1577 case GetHubDescriptor:
@@ -1505,23 +1587,16 @@ static int dummy_hub_control (
1505 /* whoever resets or resumes must GetPortStatus to 1587 /* whoever resets or resumes must GetPortStatus to
1506 * complete it!! 1588 * complete it!!
1507 */ 1589 */
1508 if (dum->resuming && time_after (jiffies, dum->re_timeout)) { 1590 if (dum->resuming &&
1591 time_after_eq (jiffies, dum->re_timeout)) {
1509 dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); 1592 dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1510 dum->port_status &= ~USB_PORT_STAT_SUSPEND; 1593 dum->port_status &= ~USB_PORT_STAT_SUSPEND;
1511 dum->resuming = 0;
1512 dum->re_timeout = 0;
1513 if (dum->driver && dum->driver->resume) {
1514 spin_unlock (&dum->lock);
1515 dum->driver->resume (&dum->gadget);
1516 spin_lock (&dum->lock);
1517 }
1518 } 1594 }
1519 if ((dum->port_status & USB_PORT_STAT_RESET) != 0 1595 if ((dum->port_status & USB_PORT_STAT_RESET) != 0 &&
1520 && time_after (jiffies, dum->re_timeout)) { 1596 time_after_eq (jiffies, dum->re_timeout)) {
1521 dum->port_status |= (USB_PORT_STAT_C_RESET << 16); 1597 dum->port_status |= (USB_PORT_STAT_C_RESET << 16);
1522 dum->port_status &= ~USB_PORT_STAT_RESET; 1598 dum->port_status &= ~USB_PORT_STAT_RESET;
1523 dum->re_timeout = 0; 1599 if (dum->pullup) {
1524 if (dum->driver) {
1525 dum->port_status |= USB_PORT_STAT_ENABLE; 1600 dum->port_status |= USB_PORT_STAT_ENABLE;
1526 /* give it the best speed we agree on */ 1601 /* give it the best speed we agree on */
1527 dum->gadget.speed = dum->driver->speed; 1602 dum->gadget.speed = dum->driver->speed;
@@ -1542,6 +1617,7 @@ static int dummy_hub_control (
1542 } 1617 }
1543 } 1618 }
1544 } 1619 }
1620 set_link_state (dum);
1545 ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); 1621 ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status);
1546 ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); 1622 ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16);
1547 break; 1623 break;
@@ -1551,42 +1627,36 @@ static int dummy_hub_control (
1551 case SetPortFeature: 1627 case SetPortFeature:
1552 switch (wValue) { 1628 switch (wValue) {
1553 case USB_PORT_FEAT_SUSPEND: 1629 case USB_PORT_FEAT_SUSPEND:
1554 if ((dum->port_status & USB_PORT_STAT_SUSPEND) 1630 if (dum->active) {
1555 == 0) {
1556 dum->port_status |= USB_PORT_STAT_SUSPEND; 1631 dum->port_status |= USB_PORT_STAT_SUSPEND;
1557 if (dum->driver && dum->driver->suspend) { 1632
1558 spin_unlock (&dum->lock); 1633 /* HNP would happen here; for now we
1559 dum->driver->suspend (&dum->gadget); 1634 * assume b_bus_req is always true.
1560 spin_lock (&dum->lock); 1635 */
1561 /* HNP would happen here; for now we 1636 set_link_state (dum);
1562 * assume b_bus_req is always true. 1637 if (((1 << USB_DEVICE_B_HNP_ENABLE)
1563 */ 1638 & dum->devstatus) != 0)
1564 if (((1 << USB_DEVICE_B_HNP_ENABLE) 1639 dev_dbg (dummy_dev(dum),
1565 & dum->devstatus) != 0)
1566 dev_dbg (dummy_dev(dum),
1567 "no HNP yet!\n"); 1640 "no HNP yet!\n");
1568 }
1569 } 1641 }
1570 break; 1642 break;
1643 case USB_PORT_FEAT_POWER:
1644 dum->port_status |= USB_PORT_STAT_POWER;
1645 set_link_state (dum);
1646 break;
1571 case USB_PORT_FEAT_RESET: 1647 case USB_PORT_FEAT_RESET:
1572 /* if it's already running, disconnect first */ 1648 /* if it's already enabled, disable */
1573 if (dum->port_status & USB_PORT_STAT_ENABLE) { 1649 dum->port_status &= ~(USB_PORT_STAT_ENABLE
1574 dum->port_status &= ~(USB_PORT_STAT_ENABLE 1650 | USB_PORT_STAT_LOW_SPEED
1575 | USB_PORT_STAT_LOW_SPEED 1651 | USB_PORT_STAT_HIGH_SPEED);
1576 | USB_PORT_STAT_HIGH_SPEED);
1577 if (dum->driver) {
1578 dev_dbg (udc_dev(dum),
1579 "disconnect\n");
1580 stop_activity (dum, dum->driver);
1581 }
1582
1583 /* FIXME test that code path! */
1584 }
1585 /* 50msec reset signaling */ 1652 /* 50msec reset signaling */
1586 dum->re_timeout = jiffies + msecs_to_jiffies(50); 1653 dum->re_timeout = jiffies + msecs_to_jiffies(50);
1587 /* FALLTHROUGH */ 1654 /* FALLS THROUGH */
1588 default: 1655 default:
1589 dum->port_status |= (1 << wValue); 1656 if ((dum->port_status & USB_PORT_STAT_POWER) != 0) {
1657 dum->port_status |= (1 << wValue);
1658 set_link_state (dum);
1659 }
1590 } 1660 }
1591 break; 1661 break;
1592 1662