diff options
Diffstat (limited to 'drivers/usb/gadget/dummy_hcd.c')
-rw-r--r-- | drivers/usb/gadget/dummy_hcd.c | 745 |
1 files changed, 505 insertions, 240 deletions
diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c index c039d2fbe7ab..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 | ||
70 | static const char driver_name [] = "dummy_hcd"; | 70 | static const char driver_name [] = "dummy_hcd"; |
71 | static const char driver_desc [] = "USB Host+Gadget Emulator"; | 71 | static const char driver_desc [] = "USB Host+Gadget Emulator"; |
@@ -141,6 +141,8 @@ static const char *const ep_name [] = { | |||
141 | }; | 141 | }; |
142 | #define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) | 142 | #define DUMMY_ENDPOINTS (sizeof(ep_name)/sizeof(char *)) |
143 | 143 | ||
144 | /*-------------------------------------------------------------------------*/ | ||
145 | |||
144 | #define FIFO_SIZE 64 | 146 | #define FIFO_SIZE 64 |
145 | 147 | ||
146 | struct urbp { | 148 | struct urbp { |
@@ -148,6 +150,13 @@ struct urbp { | |||
148 | struct list_head urbp_list; | 150 | struct list_head urbp_list; |
149 | }; | 151 | }; |
150 | 152 | ||
153 | |||
154 | enum dummy_rh_state { | ||
155 | DUMMY_RH_RESET, | ||
156 | DUMMY_RH_SUSPENDED, | ||
157 | DUMMY_RH_RUNNING | ||
158 | }; | ||
159 | |||
151 | struct dummy { | 160 | struct dummy { |
152 | spinlock_t lock; | 161 | spinlock_t lock; |
153 | 162 | ||
@@ -161,12 +170,18 @@ struct dummy { | |||
161 | struct dummy_request fifo_req; | 170 | struct dummy_request fifo_req; |
162 | u8 fifo_buf [FIFO_SIZE]; | 171 | u8 fifo_buf [FIFO_SIZE]; |
163 | u16 devstatus; | 172 | u16 devstatus; |
173 | unsigned udc_suspended:1; | ||
174 | unsigned pullup:1; | ||
175 | unsigned active:1; | ||
176 | unsigned old_active:1; | ||
164 | 177 | ||
165 | /* | 178 | /* |
166 | * MASTER/HOST side support | 179 | * MASTER/HOST side support |
167 | */ | 180 | */ |
181 | enum dummy_rh_state rh_state; | ||
168 | struct timer_list timer; | 182 | struct timer_list timer; |
169 | u32 port_status; | 183 | u32 port_status; |
184 | u32 old_status; | ||
170 | unsigned resuming:1; | 185 | unsigned resuming:1; |
171 | unsigned long re_timeout; | 186 | unsigned long re_timeout; |
172 | 187 | ||
@@ -189,6 +204,11 @@ static inline struct device *dummy_dev (struct dummy *dum) | |||
189 | return dummy_to_hcd(dum)->self.controller; | 204 | return dummy_to_hcd(dum)->self.controller; |
190 | } | 205 | } |
191 | 206 | ||
207 | static inline struct device *udc_dev (struct dummy *dum) | ||
208 | { | ||
209 | return dum->gadget.dev.parent; | ||
210 | } | ||
211 | |||
192 | static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) | 212 | static inline struct dummy *ep_to_dummy (struct dummy_ep *ep) |
193 | { | 213 | { |
194 | return container_of (ep->gadget, struct dummy, gadget); | 214 | return container_of (ep->gadget, struct dummy, gadget); |
@@ -208,16 +228,98 @@ static struct dummy *the_controller; | |||
208 | 228 | ||
209 | /*-------------------------------------------------------------------------*/ | 229 | /*-------------------------------------------------------------------------*/ |
210 | 230 | ||
211 | /* | 231 | /* SLAVE/GADGET SIDE UTILITY ROUTINES */ |
212 | * This "hardware" may look a bit odd in diagnostics since it's got both | ||
213 | * host and device sides; and it binds different drivers to each side. | ||
214 | */ | ||
215 | static struct platform_device the_pdev; | ||
216 | 232 | ||
217 | static struct device_driver dummy_driver = { | 233 | /* called with spinlock held */ |
218 | .name = (char *) driver_name, | 234 | static void nuke (struct dummy *dum, struct dummy_ep *ep) |
219 | .bus = &platform_bus_type, | 235 | { |
220 | }; | 236 | while (!list_empty (&ep->queue)) { |
237 | struct dummy_request *req; | ||
238 | |||
239 | req = list_entry (ep->queue.next, struct dummy_request, queue); | ||
240 | list_del_init (&req->queue); | ||
241 | req->req.status = -ESHUTDOWN; | ||
242 | |||
243 | spin_unlock (&dum->lock); | ||
244 | req->req.complete (&ep->ep, &req->req); | ||
245 | spin_lock (&dum->lock); | ||
246 | } | ||
247 | } | ||
248 | |||
249 | /* caller must hold lock */ | ||
250 | static void | ||
251 | stop_activity (struct dummy *dum) | ||
252 | { | ||
253 | struct dummy_ep *ep; | ||
254 | |||
255 | /* prevent any more requests */ | ||
256 | dum->address = 0; | ||
257 | |||
258 | /* The timer is left running so that outstanding URBs can fail */ | ||
259 | |||
260 | /* nuke any pending requests first, so driver i/o is quiesced */ | ||
261 | list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) | ||
262 | nuke (dum, ep); | ||
263 | |||
264 | /* driver now does any non-usb quiescing necessary */ | ||
265 | } | ||
266 | |||
267 | /* caller must hold lock */ | ||
268 | static void | ||
269 | set_link_state (struct dummy *dum) | ||
270 | { | ||
271 | dum->active = 0; | ||
272 | if ((dum->port_status & USB_PORT_STAT_POWER) == 0) | ||
273 | dum->port_status = 0; | ||
274 | |||
275 | /* UDC suspend must cause a disconnect */ | ||
276 | else if (!dum->pullup || dum->udc_suspended) { | ||
277 | dum->port_status &= ~(USB_PORT_STAT_CONNECTION | | ||
278 | USB_PORT_STAT_ENABLE | | ||
279 | USB_PORT_STAT_LOW_SPEED | | ||
280 | USB_PORT_STAT_HIGH_SPEED | | ||
281 | USB_PORT_STAT_SUSPEND); | ||
282 | if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0) | ||
283 | dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); | ||
284 | } else { | ||
285 | dum->port_status |= USB_PORT_STAT_CONNECTION; | ||
286 | if ((dum->old_status & USB_PORT_STAT_CONNECTION) == 0) | ||
287 | dum->port_status |= (USB_PORT_STAT_C_CONNECTION << 16); | ||
288 | if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0) | ||
289 | dum->port_status &= ~USB_PORT_STAT_SUSPEND; | ||
290 | else if ((dum->port_status & USB_PORT_STAT_SUSPEND) == 0 && | ||
291 | dum->rh_state != DUMMY_RH_SUSPENDED) | ||
292 | dum->active = 1; | ||
293 | } | ||
294 | |||
295 | if ((dum->port_status & USB_PORT_STAT_ENABLE) == 0 || dum->active) | ||
296 | dum->resuming = 0; | ||
297 | |||
298 | if ((dum->port_status & USB_PORT_STAT_CONNECTION) == 0 || | ||
299 | (dum->port_status & USB_PORT_STAT_RESET) != 0) { | ||
300 | if ((dum->old_status & USB_PORT_STAT_CONNECTION) != 0 && | ||
301 | (dum->old_status & USB_PORT_STAT_RESET) == 0 && | ||
302 | dum->driver) { | ||
303 | stop_activity (dum); | ||
304 | spin_unlock (&dum->lock); | ||
305 | dum->driver->disconnect (&dum->gadget); | ||
306 | spin_lock (&dum->lock); | ||
307 | } | ||
308 | } else if (dum->active != dum->old_active) { | ||
309 | if (dum->old_active && dum->driver->suspend) { | ||
310 | spin_unlock (&dum->lock); | ||
311 | dum->driver->suspend (&dum->gadget); | ||
312 | spin_lock (&dum->lock); | ||
313 | } else if (!dum->old_active && dum->driver->resume) { | ||
314 | spin_unlock (&dum->lock); | ||
315 | dum->driver->resume (&dum->gadget); | ||
316 | spin_lock (&dum->lock); | ||
317 | } | ||
318 | } | ||
319 | |||
320 | dum->old_status = dum->port_status; | ||
321 | dum->old_active = dum->active; | ||
322 | } | ||
221 | 323 | ||
222 | /*-------------------------------------------------------------------------*/ | 324 | /*-------------------------------------------------------------------------*/ |
223 | 325 | ||
@@ -324,7 +426,7 @@ dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc) | |||
324 | _ep->maxpacket = max; | 426 | _ep->maxpacket = max; |
325 | ep->desc = desc; | 427 | ep->desc = desc; |
326 | 428 | ||
327 | dev_dbg (dummy_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", | 429 | dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n", |
328 | _ep->name, | 430 | _ep->name, |
329 | desc->bEndpointAddress & 0x0f, | 431 | desc->bEndpointAddress & 0x0f, |
330 | (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", | 432 | (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out", |
@@ -345,22 +447,6 @@ done: | |||
345 | return retval; | 447 | return retval; |
346 | } | 448 | } |
347 | 449 | ||
348 | /* called with spinlock held */ | ||
349 | static void nuke (struct dummy *dum, struct dummy_ep *ep) | ||
350 | { | ||
351 | while (!list_empty (&ep->queue)) { | ||
352 | struct dummy_request *req; | ||
353 | |||
354 | req = list_entry (ep->queue.next, struct dummy_request, queue); | ||
355 | list_del_init (&req->queue); | ||
356 | req->req.status = -ESHUTDOWN; | ||
357 | |||
358 | spin_unlock (&dum->lock); | ||
359 | req->req.complete (&ep->ep, &req->req); | ||
360 | spin_lock (&dum->lock); | ||
361 | } | ||
362 | } | ||
363 | |||
364 | static int dummy_disable (struct usb_ep *_ep) | 450 | static int dummy_disable (struct usb_ep *_ep) |
365 | { | 451 | { |
366 | struct dummy_ep *ep; | 452 | struct dummy_ep *ep; |
@@ -379,7 +465,7 @@ static int dummy_disable (struct usb_ep *_ep) | |||
379 | nuke (dum, ep); | 465 | nuke (dum, ep); |
380 | spin_unlock_irqrestore (&dum->lock, flags); | 466 | spin_unlock_irqrestore (&dum->lock, flags); |
381 | 467 | ||
382 | dev_dbg (dummy_dev(dum), "disabled %s\n", _ep->name); | 468 | dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name); |
383 | return retval; | 469 | return retval; |
384 | } | 470 | } |
385 | 471 | ||
@@ -474,7 +560,7 @@ dummy_queue (struct usb_ep *_ep, struct usb_request *_req, int mem_flags) | |||
474 | return -ESHUTDOWN; | 560 | return -ESHUTDOWN; |
475 | 561 | ||
476 | #if 0 | 562 | #if 0 |
477 | dev_dbg (dummy_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", | 563 | dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n", |
478 | ep, _req, _ep->name, _req->length, _req->buf); | 564 | ep, _req, _ep->name, _req->length, _req->buf); |
479 | #endif | 565 | #endif |
480 | 566 | ||
@@ -537,7 +623,7 @@ static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req) | |||
537 | spin_unlock_irqrestore (&dum->lock, flags); | 623 | spin_unlock_irqrestore (&dum->lock, flags); |
538 | 624 | ||
539 | if (retval == 0) { | 625 | if (retval == 0) { |
540 | dev_dbg (dummy_dev(dum), | 626 | dev_dbg (udc_dev(dum), |
541 | "dequeued req %p from %s, len %d buf %p\n", | 627 | "dequeued req %p from %s, len %d buf %p\n", |
542 | req, _ep->name, _req->length, _req->buf); | 628 | req, _ep->name, _req->length, _req->buf); |
543 | _req->complete (_ep, _req); | 629 | _req->complete (_ep, _req); |
@@ -601,13 +687,21 @@ static int dummy_wakeup (struct usb_gadget *_gadget) | |||
601 | struct dummy *dum; | 687 | struct dummy *dum; |
602 | 688 | ||
603 | dum = gadget_to_dummy (_gadget); | 689 | dum = gadget_to_dummy (_gadget); |
604 | if ((dum->devstatus & (1 << USB_DEVICE_REMOTE_WAKEUP)) == 0 | 690 | if (!(dum->devstatus & ( (1 << USB_DEVICE_B_HNP_ENABLE) |
605 | || !(dum->port_status & (1 << USB_PORT_FEAT_SUSPEND))) | 691 | | (1 << USB_DEVICE_REMOTE_WAKEUP)))) |
606 | 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? */ | ||
607 | 700 | ||
608 | /* hub notices our request, issues downstream resume, etc */ | 701 | /* hub notices our request, issues downstream resume, etc */ |
609 | dum->resuming = 1; | 702 | dum->resuming = 1; |
610 | dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); | 703 | dum->re_timeout = jiffies + msecs_to_jiffies(20); |
704 | mod_timer (&dummy_to_hcd (dum)->rh_timer, dum->re_timeout); | ||
611 | return 0; | 705 | return 0; |
612 | } | 706 | } |
613 | 707 | ||
@@ -623,10 +717,26 @@ static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value) | |||
623 | return 0; | 717 | return 0; |
624 | } | 718 | } |
625 | 719 | ||
720 | static int dummy_pullup (struct usb_gadget *_gadget, int value) | ||
721 | { | ||
722 | struct dummy *dum; | ||
723 | unsigned long flags; | ||
724 | |||
725 | dum = gadget_to_dummy (_gadget); | ||
726 | spin_lock_irqsave (&dum->lock, flags); | ||
727 | dum->pullup = (value != 0); | ||
728 | set_link_state (dum); | ||
729 | spin_unlock_irqrestore (&dum->lock, flags); | ||
730 | |||
731 | usb_hcd_poll_rh_status (dummy_to_hcd (dum)); | ||
732 | return 0; | ||
733 | } | ||
734 | |||
626 | static const struct usb_gadget_ops dummy_ops = { | 735 | static const struct usb_gadget_ops dummy_ops = { |
627 | .get_frame = dummy_g_get_frame, | 736 | .get_frame = dummy_g_get_frame, |
628 | .wakeup = dummy_wakeup, | 737 | .wakeup = dummy_wakeup, |
629 | .set_selfpowered = dummy_set_selfpowered, | 738 | .set_selfpowered = dummy_set_selfpowered, |
739 | .pullup = dummy_pullup, | ||
630 | }; | 740 | }; |
631 | 741 | ||
632 | /*-------------------------------------------------------------------------*/ | 742 | /*-------------------------------------------------------------------------*/ |
@@ -641,7 +751,7 @@ show_function (struct device *dev, struct device_attribute *attr, char *buf) | |||
641 | return 0; | 751 | return 0; |
642 | return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); | 752 | return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function); |
643 | } | 753 | } |
644 | DEVICE_ATTR (function, S_IRUGO, show_function, NULL); | 754 | static DEVICE_ATTR (function, S_IRUGO, show_function, NULL); |
645 | 755 | ||
646 | /*-------------------------------------------------------------------------*/ | 756 | /*-------------------------------------------------------------------------*/ |
647 | 757 | ||
@@ -659,38 +769,6 @@ DEVICE_ATTR (function, S_IRUGO, show_function, NULL); | |||
659 | * for each driver that registers: just add to a big root hub. | 769 | * for each driver that registers: just add to a big root hub. |
660 | */ | 770 | */ |
661 | 771 | ||
662 | static void | ||
663 | dummy_udc_release (struct device *dev) | ||
664 | { | ||
665 | } | ||
666 | |||
667 | static void | ||
668 | dummy_pdev_release (struct device *dev) | ||
669 | { | ||
670 | } | ||
671 | |||
672 | static int | ||
673 | dummy_register_udc (struct dummy *dum) | ||
674 | { | ||
675 | int rc; | ||
676 | |||
677 | strcpy (dum->gadget.dev.bus_id, "udc"); | ||
678 | dum->gadget.dev.parent = dummy_dev(dum); | ||
679 | dum->gadget.dev.release = dummy_udc_release; | ||
680 | |||
681 | rc = device_register (&dum->gadget.dev); | ||
682 | if (rc == 0) | ||
683 | device_create_file (&dum->gadget.dev, &dev_attr_function); | ||
684 | return rc; | ||
685 | } | ||
686 | |||
687 | static void | ||
688 | dummy_unregister_udc (struct dummy *dum) | ||
689 | { | ||
690 | device_remove_file (&dum->gadget.dev, &dev_attr_function); | ||
691 | device_unregister (&dum->gadget.dev); | ||
692 | } | ||
693 | |||
694 | int | 772 | int |
695 | usb_gadget_register_driver (struct usb_gadget_driver *driver) | 773 | usb_gadget_register_driver (struct usb_gadget_driver *driver) |
696 | { | 774 | { |
@@ -709,12 +787,8 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) | |||
709 | * SLAVE side init ... the layer above hardware, which | 787 | * SLAVE side init ... the layer above hardware, which |
710 | * can't enumerate without help from the driver we're binding. | 788 | * can't enumerate without help from the driver we're binding. |
711 | */ | 789 | */ |
712 | dum->gadget.name = gadget_name; | ||
713 | dum->gadget.ops = &dummy_ops; | ||
714 | dum->gadget.is_dualspeed = 1; | ||
715 | 790 | ||
716 | dum->devstatus = 0; | 791 | dum->devstatus = 0; |
717 | dum->resuming = 0; | ||
718 | 792 | ||
719 | INIT_LIST_HEAD (&dum->gadget.ep_list); | 793 | INIT_LIST_HEAD (&dum->gadget.ep_list); |
720 | for (i = 0; i < DUMMY_ENDPOINTS; i++) { | 794 | for (i = 0; i < DUMMY_ENDPOINTS; i++) { |
@@ -740,7 +814,7 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) | |||
740 | 814 | ||
741 | dum->driver = driver; | 815 | dum->driver = driver; |
742 | dum->gadget.dev.driver = &driver->driver; | 816 | dum->gadget.dev.driver = &driver->driver; |
743 | dev_dbg (dummy_dev(dum), "binding gadget driver '%s'\n", | 817 | dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n", |
744 | driver->driver.name); | 818 | driver->driver.name); |
745 | if ((retval = driver->bind (&dum->gadget)) != 0) { | 819 | if ((retval = driver->bind (&dum->gadget)) != 0) { |
746 | dum->driver = NULL; | 820 | dum->driver = NULL; |
@@ -748,42 +822,21 @@ usb_gadget_register_driver (struct usb_gadget_driver *driver) | |||
748 | return retval; | 822 | return retval; |
749 | } | 823 | } |
750 | 824 | ||
751 | // FIXME: Check these calls for errors and re-order | ||
752 | driver->driver.bus = dum->gadget.dev.parent->bus; | 825 | driver->driver.bus = dum->gadget.dev.parent->bus; |
753 | driver_register (&driver->driver); | 826 | driver_register (&driver->driver); |
754 | |||
755 | device_bind_driver (&dum->gadget.dev); | 827 | device_bind_driver (&dum->gadget.dev); |
756 | 828 | ||
757 | /* khubd will enumerate this in a while */ | 829 | /* khubd will enumerate this in a while */ |
758 | dum->port_status |= USB_PORT_STAT_CONNECTION | 830 | spin_lock_irq (&dum->lock); |
759 | | (1 << USB_PORT_FEAT_C_CONNECTION); | 831 | dum->pullup = 1; |
832 | set_link_state (dum); | ||
833 | spin_unlock_irq (&dum->lock); | ||
834 | |||
835 | usb_hcd_poll_rh_status (dummy_to_hcd (dum)); | ||
760 | return 0; | 836 | return 0; |
761 | } | 837 | } |
762 | EXPORT_SYMBOL (usb_gadget_register_driver); | 838 | EXPORT_SYMBOL (usb_gadget_register_driver); |
763 | 839 | ||
764 | /* caller must hold lock */ | ||
765 | static void | ||
766 | stop_activity (struct dummy *dum, struct usb_gadget_driver *driver) | ||
767 | { | ||
768 | struct dummy_ep *ep; | ||
769 | |||
770 | /* prevent any more requests */ | ||
771 | dum->address = 0; | ||
772 | |||
773 | /* The timer is left running so that outstanding URBs can fail */ | ||
774 | |||
775 | /* nuke any pending requests first, so driver i/o is quiesced */ | ||
776 | list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list) | ||
777 | nuke (dum, ep); | ||
778 | |||
779 | /* driver now does any non-usb quiescing necessary */ | ||
780 | if (driver) { | ||
781 | spin_unlock (&dum->lock); | ||
782 | driver->disconnect (&dum->gadget); | ||
783 | spin_lock (&dum->lock); | ||
784 | } | ||
785 | } | ||
786 | |||
787 | int | 840 | int |
788 | usb_gadget_unregister_driver (struct usb_gadget_driver *driver) | 841 | usb_gadget_unregister_driver (struct usb_gadget_driver *driver) |
789 | { | 842 | { |
@@ -795,35 +848,138 @@ usb_gadget_unregister_driver (struct usb_gadget_driver *driver) | |||
795 | if (!driver || driver != dum->driver) | 848 | if (!driver || driver != dum->driver) |
796 | return -EINVAL; | 849 | return -EINVAL; |
797 | 850 | ||
798 | dev_dbg (dummy_dev(dum), "unregister gadget driver '%s'\n", | 851 | dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n", |
799 | driver->driver.name); | 852 | driver->driver.name); |
800 | 853 | ||
801 | spin_lock_irqsave (&dum->lock, flags); | 854 | spin_lock_irqsave (&dum->lock, flags); |
802 | stop_activity (dum, driver); | 855 | dum->pullup = 0; |
803 | dum->port_status &= ~(USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | | 856 | set_link_state (dum); |
804 | USB_PORT_STAT_LOW_SPEED | USB_PORT_STAT_HIGH_SPEED); | ||
805 | dum->port_status |= (1 << USB_PORT_FEAT_C_CONNECTION); | ||
806 | spin_unlock_irqrestore (&dum->lock, flags); | 857 | spin_unlock_irqrestore (&dum->lock, flags); |
807 | 858 | ||
808 | driver->unbind (&dum->gadget); | 859 | driver->unbind (&dum->gadget); |
809 | dum->driver = NULL; | 860 | dum->driver = NULL; |
810 | 861 | ||
811 | device_release_driver (&dum->gadget.dev); | 862 | device_release_driver (&dum->gadget.dev); |
812 | |||
813 | driver_unregister (&driver->driver); | 863 | driver_unregister (&driver->driver); |
814 | 864 | ||
865 | spin_lock_irqsave (&dum->lock, flags); | ||
866 | dum->pullup = 0; | ||
867 | set_link_state (dum); | ||
868 | spin_unlock_irqrestore (&dum->lock, flags); | ||
869 | |||
870 | usb_hcd_poll_rh_status (dummy_to_hcd (dum)); | ||
815 | return 0; | 871 | return 0; |
816 | } | 872 | } |
817 | EXPORT_SYMBOL (usb_gadget_unregister_driver); | 873 | EXPORT_SYMBOL (usb_gadget_unregister_driver); |
818 | 874 | ||
819 | #undef is_enabled | 875 | #undef is_enabled |
820 | 876 | ||
877 | /* just declare this in any driver that really need it */ | ||
878 | extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode); | ||
879 | |||
821 | int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) | 880 | int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode) |
822 | { | 881 | { |
823 | return -ENOSYS; | 882 | return -ENOSYS; |
824 | } | 883 | } |
825 | EXPORT_SYMBOL (net2280_set_fifo_mode); | 884 | EXPORT_SYMBOL (net2280_set_fifo_mode); |
826 | 885 | ||
886 | |||
887 | /* The gadget structure is stored inside the hcd structure and will be | ||
888 | * released along with it. */ | ||
889 | static void | ||
890 | dummy_gadget_release (struct device *dev) | ||
891 | { | ||
892 | #if 0 /* usb_bus_put isn't EXPORTed! */ | ||
893 | struct dummy *dum = gadget_dev_to_dummy (dev); | ||
894 | |||
895 | usb_bus_put (&dummy_to_hcd (dum)->self); | ||
896 | #endif | ||
897 | } | ||
898 | |||
899 | static int dummy_udc_probe (struct device *dev) | ||
900 | { | ||
901 | struct dummy *dum = the_controller; | ||
902 | int rc; | ||
903 | |||
904 | dum->gadget.name = gadget_name; | ||
905 | dum->gadget.ops = &dummy_ops; | ||
906 | dum->gadget.is_dualspeed = 1; | ||
907 | |||
908 | /* maybe claim OTG support, though we won't complete HNP */ | ||
909 | dum->gadget.is_otg = (dummy_to_hcd(dum)->self.otg_port != 0); | ||
910 | |||
911 | strcpy (dum->gadget.dev.bus_id, "gadget"); | ||
912 | dum->gadget.dev.parent = dev; | ||
913 | dum->gadget.dev.release = dummy_gadget_release; | ||
914 | rc = device_register (&dum->gadget.dev); | ||
915 | if (rc < 0) | ||
916 | return rc; | ||
917 | |||
918 | #if 0 /* usb_bus_get isn't EXPORTed! */ | ||
919 | usb_bus_get (&dummy_to_hcd (dum)->self); | ||
920 | #endif | ||
921 | |||
922 | dev_set_drvdata (dev, dum); | ||
923 | device_create_file (&dum->gadget.dev, &dev_attr_function); | ||
924 | return rc; | ||
925 | } | ||
926 | |||
927 | static int dummy_udc_remove (struct device *dev) | ||
928 | { | ||
929 | struct dummy *dum = dev_get_drvdata (dev); | ||
930 | |||
931 | dev_set_drvdata (dev, NULL); | ||
932 | device_remove_file (&dum->gadget.dev, &dev_attr_function); | ||
933 | device_unregister (&dum->gadget.dev); | ||
934 | return 0; | ||
935 | } | ||
936 | |||
937 | static 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 | |||
956 | static 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 | |||
974 | static struct device_driver dummy_udc_driver = { | ||
975 | .name = (char *) gadget_name, | ||
976 | .bus = &platform_bus_type, | ||
977 | .probe = dummy_udc_probe, | ||
978 | .remove = dummy_udc_remove, | ||
979 | .suspend = dummy_udc_suspend, | ||
980 | .resume = dummy_udc_resume, | ||
981 | }; | ||
982 | |||
827 | /*-------------------------------------------------------------------------*/ | 983 | /*-------------------------------------------------------------------------*/ |
828 | 984 | ||
829 | /* MASTER/HOST SIDE DRIVER | 985 | /* MASTER/HOST SIDE DRIVER |
@@ -880,7 +1036,16 @@ static int dummy_urb_enqueue ( | |||
880 | 1036 | ||
881 | static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) | 1037 | static int dummy_urb_dequeue (struct usb_hcd *hcd, struct urb *urb) |
882 | { | 1038 | { |
883 | /* 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); | ||
884 | return 0; | 1049 | return 0; |
885 | } | 1050 | } |
886 | 1051 | ||
@@ -1025,7 +1190,6 @@ static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep) | |||
1025 | 1190 | ||
1026 | /* high bandwidth mode */ | 1191 | /* high bandwidth mode */ |
1027 | tmp = le16_to_cpu(ep->desc->wMaxPacketSize); | 1192 | tmp = le16_to_cpu(ep->desc->wMaxPacketSize); |
1028 | tmp = le16_to_cpu (tmp); | ||
1029 | tmp = (tmp >> 11) & 0x03; | 1193 | tmp = (tmp >> 11) & 0x03; |
1030 | tmp *= 8 /* applies to entire frame */; | 1194 | tmp *= 8 /* applies to entire frame */; |
1031 | limit += limit * tmp; | 1195 | limit += limit * tmp; |
@@ -1123,7 +1287,8 @@ restart: | |||
1123 | if (urb->status != -EINPROGRESS) { | 1287 | if (urb->status != -EINPROGRESS) { |
1124 | /* likely it was just unlinked */ | 1288 | /* likely it was just unlinked */ |
1125 | goto return_urb; | 1289 | goto return_urb; |
1126 | } | 1290 | } else if (dum->rh_state != DUMMY_RH_RUNNING) |
1291 | continue; | ||
1127 | type = usb_pipetype (urb->pipe); | 1292 | type = usb_pipetype (urb->pipe); |
1128 | 1293 | ||
1129 | /* used up this frame's non-periodic bandwidth? | 1294 | /* used up this frame's non-periodic bandwidth? |
@@ -1168,12 +1333,14 @@ restart: | |||
1168 | struct usb_ctrlrequest setup; | 1333 | struct usb_ctrlrequest setup; |
1169 | int value = 1; | 1334 | int value = 1; |
1170 | struct dummy_ep *ep2; | 1335 | struct dummy_ep *ep2; |
1336 | unsigned w_index; | ||
1337 | unsigned w_value; | ||
1171 | 1338 | ||
1172 | setup = *(struct usb_ctrlrequest*) urb->setup_packet; | 1339 | setup = *(struct usb_ctrlrequest*) urb->setup_packet; |
1173 | le16_to_cpus (&setup.wIndex); | 1340 | w_index = le16_to_cpu(setup.wIndex); |
1174 | le16_to_cpus (&setup.wValue); | 1341 | w_value = le16_to_cpu(setup.wValue); |
1175 | le16_to_cpus (&setup.wLength); | 1342 | if (le16_to_cpu(setup.wLength) != |
1176 | if (setup.wLength != urb->transfer_buffer_length) { | 1343 | urb->transfer_buffer_length) { |
1177 | maybe_set_status (urb, -EOVERFLOW); | 1344 | maybe_set_status (urb, -EOVERFLOW); |
1178 | goto return_urb; | 1345 | goto return_urb; |
1179 | } | 1346 | } |
@@ -1182,7 +1349,7 @@ restart: | |||
1182 | list_for_each_entry (req, &ep->queue, queue) { | 1349 | list_for_each_entry (req, &ep->queue, queue) { |
1183 | list_del_init (&req->queue); | 1350 | list_del_init (&req->queue); |
1184 | req->req.status = -EOVERFLOW; | 1351 | req->req.status = -EOVERFLOW; |
1185 | dev_dbg (dummy_dev(dum), "stale req = %p\n", | 1352 | dev_dbg (udc_dev(dum), "stale req = %p\n", |
1186 | req); | 1353 | req); |
1187 | 1354 | ||
1188 | spin_unlock (&dum->lock); | 1355 | spin_unlock (&dum->lock); |
@@ -1203,31 +1370,40 @@ restart: | |||
1203 | case USB_REQ_SET_ADDRESS: | 1370 | case USB_REQ_SET_ADDRESS: |
1204 | if (setup.bRequestType != Dev_Request) | 1371 | if (setup.bRequestType != Dev_Request) |
1205 | break; | 1372 | break; |
1206 | dum->address = setup.wValue; | 1373 | dum->address = w_value; |
1207 | maybe_set_status (urb, 0); | 1374 | maybe_set_status (urb, 0); |
1208 | dev_dbg (dummy_dev(dum), "set_address = %d\n", | 1375 | dev_dbg (udc_dev(dum), "set_address = %d\n", |
1209 | setup.wValue); | 1376 | w_value); |
1210 | value = 0; | 1377 | value = 0; |
1211 | break; | 1378 | break; |
1212 | case USB_REQ_SET_FEATURE: | 1379 | case USB_REQ_SET_FEATURE: |
1213 | if (setup.bRequestType == Dev_Request) { | 1380 | if (setup.bRequestType == Dev_Request) { |
1214 | value = 0; | 1381 | value = 0; |
1215 | switch (setup.wValue) { | 1382 | switch (w_value) { |
1216 | case USB_DEVICE_REMOTE_WAKEUP: | 1383 | case USB_DEVICE_REMOTE_WAKEUP: |
1217 | break; | 1384 | break; |
1385 | case USB_DEVICE_B_HNP_ENABLE: | ||
1386 | dum->gadget.b_hnp_enable = 1; | ||
1387 | break; | ||
1388 | case USB_DEVICE_A_HNP_SUPPORT: | ||
1389 | dum->gadget.a_hnp_support = 1; | ||
1390 | break; | ||
1391 | case USB_DEVICE_A_ALT_HNP_SUPPORT: | ||
1392 | dum->gadget.a_alt_hnp_support | ||
1393 | = 1; | ||
1394 | break; | ||
1218 | default: | 1395 | default: |
1219 | value = -EOPNOTSUPP; | 1396 | value = -EOPNOTSUPP; |
1220 | } | 1397 | } |
1221 | if (value == 0) { | 1398 | if (value == 0) { |
1222 | dum->devstatus |= | 1399 | dum->devstatus |= |
1223 | (1 << setup.wValue); | 1400 | (1 << w_value); |
1224 | maybe_set_status (urb, 0); | 1401 | maybe_set_status (urb, 0); |
1225 | } | 1402 | } |
1226 | 1403 | ||
1227 | } else if (setup.bRequestType == Ep_Request) { | 1404 | } else if (setup.bRequestType == Ep_Request) { |
1228 | // endpoint halt | 1405 | // endpoint halt |
1229 | ep2 = find_endpoint (dum, | 1406 | ep2 = find_endpoint (dum, w_index); |
1230 | setup.wIndex); | ||
1231 | if (!ep2) { | 1407 | if (!ep2) { |
1232 | value = -EOPNOTSUPP; | 1408 | value = -EOPNOTSUPP; |
1233 | break; | 1409 | break; |
@@ -1239,7 +1415,7 @@ restart: | |||
1239 | break; | 1415 | break; |
1240 | case USB_REQ_CLEAR_FEATURE: | 1416 | case USB_REQ_CLEAR_FEATURE: |
1241 | if (setup.bRequestType == Dev_Request) { | 1417 | if (setup.bRequestType == Dev_Request) { |
1242 | switch (setup.wValue) { | 1418 | switch (w_value) { |
1243 | case USB_DEVICE_REMOTE_WAKEUP: | 1419 | case USB_DEVICE_REMOTE_WAKEUP: |
1244 | dum->devstatus &= ~(1 << | 1420 | dum->devstatus &= ~(1 << |
1245 | USB_DEVICE_REMOTE_WAKEUP); | 1421 | USB_DEVICE_REMOTE_WAKEUP); |
@@ -1252,8 +1428,7 @@ restart: | |||
1252 | } | 1428 | } |
1253 | } else if (setup.bRequestType == Ep_Request) { | 1429 | } else if (setup.bRequestType == Ep_Request) { |
1254 | // endpoint halt | 1430 | // endpoint halt |
1255 | ep2 = find_endpoint (dum, | 1431 | ep2 = find_endpoint (dum, w_index); |
1256 | setup.wIndex); | ||
1257 | if (!ep2) { | 1432 | if (!ep2) { |
1258 | value = -EOPNOTSUPP; | 1433 | value = -EOPNOTSUPP; |
1259 | break; | 1434 | break; |
@@ -1279,7 +1454,7 @@ restart: | |||
1279 | if (urb->transfer_buffer_length > 0) { | 1454 | if (urb->transfer_buffer_length > 0) { |
1280 | if (setup.bRequestType == | 1455 | if (setup.bRequestType == |
1281 | Ep_InRequest) { | 1456 | Ep_InRequest) { |
1282 | ep2 = find_endpoint (dum, setup.wIndex); | 1457 | ep2 = find_endpoint (dum, w_index); |
1283 | if (!ep2) { | 1458 | if (!ep2) { |
1284 | value = -EOPNOTSUPP; | 1459 | value = -EOPNOTSUPP; |
1285 | break; | 1460 | break; |
@@ -1321,7 +1496,7 @@ restart: | |||
1321 | 1496 | ||
1322 | if (value < 0) { | 1497 | if (value < 0) { |
1323 | if (value != -EOPNOTSUPP) | 1498 | if (value != -EOPNOTSUPP) |
1324 | dev_dbg (dummy_dev(dum), | 1499 | dev_dbg (udc_dev(dum), |
1325 | "setup --> %d\n", | 1500 | "setup --> %d\n", |
1326 | value); | 1501 | value); |
1327 | maybe_set_status (urb, -EPIPE); | 1502 | maybe_set_status (urb, -EPIPE); |
@@ -1377,12 +1552,12 @@ return_urb: | |||
1377 | goto restart; | 1552 | goto restart; |
1378 | } | 1553 | } |
1379 | 1554 | ||
1380 | /* want a 1 msec delay here */ | 1555 | if (list_empty (&dum->urbp_list)) { |
1381 | if (!list_empty (&dum->urbp_list)) | ||
1382 | mod_timer (&dum->timer, jiffies + msecs_to_jiffies(1)); | ||
1383 | else { | ||
1384 | usb_put_dev (dum->udev); | 1556 | usb_put_dev (dum->udev); |
1385 | 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)); | ||
1386 | } | 1561 | } |
1387 | 1562 | ||
1388 | spin_unlock_irqrestore (&dum->lock, flags); | 1563 | spin_unlock_irqrestore (&dum->lock, flags); |
@@ -1391,29 +1566,39 @@ return_urb: | |||
1391 | /*-------------------------------------------------------------------------*/ | 1566 | /*-------------------------------------------------------------------------*/ |
1392 | 1567 | ||
1393 | #define PORT_C_MASK \ | 1568 | #define PORT_C_MASK \ |
1394 | ((1 << USB_PORT_FEAT_C_CONNECTION) \ | 1569 | ((USB_PORT_STAT_C_CONNECTION \ |
1395 | | (1 << USB_PORT_FEAT_C_ENABLE) \ | 1570 | | USB_PORT_STAT_C_ENABLE \ |
1396 | | (1 << USB_PORT_FEAT_C_SUSPEND) \ | 1571 | | USB_PORT_STAT_C_SUSPEND \ |
1397 | | (1 << USB_PORT_FEAT_C_OVER_CURRENT) \ | 1572 | | USB_PORT_STAT_C_OVERCURRENT \ |
1398 | | (1 << USB_PORT_FEAT_C_RESET)) | 1573 | | USB_PORT_STAT_C_RESET) << 16) |
1399 | 1574 | ||
1400 | static int dummy_hub_status (struct usb_hcd *hcd, char *buf) | 1575 | static int dummy_hub_status (struct usb_hcd *hcd, char *buf) |
1401 | { | 1576 | { |
1402 | struct dummy *dum; | 1577 | struct dummy *dum; |
1403 | unsigned long flags; | 1578 | unsigned long flags; |
1404 | int retval; | 1579 | int retval = 0; |
1405 | 1580 | ||
1406 | dum = hcd_to_dummy (hcd); | 1581 | dum = hcd_to_dummy (hcd); |
1407 | 1582 | ||
1408 | spin_lock_irqsave (&dum->lock, flags); | 1583 | spin_lock_irqsave (&dum->lock, flags); |
1409 | if (!(dum->port_status & PORT_C_MASK)) | 1584 | if (hcd->state != HC_STATE_RUNNING) |
1410 | retval = 0; | 1585 | goto done; |
1411 | else { | 1586 | |
1587 | if (dum->resuming && time_after_eq (jiffies, dum->re_timeout)) { | ||
1588 | dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); | ||
1589 | dum->port_status &= ~USB_PORT_STAT_SUSPEND; | ||
1590 | set_link_state (dum); | ||
1591 | } | ||
1592 | |||
1593 | if ((dum->port_status & PORT_C_MASK) != 0) { | ||
1412 | *buf = (1 << 1); | 1594 | *buf = (1 << 1); |
1413 | 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", |
1414 | dum->port_status); | 1596 | dum->port_status); |
1415 | retval = 1; | 1597 | retval = 1; |
1598 | if (dum->rh_state == DUMMY_RH_SUSPENDED) | ||
1599 | usb_hcd_resume_root_hub (hcd); | ||
1416 | } | 1600 | } |
1601 | done: | ||
1417 | spin_unlock_irqrestore (&dum->lock, flags); | 1602 | spin_unlock_irqrestore (&dum->lock, flags); |
1418 | return retval; | 1603 | return retval; |
1419 | } | 1604 | } |
@@ -1424,7 +1609,8 @@ hub_descriptor (struct usb_hub_descriptor *desc) | |||
1424 | memset (desc, 0, sizeof *desc); | 1609 | memset (desc, 0, sizeof *desc); |
1425 | desc->bDescriptorType = 0x29; | 1610 | desc->bDescriptorType = 0x29; |
1426 | desc->bDescLength = 9; | 1611 | desc->bDescLength = 9; |
1427 | desc->wHubCharacteristics = __constant_cpu_to_le16 (0x0001); | 1612 | desc->wHubCharacteristics = (__force __u16) |
1613 | (__constant_cpu_to_le16 (0x0001)); | ||
1428 | desc->bNbrPorts = 1; | 1614 | desc->bNbrPorts = 1; |
1429 | desc->bitmap [0] = 0xff; | 1615 | desc->bitmap [0] = 0xff; |
1430 | desc->bitmap [1] = 0xff; | 1616 | desc->bitmap [1] = 0xff; |
@@ -1442,6 +1628,9 @@ static int dummy_hub_control ( | |||
1442 | int retval = 0; | 1628 | int retval = 0; |
1443 | unsigned long flags; | 1629 | unsigned long flags; |
1444 | 1630 | ||
1631 | if (hcd->state != HC_STATE_RUNNING) | ||
1632 | return -ETIMEDOUT; | ||
1633 | |||
1445 | dum = hcd_to_dummy (hcd); | 1634 | dum = hcd_to_dummy (hcd); |
1446 | spin_lock_irqsave (&dum->lock, flags); | 1635 | spin_lock_irqsave (&dum->lock, flags); |
1447 | switch (typeReq) { | 1636 | switch (typeReq) { |
@@ -1450,27 +1639,27 @@ static int dummy_hub_control ( | |||
1450 | case ClearPortFeature: | 1639 | case ClearPortFeature: |
1451 | switch (wValue) { | 1640 | switch (wValue) { |
1452 | case USB_PORT_FEAT_SUSPEND: | 1641 | case USB_PORT_FEAT_SUSPEND: |
1453 | if (dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) { | 1642 | if (dum->port_status & USB_PORT_STAT_SUSPEND) { |
1454 | /* 20msec resume signaling */ | 1643 | /* 20msec resume signaling */ |
1455 | dum->resuming = 1; | 1644 | dum->resuming = 1; |
1456 | dum->re_timeout = jiffies + | 1645 | dum->re_timeout = jiffies + |
1457 | msecs_to_jiffies(20); | 1646 | msecs_to_jiffies(20); |
1458 | } | 1647 | } |
1459 | break; | 1648 | break; |
1460 | case USB_PORT_FEAT_POWER: | 1649 | case USB_PORT_FEAT_POWER: |
1461 | dum->port_status = 0; | 1650 | if (dum->port_status & USB_PORT_STAT_POWER) |
1462 | dum->resuming = 0; | 1651 | dev_dbg (dummy_dev(dum), "power-off\n"); |
1463 | stop_activity(dum, dum->driver); | 1652 | /* FALLS THROUGH */ |
1464 | break; | ||
1465 | default: | 1653 | default: |
1466 | dum->port_status &= ~(1 << wValue); | 1654 | dum->port_status &= ~(1 << wValue); |
1655 | set_link_state (dum); | ||
1467 | } | 1656 | } |
1468 | break; | 1657 | break; |
1469 | case GetHubDescriptor: | 1658 | case GetHubDescriptor: |
1470 | hub_descriptor ((struct usb_hub_descriptor *) buf); | 1659 | hub_descriptor ((struct usb_hub_descriptor *) buf); |
1471 | break; | 1660 | break; |
1472 | case GetHubStatus: | 1661 | case GetHubStatus: |
1473 | *(u32 *) buf = __constant_cpu_to_le32 (0); | 1662 | *(__le32 *) buf = __constant_cpu_to_le32 (0); |
1474 | break; | 1663 | break; |
1475 | case GetPortStatus: | 1664 | case GetPortStatus: |
1476 | if (wIndex != 1) | 1665 | if (wIndex != 1) |
@@ -1479,23 +1668,16 @@ static int dummy_hub_control ( | |||
1479 | /* whoever resets or resumes must GetPortStatus to | 1668 | /* whoever resets or resumes must GetPortStatus to |
1480 | * complete it!! | 1669 | * complete it!! |
1481 | */ | 1670 | */ |
1482 | if (dum->resuming && time_after (jiffies, dum->re_timeout)) { | 1671 | if (dum->resuming && |
1483 | dum->port_status |= (1 << USB_PORT_FEAT_C_SUSPEND); | 1672 | time_after_eq (jiffies, dum->re_timeout)) { |
1484 | dum->port_status &= ~(1 << USB_PORT_FEAT_SUSPEND); | 1673 | dum->port_status |= (USB_PORT_STAT_C_SUSPEND << 16); |
1485 | dum->resuming = 0; | 1674 | dum->port_status &= ~USB_PORT_STAT_SUSPEND; |
1486 | dum->re_timeout = 0; | ||
1487 | if (dum->driver && dum->driver->resume) { | ||
1488 | spin_unlock (&dum->lock); | ||
1489 | dum->driver->resume (&dum->gadget); | ||
1490 | spin_lock (&dum->lock); | ||
1491 | } | ||
1492 | } | 1675 | } |
1493 | if ((dum->port_status & (1 << USB_PORT_FEAT_RESET)) != 0 | 1676 | if ((dum->port_status & USB_PORT_STAT_RESET) != 0 && |
1494 | && time_after (jiffies, dum->re_timeout)) { | 1677 | time_after_eq (jiffies, dum->re_timeout)) { |
1495 | dum->port_status |= (1 << USB_PORT_FEAT_C_RESET); | 1678 | dum->port_status |= (USB_PORT_STAT_C_RESET << 16); |
1496 | dum->port_status &= ~(1 << USB_PORT_FEAT_RESET); | 1679 | dum->port_status &= ~USB_PORT_STAT_RESET; |
1497 | dum->re_timeout = 0; | 1680 | if (dum->pullup) { |
1498 | if (dum->driver) { | ||
1499 | dum->port_status |= USB_PORT_STAT_ENABLE; | 1681 | dum->port_status |= USB_PORT_STAT_ENABLE; |
1500 | /* give it the best speed we agree on */ | 1682 | /* give it the best speed we agree on */ |
1501 | dum->gadget.speed = dum->driver->speed; | 1683 | dum->gadget.speed = dum->driver->speed; |
@@ -1516,8 +1698,9 @@ static int dummy_hub_control ( | |||
1516 | } | 1698 | } |
1517 | } | 1699 | } |
1518 | } | 1700 | } |
1519 | ((u16 *) buf)[0] = cpu_to_le16 (dum->port_status); | 1701 | set_link_state (dum); |
1520 | ((u16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); | 1702 | ((__le16 *) buf)[0] = cpu_to_le16 (dum->port_status); |
1703 | ((__le16 *) buf)[1] = cpu_to_le16 (dum->port_status >> 16); | ||
1521 | break; | 1704 | break; |
1522 | case SetHubFeature: | 1705 | case SetHubFeature: |
1523 | retval = -EPIPE; | 1706 | retval = -EPIPE; |
@@ -1525,36 +1708,37 @@ static int dummy_hub_control ( | |||
1525 | case SetPortFeature: | 1708 | case SetPortFeature: |
1526 | switch (wValue) { | 1709 | switch (wValue) { |
1527 | case USB_PORT_FEAT_SUSPEND: | 1710 | case USB_PORT_FEAT_SUSPEND: |
1528 | if ((dum->port_status & (1 << USB_PORT_FEAT_SUSPEND)) | 1711 | if (dum->active) { |
1529 | == 0) { | 1712 | dum->port_status |= USB_PORT_STAT_SUSPEND; |
1530 | dum->port_status |= | 1713 | |
1531 | (1 << USB_PORT_FEAT_SUSPEND); | 1714 | /* HNP would happen here; for now we |
1532 | if (dum->driver && dum->driver->suspend) { | 1715 | * assume b_bus_req is always true. |
1533 | spin_unlock (&dum->lock); | 1716 | */ |
1534 | dum->driver->suspend (&dum->gadget); | 1717 | set_link_state (dum); |
1535 | spin_lock (&dum->lock); | 1718 | if (((1 << USB_DEVICE_B_HNP_ENABLE) |
1536 | } | 1719 | & dum->devstatus) != 0) |
1720 | dev_dbg (dummy_dev(dum), | ||
1721 | "no HNP yet!\n"); | ||
1537 | } | 1722 | } |
1538 | break; | 1723 | break; |
1724 | case USB_PORT_FEAT_POWER: | ||
1725 | dum->port_status |= USB_PORT_STAT_POWER; | ||
1726 | set_link_state (dum); | ||
1727 | break; | ||
1539 | case USB_PORT_FEAT_RESET: | 1728 | case USB_PORT_FEAT_RESET: |
1540 | /* if it's already running, disconnect first */ | 1729 | /* if it's already enabled, disable */ |
1541 | if (dum->port_status & USB_PORT_STAT_ENABLE) { | 1730 | dum->port_status &= ~(USB_PORT_STAT_ENABLE |
1542 | dum->port_status &= ~(USB_PORT_STAT_ENABLE | 1731 | | USB_PORT_STAT_LOW_SPEED |
1543 | | USB_PORT_STAT_LOW_SPEED | 1732 | | USB_PORT_STAT_HIGH_SPEED); |
1544 | | USB_PORT_STAT_HIGH_SPEED); | 1733 | dum->devstatus = 0; |
1545 | if (dum->driver) { | ||
1546 | dev_dbg (dummy_dev(dum), | ||
1547 | "disconnect\n"); | ||
1548 | stop_activity (dum, dum->driver); | ||
1549 | } | ||
1550 | |||
1551 | /* FIXME test that code path! */ | ||
1552 | } | ||
1553 | /* 50msec reset signaling */ | 1734 | /* 50msec reset signaling */ |
1554 | dum->re_timeout = jiffies + msecs_to_jiffies(50); | 1735 | dum->re_timeout = jiffies + msecs_to_jiffies(50); |
1555 | /* FALLTHROUGH */ | 1736 | /* FALLS THROUGH */ |
1556 | default: | 1737 | default: |
1557 | dum->port_status |= (1 << wValue); | 1738 | if ((dum->port_status & USB_PORT_STAT_POWER) != 0) { |
1739 | dum->port_status |= (1 << wValue); | ||
1740 | set_link_state (dum); | ||
1741 | } | ||
1558 | } | 1742 | } |
1559 | break; | 1743 | break; |
1560 | 1744 | ||
@@ -1567,9 +1751,35 @@ static int dummy_hub_control ( | |||
1567 | retval = -EPIPE; | 1751 | retval = -EPIPE; |
1568 | } | 1752 | } |
1569 | spin_unlock_irqrestore (&dum->lock, flags); | 1753 | spin_unlock_irqrestore (&dum->lock, flags); |
1754 | |||
1755 | if ((dum->port_status & PORT_C_MASK) != 0) | ||
1756 | usb_hcd_poll_rh_status (hcd); | ||
1570 | return retval; | 1757 | return retval; |
1571 | } | 1758 | } |
1572 | 1759 | ||
1760 | static 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 | |||
1771 | static 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 | } | ||
1573 | 1783 | ||
1574 | /*-------------------------------------------------------------------------*/ | 1784 | /*-------------------------------------------------------------------------*/ |
1575 | 1785 | ||
@@ -1625,8 +1835,6 @@ static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL); | |||
1625 | static int dummy_start (struct usb_hcd *hcd) | 1835 | static int dummy_start (struct usb_hcd *hcd) |
1626 | { | 1836 | { |
1627 | struct dummy *dum; | 1837 | struct dummy *dum; |
1628 | struct usb_device *root; | ||
1629 | int retval; | ||
1630 | 1838 | ||
1631 | dum = hcd_to_dummy (hcd); | 1839 | dum = hcd_to_dummy (hcd); |
1632 | 1840 | ||
@@ -1639,38 +1847,22 @@ static int dummy_start (struct usb_hcd *hcd) | |||
1639 | init_timer (&dum->timer); | 1847 | init_timer (&dum->timer); |
1640 | dum->timer.function = dummy_timer; | 1848 | dum->timer.function = dummy_timer; |
1641 | dum->timer.data = (unsigned long) dum; | 1849 | dum->timer.data = (unsigned long) dum; |
1850 | dum->rh_state = DUMMY_RH_RUNNING; | ||
1642 | 1851 | ||
1643 | INIT_LIST_HEAD (&dum->urbp_list); | 1852 | INIT_LIST_HEAD (&dum->urbp_list); |
1644 | 1853 | ||
1645 | root = usb_alloc_dev (NULL, &hcd->self, 0); | ||
1646 | if (!root) | ||
1647 | return -ENOMEM; | ||
1648 | |||
1649 | /* root hub enters addressed state... */ | ||
1650 | hcd->state = HC_STATE_RUNNING; | ||
1651 | root->speed = USB_SPEED_HIGH; | ||
1652 | |||
1653 | /* ...then configured, so khubd sees us. */ | ||
1654 | if ((retval = usb_hcd_register_root_hub (root, hcd)) != 0) { | ||
1655 | goto err1; | ||
1656 | } | ||
1657 | |||
1658 | /* only show a low-power port: just 8mA */ | 1854 | /* only show a low-power port: just 8mA */ |
1659 | hub_set_power_budget (root, 8); | 1855 | hcd->power_budget = 8; |
1856 | hcd->state = HC_STATE_RUNNING; | ||
1857 | hcd->uses_new_polling = 1; | ||
1660 | 1858 | ||
1661 | if ((retval = dummy_register_udc (dum)) != 0) | 1859 | #ifdef CONFIG_USB_OTG |
1662 | goto err2; | 1860 | hcd->self.otg_port = 1; |
1861 | #endif | ||
1663 | 1862 | ||
1664 | /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ | 1863 | /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */ |
1665 | device_create_file (dummy_dev(dum), &dev_attr_urbs); | 1864 | device_create_file (dummy_dev(dum), &dev_attr_urbs); |
1666 | return 0; | 1865 | return 0; |
1667 | |||
1668 | err2: | ||
1669 | usb_disconnect (&hcd->self.root_hub); | ||
1670 | err1: | ||
1671 | usb_put_dev (root); | ||
1672 | hcd->state = HC_STATE_QUIESCING; | ||
1673 | return retval; | ||
1674 | } | 1866 | } |
1675 | 1867 | ||
1676 | static void dummy_stop (struct usb_hcd *hcd) | 1868 | static void dummy_stop (struct usb_hcd *hcd) |
@@ -1680,10 +1872,7 @@ static void dummy_stop (struct usb_hcd *hcd) | |||
1680 | dum = hcd_to_dummy (hcd); | 1872 | dum = hcd_to_dummy (hcd); |
1681 | 1873 | ||
1682 | device_remove_file (dummy_dev(dum), &dev_attr_urbs); | 1874 | device_remove_file (dummy_dev(dum), &dev_attr_urbs); |
1683 | |||
1684 | usb_gadget_unregister_driver (dum->driver); | 1875 | usb_gadget_unregister_driver (dum->driver); |
1685 | dummy_unregister_udc (dum); | ||
1686 | |||
1687 | dev_info (dummy_dev(dum), "stopped\n"); | 1876 | dev_info (dummy_dev(dum), "stopped\n"); |
1688 | } | 1877 | } |
1689 | 1878 | ||
@@ -1711,9 +1900,11 @@ static const struct hc_driver dummy_hcd = { | |||
1711 | 1900 | ||
1712 | .hub_status_data = dummy_hub_status, | 1901 | .hub_status_data = dummy_hub_status, |
1713 | .hub_control = dummy_hub_control, | 1902 | .hub_control = dummy_hub_control, |
1903 | .hub_suspend = dummy_hub_suspend, | ||
1904 | .hub_resume = dummy_hub_resume, | ||
1714 | }; | 1905 | }; |
1715 | 1906 | ||
1716 | static int dummy_probe (struct device *dev) | 1907 | static int dummy_hcd_probe (struct device *dev) |
1717 | { | 1908 | { |
1718 | struct usb_hcd *hcd; | 1909 | struct usb_hcd *hcd; |
1719 | int retval; | 1910 | int retval; |
@@ -1733,7 +1924,7 @@ static int dummy_probe (struct device *dev) | |||
1733 | return retval; | 1924 | return retval; |
1734 | } | 1925 | } |
1735 | 1926 | ||
1736 | static void dummy_remove (struct device *dev) | 1927 | static int dummy_hcd_remove (struct device *dev) |
1737 | { | 1928 | { |
1738 | struct usb_hcd *hcd; | 1929 | struct usb_hcd *hcd; |
1739 | 1930 | ||
@@ -1741,53 +1932,127 @@ static void dummy_remove (struct device *dev) | |||
1741 | usb_remove_hcd (hcd); | 1932 | usb_remove_hcd (hcd); |
1742 | usb_put_hcd (hcd); | 1933 | usb_put_hcd (hcd); |
1743 | the_controller = NULL; | 1934 | the_controller = NULL; |
1935 | return 0; | ||
1744 | } | 1936 | } |
1745 | 1937 | ||
1746 | /*-------------------------------------------------------------------------*/ | 1938 | static int dummy_hcd_suspend (struct device *dev, pm_message_t state, |
1747 | 1939 | u32 level) | |
1748 | static int dummy_pdev_detect (void) | ||
1749 | { | 1940 | { |
1750 | int retval; | 1941 | struct usb_hcd *hcd; |
1751 | 1942 | ||
1752 | retval = driver_register (&dummy_driver); | 1943 | if (level != SUSPEND_DISABLE) |
1753 | if (retval < 0) | 1944 | return 0; |
1754 | return retval; | 1945 | |
1946 | dev_dbg (dev, "%s\n", __FUNCTION__); | ||
1947 | hcd = dev_get_drvdata (dev); | ||
1755 | 1948 | ||
1756 | the_pdev.name = "hc"; | 1949 | #ifndef CONFIG_USB_SUSPEND |
1757 | the_pdev.dev.driver = &dummy_driver; | 1950 | /* Otherwise this would never happen */ |
1758 | the_pdev.dev.release = dummy_pdev_release; | 1951 | usb_lock_device (hcd->self.root_hub); |
1952 | dummy_hub_suspend (hcd); | ||
1953 | usb_unlock_device (hcd->self.root_hub); | ||
1954 | #endif | ||
1759 | 1955 | ||
1760 | retval = platform_device_register (&the_pdev); | 1956 | hcd->state = HC_STATE_SUSPENDED; |
1761 | if (retval < 0) | 1957 | return 0; |
1762 | driver_unregister (&dummy_driver); | ||
1763 | return retval; | ||
1764 | } | 1958 | } |
1765 | 1959 | ||
1766 | static void dummy_pdev_remove (void) | 1960 | static int dummy_hcd_resume (struct device *dev, u32 level) |
1767 | { | 1961 | { |
1768 | platform_device_unregister (&the_pdev); | 1962 | struct usb_hcd *hcd; |
1769 | driver_unregister (&dummy_driver); | 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; | ||
1770 | } | 1980 | } |
1771 | 1981 | ||
1982 | static struct device_driver dummy_hcd_driver = { | ||
1983 | .name = (char *) driver_name, | ||
1984 | .bus = &platform_bus_type, | ||
1985 | .probe = dummy_hcd_probe, | ||
1986 | .remove = dummy_hcd_remove, | ||
1987 | .suspend = dummy_hcd_suspend, | ||
1988 | .resume = dummy_hcd_resume, | ||
1989 | }; | ||
1990 | |||
1772 | /*-------------------------------------------------------------------------*/ | 1991 | /*-------------------------------------------------------------------------*/ |
1773 | 1992 | ||
1993 | /* These don't need to do anything because the pdev structures are | ||
1994 | * statically allocated. */ | ||
1995 | static void | ||
1996 | dummy_udc_release (struct device *dev) {} | ||
1997 | |||
1998 | static void | ||
1999 | dummy_hcd_release (struct device *dev) {} | ||
2000 | |||
2001 | static struct platform_device the_udc_pdev = { | ||
2002 | .name = (char *) gadget_name, | ||
2003 | .id = -1, | ||
2004 | .dev = { | ||
2005 | .release = dummy_udc_release, | ||
2006 | }, | ||
2007 | }; | ||
2008 | |||
2009 | static struct platform_device the_hcd_pdev = { | ||
2010 | .name = (char *) driver_name, | ||
2011 | .id = -1, | ||
2012 | .dev = { | ||
2013 | .release = dummy_hcd_release, | ||
2014 | }, | ||
2015 | }; | ||
2016 | |||
1774 | static int __init init (void) | 2017 | static int __init init (void) |
1775 | { | 2018 | { |
1776 | int retval; | 2019 | int retval; |
1777 | 2020 | ||
1778 | if (usb_disabled ()) | 2021 | if (usb_disabled ()) |
1779 | return -ENODEV; | 2022 | return -ENODEV; |
1780 | if ((retval = dummy_pdev_detect ()) != 0) | 2023 | |
2024 | retval = driver_register (&dummy_hcd_driver); | ||
2025 | if (retval < 0) | ||
1781 | return retval; | 2026 | return retval; |
1782 | if ((retval = dummy_probe (&the_pdev.dev)) != 0) | 2027 | |
1783 | dummy_pdev_remove (); | 2028 | retval = driver_register (&dummy_udc_driver); |
2029 | if (retval < 0) | ||
2030 | goto err_register_udc_driver; | ||
2031 | |||
2032 | retval = platform_device_register (&the_hcd_pdev); | ||
2033 | if (retval < 0) | ||
2034 | goto err_register_hcd; | ||
2035 | |||
2036 | retval = platform_device_register (&the_udc_pdev); | ||
2037 | if (retval < 0) | ||
2038 | goto err_register_udc; | ||
2039 | return retval; | ||
2040 | |||
2041 | err_register_udc: | ||
2042 | platform_device_unregister (&the_hcd_pdev); | ||
2043 | err_register_hcd: | ||
2044 | driver_unregister (&dummy_udc_driver); | ||
2045 | err_register_udc_driver: | ||
2046 | driver_unregister (&dummy_hcd_driver); | ||
1784 | return retval; | 2047 | return retval; |
1785 | } | 2048 | } |
1786 | module_init (init); | 2049 | module_init (init); |
1787 | 2050 | ||
1788 | static void __exit cleanup (void) | 2051 | static void __exit cleanup (void) |
1789 | { | 2052 | { |
1790 | dummy_remove (&the_pdev.dev); | 2053 | platform_device_unregister (&the_udc_pdev); |
1791 | dummy_pdev_remove (); | 2054 | platform_device_unregister (&the_hcd_pdev); |
2055 | driver_unregister (&dummy_udc_driver); | ||
2056 | driver_unregister (&dummy_hcd_driver); | ||
1792 | } | 2057 | } |
1793 | module_exit (cleanup); | 2058 | module_exit (cleanup); |