blob: a4896df3296cf718c468d6499732a01708ecbcbe [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * dummy_hcd.c -- Dummy/Loopback USB host and device emulator driver.
3 *
4 * Maintainer: Alan Stern <stern@rowland.harvard.edu>
5 *
6 * Copyright (C) 2003 David Brownell
7 * Copyright (C) 2003-2005 Alan Stern
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24
25/*
26 * This exposes a device side "USB gadget" API, driven by requests to a
27 * Linux-USB host controller driver. USB traffic is simulated; there's
28 * no need for USB hardware. Use this with two other drivers:
29 *
30 * - Gadget driver, responding to requests (slave);
31 * - Host-side device driver, as already familiar in Linux.
32 *
33 * Having this all in one kernel can help some stages of development,
34 * bypassing some hardware (and driver) issues. UML could help too.
35 */
36
Linus Torvalds1da177e2005-04-16 15:20:36 -070037#include <linux/module.h>
38#include <linux/kernel.h>
39#include <linux/delay.h>
40#include <linux/ioport.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070041#include <linux/slab.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070042#include <linux/errno.h>
43#include <linux/init.h>
44#include <linux/timer.h>
45#include <linux/list.h>
46#include <linux/interrupt.h>
Russell Kingd052d1b2005-10-29 19:07:23 +010047#include <linux/platform_device.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070048#include <linux/usb.h>
David Brownell9454a572007-10-04 18:05:17 -070049#include <linux/usb/gadget.h>
Eric Lescouet27729aa2010-04-24 23:21:52 +020050#include <linux/usb/hcd.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070051
52#include <asm/byteorder.h>
53#include <asm/io.h>
54#include <asm/irq.h>
55#include <asm/system.h>
56#include <asm/unaligned.h>
57
58
Linus Torvalds1da177e2005-04-16 15:20:36 -070059#define DRIVER_DESC "USB Host+Gadget Emulator"
Alan Stern391eca92005-05-10 15:34:16 -040060#define DRIVER_VERSION "02 May 2005"
Linus Torvalds1da177e2005-04-16 15:20:36 -070061
Alan Sterncaf29f62007-12-06 11:10:39 -050062#define POWER_BUDGET 500 /* in mA; use 8 for low-power port testing */
63
Linus Torvalds1da177e2005-04-16 15:20:36 -070064static const char driver_name [] = "dummy_hcd";
65static const char driver_desc [] = "USB Host+Gadget Emulator";
66
67static const char gadget_name [] = "dummy_udc";
68
69MODULE_DESCRIPTION (DRIVER_DESC);
70MODULE_AUTHOR ("David Brownell");
71MODULE_LICENSE ("GPL");
72
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +030073struct dummy_hcd_module_parameters {
74 bool is_super_speed;
75};
76
77static struct dummy_hcd_module_parameters mod_data = {
78 .is_super_speed = false
79};
80module_param_named(is_super_speed, mod_data.is_super_speed, bool, S_IRUGO);
81MODULE_PARM_DESC(is_super_speed, "true to simulate SuperSpeed connection");
Linus Torvalds1da177e2005-04-16 15:20:36 -070082/*-------------------------------------------------------------------------*/
83
84/* gadget side driver data structres */
85struct dummy_ep {
86 struct list_head queue;
87 unsigned long last_io; /* jiffies timestamp */
88 struct usb_gadget *gadget;
89 const struct usb_endpoint_descriptor *desc;
90 struct usb_ep ep;
91 unsigned halted : 1;
Alan Stern851a5262008-08-14 15:48:30 -040092 unsigned wedged : 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -070093 unsigned already_seen : 1;
94 unsigned setup_stage : 1;
95};
96
97struct dummy_request {
98 struct list_head queue; /* ep's requests */
99 struct usb_request req;
100};
101
102static inline struct dummy_ep *usb_ep_to_dummy_ep (struct usb_ep *_ep)
103{
104 return container_of (_ep, struct dummy_ep, ep);
105}
106
107static inline struct dummy_request *usb_request_to_dummy_request
108 (struct usb_request *_req)
109{
110 return container_of (_req, struct dummy_request, req);
111}
112
113/*-------------------------------------------------------------------------*/
114
115/*
116 * Every device has ep0 for control requests, plus up to 30 more endpoints,
117 * in one of two types:
118 *
119 * - Configurable: direction (in/out), type (bulk, iso, etc), and endpoint
120 * number can be changed. Names like "ep-a" are used for this type.
121 *
122 * - Fixed Function: in other cases. some characteristics may be mutable;
123 * that'd be hardware-specific. Names like "ep12out-bulk" are used.
124 *
125 * Gadget drivers are responsible for not setting up conflicting endpoint
126 * configurations, illegal or unsupported packet lengths, and so on.
127 */
128
129static const char ep0name [] = "ep0";
130
131static const char *const ep_name [] = {
132 ep0name, /* everyone has ep0 */
133
134 /* act like a net2280: high speed, six configurable endpoints */
135 "ep-a", "ep-b", "ep-c", "ep-d", "ep-e", "ep-f",
136
137 /* or like pxa250: fifteen fixed function endpoints */
138 "ep1in-bulk", "ep2out-bulk", "ep3in-iso", "ep4out-iso", "ep5in-int",
139 "ep6in-bulk", "ep7out-bulk", "ep8in-iso", "ep9out-iso", "ep10in-int",
140 "ep11in-bulk", "ep12out-bulk", "ep13in-iso", "ep14out-iso",
141 "ep15in-int",
142
143 /* or like sa1100: two fixed function endpoints */
144 "ep1out-bulk", "ep2in-bulk",
145};
Tobias Klauser52950ed2005-12-11 16:20:08 +0100146#define DUMMY_ENDPOINTS ARRAY_SIZE(ep_name)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700147
Alan Sternd9b76252005-05-03 16:15:43 -0400148/*-------------------------------------------------------------------------*/
149
Linus Torvalds1da177e2005-04-16 15:20:36 -0700150#define FIFO_SIZE 64
151
152struct urbp {
153 struct urb *urb;
154 struct list_head urbp_list;
155};
156
Alan Stern391eca92005-05-10 15:34:16 -0400157
158enum dummy_rh_state {
159 DUMMY_RH_RESET,
160 DUMMY_RH_SUSPENDED,
161 DUMMY_RH_RUNNING
162};
163
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300164struct dummy_hcd {
165 struct dummy *dum;
166 enum dummy_rh_state rh_state;
167 struct timer_list timer;
168 u32 port_status;
169 u32 old_status;
170 unsigned long re_timeout;
171
172 struct usb_device *udev;
173 struct list_head urbp_list;
174
175 unsigned active:1;
176 unsigned old_active:1;
177 unsigned resuming:1;
178};
179
Linus Torvalds1da177e2005-04-16 15:20:36 -0700180struct dummy {
181 spinlock_t lock;
182
183 /*
184 * SLAVE/GADGET side support
185 */
186 struct dummy_ep ep [DUMMY_ENDPOINTS];
187 int address;
188 struct usb_gadget gadget;
189 struct usb_gadget_driver *driver;
190 struct dummy_request fifo_req;
191 u8 fifo_buf [FIFO_SIZE];
192 u16 devstatus;
Alan Stern391eca92005-05-10 15:34:16 -0400193 unsigned udc_suspended:1;
Alan Sternf1c39fa2005-05-03 16:24:04 -0400194 unsigned pullup:1;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700195
196 /*
197 * MASTER/HOST side support
198 */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300199 struct dummy_hcd *hs_hcd;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300200 struct dummy_hcd *ss_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700201};
202
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300203static inline struct dummy_hcd *hcd_to_dummy_hcd(struct usb_hcd *hcd)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700204{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300205 return (struct dummy_hcd *) (hcd->hcd_priv);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700206}
207
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300208static inline struct usb_hcd *dummy_hcd_to_hcd(struct dummy_hcd *dum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700209{
210 return container_of((void *) dum, struct usb_hcd, hcd_priv);
211}
212
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300213static inline struct device *dummy_dev(struct dummy_hcd *dum)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700214{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300215 return dummy_hcd_to_hcd(dum)->self.controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700216}
217
Alan Sternd9b76252005-05-03 16:15:43 -0400218static inline struct device *udc_dev (struct dummy *dum)
219{
220 return dum->gadget.dev.parent;
221}
222
Linus Torvalds1da177e2005-04-16 15:20:36 -0700223static inline struct dummy *ep_to_dummy (struct dummy_ep *ep)
224{
225 return container_of (ep->gadget, struct dummy, gadget);
226}
227
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300228static inline struct dummy_hcd *gadget_to_dummy_hcd(struct usb_gadget *gadget)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700229{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300230 struct dummy *dum = container_of(gadget, struct dummy, gadget);
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300231 if (dum->gadget.speed == USB_SPEED_SUPER)
232 return dum->ss_hcd;
233 else
234 return dum->hs_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700235}
236
237static inline struct dummy *gadget_dev_to_dummy (struct device *dev)
238{
239 return container_of (dev, struct dummy, gadget.dev);
240}
241
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300242static struct dummy the_controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700243
244/*-------------------------------------------------------------------------*/
245
Alan Sternf1c39fa2005-05-03 16:24:04 -0400246/* SLAVE/GADGET SIDE UTILITY ROUTINES */
247
248/* called with spinlock held */
249static void nuke (struct dummy *dum, struct dummy_ep *ep)
250{
251 while (!list_empty (&ep->queue)) {
252 struct dummy_request *req;
253
254 req = list_entry (ep->queue.next, struct dummy_request, queue);
255 list_del_init (&req->queue);
256 req->req.status = -ESHUTDOWN;
257
258 spin_unlock (&dum->lock);
259 req->req.complete (&ep->ep, &req->req);
260 spin_lock (&dum->lock);
261 }
262}
263
264/* caller must hold lock */
265static void
266stop_activity (struct dummy *dum)
267{
268 struct dummy_ep *ep;
269
270 /* prevent any more requests */
271 dum->address = 0;
272
273 /* The timer is left running so that outstanding URBs can fail */
274
275 /* nuke any pending requests first, so driver i/o is quiesced */
276 list_for_each_entry (ep, &dum->gadget.ep_list, ep.ep_list)
277 nuke (dum, ep);
278
279 /* driver now does any non-usb quiescing necessary */
280}
281
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300282/**
283 * set_link_state_by_speed() - Sets the current state of the link according to
284 * the hcd speed
285 * @dum_hcd: pointer to the dummy_hcd structure to update the link state for
286 *
287 * This function updates the port_status according to the link state and the
288 * speed of the hcd.
289 */
290static void set_link_state_by_speed(struct dummy_hcd *dum_hcd)
291{
292 struct dummy *dum = dum_hcd->dum;
293
294 if (dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3) {
295 if ((dum_hcd->port_status & USB_SS_PORT_STAT_POWER) == 0) {
296 dum_hcd->port_status = 0;
297 } else if (!dum->pullup || dum->udc_suspended) {
298 /* UDC suspend must cause a disconnect */
299 dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
300 USB_PORT_STAT_ENABLE);
301 if ((dum_hcd->old_status &
302 USB_PORT_STAT_CONNECTION) != 0)
303 dum_hcd->port_status |=
304 (USB_PORT_STAT_C_CONNECTION << 16);
305 } else {
306 /* device is connected and not suspended */
307 dum_hcd->port_status |= (USB_PORT_STAT_CONNECTION |
308 USB_PORT_STAT_SPEED_5GBPS) ;
309 if ((dum_hcd->old_status &
310 USB_PORT_STAT_CONNECTION) == 0)
311 dum_hcd->port_status |=
312 (USB_PORT_STAT_C_CONNECTION << 16);
313 if ((dum_hcd->port_status &
314 USB_PORT_STAT_ENABLE) == 1 &&
315 (dum_hcd->port_status &
316 USB_SS_PORT_LS_U0) == 1 &&
317 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
318 dum_hcd->active = 1;
319 }
320 } else {
321 if ((dum_hcd->port_status & USB_PORT_STAT_POWER) == 0) {
322 dum_hcd->port_status = 0;
323 } else if (!dum->pullup || dum->udc_suspended) {
324 /* UDC suspend must cause a disconnect */
325 dum_hcd->port_status &= ~(USB_PORT_STAT_CONNECTION |
326 USB_PORT_STAT_ENABLE |
327 USB_PORT_STAT_LOW_SPEED |
328 USB_PORT_STAT_HIGH_SPEED |
329 USB_PORT_STAT_SUSPEND);
330 if ((dum_hcd->old_status &
331 USB_PORT_STAT_CONNECTION) != 0)
332 dum_hcd->port_status |=
333 (USB_PORT_STAT_C_CONNECTION << 16);
334 } else {
335 dum_hcd->port_status |= USB_PORT_STAT_CONNECTION;
336 if ((dum_hcd->old_status &
337 USB_PORT_STAT_CONNECTION) == 0)
338 dum_hcd->port_status |=
339 (USB_PORT_STAT_C_CONNECTION << 16);
340 if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0)
341 dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
342 else if ((dum_hcd->port_status &
343 USB_PORT_STAT_SUSPEND) == 0 &&
344 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
345 dum_hcd->active = 1;
346 }
347 }
348}
349
Alan Sternf1c39fa2005-05-03 16:24:04 -0400350/* caller must hold lock */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300351static void set_link_state(struct dummy_hcd *dum_hcd)
Alan Sternf1c39fa2005-05-03 16:24:04 -0400352{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300353 struct dummy *dum = dum_hcd->dum;
354
355 dum_hcd->active = 0;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300356 if (dum->pullup)
357 if ((dummy_hcd_to_hcd(dum_hcd)->speed == HCD_USB3 &&
358 dum->gadget.speed != USB_SPEED_SUPER) ||
359 (dummy_hcd_to_hcd(dum_hcd)->speed != HCD_USB3 &&
360 dum->gadget.speed == USB_SPEED_SUPER))
361 return;
Alan Stern391eca92005-05-10 15:34:16 -0400362
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300363 set_link_state_by_speed(dum_hcd);
Alan Sternf1c39fa2005-05-03 16:24:04 -0400364
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300365 if ((dum_hcd->port_status & USB_PORT_STAT_ENABLE) == 0 ||
366 dum_hcd->active)
367 dum_hcd->resuming = 0;
Alan Sternf1c39fa2005-05-03 16:24:04 -0400368
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300369 /* if !connected or reset */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300370 if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0 ||
371 (dum_hcd->port_status & USB_PORT_STAT_RESET) != 0) {
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300372 /*
373 * We're connected and not reset (reset occurred now),
374 * and driver attached - disconnect!
375 */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300376 if ((dum_hcd->old_status & USB_PORT_STAT_CONNECTION) != 0 &&
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300377 (dum_hcd->old_status & USB_PORT_STAT_RESET) == 0 &&
378 dum->driver) {
379 stop_activity(dum);
380 spin_unlock(&dum->lock);
381 dum->driver->disconnect(&dum->gadget);
382 spin_lock(&dum->lock);
Alan Sternf1c39fa2005-05-03 16:24:04 -0400383 }
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300384 } else if (dum_hcd->active != dum_hcd->old_active) {
385 if (dum_hcd->old_active && dum->driver->suspend) {
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300386 spin_unlock(&dum->lock);
387 dum->driver->suspend(&dum->gadget);
388 spin_lock(&dum->lock);
389 } else if (!dum_hcd->old_active && dum->driver->resume) {
390 spin_unlock(&dum->lock);
391 dum->driver->resume(&dum->gadget);
392 spin_lock(&dum->lock);
Alan Sternf1c39fa2005-05-03 16:24:04 -0400393 }
394 }
395
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300396 dum_hcd->old_status = dum_hcd->port_status;
397 dum_hcd->old_active = dum_hcd->active;
Alan Sternf1c39fa2005-05-03 16:24:04 -0400398}
399
400/*-------------------------------------------------------------------------*/
401
Linus Torvalds1da177e2005-04-16 15:20:36 -0700402/* SLAVE/GADGET SIDE DRIVER
403 *
404 * This only tracks gadget state. All the work is done when the host
405 * side tries some (emulated) i/o operation. Real device controller
406 * drivers would do real i/o using dma, fifos, irqs, timers, etc.
407 */
408
409#define is_enabled(dum) \
410 (dum->port_status & USB_PORT_STAT_ENABLE)
411
412static int
413dummy_enable (struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
414{
415 struct dummy *dum;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300416 struct dummy_hcd *dum_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700417 struct dummy_ep *ep;
418 unsigned max;
419 int retval;
420
421 ep = usb_ep_to_dummy_ep (_ep);
422 if (!_ep || !desc || ep->desc || _ep->name == ep0name
423 || desc->bDescriptorType != USB_DT_ENDPOINT)
424 return -EINVAL;
425 dum = ep_to_dummy (ep);
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300426 if (!dum->driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700427 return -ESHUTDOWN;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300428 if (dum->gadget.speed == USB_SPEED_SUPER)
429 dum_hcd = dum->ss_hcd;
430 else
431 dum_hcd = dum->hs_hcd;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300432 if (!is_enabled(dum_hcd))
433 return -ESHUTDOWN;
434
435 /*
436 * For HS/FS devices only bits 0..10 of the wMaxPacketSize represent the
437 * maximum packet size.
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300438 * For SS devices the wMaxPacketSize is limited by 1024.
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300439 */
440 max = le16_to_cpu(desc->wMaxPacketSize) & 0x7ff;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700441
442 /* drivers must not request bad settings, since lower levels
443 * (hardware or its drivers) may not check. some endpoints
444 * can't do iso, many have maxpacket limitations, etc.
445 *
446 * since this "hardware" driver is here to help debugging, we
447 * have some extra sanity checks. (there could be more though,
448 * especially for "ep9out" style fixed function ones.)
449 */
450 retval = -EINVAL;
451 switch (desc->bmAttributes & 0x03) {
452 case USB_ENDPOINT_XFER_BULK:
453 if (strstr (ep->ep.name, "-iso")
454 || strstr (ep->ep.name, "-int")) {
455 goto done;
456 }
457 switch (dum->gadget.speed) {
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300458 case USB_SPEED_SUPER:
459 if (max == 1024)
460 break;
461 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700462 case USB_SPEED_HIGH:
463 if (max == 512)
464 break;
Ingo van Lil9063ff42008-03-28 14:50:26 -0700465 goto done;
466 case USB_SPEED_FULL:
467 if (max == 8 || max == 16 || max == 32 || max == 64)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700468 /* we'll fake any legal size */
469 break;
Ingo van Lil9063ff42008-03-28 14:50:26 -0700470 /* save a return statement */
471 default:
472 goto done;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700473 }
474 break;
475 case USB_ENDPOINT_XFER_INT:
476 if (strstr (ep->ep.name, "-iso")) /* bulk is ok */
477 goto done;
478 /* real hardware might not handle all packet sizes */
479 switch (dum->gadget.speed) {
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300480 case USB_SPEED_SUPER:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700481 case USB_SPEED_HIGH:
482 if (max <= 1024)
483 break;
484 /* save a return statement */
485 case USB_SPEED_FULL:
486 if (max <= 64)
487 break;
488 /* save a return statement */
489 default:
490 if (max <= 8)
491 break;
492 goto done;
493 }
494 break;
495 case USB_ENDPOINT_XFER_ISOC:
496 if (strstr (ep->ep.name, "-bulk")
497 || strstr (ep->ep.name, "-int"))
498 goto done;
499 /* real hardware might not handle all packet sizes */
500 switch (dum->gadget.speed) {
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300501 case USB_SPEED_SUPER:
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502 case USB_SPEED_HIGH:
503 if (max <= 1024)
504 break;
505 /* save a return statement */
506 case USB_SPEED_FULL:
507 if (max <= 1023)
508 break;
509 /* save a return statement */
510 default:
511 goto done;
512 }
513 break;
514 default:
515 /* few chips support control except on ep0 */
516 goto done;
517 }
518
519 _ep->maxpacket = max;
520 ep->desc = desc;
521
Alan Sternd9b76252005-05-03 16:15:43 -0400522 dev_dbg (udc_dev(dum), "enabled %s (ep%d%s-%s) maxpacket %d\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523 _ep->name,
524 desc->bEndpointAddress & 0x0f,
525 (desc->bEndpointAddress & USB_DIR_IN) ? "in" : "out",
526 ({ char *val;
527 switch (desc->bmAttributes & 0x03) {
Tatyana Brokhman7c884fe2011-06-28 16:33:52 +0300528 case USB_ENDPOINT_XFER_BULK:
529 val = "bulk";
530 break;
531 case USB_ENDPOINT_XFER_ISOC:
532 val = "iso";
533 break;
534 case USB_ENDPOINT_XFER_INT:
535 val = "intr";
536 break;
537 default:
538 val = "ctrl";
539 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700540 }; val; }),
541 max);
542
543 /* at this point real hardware should be NAKing transfers
544 * to that endpoint, until a buffer is queued to it.
545 */
Alan Stern851a5262008-08-14 15:48:30 -0400546 ep->halted = ep->wedged = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700547 retval = 0;
548done:
549 return retval;
550}
551
Linus Torvalds1da177e2005-04-16 15:20:36 -0700552static int dummy_disable (struct usb_ep *_ep)
553{
554 struct dummy_ep *ep;
555 struct dummy *dum;
556 unsigned long flags;
557 int retval;
558
559 ep = usb_ep_to_dummy_ep (_ep);
560 if (!_ep || !ep->desc || _ep->name == ep0name)
561 return -EINVAL;
562 dum = ep_to_dummy (ep);
563
564 spin_lock_irqsave (&dum->lock, flags);
565 ep->desc = NULL;
566 retval = 0;
567 nuke (dum, ep);
568 spin_unlock_irqrestore (&dum->lock, flags);
569
Alan Sternd9b76252005-05-03 16:15:43 -0400570 dev_dbg (udc_dev(dum), "disabled %s\n", _ep->name);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700571 return retval;
572}
573
574static struct usb_request *
Al Viro55016f12005-10-21 03:21:58 -0400575dummy_alloc_request (struct usb_ep *_ep, gfp_t mem_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700576{
577 struct dummy_ep *ep;
578 struct dummy_request *req;
579
580 if (!_ep)
581 return NULL;
582 ep = usb_ep_to_dummy_ep (_ep);
583
Eric Sesterhenn7039f422006-02-27 13:34:10 -0800584 req = kzalloc(sizeof(*req), mem_flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700585 if (!req)
586 return NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700587 INIT_LIST_HEAD (&req->queue);
588 return &req->req;
589}
590
591static void
592dummy_free_request (struct usb_ep *_ep, struct usb_request *_req)
593{
594 struct dummy_ep *ep;
595 struct dummy_request *req;
596
597 ep = usb_ep_to_dummy_ep (_ep);
598 if (!ep || !_req || (!ep->desc && _ep->name != ep0name))
599 return;
600
601 req = usb_request_to_dummy_request (_req);
602 WARN_ON (!list_empty (&req->queue));
603 kfree (req);
604}
605
Linus Torvalds1da177e2005-04-16 15:20:36 -0700606static void
607fifo_complete (struct usb_ep *ep, struct usb_request *req)
608{
609}
610
611static int
Olav Kongas5db539e2005-06-23 20:25:36 +0300612dummy_queue (struct usb_ep *_ep, struct usb_request *_req,
Al Viro55016f12005-10-21 03:21:58 -0400613 gfp_t mem_flags)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700614{
615 struct dummy_ep *ep;
616 struct dummy_request *req;
617 struct dummy *dum;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300618 struct dummy_hcd *dum_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700619 unsigned long flags;
620
621 req = usb_request_to_dummy_request (_req);
622 if (!_req || !list_empty (&req->queue) || !_req->complete)
623 return -EINVAL;
624
625 ep = usb_ep_to_dummy_ep (_ep);
626 if (!_ep || (!ep->desc && _ep->name != ep0name))
627 return -EINVAL;
628
629 dum = ep_to_dummy (ep);
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300630 if (dum->gadget.speed == USB_SPEED_SUPER)
631 dum_hcd = dum->ss_hcd;
632 else
633 dum_hcd = dum->hs_hcd;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300634 if (!dum->driver || !is_enabled(dum_hcd))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700635 return -ESHUTDOWN;
636
637#if 0
Alan Sternd9b76252005-05-03 16:15:43 -0400638 dev_dbg (udc_dev(dum), "ep %p queue req %p to %s, len %d buf %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700639 ep, _req, _ep->name, _req->length, _req->buf);
640#endif
641
642 _req->status = -EINPROGRESS;
643 _req->actual = 0;
644 spin_lock_irqsave (&dum->lock, flags);
645
646 /* implement an emulated single-request FIFO */
647 if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
648 list_empty (&dum->fifo_req.queue) &&
649 list_empty (&ep->queue) &&
650 _req->length <= FIFO_SIZE) {
651 req = &dum->fifo_req;
652 req->req = *_req;
653 req->req.buf = dum->fifo_buf;
654 memcpy (dum->fifo_buf, _req->buf, _req->length);
655 req->req.context = dum;
656 req->req.complete = fifo_complete;
657
David Brownellc728df72008-07-26 08:06:24 -0700658 list_add_tail(&req->queue, &ep->queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700659 spin_unlock (&dum->lock);
660 _req->actual = _req->length;
661 _req->status = 0;
662 _req->complete (_ep, _req);
663 spin_lock (&dum->lock);
David Brownellc728df72008-07-26 08:06:24 -0700664 } else
665 list_add_tail(&req->queue, &ep->queue);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700666 spin_unlock_irqrestore (&dum->lock, flags);
667
668 /* real hardware would likely enable transfers here, in case
669 * it'd been left NAKing.
670 */
671 return 0;
672}
673
674static int dummy_dequeue (struct usb_ep *_ep, struct usb_request *_req)
675{
676 struct dummy_ep *ep;
677 struct dummy *dum;
678 int retval = -EINVAL;
679 unsigned long flags;
680 struct dummy_request *req = NULL;
681
682 if (!_ep || !_req)
683 return retval;
684 ep = usb_ep_to_dummy_ep (_ep);
685 dum = ep_to_dummy (ep);
686
687 if (!dum->driver)
688 return -ESHUTDOWN;
689
Alan Sternb4dbda12006-07-28 17:07:34 -0400690 local_irq_save (flags);
691 spin_lock (&dum->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700692 list_for_each_entry (req, &ep->queue, queue) {
693 if (&req->req == _req) {
694 list_del_init (&req->queue);
695 _req->status = -ECONNRESET;
696 retval = 0;
697 break;
698 }
699 }
Alan Sternb4dbda12006-07-28 17:07:34 -0400700 spin_unlock (&dum->lock);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700701
702 if (retval == 0) {
Alan Sternd9b76252005-05-03 16:15:43 -0400703 dev_dbg (udc_dev(dum),
Linus Torvalds1da177e2005-04-16 15:20:36 -0700704 "dequeued req %p from %s, len %d buf %p\n",
705 req, _ep->name, _req->length, _req->buf);
706 _req->complete (_ep, _req);
707 }
Alan Sternb4dbda12006-07-28 17:07:34 -0400708 local_irq_restore (flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 return retval;
710}
711
712static int
Alan Stern851a5262008-08-14 15:48:30 -0400713dummy_set_halt_and_wedge(struct usb_ep *_ep, int value, int wedged)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700714{
715 struct dummy_ep *ep;
716 struct dummy *dum;
717
718 if (!_ep)
719 return -EINVAL;
720 ep = usb_ep_to_dummy_ep (_ep);
721 dum = ep_to_dummy (ep);
722 if (!dum->driver)
723 return -ESHUTDOWN;
724 if (!value)
Alan Stern851a5262008-08-14 15:48:30 -0400725 ep->halted = ep->wedged = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700726 else if (ep->desc && (ep->desc->bEndpointAddress & USB_DIR_IN) &&
727 !list_empty (&ep->queue))
728 return -EAGAIN;
Alan Stern851a5262008-08-14 15:48:30 -0400729 else {
Linus Torvalds1da177e2005-04-16 15:20:36 -0700730 ep->halted = 1;
Alan Stern851a5262008-08-14 15:48:30 -0400731 if (wedged)
732 ep->wedged = 1;
733 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700734 /* FIXME clear emulated data toggle too */
735 return 0;
736}
737
Alan Stern851a5262008-08-14 15:48:30 -0400738static int
739dummy_set_halt(struct usb_ep *_ep, int value)
740{
741 return dummy_set_halt_and_wedge(_ep, value, 0);
742}
743
744static int dummy_set_wedge(struct usb_ep *_ep)
745{
746 if (!_ep || _ep->name == ep0name)
747 return -EINVAL;
748 return dummy_set_halt_and_wedge(_ep, 1, 1);
749}
750
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751static const struct usb_ep_ops dummy_ep_ops = {
752 .enable = dummy_enable,
753 .disable = dummy_disable,
754
755 .alloc_request = dummy_alloc_request,
756 .free_request = dummy_free_request,
757
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 .queue = dummy_queue,
759 .dequeue = dummy_dequeue,
760
761 .set_halt = dummy_set_halt,
Alan Stern851a5262008-08-14 15:48:30 -0400762 .set_wedge = dummy_set_wedge,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700763};
764
765/*-------------------------------------------------------------------------*/
766
767/* there are both host and device side versions of this call ... */
768static int dummy_g_get_frame (struct usb_gadget *_gadget)
769{
770 struct timeval tv;
771
772 do_gettimeofday (&tv);
773 return tv.tv_usec / 1000;
774}
775
776static int dummy_wakeup (struct usb_gadget *_gadget)
777{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300778 struct dummy_hcd *dum_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700779
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300780 dum_hcd = gadget_to_dummy_hcd(_gadget);
781 if (!(dum_hcd->dum->devstatus & ((1 << USB_DEVICE_B_HNP_ENABLE)
Alan Stern5742b0c2005-05-02 11:25:17 -0400782 | (1 << USB_DEVICE_REMOTE_WAKEUP))))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700783 return -EINVAL;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300784 if ((dum_hcd->port_status & USB_PORT_STAT_CONNECTION) == 0)
Alan Stern391eca92005-05-10 15:34:16 -0400785 return -ENOLINK;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300786 if ((dum_hcd->port_status & USB_PORT_STAT_SUSPEND) == 0 &&
787 dum_hcd->rh_state != DUMMY_RH_SUSPENDED)
Alan Stern391eca92005-05-10 15:34:16 -0400788 return -EIO;
789
790 /* FIXME: What if the root hub is suspended but the port isn't? */
Linus Torvalds1da177e2005-04-16 15:20:36 -0700791
792 /* hub notices our request, issues downstream resume, etc */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300793 dum_hcd->resuming = 1;
794 dum_hcd->re_timeout = jiffies + msecs_to_jiffies(20);
795 mod_timer(&dummy_hcd_to_hcd(dum_hcd)->rh_timer, dum_hcd->re_timeout);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796 return 0;
797}
798
799static int dummy_set_selfpowered (struct usb_gadget *_gadget, int value)
800{
801 struct dummy *dum;
802
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300803 dum = (gadget_to_dummy_hcd(_gadget))->dum;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700804 if (value)
805 dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
806 else
807 dum->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
808 return 0;
809}
810
Alan Sternf1c39fa2005-05-03 16:24:04 -0400811static int dummy_pullup (struct usb_gadget *_gadget, int value)
812{
813 struct dummy *dum;
814 unsigned long flags;
815
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300816 dum = gadget_to_dummy_hcd(_gadget)->dum;
Alan Sternf1c39fa2005-05-03 16:24:04 -0400817 spin_lock_irqsave (&dum->lock, flags);
818 dum->pullup = (value != 0);
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300819 set_link_state((dum->gadget.speed == USB_SPEED_SUPER ?
820 dum->ss_hcd : dum->hs_hcd));
Alan Sternf1c39fa2005-05-03 16:24:04 -0400821 spin_unlock_irqrestore (&dum->lock, flags);
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300822 usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
823 dummy_hcd_to_hcd(dum->ss_hcd) :
824 dummy_hcd_to_hcd(dum->hs_hcd)));
Alan Sternf1c39fa2005-05-03 16:24:04 -0400825 return 0;
826}
827
Sebastian Andrzej Siewior0f913492011-06-28 16:33:47 +0300828static int dummy_udc_start(struct usb_gadget_driver *driver,
829 int (*bind)(struct usb_gadget *));
830static int dummy_udc_stop(struct usb_gadget_driver *driver);
831
Linus Torvalds1da177e2005-04-16 15:20:36 -0700832static const struct usb_gadget_ops dummy_ops = {
833 .get_frame = dummy_g_get_frame,
834 .wakeup = dummy_wakeup,
835 .set_selfpowered = dummy_set_selfpowered,
Alan Sternf1c39fa2005-05-03 16:24:04 -0400836 .pullup = dummy_pullup,
Sebastian Andrzej Siewior0f913492011-06-28 16:33:47 +0300837 .start = dummy_udc_start,
838 .stop = dummy_udc_stop,
Linus Torvalds1da177e2005-04-16 15:20:36 -0700839};
840
841/*-------------------------------------------------------------------------*/
842
843/* "function" sysfs attribute */
844static ssize_t
Yani Ioannou10523b32005-05-17 06:43:37 -0400845show_function (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700846{
847 struct dummy *dum = gadget_dev_to_dummy (dev);
848
849 if (!dum->driver || !dum->driver->function)
850 return 0;
851 return scnprintf (buf, PAGE_SIZE, "%s\n", dum->driver->function);
852}
Alan Sterncc095b02005-05-10 15:28:38 -0400853static DEVICE_ATTR (function, S_IRUGO, show_function, NULL);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700854
855/*-------------------------------------------------------------------------*/
856
857/*
858 * Driver registration/unregistration.
859 *
860 * This is basically hardware-specific; there's usually only one real USB
861 * device (not host) controller since that's how USB devices are intended
862 * to work. So most implementations of these api calls will rely on the
863 * fact that only one driver will ever bind to the hardware. But curious
864 * hardware can be built with discrete components, so the gadget API doesn't
865 * require that assumption.
866 *
867 * For this emulator, it might be convenient to create a usb slave device
868 * for each driver that registers: just add to a big root hub.
869 */
870
Sebastian Andrzej Siewior0f913492011-06-28 16:33:47 +0300871static int dummy_udc_start(struct usb_gadget_driver *driver,
Uwe Kleine-Königb0fca502010-08-12 17:43:53 +0200872 int (*bind)(struct usb_gadget *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700873{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300874 struct dummy *dum = &the_controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700875 int retval, i;
876
877 if (!dum)
878 return -EINVAL;
879 if (dum->driver)
880 return -EBUSY;
Uwe Kleine-Königb0fca502010-08-12 17:43:53 +0200881 if (!bind || !driver->setup || driver->speed == USB_SPEED_UNKNOWN)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700882 return -EINVAL;
883
884 /*
885 * SLAVE side init ... the layer above hardware, which
886 * can't enumerate without help from the driver we're binding.
887 */
Alan Stern5742b0c2005-05-02 11:25:17 -0400888
Linus Torvalds1da177e2005-04-16 15:20:36 -0700889 dum->devstatus = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700890
891 INIT_LIST_HEAD (&dum->gadget.ep_list);
892 for (i = 0; i < DUMMY_ENDPOINTS; i++) {
893 struct dummy_ep *ep = &dum->ep [i];
894
895 if (!ep_name [i])
896 break;
897 ep->ep.name = ep_name [i];
898 ep->ep.ops = &dummy_ep_ops;
899 list_add_tail (&ep->ep.ep_list, &dum->gadget.ep_list);
Alan Stern851a5262008-08-14 15:48:30 -0400900 ep->halted = ep->wedged = ep->already_seen =
901 ep->setup_stage = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700902 ep->ep.maxpacket = ~0;
903 ep->last_io = jiffies;
904 ep->gadget = &dum->gadget;
905 ep->desc = NULL;
906 INIT_LIST_HEAD (&ep->queue);
907 }
908
909 dum->gadget.ep0 = &dum->ep [0].ep;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300910 if (mod_data.is_super_speed)
911 dum->gadget.speed = driver->speed;
912 else
913 dum->gadget.speed = min((u8)USB_SPEED_HIGH, (u8)driver->speed);
914 if (dum->gadget.speed < driver->speed)
915 dev_dbg(udc_dev(dum), "This device can perform faster if"
916 " you connect it to a "
917 "SupeSpeed port...\n");
918
919 if (dum->gadget.speed == USB_SPEED_SUPER) {
920 for (i = 0; i < DUMMY_ENDPOINTS; i++)
921 dum->ep[i].ep.max_streams = 0x10;
922 dum->ep[0].ep.maxpacket = 9;
923 } else
924 dum->ep[0].ep.maxpacket = 64;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700925 list_del_init (&dum->ep [0].ep.ep_list);
926 INIT_LIST_HEAD(&dum->fifo_req.queue);
927
Alan Stern59331012007-11-20 16:28:55 -0500928 driver->driver.bus = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700929 dum->driver = driver;
930 dum->gadget.dev.driver = &driver->driver;
Alan Sternd9b76252005-05-03 16:15:43 -0400931 dev_dbg (udc_dev(dum), "binding gadget driver '%s'\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700932 driver->driver.name);
Uwe Kleine-Königb0fca502010-08-12 17:43:53 +0200933 retval = bind(&dum->gadget);
Alan Stern59331012007-11-20 16:28:55 -0500934 if (retval) {
935 dum->driver = NULL;
936 dum->gadget.dev.driver = NULL;
937 return retval;
938 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939
940 /* khubd will enumerate this in a while */
Alan Sternf1c39fa2005-05-03 16:24:04 -0400941 spin_lock_irq (&dum->lock);
942 dum->pullup = 1;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300943 if (dum->gadget.speed == USB_SPEED_SUPER) {
944 dum->gadget.is_otg =
945 (dummy_hcd_to_hcd(dum->ss_hcd)->self.otg_port != 0);
946 set_link_state(dum->ss_hcd);
947 } else {
948 dum->gadget.is_otg =
949 (dummy_hcd_to_hcd(dum->hs_hcd)->self.otg_port != 0);
950 set_link_state(dum->hs_hcd);
951 }
952
Alan Sternf1c39fa2005-05-03 16:24:04 -0400953 spin_unlock_irq (&dum->lock);
Alan Stern685eb932005-05-03 16:27:26 -0400954
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300955 usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
956 dummy_hcd_to_hcd(dum->ss_hcd) :
957 dummy_hcd_to_hcd(dum->hs_hcd)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700958 return 0;
959}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700960
Sebastian Andrzej Siewior0f913492011-06-28 16:33:47 +0300961static int dummy_udc_stop(struct usb_gadget_driver *driver)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700962{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +0300963 struct dummy *dum = &the_controller;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700964 unsigned long flags;
965
966 if (!dum)
967 return -ENODEV;
David Brownell6bea4762006-12-05 03:15:33 -0800968 if (!driver || driver != dum->driver || !driver->unbind)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700969 return -EINVAL;
970
Alan Sternd9b76252005-05-03 16:15:43 -0400971 dev_dbg (udc_dev(dum), "unregister gadget driver '%s'\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -0700972 driver->driver.name);
973
974 spin_lock_irqsave (&dum->lock, flags);
Alan Sternf1c39fa2005-05-03 16:24:04 -0400975 dum->pullup = 0;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300976 set_link_state((dum->gadget.speed == USB_SPEED_SUPER ?
977 dum->ss_hcd : dum->hs_hcd));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700978 spin_unlock_irqrestore (&dum->lock, flags);
979
980 driver->unbind (&dum->gadget);
Alan Stern59331012007-11-20 16:28:55 -0500981 dum->gadget.dev.driver = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700982 dum->driver = NULL;
Alan Sternf1c39fa2005-05-03 16:24:04 -0400983 spin_lock_irqsave (&dum->lock, flags);
984 dum->pullup = 0;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300985 set_link_state((dum->gadget.speed == USB_SPEED_SUPER ?
986 dum->ss_hcd : dum->hs_hcd));
Alan Sternf1c39fa2005-05-03 16:24:04 -0400987 spin_unlock_irqrestore (&dum->lock, flags);
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +0300988 usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
989 dummy_hcd_to_hcd(dum->ss_hcd) :
990 dummy_hcd_to_hcd(dum->hs_hcd)));
Linus Torvalds1da177e2005-04-16 15:20:36 -0700991 return 0;
992}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700993
994#undef is_enabled
995
Alan Sterncc095b02005-05-10 15:28:38 -0400996/* just declare this in any driver that really need it */
997extern int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode);
998
Linus Torvalds1da177e2005-04-16 15:20:36 -0700999int net2280_set_fifo_mode (struct usb_gadget *gadget, int mode)
1000{
1001 return -ENOSYS;
1002}
1003EXPORT_SYMBOL (net2280_set_fifo_mode);
1004
Alan Sternd9b76252005-05-03 16:15:43 -04001005
1006/* The gadget structure is stored inside the hcd structure and will be
1007 * released along with it. */
1008static void
1009dummy_gadget_release (struct device *dev)
1010{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001011 return;
Alan Sternd9b76252005-05-03 16:15:43 -04001012}
1013
Alan Stern8364d6b2005-11-14 12:16:30 -05001014static int dummy_udc_probe (struct platform_device *pdev)
Alan Sternd9b76252005-05-03 16:15:43 -04001015{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001016 struct dummy *dum = &the_controller;
Alan Sternd9b76252005-05-03 16:15:43 -04001017 int rc;
1018
1019 dum->gadget.name = gadget_name;
1020 dum->gadget.ops = &dummy_ops;
1021 dum->gadget.is_dualspeed = 1;
1022
Kay Sievers0031a062008-05-02 06:02:41 +02001023 dev_set_name(&dum->gadget.dev, "gadget");
Alan Stern8364d6b2005-11-14 12:16:30 -05001024 dum->gadget.dev.parent = &pdev->dev;
Alan Sternd9b76252005-05-03 16:15:43 -04001025 dum->gadget.dev.release = dummy_gadget_release;
1026 rc = device_register (&dum->gadget.dev);
Rahul Ruikar75d87cd2010-10-07 09:40:45 +05301027 if (rc < 0) {
1028 put_device(&dum->gadget.dev);
Alan Sternd9b76252005-05-03 16:15:43 -04001029 return rc;
Rahul Ruikar75d87cd2010-10-07 09:40:45 +05301030 }
Alan Sternd9b76252005-05-03 16:15:43 -04001031
Sebastian Andrzej Siewior0f913492011-06-28 16:33:47 +03001032 rc = usb_add_gadget_udc(&pdev->dev, &dum->gadget);
1033 if (rc < 0)
1034 goto err_udc;
1035
Alan Sternefd54a32006-09-25 11:55:56 -04001036 rc = device_create_file (&dum->gadget.dev, &dev_attr_function);
1037 if (rc < 0)
Sebastian Andrzej Siewior0f913492011-06-28 16:33:47 +03001038 goto err_dev;
1039 platform_set_drvdata(pdev, dum);
1040 return rc;
1041
1042err_dev:
1043 usb_del_gadget_udc(&dum->gadget);
1044err_udc:
1045 device_unregister(&dum->gadget.dev);
Alan Sternd9b76252005-05-03 16:15:43 -04001046 return rc;
1047}
1048
Alan Stern8364d6b2005-11-14 12:16:30 -05001049static int dummy_udc_remove (struct platform_device *pdev)
Alan Sternd9b76252005-05-03 16:15:43 -04001050{
Alan Stern8364d6b2005-11-14 12:16:30 -05001051 struct dummy *dum = platform_get_drvdata (pdev);
Alan Sternd9b76252005-05-03 16:15:43 -04001052
Sebastian Andrzej Siewior0f913492011-06-28 16:33:47 +03001053 usb_del_gadget_udc(&dum->gadget);
Alan Stern8364d6b2005-11-14 12:16:30 -05001054 platform_set_drvdata (pdev, NULL);
Alan Sternd9b76252005-05-03 16:15:43 -04001055 device_remove_file (&dum->gadget.dev, &dev_attr_function);
1056 device_unregister (&dum->gadget.dev);
1057 return 0;
1058}
1059
Alan Stern8364d6b2005-11-14 12:16:30 -05001060static int dummy_udc_suspend (struct platform_device *pdev, pm_message_t state)
Alan Stern391eca92005-05-10 15:34:16 -04001061{
Alan Stern8364d6b2005-11-14 12:16:30 -05001062 struct dummy *dum = platform_get_drvdata(pdev);
Alan Stern391eca92005-05-10 15:34:16 -04001063
Harvey Harrison441b62c2008-03-03 16:08:34 -08001064 dev_dbg (&pdev->dev, "%s\n", __func__);
Alan Stern391eca92005-05-10 15:34:16 -04001065 spin_lock_irq (&dum->lock);
1066 dum->udc_suspended = 1;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001067 set_link_state((dum->gadget.speed == USB_SPEED_SUPER ?
1068 dum->ss_hcd : dum->hs_hcd));
Alan Stern391eca92005-05-10 15:34:16 -04001069 spin_unlock_irq (&dum->lock);
1070
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001071 usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
1072 dummy_hcd_to_hcd(dum->ss_hcd) :
1073 dummy_hcd_to_hcd(dum->hs_hcd)));
Alan Stern391eca92005-05-10 15:34:16 -04001074 return 0;
1075}
1076
Alan Stern8364d6b2005-11-14 12:16:30 -05001077static int dummy_udc_resume (struct platform_device *pdev)
Alan Stern391eca92005-05-10 15:34:16 -04001078{
Alan Stern8364d6b2005-11-14 12:16:30 -05001079 struct dummy *dum = platform_get_drvdata(pdev);
Alan Stern391eca92005-05-10 15:34:16 -04001080
Harvey Harrison441b62c2008-03-03 16:08:34 -08001081 dev_dbg (&pdev->dev, "%s\n", __func__);
Alan Stern391eca92005-05-10 15:34:16 -04001082 spin_lock_irq (&dum->lock);
1083 dum->udc_suspended = 0;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001084 set_link_state((dum->gadget.speed == USB_SPEED_SUPER ?
1085 dum->ss_hcd : dum->hs_hcd));
Alan Stern391eca92005-05-10 15:34:16 -04001086 spin_unlock_irq (&dum->lock);
1087
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001088 usb_hcd_poll_rh_status((dum->gadget.speed == USB_SPEED_SUPER ?
1089 dummy_hcd_to_hcd(dum->ss_hcd) :
1090 dummy_hcd_to_hcd(dum->hs_hcd)));
Alan Stern391eca92005-05-10 15:34:16 -04001091 return 0;
1092}
1093
Russell King3ae5eae2005-11-09 22:32:44 +00001094static struct platform_driver dummy_udc_driver = {
Alan Sternd9b76252005-05-03 16:15:43 -04001095 .probe = dummy_udc_probe,
1096 .remove = dummy_udc_remove,
Alan Stern391eca92005-05-10 15:34:16 -04001097 .suspend = dummy_udc_suspend,
1098 .resume = dummy_udc_resume,
Russell King3ae5eae2005-11-09 22:32:44 +00001099 .driver = {
1100 .name = (char *) gadget_name,
1101 .owner = THIS_MODULE,
1102 },
Alan Sternd9b76252005-05-03 16:15:43 -04001103};
1104
Linus Torvalds1da177e2005-04-16 15:20:36 -07001105/*-------------------------------------------------------------------------*/
1106
1107/* MASTER/HOST SIDE DRIVER
1108 *
1109 * this uses the hcd framework to hook up to host side drivers.
1110 * its root hub will only have one device, otherwise it acts like
1111 * a normal host controller.
1112 *
1113 * when urbs are queued, they're just stuck on a list that we
1114 * scan in a timer callback. that callback connects writes from
1115 * the host with reads from the device, and so on, based on the
1116 * usb 2.0 rules.
1117 */
1118
1119static int dummy_urb_enqueue (
1120 struct usb_hcd *hcd,
Linus Torvalds1da177e2005-04-16 15:20:36 -07001121 struct urb *urb,
Al Viro55016f12005-10-21 03:21:58 -04001122 gfp_t mem_flags
Linus Torvalds1da177e2005-04-16 15:20:36 -07001123) {
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001124 struct dummy_hcd *dum_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001125 struct urbp *urbp;
1126 unsigned long flags;
Alan Sterne9df41c2007-08-08 11:48:02 -04001127 int rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001128
1129 if (!urb->transfer_buffer && urb->transfer_buffer_length)
1130 return -EINVAL;
1131
1132 urbp = kmalloc (sizeof *urbp, mem_flags);
1133 if (!urbp)
1134 return -ENOMEM;
1135 urbp->urb = urb;
1136
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001137 dum_hcd = hcd_to_dummy_hcd(hcd);
1138 spin_lock_irqsave(&dum_hcd->dum->lock, flags);
Alan Sterne9df41c2007-08-08 11:48:02 -04001139 rc = usb_hcd_link_urb_to_ep(hcd, urb);
1140 if (rc) {
1141 kfree(urbp);
1142 goto done;
1143 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001144
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001145 if (!dum_hcd->udev) {
1146 dum_hcd->udev = urb->dev;
1147 usb_get_dev(dum_hcd->udev);
1148 } else if (unlikely(dum_hcd->udev != urb->dev))
1149 dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001150
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001151 list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001152 urb->hcpriv = urbp;
1153 if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
1154 urb->error_count = 1; /* mark as a new urb */
1155
1156 /* kick the scheduler, it'll do the rest */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001157 if (!timer_pending(&dum_hcd->timer))
1158 mod_timer(&dum_hcd->timer, jiffies + 1);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001159
Alan Sterne9df41c2007-08-08 11:48:02 -04001160 done:
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001161 spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
Alan Sterne9df41c2007-08-08 11:48:02 -04001162 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001163}
1164
Alan Sterne9df41c2007-08-08 11:48:02 -04001165static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001166{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001167 struct dummy_hcd *dum_hcd;
Alan Stern391eca92005-05-10 15:34:16 -04001168 unsigned long flags;
Alan Sterne9df41c2007-08-08 11:48:02 -04001169 int rc;
Alan Stern391eca92005-05-10 15:34:16 -04001170
1171 /* giveback happens automatically in timer callback,
1172 * so make sure the callback happens */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001173 dum_hcd = hcd_to_dummy_hcd(hcd);
1174 spin_lock_irqsave(&dum_hcd->dum->lock, flags);
Alan Sterne9df41c2007-08-08 11:48:02 -04001175
1176 rc = usb_hcd_check_unlink_urb(hcd, urb, status);
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001177 if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
1178 !list_empty(&dum_hcd->urbp_list))
1179 mod_timer(&dum_hcd->timer, jiffies);
Alan Sterne9df41c2007-08-08 11:48:02 -04001180
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001181 spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
Alan Sterne9df41c2007-08-08 11:48:02 -04001182 return rc;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001183}
1184
Linus Torvalds1da177e2005-04-16 15:20:36 -07001185/* transfer up to a frame's worth; caller must own lock */
1186static int
Alan Stern4d2f1102007-08-24 15:40:10 -04001187transfer(struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit,
1188 int *status)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001189{
1190 struct dummy_request *req;
1191
1192top:
1193 /* if there's no request queued, the device is NAKing; return */
1194 list_for_each_entry (req, &ep->queue, queue) {
1195 unsigned host_len, dev_len, len;
1196 int is_short, to_host;
1197 int rescan = 0;
1198
1199 /* 1..N packets of ep->ep.maxpacket each ... the last one
1200 * may be short (including zero length).
1201 *
1202 * writer can send a zlp explicitly (length 0) or implicitly
1203 * (length mod maxpacket zero, and 'zero' flag); they always
1204 * terminate reads.
1205 */
1206 host_len = urb->transfer_buffer_length - urb->actual_length;
1207 dev_len = req->req.length - req->req.actual;
1208 len = min (host_len, dev_len);
1209
1210 /* FIXME update emulated data toggle too */
1211
1212 to_host = usb_pipein (urb->pipe);
1213 if (unlikely (len == 0))
1214 is_short = 1;
1215 else {
1216 char *ubuf, *rbuf;
1217
1218 /* not enough bandwidth left? */
1219 if (limit < ep->ep.maxpacket && limit < len)
1220 break;
1221 len = min (len, (unsigned) limit);
1222 if (len == 0)
1223 break;
1224
1225 /* use an extra pass for the final short packet */
1226 if (len > ep->ep.maxpacket) {
1227 rescan = 1;
1228 len -= (len % ep->ep.maxpacket);
1229 }
1230 is_short = (len % ep->ep.maxpacket) != 0;
1231
1232 /* else transfer packet(s) */
1233 ubuf = urb->transfer_buffer + urb->actual_length;
1234 rbuf = req->req.buf + req->req.actual;
1235 if (to_host)
1236 memcpy (ubuf, rbuf, len);
1237 else
1238 memcpy (rbuf, ubuf, len);
1239 ep->last_io = jiffies;
1240
1241 limit -= len;
1242 urb->actual_length += len;
1243 req->req.actual += len;
1244 }
1245
1246 /* short packets terminate, maybe with overflow/underflow.
1247 * it's only really an error to write too much.
1248 *
1249 * partially filling a buffer optionally blocks queue advances
1250 * (so completion handlers can clean up the queue) but we don't
Alan Sternb0d9efb2007-08-21 15:39:21 -04001251 * need to emulate such data-in-flight.
Linus Torvalds1da177e2005-04-16 15:20:36 -07001252 */
1253 if (is_short) {
1254 if (host_len == dev_len) {
1255 req->req.status = 0;
Alan Stern4d2f1102007-08-24 15:40:10 -04001256 *status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001257 } else if (to_host) {
1258 req->req.status = 0;
1259 if (dev_len > host_len)
Alan Stern4d2f1102007-08-24 15:40:10 -04001260 *status = -EOVERFLOW;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001261 else
Alan Stern4d2f1102007-08-24 15:40:10 -04001262 *status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001263 } else if (!to_host) {
Alan Stern4d2f1102007-08-24 15:40:10 -04001264 *status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001265 if (host_len > dev_len)
1266 req->req.status = -EOVERFLOW;
1267 else
1268 req->req.status = 0;
1269 }
1270
1271 /* many requests terminate without a short packet */
1272 } else {
1273 if (req->req.length == req->req.actual
1274 && !req->req.zero)
1275 req->req.status = 0;
1276 if (urb->transfer_buffer_length == urb->actual_length
1277 && !(urb->transfer_flags
Alan Stern4d2f1102007-08-24 15:40:10 -04001278 & URB_ZERO_PACKET))
1279 *status = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001280 }
1281
1282 /* device side completion --> continuable */
1283 if (req->req.status != -EINPROGRESS) {
1284 list_del_init (&req->queue);
1285
1286 spin_unlock (&dum->lock);
1287 req->req.complete (&ep->ep, &req->req);
1288 spin_lock (&dum->lock);
1289
1290 /* requests might have been unlinked... */
1291 rescan = 1;
1292 }
1293
1294 /* host side completion --> terminate */
Alan Stern4d2f1102007-08-24 15:40:10 -04001295 if (*status != -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001296 break;
1297
1298 /* rescan to continue with any other queued i/o */
1299 if (rescan)
1300 goto top;
1301 }
1302 return limit;
1303}
1304
1305static int periodic_bytes (struct dummy *dum, struct dummy_ep *ep)
1306{
1307 int limit = ep->ep.maxpacket;
1308
1309 if (dum->gadget.speed == USB_SPEED_HIGH) {
1310 int tmp;
1311
1312 /* high bandwidth mode */
1313 tmp = le16_to_cpu(ep->desc->wMaxPacketSize);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001314 tmp = (tmp >> 11) & 0x03;
1315 tmp *= 8 /* applies to entire frame */;
1316 limit += limit * tmp;
1317 }
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001318 if (dum->gadget.speed == USB_SPEED_SUPER) {
1319 switch (ep->desc->bmAttributes & 0x03) {
1320 case USB_ENDPOINT_XFER_ISOC:
1321 /* Sec. 4.4.8.2 USB3.0 Spec */
1322 limit = 3 * 16 * 1024 * 8;
1323 break;
1324 case USB_ENDPOINT_XFER_INT:
1325 /* Sec. 4.4.7.2 USB3.0 Spec */
1326 limit = 3 * 1024 * 8;
1327 break;
1328 case USB_ENDPOINT_XFER_BULK:
1329 default:
1330 break;
1331 }
1332 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001333 return limit;
1334}
1335
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001336#define is_active(dum_hcd) ((dum_hcd->port_status & \
Linus Torvalds1da177e2005-04-16 15:20:36 -07001337 (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE | \
1338 USB_PORT_STAT_SUSPEND)) \
1339 == (USB_PORT_STAT_CONNECTION | USB_PORT_STAT_ENABLE))
1340
1341static struct dummy_ep *find_endpoint (struct dummy *dum, u8 address)
1342{
1343 int i;
1344
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001345 if (!is_active((dum->gadget.speed == USB_SPEED_SUPER ?
1346 dum->ss_hcd : dum->hs_hcd)))
Linus Torvalds1da177e2005-04-16 15:20:36 -07001347 return NULL;
1348 if ((address & ~USB_DIR_IN) == 0)
1349 return &dum->ep [0];
1350 for (i = 1; i < DUMMY_ENDPOINTS; i++) {
1351 struct dummy_ep *ep = &dum->ep [i];
1352
1353 if (!ep->desc)
1354 continue;
1355 if (ep->desc->bEndpointAddress == address)
1356 return ep;
1357 }
1358 return NULL;
1359}
1360
1361#undef is_active
1362
1363#define Dev_Request (USB_TYPE_STANDARD | USB_RECIP_DEVICE)
1364#define Dev_InRequest (Dev_Request | USB_DIR_IN)
1365#define Intf_Request (USB_TYPE_STANDARD | USB_RECIP_INTERFACE)
1366#define Intf_InRequest (Intf_Request | USB_DIR_IN)
1367#define Ep_Request (USB_TYPE_STANDARD | USB_RECIP_ENDPOINT)
1368#define Ep_InRequest (Ep_Request | USB_DIR_IN)
1369
Tatyana Brokhman8be8a9d2010-11-01 17:38:05 +02001370
1371/**
1372 * handle_control_request() - handles all control transfers
1373 * @dum: pointer to dummy (the_controller)
1374 * @urb: the urb request to handle
1375 * @setup: pointer to the setup data for a USB device control
1376 * request
1377 * @status: pointer to request handling status
1378 *
1379 * Return 0 - if the request was handled
1380 * 1 - if the request wasn't handles
1381 * error code on error
1382 */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001383static int handle_control_request(struct dummy_hcd *dum_hcd, struct urb *urb,
Tatyana Brokhman8be8a9d2010-11-01 17:38:05 +02001384 struct usb_ctrlrequest *setup,
1385 int *status)
1386{
1387 struct dummy_ep *ep2;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001388 struct dummy *dum = dum_hcd->dum;
Tatyana Brokhman8be8a9d2010-11-01 17:38:05 +02001389 int ret_val = 1;
1390 unsigned w_index;
1391 unsigned w_value;
1392
1393 w_index = le16_to_cpu(setup->wIndex);
1394 w_value = le16_to_cpu(setup->wValue);
1395 switch (setup->bRequest) {
1396 case USB_REQ_SET_ADDRESS:
1397 if (setup->bRequestType != Dev_Request)
1398 break;
1399 dum->address = w_value;
1400 *status = 0;
1401 dev_dbg(udc_dev(dum), "set_address = %d\n",
1402 w_value);
1403 ret_val = 0;
1404 break;
1405 case USB_REQ_SET_FEATURE:
1406 if (setup->bRequestType == Dev_Request) {
1407 ret_val = 0;
1408 switch (w_value) {
1409 case USB_DEVICE_REMOTE_WAKEUP:
1410 break;
1411 case USB_DEVICE_B_HNP_ENABLE:
1412 dum->gadget.b_hnp_enable = 1;
1413 break;
1414 case USB_DEVICE_A_HNP_SUPPORT:
1415 dum->gadget.a_hnp_support = 1;
1416 break;
1417 case USB_DEVICE_A_ALT_HNP_SUPPORT:
1418 dum->gadget.a_alt_hnp_support = 1;
1419 break;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001420 case USB_DEVICE_U1_ENABLE:
1421 if (dummy_hcd_to_hcd(dum_hcd)->speed ==
1422 HCD_USB3)
1423 w_value = USB_DEV_STAT_U1_ENABLED;
1424 else
1425 ret_val = -EOPNOTSUPP;
1426 break;
1427 case USB_DEVICE_U2_ENABLE:
1428 if (dummy_hcd_to_hcd(dum_hcd)->speed ==
1429 HCD_USB3)
1430 w_value = USB_DEV_STAT_U2_ENABLED;
1431 else
1432 ret_val = -EOPNOTSUPP;
1433 break;
1434 case USB_DEVICE_LTM_ENABLE:
1435 if (dummy_hcd_to_hcd(dum_hcd)->speed ==
1436 HCD_USB3)
1437 w_value = USB_DEV_STAT_LTM_ENABLED;
1438 else
1439 ret_val = -EOPNOTSUPP;
1440 break;
Tatyana Brokhman8be8a9d2010-11-01 17:38:05 +02001441 default:
1442 ret_val = -EOPNOTSUPP;
1443 }
1444 if (ret_val == 0) {
1445 dum->devstatus |= (1 << w_value);
1446 *status = 0;
1447 }
1448 } else if (setup->bRequestType == Ep_Request) {
1449 /* endpoint halt */
1450 ep2 = find_endpoint(dum, w_index);
1451 if (!ep2 || ep2->ep.name == ep0name) {
1452 ret_val = -EOPNOTSUPP;
1453 break;
1454 }
1455 ep2->halted = 1;
1456 ret_val = 0;
1457 *status = 0;
1458 }
1459 break;
1460 case USB_REQ_CLEAR_FEATURE:
1461 if (setup->bRequestType == Dev_Request) {
1462 ret_val = 0;
1463 switch (w_value) {
1464 case USB_DEVICE_REMOTE_WAKEUP:
1465 w_value = USB_DEVICE_REMOTE_WAKEUP;
1466 break;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001467 case USB_DEVICE_U1_ENABLE:
1468 if (dummy_hcd_to_hcd(dum_hcd)->speed ==
1469 HCD_USB3)
1470 w_value = USB_DEV_STAT_U1_ENABLED;
1471 else
1472 ret_val = -EOPNOTSUPP;
1473 break;
1474 case USB_DEVICE_U2_ENABLE:
1475 if (dummy_hcd_to_hcd(dum_hcd)->speed ==
1476 HCD_USB3)
1477 w_value = USB_DEV_STAT_U2_ENABLED;
1478 else
1479 ret_val = -EOPNOTSUPP;
1480 break;
1481 case USB_DEVICE_LTM_ENABLE:
1482 if (dummy_hcd_to_hcd(dum_hcd)->speed ==
1483 HCD_USB3)
1484 w_value = USB_DEV_STAT_LTM_ENABLED;
1485 else
1486 ret_val = -EOPNOTSUPP;
1487 break;
Tatyana Brokhman8be8a9d2010-11-01 17:38:05 +02001488 default:
1489 ret_val = -EOPNOTSUPP;
1490 break;
1491 }
1492 if (ret_val == 0) {
1493 dum->devstatus &= ~(1 << w_value);
1494 *status = 0;
1495 }
1496 } else if (setup->bRequestType == Ep_Request) {
1497 /* endpoint halt */
1498 ep2 = find_endpoint(dum, w_index);
1499 if (!ep2) {
1500 ret_val = -EOPNOTSUPP;
1501 break;
1502 }
1503 if (!ep2->wedged)
1504 ep2->halted = 0;
1505 ret_val = 0;
1506 *status = 0;
1507 }
1508 break;
1509 case USB_REQ_GET_STATUS:
1510 if (setup->bRequestType == Dev_InRequest
1511 || setup->bRequestType == Intf_InRequest
1512 || setup->bRequestType == Ep_InRequest) {
1513 char *buf;
1514 /*
1515 * device: remote wakeup, selfpowered
1516 * interface: nothing
1517 * endpoint: halt
1518 */
1519 buf = (char *)urb->transfer_buffer;
1520 if (urb->transfer_buffer_length > 0) {
1521 if (setup->bRequestType == Ep_InRequest) {
1522 ep2 = find_endpoint(dum, w_index);
1523 if (!ep2) {
1524 ret_val = -EOPNOTSUPP;
1525 break;
1526 }
1527 buf[0] = ep2->halted;
1528 } else if (setup->bRequestType ==
1529 Dev_InRequest) {
1530 buf[0] = (u8)dum->devstatus;
1531 } else
1532 buf[0] = 0;
1533 }
1534 if (urb->transfer_buffer_length > 1)
1535 buf[1] = 0;
1536 urb->actual_length = min_t(u32, 2,
1537 urb->transfer_buffer_length);
1538 ret_val = 0;
1539 *status = 0;
1540 }
1541 break;
1542 }
1543 return ret_val;
1544}
1545
Linus Torvalds1da177e2005-04-16 15:20:36 -07001546/* drive both sides of the transfers; looks like irq handlers to
1547 * both drivers except the callbacks aren't in_irq().
1548 */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001549static void dummy_timer(unsigned long _dum_hcd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001550{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001551 struct dummy_hcd *dum_hcd = (struct dummy_hcd *) _dum_hcd;
1552 struct dummy *dum = dum_hcd->dum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001553 struct urbp *urbp, *tmp;
1554 unsigned long flags;
1555 int limit, total;
1556 int i;
1557
1558 /* simplistic model for one frame's bandwidth */
1559 switch (dum->gadget.speed) {
1560 case USB_SPEED_LOW:
1561 total = 8/*bytes*/ * 12/*packets*/;
1562 break;
1563 case USB_SPEED_FULL:
1564 total = 64/*bytes*/ * 19/*packets*/;
1565 break;
1566 case USB_SPEED_HIGH:
1567 total = 512/*bytes*/ * 13/*packets*/ * 8/*uframes*/;
1568 break;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001569 case USB_SPEED_SUPER:
1570 /* Bus speed is 500000 bytes/ms, so use a little less */
1571 total = 490000;
1572 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001573 default:
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001574 dev_err(dummy_dev(dum_hcd), "bogus device speed\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001575 return;
1576 }
1577
1578 /* FIXME if HZ != 1000 this will probably misbehave ... */
1579
1580 /* look at each urb queued by the host side driver */
1581 spin_lock_irqsave (&dum->lock, flags);
1582
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001583 if (!dum_hcd->udev) {
1584 dev_err(dummy_dev(dum_hcd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001585 "timer fired with no URBs pending?\n");
1586 spin_unlock_irqrestore (&dum->lock, flags);
1587 return;
1588 }
1589
1590 for (i = 0; i < DUMMY_ENDPOINTS; i++) {
1591 if (!ep_name [i])
1592 break;
1593 dum->ep [i].already_seen = 0;
1594 }
1595
1596restart:
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001597 list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001598 struct urb *urb;
1599 struct dummy_request *req;
1600 u8 address;
1601 struct dummy_ep *ep = NULL;
1602 int type;
Alan Stern4d2f1102007-08-24 15:40:10 -04001603 int status = -EINPROGRESS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001604
1605 urb = urbp->urb;
Alan Sterneb231052007-08-21 15:40:36 -04001606 if (urb->unlinked)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001607 goto return_urb;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001608 else if (dum_hcd->rh_state != DUMMY_RH_RUNNING)
Alan Stern391eca92005-05-10 15:34:16 -04001609 continue;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001610 type = usb_pipetype (urb->pipe);
1611
1612 /* used up this frame's non-periodic bandwidth?
1613 * FIXME there's infinite bandwidth for control and
1614 * periodic transfers ... unrealistic.
1615 */
1616 if (total <= 0 && type == PIPE_BULK)
1617 continue;
1618
1619 /* find the gadget's ep for this request (if configured) */
1620 address = usb_pipeendpoint (urb->pipe);
1621 if (usb_pipein (urb->pipe))
1622 address |= USB_DIR_IN;
1623 ep = find_endpoint(dum, address);
1624 if (!ep) {
1625 /* set_configuration() disagreement */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001626 dev_dbg(dummy_dev(dum_hcd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001627 "no ep configured for urb %p\n",
1628 urb);
Alan Stern4d2f1102007-08-24 15:40:10 -04001629 status = -EPROTO;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001630 goto return_urb;
1631 }
1632
1633 if (ep->already_seen)
1634 continue;
1635 ep->already_seen = 1;
1636 if (ep == &dum->ep [0] && urb->error_count) {
1637 ep->setup_stage = 1; /* a new urb */
1638 urb->error_count = 0;
1639 }
1640 if (ep->halted && !ep->setup_stage) {
1641 /* NOTE: must not be iso! */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001642 dev_dbg(dummy_dev(dum_hcd), "ep %s halted, urb %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001643 ep->ep.name, urb);
Alan Stern4d2f1102007-08-24 15:40:10 -04001644 status = -EPIPE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001645 goto return_urb;
1646 }
1647 /* FIXME make sure both ends agree on maxpacket */
1648
1649 /* handle control requests */
1650 if (ep == &dum->ep [0] && ep->setup_stage) {
1651 struct usb_ctrlrequest setup;
1652 int value = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001653
1654 setup = *(struct usb_ctrlrequest*) urb->setup_packet;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001655 /* paranoia, in case of stale queued data */
1656 list_for_each_entry (req, &ep->queue, queue) {
1657 list_del_init (&req->queue);
1658 req->req.status = -EOVERFLOW;
Alan Sternd9b76252005-05-03 16:15:43 -04001659 dev_dbg (udc_dev(dum), "stale req = %p\n",
Linus Torvalds1da177e2005-04-16 15:20:36 -07001660 req);
1661
1662 spin_unlock (&dum->lock);
1663 req->req.complete (&ep->ep, &req->req);
1664 spin_lock (&dum->lock);
1665 ep->already_seen = 0;
1666 goto restart;
1667 }
1668
1669 /* gadget driver never sees set_address or operations
1670 * on standard feature flags. some hardware doesn't
1671 * even expose them.
1672 */
1673 ep->last_io = jiffies;
1674 ep->setup_stage = 0;
1675 ep->halted = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001676
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001677 value = handle_control_request(dum_hcd, urb, &setup,
Tatyana Brokhman8be8a9d2010-11-01 17:38:05 +02001678 &status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001679
1680 /* gadget driver handles all other requests. block
1681 * until setup() returns; no reentrancy issues etc.
1682 */
1683 if (value > 0) {
1684 spin_unlock (&dum->lock);
1685 value = dum->driver->setup (&dum->gadget,
1686 &setup);
1687 spin_lock (&dum->lock);
1688
1689 if (value >= 0) {
1690 /* no delays (max 64KB data stage) */
1691 limit = 64*1024;
1692 goto treat_control_like_bulk;
1693 }
1694 /* error, see below */
1695 }
1696
1697 if (value < 0) {
1698 if (value != -EOPNOTSUPP)
Alan Sternd9b76252005-05-03 16:15:43 -04001699 dev_dbg (udc_dev(dum),
Linus Torvalds1da177e2005-04-16 15:20:36 -07001700 "setup --> %d\n",
1701 value);
Alan Stern4d2f1102007-08-24 15:40:10 -04001702 status = -EPIPE;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001703 urb->actual_length = 0;
1704 }
1705
1706 goto return_urb;
1707 }
1708
1709 /* non-control requests */
1710 limit = total;
1711 switch (usb_pipetype (urb->pipe)) {
1712 case PIPE_ISOCHRONOUS:
1713 /* FIXME is it urb->interval since the last xfer?
1714 * use urb->iso_frame_desc[i].
1715 * complete whether or not ep has requests queued.
1716 * report random errors, to debug drivers.
1717 */
1718 limit = max (limit, periodic_bytes (dum, ep));
Alan Stern4d2f1102007-08-24 15:40:10 -04001719 status = -ENOSYS;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001720 break;
1721
1722 case PIPE_INTERRUPT:
1723 /* FIXME is it urb->interval since the last xfer?
1724 * this almost certainly polls too fast.
1725 */
1726 limit = max (limit, periodic_bytes (dum, ep));
1727 /* FALLTHROUGH */
1728
1729 // case PIPE_BULK: case PIPE_CONTROL:
1730 default:
1731 treat_control_like_bulk:
1732 ep->last_io = jiffies;
Alan Stern4d2f1102007-08-24 15:40:10 -04001733 total = transfer(dum, urb, ep, limit, &status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001734 break;
1735 }
1736
1737 /* incomplete transfer? */
Alan Stern4d2f1102007-08-24 15:40:10 -04001738 if (status == -EINPROGRESS)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001739 continue;
1740
1741return_urb:
Linus Torvalds1da177e2005-04-16 15:20:36 -07001742 list_del (&urbp->urbp_list);
1743 kfree (urbp);
1744 if (ep)
1745 ep->already_seen = ep->setup_stage = 0;
1746
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001747 usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001748 spin_unlock (&dum->lock);
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001749 usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001750 spin_lock (&dum->lock);
1751
1752 goto restart;
1753 }
1754
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001755 if (list_empty(&dum_hcd->urbp_list)) {
1756 usb_put_dev(dum_hcd->udev);
1757 dum_hcd->udev = NULL;
1758 } else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
Alan Stern391eca92005-05-10 15:34:16 -04001759 /* want a 1 msec delay here */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001760 mod_timer(&dum_hcd->timer, jiffies + msecs_to_jiffies(1));
Linus Torvalds1da177e2005-04-16 15:20:36 -07001761 }
1762
1763 spin_unlock_irqrestore (&dum->lock, flags);
1764}
1765
1766/*-------------------------------------------------------------------------*/
1767
1768#define PORT_C_MASK \
Alan Sternc2db8b52005-04-29 16:30:48 -04001769 ((USB_PORT_STAT_C_CONNECTION \
1770 | USB_PORT_STAT_C_ENABLE \
1771 | USB_PORT_STAT_C_SUSPEND \
1772 | USB_PORT_STAT_C_OVERCURRENT \
1773 | USB_PORT_STAT_C_RESET) << 16)
Linus Torvalds1da177e2005-04-16 15:20:36 -07001774
1775static int dummy_hub_status (struct usb_hcd *hcd, char *buf)
1776{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001777 struct dummy_hcd *dum_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001778 unsigned long flags;
Alan Stern391eca92005-05-10 15:34:16 -04001779 int retval = 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001780
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001781 dum_hcd = hcd_to_dummy_hcd(hcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001782
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001783 spin_lock_irqsave(&dum_hcd->dum->lock, flags);
Alan Stern541c7d42010-06-22 16:39:10 -04001784 if (!HCD_HW_ACCESSIBLE(hcd))
Alan Stern391eca92005-05-10 15:34:16 -04001785 goto done;
Alan Sternf1c39fa2005-05-03 16:24:04 -04001786
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001787 if (dum_hcd->resuming && time_after_eq(jiffies, dum_hcd->re_timeout)) {
1788 dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1789 dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
1790 set_link_state(dum_hcd);
Alan Sternf1c39fa2005-05-03 16:24:04 -04001791 }
1792
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001793 if ((dum_hcd->port_status & PORT_C_MASK) != 0) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001794 *buf = (1 << 1);
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001795 dev_dbg(dummy_dev(dum_hcd), "port status 0x%08x has changes\n",
1796 dum_hcd->port_status);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001797 retval = 1;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001798 if (dum_hcd->rh_state == DUMMY_RH_SUSPENDED)
Alan Stern391eca92005-05-10 15:34:16 -04001799 usb_hcd_resume_root_hub (hcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001800 }
Alan Stern391eca92005-05-10 15:34:16 -04001801done:
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001802 spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001803 return retval;
1804}
1805
1806static inline void
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001807ss_hub_descriptor(struct usb_hub_descriptor *desc)
1808{
1809 memset(desc, 0, sizeof *desc);
1810 desc->bDescriptorType = 0x2a;
1811 desc->bDescLength = 12;
1812 desc->wHubCharacteristics = cpu_to_le16(0x0001);
1813 desc->bNbrPorts = 1;
1814 desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
1815 desc->u.ss.DeviceRemovable = 0xffff;
1816}
1817
1818static inline void
Linus Torvalds1da177e2005-04-16 15:20:36 -07001819hub_descriptor (struct usb_hub_descriptor *desc)
1820{
1821 memset (desc, 0, sizeof *desc);
1822 desc->bDescriptorType = 0x29;
1823 desc->bDescLength = 9;
Al Virofd05e722008-04-28 07:00:16 +01001824 desc->wHubCharacteristics = cpu_to_le16(0x0001);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001825 desc->bNbrPorts = 1;
John Youndbe79bb2001-09-17 00:00:00 -07001826 desc->u.hs.DeviceRemovable[0] = 0xff;
1827 desc->u.hs.DeviceRemovable[1] = 0xff;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001828}
1829
1830static int dummy_hub_control (
1831 struct usb_hcd *hcd,
1832 u16 typeReq,
1833 u16 wValue,
1834 u16 wIndex,
1835 char *buf,
1836 u16 wLength
1837) {
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001838 struct dummy_hcd *dum_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001839 int retval = 0;
1840 unsigned long flags;
1841
Alan Stern541c7d42010-06-22 16:39:10 -04001842 if (!HCD_HW_ACCESSIBLE(hcd))
Alan Stern391eca92005-05-10 15:34:16 -04001843 return -ETIMEDOUT;
1844
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001845 dum_hcd = hcd_to_dummy_hcd(hcd);
1846
1847 spin_lock_irqsave(&dum_hcd->dum->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001848 switch (typeReq) {
1849 case ClearHubFeature:
1850 break;
1851 case ClearPortFeature:
1852 switch (wValue) {
1853 case USB_PORT_FEAT_SUSPEND:
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001854 if (hcd->speed == HCD_USB3) {
1855 dev_dbg(dummy_dev(dum_hcd),
1856 "USB_PORT_FEAT_SUSPEND req not "
1857 "supported for USB 3.0 roothub\n");
1858 goto error;
1859 }
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001860 if (dum_hcd->port_status & USB_PORT_STAT_SUSPEND) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07001861 /* 20msec resume signaling */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001862 dum_hcd->resuming = 1;
1863 dum_hcd->re_timeout = jiffies +
Alan Sternf1c39fa2005-05-03 16:24:04 -04001864 msecs_to_jiffies(20);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001865 }
1866 break;
1867 case USB_PORT_FEAT_POWER:
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001868 if (hcd->speed == HCD_USB3) {
1869 if (dum_hcd->port_status & USB_PORT_STAT_POWER)
1870 dev_dbg(dummy_dev(dum_hcd),
1871 "power-off\n");
1872 } else
1873 if (dum_hcd->port_status &
1874 USB_SS_PORT_STAT_POWER)
1875 dev_dbg(dummy_dev(dum_hcd),
1876 "power-off\n");
Alan Sternf1c39fa2005-05-03 16:24:04 -04001877 /* FALLS THROUGH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07001878 default:
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001879 dum_hcd->port_status &= ~(1 << wValue);
1880 set_link_state(dum_hcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001881 }
1882 break;
1883 case GetHubDescriptor:
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001884 if (hcd->speed == HCD_USB3 &&
1885 (wLength < USB_DT_SS_HUB_SIZE ||
1886 wValue != (USB_DT_SS_HUB << 8))) {
1887 dev_dbg(dummy_dev(dum_hcd),
1888 "Wrong hub descriptor type for "
1889 "USB 3.0 roothub.\n");
1890 goto error;
1891 }
1892 if (hcd->speed == HCD_USB3)
1893 ss_hub_descriptor((struct usb_hub_descriptor *) buf);
1894 else
1895 hub_descriptor((struct usb_hub_descriptor *) buf);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001896 break;
1897 case GetHubStatus:
Harvey Harrison551509d2009-02-11 14:11:36 -08001898 *(__le32 *) buf = cpu_to_le32 (0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001899 break;
1900 case GetPortStatus:
1901 if (wIndex != 1)
1902 retval = -EPIPE;
1903
1904 /* whoever resets or resumes must GetPortStatus to
1905 * complete it!!
1906 */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001907 if (dum_hcd->resuming &&
1908 time_after_eq(jiffies, dum_hcd->re_timeout)) {
1909 dum_hcd->port_status |= (USB_PORT_STAT_C_SUSPEND << 16);
1910 dum_hcd->port_status &= ~USB_PORT_STAT_SUSPEND;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001911 }
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001912 if ((dum_hcd->port_status & USB_PORT_STAT_RESET) != 0 &&
1913 time_after_eq(jiffies, dum_hcd->re_timeout)) {
1914 dum_hcd->port_status |= (USB_PORT_STAT_C_RESET << 16);
1915 dum_hcd->port_status &= ~USB_PORT_STAT_RESET;
1916 if (dum_hcd->dum->pullup) {
1917 dum_hcd->port_status |= USB_PORT_STAT_ENABLE;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001918
1919 if (hcd->speed < HCD_USB3) {
1920 switch (dum_hcd->dum->gadget.speed) {
1921 case USB_SPEED_HIGH:
1922 dum_hcd->port_status |=
1923 USB_PORT_STAT_HIGH_SPEED;
1924 break;
1925 case USB_SPEED_LOW:
1926 dum_hcd->dum->gadget.ep0->
1927 maxpacket = 8;
1928 dum_hcd->port_status |=
1929 USB_PORT_STAT_LOW_SPEED;
1930 break;
1931 default:
1932 dum_hcd->dum->gadget.speed =
1933 USB_SPEED_FULL;
1934 break;
1935 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07001936 }
1937 }
1938 }
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001939 set_link_state(dum_hcd);
1940 ((__le16 *) buf)[0] = cpu_to_le16 (dum_hcd->port_status);
1941 ((__le16 *) buf)[1] = cpu_to_le16 (dum_hcd->port_status >> 16);
Linus Torvalds1da177e2005-04-16 15:20:36 -07001942 break;
1943 case SetHubFeature:
1944 retval = -EPIPE;
1945 break;
1946 case SetPortFeature:
1947 switch (wValue) {
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001948 case USB_PORT_FEAT_LINK_STATE:
1949 if (hcd->speed != HCD_USB3) {
1950 dev_dbg(dummy_dev(dum_hcd),
1951 "USB_PORT_FEAT_LINK_STATE req not "
1952 "supported for USB 2.0 roothub\n");
1953 goto error;
1954 }
1955 /*
1956 * Since this is dummy we don't have an actual link so
1957 * there is nothing to do for the SET_LINK_STATE cmd
1958 */
1959 break;
1960 case USB_PORT_FEAT_U1_TIMEOUT:
1961 case USB_PORT_FEAT_U2_TIMEOUT:
1962 /* TODO: add suspend/resume support! */
1963 if (hcd->speed != HCD_USB3) {
1964 dev_dbg(dummy_dev(dum_hcd),
1965 "USB_PORT_FEAT_U1/2_TIMEOUT req not "
1966 "supported for USB 2.0 roothub\n");
1967 goto error;
1968 }
1969 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07001970 case USB_PORT_FEAT_SUSPEND:
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001971 /* Applicable only for USB2.0 hub */
1972 if (hcd->speed == HCD_USB3) {
1973 dev_dbg(dummy_dev(dum_hcd),
1974 "USB_PORT_FEAT_SUSPEND req not "
1975 "supported for USB 3.0 roothub\n");
1976 goto error;
1977 }
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001978 if (dum_hcd->active) {
1979 dum_hcd->port_status |= USB_PORT_STAT_SUSPEND;
Alan Sternf1c39fa2005-05-03 16:24:04 -04001980
1981 /* HNP would happen here; for now we
1982 * assume b_bus_req is always true.
1983 */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001984 set_link_state(dum_hcd);
Alan Sternf1c39fa2005-05-03 16:24:04 -04001985 if (((1 << USB_DEVICE_B_HNP_ENABLE)
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001986 & dum_hcd->dum->devstatus) != 0)
1987 dev_dbg(dummy_dev(dum_hcd),
Alan Stern5742b0c2005-05-02 11:25:17 -04001988 "no HNP yet!\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07001989 }
1990 break;
Alan Sternf1c39fa2005-05-03 16:24:04 -04001991 case USB_PORT_FEAT_POWER:
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001992 if (hcd->speed == HCD_USB3)
1993 dum_hcd->port_status |= USB_SS_PORT_STAT_POWER;
1994 else
1995 dum_hcd->port_status |= USB_PORT_STAT_POWER;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03001996 set_link_state(dum_hcd);
Alan Sternf1c39fa2005-05-03 16:24:04 -04001997 break;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03001998 case USB_PORT_FEAT_BH_PORT_RESET:
1999 /* Applicable only for USB3.0 hub */
2000 if (hcd->speed != HCD_USB3) {
2001 dev_dbg(dummy_dev(dum_hcd),
2002 "USB_PORT_FEAT_BH_PORT_RESET req not "
2003 "supported for USB 2.0 roothub\n");
2004 goto error;
2005 }
2006 /* FALLS THROUGH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002007 case USB_PORT_FEAT_RESET:
Alan Sternf1c39fa2005-05-03 16:24:04 -04002008 /* if it's already enabled, disable */
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002009 if (hcd->speed == HCD_USB3) {
2010 dum_hcd->port_status = 0;
2011 dum_hcd->port_status =
2012 (USB_SS_PORT_STAT_POWER |
2013 USB_PORT_STAT_CONNECTION |
2014 USB_PORT_STAT_RESET);
2015 } else
2016 dum_hcd->port_status &= ~(USB_PORT_STAT_ENABLE
Alan Sternf1c39fa2005-05-03 16:24:04 -04002017 | USB_PORT_STAT_LOW_SPEED
2018 | USB_PORT_STAT_HIGH_SPEED);
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002019 /*
2020 * We want to reset device status. All but the
2021 * Self powered feature
2022 */
2023 dum_hcd->dum->devstatus &=
2024 (1 << USB_DEVICE_SELF_POWERED);
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002025 /*
2026 * FIXME USB3.0: what is the correct reset signaling
2027 * interval? Is it still 50msec as for HS?
2028 */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002029 dum_hcd->re_timeout = jiffies + msecs_to_jiffies(50);
Alan Sternf1c39fa2005-05-03 16:24:04 -04002030 /* FALLS THROUGH */
Linus Torvalds1da177e2005-04-16 15:20:36 -07002031 default:
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002032 if (hcd->speed == HCD_USB3) {
2033 if ((dum_hcd->port_status &
2034 USB_SS_PORT_STAT_POWER) != 0) {
2035 dum_hcd->port_status |= (1 << wValue);
2036 set_link_state(dum_hcd);
2037 }
2038 } else
2039 if ((dum_hcd->port_status &
2040 USB_PORT_STAT_POWER) != 0) {
2041 dum_hcd->port_status |= (1 << wValue);
2042 set_link_state(dum_hcd);
2043 }
Linus Torvalds1da177e2005-04-16 15:20:36 -07002044 }
2045 break;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002046 case GetPortErrorCount:
2047 if (hcd->speed != HCD_USB3) {
2048 dev_dbg(dummy_dev(dum_hcd),
2049 "GetPortErrorCount req not "
2050 "supported for USB 2.0 roothub\n");
2051 goto error;
2052 }
2053 /* We'll always return 0 since this is a dummy hub */
2054 *(__le32 *) buf = cpu_to_le32(0);
2055 break;
2056 case SetHubDepth:
2057 if (hcd->speed != HCD_USB3) {
2058 dev_dbg(dummy_dev(dum_hcd),
2059 "SetHubDepth req not supported for "
2060 "USB 2.0 roothub\n");
2061 goto error;
2062 }
2063 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002064 default:
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002065 dev_dbg(dummy_dev(dum_hcd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002066 "hub control req%04x v%04x i%04x l%d\n",
2067 typeReq, wValue, wIndex, wLength);
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002068error:
Linus Torvalds1da177e2005-04-16 15:20:36 -07002069 /* "protocol stall" on error */
2070 retval = -EPIPE;
2071 }
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002072 spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
Alan Stern685eb932005-05-03 16:27:26 -04002073
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002074 if ((dum_hcd->port_status & PORT_C_MASK) != 0)
Alan Stern685eb932005-05-03 16:27:26 -04002075 usb_hcd_poll_rh_status (hcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002076 return retval;
2077}
2078
Alan Stern0c0382e2005-10-13 17:08:02 -04002079static int dummy_bus_suspend (struct usb_hcd *hcd)
Alan Stern391eca92005-05-10 15:34:16 -04002080{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002081 struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
Alan Stern391eca92005-05-10 15:34:16 -04002082
Harvey Harrison441b62c2008-03-03 16:08:34 -08002083 dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
Alan Stern3cf0a222005-11-29 12:08:15 -05002084
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002085 spin_lock_irq(&dum_hcd->dum->lock);
2086 dum_hcd->rh_state = DUMMY_RH_SUSPENDED;
2087 set_link_state(dum_hcd);
Alan Stern3cf0a222005-11-29 12:08:15 -05002088 hcd->state = HC_STATE_SUSPENDED;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002089 spin_unlock_irq(&dum_hcd->dum->lock);
Alan Stern391eca92005-05-10 15:34:16 -04002090 return 0;
2091}
2092
Alan Stern0c0382e2005-10-13 17:08:02 -04002093static int dummy_bus_resume (struct usb_hcd *hcd)
Alan Stern391eca92005-05-10 15:34:16 -04002094{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002095 struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
Alan Stern3cf0a222005-11-29 12:08:15 -05002096 int rc = 0;
2097
Harvey Harrison441b62c2008-03-03 16:08:34 -08002098 dev_dbg (&hcd->self.root_hub->dev, "%s\n", __func__);
Alan Stern391eca92005-05-10 15:34:16 -04002099
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002100 spin_lock_irq(&dum_hcd->dum->lock);
Alan Stern541c7d42010-06-22 16:39:10 -04002101 if (!HCD_HW_ACCESSIBLE(hcd)) {
Alan Sterncfa59da2007-06-21 16:25:35 -04002102 rc = -ESHUTDOWN;
Alan Stern3cf0a222005-11-29 12:08:15 -05002103 } else {
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002104 dum_hcd->rh_state = DUMMY_RH_RUNNING;
2105 set_link_state(dum_hcd);
2106 if (!list_empty(&dum_hcd->urbp_list))
2107 mod_timer(&dum_hcd->timer, jiffies);
Alan Stern3cf0a222005-11-29 12:08:15 -05002108 hcd->state = HC_STATE_RUNNING;
2109 }
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002110 spin_unlock_irq(&dum_hcd->dum->lock);
Alan Stern3cf0a222005-11-29 12:08:15 -05002111 return rc;
Alan Stern391eca92005-05-10 15:34:16 -04002112}
Linus Torvalds1da177e2005-04-16 15:20:36 -07002113
2114/*-------------------------------------------------------------------------*/
2115
2116static inline ssize_t
2117show_urb (char *buf, size_t size, struct urb *urb)
2118{
2119 int ep = usb_pipeendpoint (urb->pipe);
2120
2121 return snprintf (buf, size,
2122 "urb/%p %s ep%d%s%s len %d/%d\n",
2123 urb,
2124 ({ char *s;
2125 switch (urb->dev->speed) {
Tatyana Brokhman7c884fe2011-06-28 16:33:52 +03002126 case USB_SPEED_LOW:
2127 s = "ls";
2128 break;
2129 case USB_SPEED_FULL:
2130 s = "fs";
2131 break;
2132 case USB_SPEED_HIGH:
2133 s = "hs";
2134 break;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002135 case USB_SPEED_SUPER:
2136 s = "ss";
2137 break;
Tatyana Brokhman7c884fe2011-06-28 16:33:52 +03002138 default:
2139 s = "?";
2140 break;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002141 }; s; }),
2142 ep, ep ? (usb_pipein (urb->pipe) ? "in" : "out") : "",
2143 ({ char *s; \
2144 switch (usb_pipetype (urb->pipe)) { \
Tatyana Brokhman7c884fe2011-06-28 16:33:52 +03002145 case PIPE_CONTROL: \
2146 s = ""; \
2147 break; \
2148 case PIPE_BULK: \
2149 s = "-bulk"; \
2150 break; \
2151 case PIPE_INTERRUPT: \
2152 s = "-int"; \
2153 break; \
2154 default: \
2155 s = "-iso"; \
2156 break; \
Linus Torvalds1da177e2005-04-16 15:20:36 -07002157 }; s;}),
2158 urb->actual_length, urb->transfer_buffer_length);
2159}
2160
2161static ssize_t
Yani Ioannou10523b32005-05-17 06:43:37 -04002162show_urbs (struct device *dev, struct device_attribute *attr, char *buf)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002163{
2164 struct usb_hcd *hcd = dev_get_drvdata (dev);
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002165 struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002166 struct urbp *urbp;
2167 size_t size = 0;
2168 unsigned long flags;
2169
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002170 spin_lock_irqsave(&dum_hcd->dum->lock, flags);
2171 list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002172 size_t temp;
2173
2174 temp = show_urb (buf, PAGE_SIZE - size, urbp->urb);
2175 buf += temp;
2176 size += temp;
2177 }
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002178 spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002179
2180 return size;
2181}
2182static DEVICE_ATTR (urbs, S_IRUGO, show_urbs, NULL);
2183
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002184static int dummy_start_ss(struct dummy_hcd *dum_hcd)
2185{
2186 init_timer(&dum_hcd->timer);
2187 dum_hcd->timer.function = dummy_timer;
2188 dum_hcd->timer.data = (unsigned long)dum_hcd;
2189 dum_hcd->rh_state = DUMMY_RH_RUNNING;
2190 INIT_LIST_HEAD(&dum_hcd->urbp_list);
2191 dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
2192 dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
2193 dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
2194#ifdef CONFIG_USB_OTG
2195 dummy_hcd_to_hcd(dum_hcd)->self.otg_port = 1;
2196#endif
2197 return 0;
2198
2199 /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
2200 return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
2201}
2202
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002203static int dummy_start(struct usb_hcd *hcd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002204{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002205 struct dummy_hcd *dum_hcd = hcd_to_dummy_hcd(hcd);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002206
2207 /*
2208 * MASTER side init ... we emulate a root hub that'll only ever
2209 * talk to one device (the slave side). Also appears in sysfs,
2210 * just like more familiar pci-based HCDs.
2211 */
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002212 if (!usb_hcd_is_primary_hcd(hcd))
2213 return dummy_start_ss(dum_hcd);
2214
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002215 spin_lock_init(&dum_hcd->dum->lock);
2216 init_timer(&dum_hcd->timer);
2217 dum_hcd->timer.function = dummy_timer;
2218 dum_hcd->timer.data = (unsigned long)dum_hcd;
2219 dum_hcd->rh_state = DUMMY_RH_RUNNING;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002220
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002221 INIT_LIST_HEAD(&dum_hcd->urbp_list);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002222
Alan Sterncaf29f62007-12-06 11:10:39 -05002223 hcd->power_budget = POWER_BUDGET;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002224 hcd->state = HC_STATE_RUNNING;
Alan Stern685eb932005-05-03 16:27:26 -04002225 hcd->uses_new_polling = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002226
Alan Stern5742b0c2005-05-02 11:25:17 -04002227#ifdef CONFIG_USB_OTG
2228 hcd->self.otg_port = 1;
2229#endif
2230
Linus Torvalds1da177e2005-04-16 15:20:36 -07002231 /* FIXME 'urbs' should be a per-device thing, maybe in usbcore */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002232 return device_create_file(dummy_dev(dum_hcd), &dev_attr_urbs);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002233}
2234
2235static void dummy_stop (struct usb_hcd *hcd)
2236{
2237 struct dummy *dum;
2238
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002239 dum = (hcd_to_dummy_hcd(hcd))->dum;
2240 device_remove_file(dummy_dev(hcd_to_dummy_hcd(hcd)), &dev_attr_urbs);
2241 usb_gadget_unregister_driver(dum->driver);
2242 dev_info(dummy_dev(hcd_to_dummy_hcd(hcd)), "stopped\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -07002243}
2244
2245/*-------------------------------------------------------------------------*/
2246
2247static int dummy_h_get_frame (struct usb_hcd *hcd)
2248{
2249 return dummy_g_get_frame (NULL);
2250}
2251
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002252static int dummy_setup(struct usb_hcd *hcd)
2253{
2254 if (usb_hcd_is_primary_hcd(hcd)) {
2255 the_controller.hs_hcd = hcd_to_dummy_hcd(hcd);
2256 the_controller.hs_hcd->dum = &the_controller;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002257 /*
2258 * Mark the first roothub as being USB 2.0.
2259 * The USB 3.0 roothub will be registered later by
2260 * dummy_hcd_probe()
2261 */
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002262 hcd->speed = HCD_USB2;
2263 hcd->self.root_hub->speed = USB_SPEED_HIGH;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002264 } else {
2265 the_controller.ss_hcd = hcd_to_dummy_hcd(hcd);
2266 the_controller.ss_hcd->dum = &the_controller;
2267 hcd->speed = HCD_USB3;
2268 hcd->self.root_hub->speed = USB_SPEED_SUPER;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002269 }
2270 return 0;
2271}
2272
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002273/* Change a group of bulk endpoints to support multiple stream IDs */
2274int dummy_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
2275 struct usb_host_endpoint **eps, unsigned int num_eps,
2276 unsigned int num_streams, gfp_t mem_flags)
2277{
2278 if (hcd->speed != HCD_USB3)
2279 dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
2280 "%s() - ERROR! Not supported for USB2.0 roothub\n",
2281 __func__);
2282 return 0;
2283}
2284
2285/* Reverts a group of bulk endpoints back to not using stream IDs. */
2286int dummy_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
2287 struct usb_host_endpoint **eps, unsigned int num_eps,
2288 gfp_t mem_flags)
2289{
2290 if (hcd->speed != HCD_USB3)
2291 dev_dbg(dummy_dev(hcd_to_dummy_hcd(hcd)),
2292 "%s() - ERROR! Not supported for USB2.0 roothub\n",
2293 __func__);
2294 return 0;
2295}
2296
2297static struct hc_driver dummy_hcd = {
Linus Torvalds1da177e2005-04-16 15:20:36 -07002298 .description = (char *) driver_name,
2299 .product_desc = "Dummy host controller",
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002300 .hcd_priv_size = sizeof(struct dummy_hcd),
Linus Torvalds1da177e2005-04-16 15:20:36 -07002301
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002302 .flags = HCD_USB3 | HCD_SHARED,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002303
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002304 .reset = dummy_setup,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002305 .start = dummy_start,
2306 .stop = dummy_stop,
2307
2308 .urb_enqueue = dummy_urb_enqueue,
2309 .urb_dequeue = dummy_urb_dequeue,
2310
2311 .get_frame_number = dummy_h_get_frame,
2312
2313 .hub_status_data = dummy_hub_status,
2314 .hub_control = dummy_hub_control,
Alan Stern0c0382e2005-10-13 17:08:02 -04002315 .bus_suspend = dummy_bus_suspend,
2316 .bus_resume = dummy_bus_resume,
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002317
2318 .alloc_streams = dummy_alloc_streams,
2319 .free_streams = dummy_free_streams,
Linus Torvalds1da177e2005-04-16 15:20:36 -07002320};
2321
Alan Stern8364d6b2005-11-14 12:16:30 -05002322static int dummy_hcd_probe(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002323{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002324 struct usb_hcd *hs_hcd;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002325 struct usb_hcd *ss_hcd;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002326 int retval;
2327
Alan Stern8364d6b2005-11-14 12:16:30 -05002328 dev_info(&pdev->dev, "%s, driver " DRIVER_VERSION "\n", driver_desc);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002329
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002330 if (!mod_data.is_super_speed)
2331 dummy_hcd.flags = HCD_USB2;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002332 hs_hcd = usb_create_hcd(&dummy_hcd, &pdev->dev, dev_name(&pdev->dev));
2333 if (!hs_hcd)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002334 return -ENOMEM;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002335 hs_hcd->has_tt = 1;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002336
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002337 retval = usb_add_hcd(hs_hcd, 0, 0);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002338 if (retval != 0) {
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002339 usb_put_hcd(hs_hcd);
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002340 return retval;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002341 }
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002342
2343 if (mod_data.is_super_speed) {
2344 ss_hcd = usb_create_shared_hcd(&dummy_hcd, &pdev->dev,
2345 dev_name(&pdev->dev), hs_hcd);
2346 if (!ss_hcd) {
2347 retval = -ENOMEM;
2348 goto dealloc_usb2_hcd;
2349 }
2350
2351 retval = usb_add_hcd(ss_hcd, 0, 0);
2352 if (retval)
2353 goto put_usb3_hcd;
2354 }
2355 return 0;
2356
2357put_usb3_hcd:
2358 usb_put_hcd(ss_hcd);
2359dealloc_usb2_hcd:
2360 usb_put_hcd(hs_hcd);
2361 the_controller.hs_hcd = the_controller.ss_hcd = NULL;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002362 return retval;
2363}
2364
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002365static int dummy_hcd_remove(struct platform_device *pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002366{
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002367 struct dummy *dum;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002368
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002369 dum = (hcd_to_dummy_hcd(platform_get_drvdata(pdev)))->dum;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002370
2371 if (dum->ss_hcd) {
2372 usb_remove_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
2373 usb_put_hcd(dummy_hcd_to_hcd(dum->ss_hcd));
2374 }
2375
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002376 usb_remove_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
2377 usb_put_hcd(dummy_hcd_to_hcd(dum->hs_hcd));
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002378
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002379 the_controller.hs_hcd = NULL;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002380 the_controller.ss_hcd = NULL;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002381
Alan Sternd9b76252005-05-03 16:15:43 -04002382 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002383}
2384
Alan Stern8364d6b2005-11-14 12:16:30 -05002385static int dummy_hcd_suspend (struct platform_device *pdev, pm_message_t state)
Alan Stern391eca92005-05-10 15:34:16 -04002386{
2387 struct usb_hcd *hcd;
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002388 struct dummy_hcd *dum_hcd;
Alan Stern3cf0a222005-11-29 12:08:15 -05002389 int rc = 0;
Alan Stern391eca92005-05-10 15:34:16 -04002390
Harvey Harrison441b62c2008-03-03 16:08:34 -08002391 dev_dbg (&pdev->dev, "%s\n", __func__);
Alan Stern391eca92005-05-10 15:34:16 -04002392
Alan Stern3cf0a222005-11-29 12:08:15 -05002393 hcd = platform_get_drvdata (pdev);
Tatyana Brokhmancdfcbd22011-06-29 16:41:51 +03002394 dum_hcd = hcd_to_dummy_hcd(hcd);
2395 if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
Alan Stern3cf0a222005-11-29 12:08:15 -05002396 dev_warn(&pdev->dev, "Root hub isn't suspended!\n");
2397 rc = -EBUSY;
2398 } else
2399 clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
2400 return rc;
Alan Stern391eca92005-05-10 15:34:16 -04002401}
2402
Alan Stern8364d6b2005-11-14 12:16:30 -05002403static int dummy_hcd_resume (struct platform_device *pdev)
Alan Stern391eca92005-05-10 15:34:16 -04002404{
2405 struct usb_hcd *hcd;
2406
Harvey Harrison441b62c2008-03-03 16:08:34 -08002407 dev_dbg (&pdev->dev, "%s\n", __func__);
Alan Stern391eca92005-05-10 15:34:16 -04002408
Alan Stern3cf0a222005-11-29 12:08:15 -05002409 hcd = platform_get_drvdata (pdev);
2410 set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags);
Alan Stern391eca92005-05-10 15:34:16 -04002411 usb_hcd_poll_rh_status (hcd);
2412 return 0;
2413}
2414
Russell King3ae5eae2005-11-09 22:32:44 +00002415static struct platform_driver dummy_hcd_driver = {
Alan Sternd9b76252005-05-03 16:15:43 -04002416 .probe = dummy_hcd_probe,
2417 .remove = dummy_hcd_remove,
Alan Stern391eca92005-05-10 15:34:16 -04002418 .suspend = dummy_hcd_suspend,
2419 .resume = dummy_hcd_resume,
Russell King3ae5eae2005-11-09 22:32:44 +00002420 .driver = {
2421 .name = (char *) driver_name,
2422 .owner = THIS_MODULE,
2423 },
Alan Sternd9b76252005-05-03 16:15:43 -04002424};
2425
Linus Torvalds1da177e2005-04-16 15:20:36 -07002426/*-------------------------------------------------------------------------*/
2427
Alan Sterna89a2cd2008-04-07 15:03:25 -04002428static struct platform_device *the_udc_pdev;
2429static struct platform_device *the_hcd_pdev;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002430
2431static int __init init (void)
2432{
Alan Sterna89a2cd2008-04-07 15:03:25 -04002433 int retval = -ENOMEM;
Linus Torvalds1da177e2005-04-16 15:20:36 -07002434
2435 if (usb_disabled ())
2436 return -ENODEV;
Alan Sternd9b76252005-05-03 16:15:43 -04002437
Alan Sterna89a2cd2008-04-07 15:03:25 -04002438 the_hcd_pdev = platform_device_alloc(driver_name, -1);
2439 if (!the_hcd_pdev)
Linus Torvalds1da177e2005-04-16 15:20:36 -07002440 return retval;
Alan Sterna89a2cd2008-04-07 15:03:25 -04002441 the_udc_pdev = platform_device_alloc(gadget_name, -1);
2442 if (!the_udc_pdev)
2443 goto err_alloc_udc;
Alan Sternd9b76252005-05-03 16:15:43 -04002444
Alan Sterna89a2cd2008-04-07 15:03:25 -04002445 retval = platform_driver_register(&dummy_hcd_driver);
2446 if (retval < 0)
2447 goto err_register_hcd_driver;
2448 retval = platform_driver_register(&dummy_udc_driver);
Alan Sternd9b76252005-05-03 16:15:43 -04002449 if (retval < 0)
2450 goto err_register_udc_driver;
2451
Alan Sterna89a2cd2008-04-07 15:03:25 -04002452 retval = platform_device_add(the_hcd_pdev);
Alan Sternd9b76252005-05-03 16:15:43 -04002453 if (retval < 0)
Alan Sterna89a2cd2008-04-07 15:03:25 -04002454 goto err_add_hcd;
Tatyana Brokhman1cd8fd22011-06-29 16:41:52 +03002455 if (!the_controller.hs_hcd ||
2456 (!the_controller.ss_hcd && mod_data.is_super_speed)) {
Sebastian Andrzej Siewior865835f2011-04-15 20:37:06 +02002457 /*
2458 * The hcd was added successfully but its probe function failed
2459 * for some reason.
2460 */
2461 retval = -EINVAL;
2462 goto err_add_udc;
2463 }
Alan Sterna89a2cd2008-04-07 15:03:25 -04002464 retval = platform_device_add(the_udc_pdev);
Alan Sternd9b76252005-05-03 16:15:43 -04002465 if (retval < 0)
Alan Sterna89a2cd2008-04-07 15:03:25 -04002466 goto err_add_udc;
Sebastian Andrzej Siewior865835f2011-04-15 20:37:06 +02002467 if (!platform_get_drvdata(the_udc_pdev)) {
2468 /*
2469 * The udc was added successfully but its probe function failed
2470 * for some reason.
2471 */
2472 retval = -EINVAL;
2473 goto err_probe_udc;
2474 }
Alan Sternd9b76252005-05-03 16:15:43 -04002475 return retval;
2476
Sebastian Andrzej Siewior865835f2011-04-15 20:37:06 +02002477err_probe_udc:
2478 platform_device_del(the_udc_pdev);
Alan Sterna89a2cd2008-04-07 15:03:25 -04002479err_add_udc:
2480 platform_device_del(the_hcd_pdev);
2481err_add_hcd:
2482 platform_driver_unregister(&dummy_udc_driver);
Alan Sternd9b76252005-05-03 16:15:43 -04002483err_register_udc_driver:
Alan Sterna89a2cd2008-04-07 15:03:25 -04002484 platform_driver_unregister(&dummy_hcd_driver);
2485err_register_hcd_driver:
2486 platform_device_put(the_udc_pdev);
2487err_alloc_udc:
2488 platform_device_put(the_hcd_pdev);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002489 return retval;
2490}
2491module_init (init);
2492
2493static void __exit cleanup (void)
2494{
Alan Sterna89a2cd2008-04-07 15:03:25 -04002495 platform_device_unregister(the_udc_pdev);
2496 platform_device_unregister(the_hcd_pdev);
2497 platform_driver_unregister(&dummy_udc_driver);
2498 platform_driver_unregister(&dummy_hcd_driver);
Linus Torvalds1da177e2005-04-16 15:20:36 -07002499}
2500module_exit (cleanup);