===================================================================
@@ -84,6 +84,9 @@ struct dummy_ep {
struct usb_gadget *gadget;
const struct usb_endpoint_descriptor *desc;
struct usb_ep ep;
+ int iso_desc_num;
+ int iso_status;
+ int interval_left;
unsigned halted : 1;
unsigned already_seen : 1;
unsigned setup_stage : 1;
@@ -808,6 +811,7 @@ usb_gadget_register_driver (struct usb_g
dum->gadget.ep0 = &dum->ep [0].ep;
dum->ep [0].ep.maxpacket = 64;
+ dum->ep [0].setup_stage = 1;
list_del_init (&dum->ep [0].ep.ep_list);
INIT_LIST_HEAD(&dum->fifo_req.queue);
@@ -1017,8 +1021,7 @@ static int dummy_urb_enqueue (
list_add_tail (&urbp->urbp_list, &dum->urbp_list);
urb->hcpriv = urbp;
- if (usb_pipetype (urb->pipe) == PIPE_CONTROL)
- urb->error_count = 1; /* mark as a new urb */
+ urb->error_count = 0;
/* kick the scheduler, it'll do the rest */
if (!timer_pending (&dum->timer))
@@ -1056,13 +1059,44 @@ static int
transfer (struct dummy *dum, struct urb *urb, struct dummy_ep *ep, int limit)
{
struct dummy_request *req;
+ struct usb_iso_packet_descriptor *iso;
+ int to_host;
+
+ to_host = usb_pipein (urb->pipe);
+ iso = NULL;
+ if (usb_pipetype (urb->pipe) == PIPE_ISOCHRONOUS)
+ iso = &urb->iso_frame_desc [ep->iso_desc_num];
top:
+ /* isochronous transfers go through even without a responder */
+ if (iso && list_empty (&ep->queue)) {
+ int limit2 = limit;
+ int maxlen = ep->ep.maxpacket;
+
+ while (maxlen <= limit2) {
+ limit2 -= maxlen;
+ if (to_host)
+ ep->iso_status = iso->status = -EPROTO;
+ else {
+ iso->status = 0;
+ iso->actual_length = iso->length;
+ urb->actual_length += iso->length;
+ }
+ ++iso;
+ if (++ep->iso_desc_num >= urb->number_of_packets) {
+ maybe_set_status (urb, ep->iso_status);
+ break;
+ }
+ }
+ return limit;
+ }
+
/* if there's no request queued, the device is NAKing; return */
list_for_each_entry (req, &ep->queue, queue) {
unsigned host_len, dev_len, len;
- int is_short, to_host;
+ int is_short;
int rescan = 0;
+ int ustatus;
/* 1..N packets of ep->ep.maxpacket each ... the last one
* may be short (including zero length).
@@ -1071,24 +1105,22 @@ top:
* (length mod maxpacket zero, and 'zero' flag); they always
* terminate reads.
*/
- host_len = urb->transfer_buffer_length - urb->actual_length;
+ host_len = (iso ? iso->length : urb->transfer_buffer_length -
+ urb->actual_length);
dev_len = req->req.length - req->req.actual;
len = min (host_len, dev_len);
/* FIXME update emulated data toggle too */
- to_host = usb_pipein (urb->pipe);
if (unlikely (len == 0))
is_short = 1;
else {
char *ubuf, *rbuf;
/* not enough bandwidth left? */
- if (limit < ep->ep.maxpacket && limit < len)
+ if (limit < ep->ep.maxpacket && limit < host_len)
break;
len = min (len, (unsigned) limit);
- if (len == 0)
- break;
/* use an extra pass for the final short packet */
if (len > ep->ep.maxpacket) {
@@ -1098,15 +1130,15 @@ top:
is_short = (len % ep->ep.maxpacket) != 0;
/* else transfer packet(s) */
- ubuf = urb->transfer_buffer + urb->actual_length;
+ ubuf = urb->transfer_buffer + (iso ?
+ iso->offset : urb->actual_length);
rbuf = req->req.buf + req->req.actual;
if (to_host)
memcpy (ubuf, rbuf, len);
else
memcpy (rbuf, ubuf, len);
- ep->last_io = jiffies;
- limit -= len;
+ limit -= (iso ? ep->ep.maxpacket : len);
urb->actual_length += len;
req->req.actual += len;
}
@@ -1119,21 +1151,18 @@ top:
* need to emulate such data-in-flight. so we only show part
* of the URB_SHORT_NOT_OK effect: completion status.
*/
+ ustatus = 0;
if (is_short) {
if (host_len == dev_len) {
req->req.status = 0;
- maybe_set_status (urb, 0);
} else if (to_host) {
req->req.status = 0;
if (dev_len > host_len)
- maybe_set_status (urb, -EOVERFLOW);
- else
- maybe_set_status (urb,
- (urb->transfer_flags
- & URB_SHORT_NOT_OK)
- ? -EREMOTEIO : 0);
- } else if (!to_host) {
- maybe_set_status (urb, 0);
+ ustatus = -EOVERFLOW;
+ else if (urb->transfer_flags &
+ URB_SHORT_NOT_OK)
+ ustatus = -EREMOTEIO;
+ } else {
if (host_len > dev_len)
req->req.status = -EOVERFLOW;
else
@@ -1147,10 +1176,25 @@ top:
req->req.status = 0;
if (urb->transfer_buffer_length == urb->actual_length
&& !(urb->transfer_flags
- & URB_ZERO_PACKET)) {
- maybe_set_status (urb, 0);
+ & URB_ZERO_PACKET))
+ ; /* URB is done */
+ else if (!iso)
+ ustatus = 1; /* URB continues */
+ }
+
+ if (iso) {
+ iso->actual_length = len;
+ iso->status = ustatus;
+ if (ustatus) {
+ ep->iso_status = ustatus;
+ ++urb->error_count;
}
+ ++iso;
+ if (++ep->iso_desc_num >= urb->number_of_packets)
+ maybe_set_status (urb, ep->iso_status);
}
+ else if (ustatus <= 0)
+ maybe_set_status (urb, ustatus);
/* device side completion --> continuable */
if (req->req.status != -EINPROGRESS) {
@@ -1309,10 +1353,6 @@ restart:
if (ep->already_seen)
continue;
ep->already_seen = 1;
- if (ep == &dum->ep [0] && urb->error_count) {
- ep->setup_stage = 1; /* a new urb */
- urb->error_count = 0;
- }
if (ep->halted && !ep->setup_stage) {
/* NOTE: must not be iso! */
dev_dbg (dummy_dev(dum), "ep %s halted, urb %p\n",
@@ -1323,7 +1363,7 @@ restart:
/* FIXME make sure both ends agree on maxpacket */
/* handle control requests */
- if (ep == &dum->ep [0] && ep->setup_stage) {
+ if (ep->setup_stage) {
struct usb_ctrlrequest setup;
int value = 1;
struct dummy_ep *ep2;
@@ -1483,7 +1523,7 @@ restart:
if (value >= 0) {
/* no delays (max 64KB data stage) */
limit = 64*1024;
- goto treat_control_like_bulk;
+ goto treat_like_bulk;
}
/* error, see below */
}
@@ -1504,25 +1544,24 @@ restart:
limit = total;
switch (usb_pipetype (urb->pipe)) {
case PIPE_ISOCHRONOUS:
- /* FIXME is it urb->interval since the last xfer?
- * use urb->iso_frame_desc[i].
- * complete whether or not ep has requests queued.
- * report random errors, to debug drivers.
+ /* FIXME: report random errors, to debug drivers.
*/
+ if (--ep->interval_left > 0)
+ break;
+ ep->interval_left = urb->interval;
limit = max (limit, periodic_bytes (dum, ep));
- maybe_set_status (urb, -ENOSYS);
- break;
+ goto treat_like_bulk;
case PIPE_INTERRUPT:
- /* FIXME is it urb->interval since the last xfer?
- * this almost certainly polls too fast.
- */
+ if (--ep->interval_left > 0)
+ break;
+ ep->interval_left = urb->interval;
limit = max (limit, periodic_bytes (dum, ep));
/* FALLTHROUGH */
// case PIPE_BULK: case PIPE_CONTROL:
default:
- treat_control_like_bulk:
+ treat_like_bulk:
ep->last_io = jiffies;
total = transfer (dum, urb, ep, limit);
break;
@@ -1536,8 +1575,13 @@ return_urb:
urb->hcpriv = NULL;
list_del (&urbp->urbp_list);
kfree (urbp);
- if (ep)
- ep->already_seen = ep->setup_stage = 0;
+ if (ep) {
+ ep->already_seen = 0;
+ ep->iso_desc_num = 0;
+ ep->iso_status = 0;
+ if (ep == &dum->ep [0])
+ ep->setup_stage = 1;
+ }
spin_unlock (&dum->lock);
usb_hcd_giveback_urb (dummy_to_hcd(dum), urb, NULL);