Revision 060dc841
b/usb-linux.c | ||
---|---|---|
92 | 92 |
static int usb_fs_type; |
93 | 93 |
|
94 | 94 |
/* endpoint association data */ |
95 |
#define ISO_FRAME_DESC_PER_URB 32 |
|
96 |
#define ISO_URB_COUNT 3 |
|
97 |
|
|
98 |
typedef struct AsyncURB AsyncURB; |
|
99 |
|
|
95 | 100 |
struct endp_data { |
96 | 101 |
uint8_t type; |
97 | 102 |
uint8_t halted; |
103 |
AsyncURB *iso_urb; |
|
104 |
int iso_urb_idx; |
|
105 |
int max_packet_size; |
|
98 | 106 |
}; |
99 | 107 |
|
100 | 108 |
enum { |
... | ... | |
175 | 183 |
s->endp_table[ep - 1].halted = 1; |
176 | 184 |
} |
177 | 185 |
|
186 |
static void set_iso_urb(USBHostDevice *s, int ep, AsyncURB *iso_urb) |
|
187 |
{ |
|
188 |
s->endp_table[ep - 1].iso_urb = iso_urb; |
|
189 |
} |
|
190 |
|
|
191 |
static AsyncURB *get_iso_urb(USBHostDevice *s, int ep) |
|
192 |
{ |
|
193 |
return s->endp_table[ep - 1].iso_urb; |
|
194 |
} |
|
195 |
|
|
196 |
static void set_iso_urb_idx(USBHostDevice *s, int ep, int i) |
|
197 |
{ |
|
198 |
s->endp_table[ep - 1].iso_urb_idx = i; |
|
199 |
} |
|
200 |
|
|
201 |
static int get_iso_urb_idx(USBHostDevice *s, int ep) |
|
202 |
{ |
|
203 |
return s->endp_table[ep - 1].iso_urb_idx; |
|
204 |
} |
|
205 |
|
|
206 |
static int get_max_packet_size(USBHostDevice *s, int ep) |
|
207 |
{ |
|
208 |
return s->endp_table[ep - 1].max_packet_size; |
|
209 |
} |
|
210 |
|
|
178 | 211 |
/* |
179 | 212 |
* Async URB state. |
180 |
* We always allocate one isoc descriptor even for bulk transfers
|
|
213 |
* We always allocate iso packet descriptors even for bulk transfers
|
|
181 | 214 |
* to simplify allocation and casts. |
182 | 215 |
*/ |
183 |
typedef struct AsyncURB
|
|
216 |
struct AsyncURB |
|
184 | 217 |
{ |
185 | 218 |
struct usbdevfs_urb urb; |
186 |
struct usbdevfs_iso_packet_desc isocpd; |
|
219 |
struct usbdevfs_iso_packet_desc isocpd[ISO_FRAME_DESC_PER_URB];
|
|
187 | 220 |
|
221 |
/* For regular async urbs */ |
|
188 | 222 |
USBPacket *packet; |
189 | 223 |
USBHostDevice *hdev; |
190 |
} AsyncURB; |
|
224 |
|
|
225 |
/* For buffered iso handling */ |
|
226 |
int iso_frame_idx; /* -1 means in flight */ |
|
227 |
}; |
|
191 | 228 |
|
192 | 229 |
static AsyncURB *async_alloc(void) |
193 | 230 |
{ |
... | ... | |
244 | 281 |
return; |
245 | 282 |
} |
246 | 283 |
|
247 |
p = aurb->packet; |
|
248 |
|
|
249 | 284 |
DPRINTF("husb: async completed. aurb %p status %d alen %d\n", |
250 | 285 |
aurb, aurb->urb.status, aurb->urb.actual_length); |
251 | 286 |
|
287 |
/* If this is a buffered iso urb mark it as complete and don't do |
|
288 |
anything else (it is handled further in usb_host_handle_iso_data) */ |
|
289 |
if (aurb->iso_frame_idx == -1) { |
|
290 |
if (aurb->urb.status == -EPIPE) { |
|
291 |
set_halt(s, aurb->urb.endpoint & 0xf); |
|
292 |
} |
|
293 |
aurb->iso_frame_idx = 0; |
|
294 |
continue; |
|
295 |
} |
|
296 |
|
|
297 |
p = aurb->packet; |
|
298 |
|
|
252 | 299 |
if (p) { |
253 | 300 |
switch (aurb->urb.status) { |
254 | 301 |
case 0: |
... | ... | |
415 | 462 |
|
416 | 463 |
static int usb_linux_update_endp_table(USBHostDevice *s); |
417 | 464 |
|
465 |
/* iso data is special, we need to keep enough urbs in flight to make sure |
|
466 |
that the controller never runs out of them, otherwise the device will |
|
467 |
likely suffer a buffer underrun / overrun. */ |
|
468 |
static AsyncURB *usb_host_alloc_iso(USBHostDevice *s, uint8_t ep, int in) |
|
469 |
{ |
|
470 |
AsyncURB *aurb; |
|
471 |
int i, j, len = get_max_packet_size(s, ep); |
|
472 |
|
|
473 |
aurb = qemu_mallocz(ISO_URB_COUNT * sizeof(*aurb)); |
|
474 |
for (i = 0; i < ISO_URB_COUNT; i++) { |
|
475 |
aurb[i].urb.endpoint = ep; |
|
476 |
aurb[i].urb.buffer_length = ISO_FRAME_DESC_PER_URB * len; |
|
477 |
aurb[i].urb.buffer = qemu_malloc(aurb[i].urb.buffer_length); |
|
478 |
aurb[i].urb.type = USBDEVFS_URB_TYPE_ISO; |
|
479 |
aurb[i].urb.flags = USBDEVFS_URB_ISO_ASAP; |
|
480 |
aurb[i].urb.number_of_packets = ISO_FRAME_DESC_PER_URB; |
|
481 |
for (j = 0 ; j < ISO_FRAME_DESC_PER_URB; j++) |
|
482 |
aurb[i].urb.iso_frame_desc[j].length = len; |
|
483 |
if (in) { |
|
484 |
aurb[i].urb.endpoint |= 0x80; |
|
485 |
/* Mark as fully consumed (idle) */ |
|
486 |
aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB; |
|
487 |
} |
|
488 |
} |
|
489 |
set_iso_urb(s, ep, aurb); |
|
490 |
|
|
491 |
return aurb; |
|
492 |
} |
|
493 |
|
|
494 |
static void usb_host_stop_n_free_iso(USBHostDevice *s, uint8_t ep) |
|
495 |
{ |
|
496 |
AsyncURB *aurb; |
|
497 |
int i, ret, killed = 0, free = 1; |
|
498 |
|
|
499 |
aurb = get_iso_urb(s, ep); |
|
500 |
if (!aurb) { |
|
501 |
return; |
|
502 |
} |
|
503 |
|
|
504 |
for (i = 0; i < ISO_URB_COUNT; i++) { |
|
505 |
/* in flight? */ |
|
506 |
if (aurb[i].iso_frame_idx == -1) { |
|
507 |
ret = ioctl(s->fd, USBDEVFS_DISCARDURB, &aurb[i]); |
|
508 |
if (ret < 0) { |
|
509 |
printf("husb: discard isoc in urb failed errno %d\n", errno); |
|
510 |
free = 0; |
|
511 |
continue; |
|
512 |
} |
|
513 |
killed++; |
|
514 |
} |
|
515 |
} |
|
516 |
|
|
517 |
/* Make sure any urbs we've killed are reaped before we free them */ |
|
518 |
if (killed) { |
|
519 |
async_complete(s); |
|
520 |
} |
|
521 |
|
|
522 |
for (i = 0; i < ISO_URB_COUNT; i++) { |
|
523 |
qemu_free(aurb[i].urb.buffer); |
|
524 |
} |
|
525 |
|
|
526 |
if (free) |
|
527 |
qemu_free(aurb); |
|
528 |
else |
|
529 |
printf("husb: leaking iso urbs because of discard failure\n"); |
|
530 |
set_iso_urb(s, ep, NULL); |
|
531 |
} |
|
532 |
|
|
533 |
static int urb_status_to_usb_ret(int status) |
|
534 |
{ |
|
535 |
switch (status) { |
|
536 |
case -EPIPE: |
|
537 |
return USB_RET_STALL; |
|
538 |
default: |
|
539 |
return USB_RET_NAK; |
|
540 |
} |
|
541 |
} |
|
542 |
|
|
543 |
static int usb_host_handle_iso_data(USBHostDevice *s, USBPacket *p) |
|
544 |
{ |
|
545 |
AsyncURB *aurb; |
|
546 |
int i, j, ret, len = 0; |
|
547 |
|
|
548 |
aurb = get_iso_urb(s, p->devep); |
|
549 |
if (!aurb) { |
|
550 |
aurb = usb_host_alloc_iso(s, p->devep, 1); |
|
551 |
} |
|
552 |
|
|
553 |
i = get_iso_urb_idx(s, p->devep); |
|
554 |
j = aurb[i].iso_frame_idx; |
|
555 |
if (j >= 0 && j < ISO_FRAME_DESC_PER_URB) { |
|
556 |
/* Check urb status */ |
|
557 |
if (aurb[i].urb.status) { |
|
558 |
len = urb_status_to_usb_ret(aurb[i].urb.status); |
|
559 |
/* Move to the next urb */ |
|
560 |
aurb[i].iso_frame_idx = ISO_FRAME_DESC_PER_URB - 1; |
|
561 |
/* Check frame status */ |
|
562 |
} else if (aurb[i].urb.iso_frame_desc[j].status) { |
|
563 |
len = urb_status_to_usb_ret(aurb[i].urb.iso_frame_desc[j].status); |
|
564 |
/* Check the frame fits */ |
|
565 |
} else if (aurb[i].urb.iso_frame_desc[j].actual_length > p->len) { |
|
566 |
printf("husb: error received isoc data is larger then packet\n"); |
|
567 |
len = USB_RET_NAK; |
|
568 |
/* All good copy data over */ |
|
569 |
} else { |
|
570 |
len = aurb[i].urb.iso_frame_desc[j].actual_length; |
|
571 |
memcpy(p->data, |
|
572 |
aurb[i].urb.buffer + |
|
573 |
j * aurb[i].urb.iso_frame_desc[0].length, |
|
574 |
len); |
|
575 |
} |
|
576 |
aurb[i].iso_frame_idx++; |
|
577 |
if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) { |
|
578 |
i = (i + 1) % ISO_URB_COUNT; |
|
579 |
set_iso_urb_idx(s, p->devep, i); |
|
580 |
} |
|
581 |
} |
|
582 |
|
|
583 |
/* (Re)-submit all fully consumed urbs */ |
|
584 |
for (i = 0; i < ISO_URB_COUNT; i++) { |
|
585 |
if (aurb[i].iso_frame_idx == ISO_FRAME_DESC_PER_URB) { |
|
586 |
ret = ioctl(s->fd, USBDEVFS_SUBMITURB, &aurb[i]); |
|
587 |
if (ret < 0) { |
|
588 |
printf("husb error submitting isoc urb %d: %d\n", i, errno); |
|
589 |
if (len == 0) { |
|
590 |
switch(errno) { |
|
591 |
case ETIMEDOUT: |
|
592 |
len = USB_RET_NAK; |
|
593 |
case EPIPE: |
|
594 |
default: |
|
595 |
len = USB_RET_STALL; |
|
596 |
} |
|
597 |
} |
|
598 |
break; |
|
599 |
} |
|
600 |
aurb[i].iso_frame_idx = -1; |
|
601 |
} |
|
602 |
} |
|
603 |
|
|
604 |
return len; |
|
605 |
} |
|
606 |
|
|
418 | 607 |
static int usb_host_handle_data(USBHostDevice *s, USBPacket *p) |
419 | 608 |
{ |
420 | 609 |
struct usbdevfs_urb *urb; |
421 | 610 |
AsyncURB *aurb; |
422 | 611 |
int ret; |
423 |
|
|
424 |
aurb = async_alloc(); |
|
425 |
aurb->hdev = s; |
|
426 |
aurb->packet = p; |
|
427 |
|
|
428 |
urb = &aurb->urb; |
|
612 |
uint8_t ep; |
|
429 | 613 |
|
430 | 614 |
if (p->pid == USB_TOKEN_IN) { |
431 |
urb->endpoint = p->devep | 0x80;
|
|
615 |
ep = p->devep | 0x80;
|
|
432 | 616 |
} else { |
433 |
urb->endpoint = p->devep;
|
|
617 |
ep = p->devep;
|
|
434 | 618 |
} |
435 | 619 |
|
436 | 620 |
if (is_halted(s, p->devep)) { |
437 |
ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &urb->endpoint);
|
|
621 |
ret = ioctl(s->fd, USBDEVFS_CLEAR_HALT, &ep);
|
|
438 | 622 |
if (ret < 0) { |
439 | 623 |
DPRINTF("husb: failed to clear halt. ep 0x%x errno %d\n", |
440 |
urb->endpoint, errno);
|
|
624 |
ep, errno);
|
|
441 | 625 |
return USB_RET_NAK; |
442 | 626 |
} |
443 | 627 |
clear_halt(s, p->devep); |
444 | 628 |
} |
445 | 629 |
|
630 |
if (is_isoc(s, p->devep) && p->pid == USB_TOKEN_IN) |
|
631 |
return usb_host_handle_iso_data(s, p); |
|
632 |
|
|
633 |
aurb = async_alloc(); |
|
634 |
aurb->hdev = s; |
|
635 |
aurb->packet = p; |
|
636 |
|
|
637 |
urb = &aurb->urb; |
|
638 |
|
|
639 |
urb->endpoint = ep; |
|
446 | 640 |
urb->buffer = p->data; |
447 | 641 |
urb->buffer_length = p->len; |
448 | 642 |
|
... | ... | |
515 | 709 |
static int usb_host_set_interface(USBHostDevice *s, int iface, int alt) |
516 | 710 |
{ |
517 | 711 |
struct usbdevfs_setinterface si; |
518 |
int ret; |
|
712 |
int i, ret; |
|
713 |
|
|
714 |
for (i = 1; i < MAX_ENDPOINTS; i++) { |
|
715 |
if (is_isoc(s, i)) { |
|
716 |
usb_host_stop_n_free_iso(s, i); |
|
717 |
} |
|
718 |
} |
|
519 | 719 |
|
520 | 720 |
si.interface = iface; |
521 | 721 |
si.altsetting = alt; |
... | ... | |
927 | 1127 |
break; |
928 | 1128 |
case 0x01: |
929 | 1129 |
type = USBDEVFS_URB_TYPE_ISO; |
1130 |
s->endp_table[(devep & 0xf) - 1].max_packet_size = |
|
1131 |
descriptors[i + 4] + (descriptors[i + 5] << 8); |
|
930 | 1132 |
break; |
931 | 1133 |
case 0x02: |
932 | 1134 |
type = USBDEVFS_URB_TYPE_BULK; |
... | ... | |
1049 | 1251 |
|
1050 | 1252 |
static int usb_host_close(USBHostDevice *dev) |
1051 | 1253 |
{ |
1254 |
int i; |
|
1255 |
|
|
1052 | 1256 |
if (dev->fd == -1) { |
1053 | 1257 |
return -1; |
1054 | 1258 |
} |
1055 | 1259 |
|
1056 | 1260 |
qemu_set_fd_handler(dev->fd, NULL, NULL, NULL); |
1057 | 1261 |
dev->closing = 1; |
1262 |
for (i = 1; i < MAX_ENDPOINTS; i++) { |
|
1263 |
if (is_isoc(dev, i)) { |
|
1264 |
usb_host_stop_n_free_iso(dev, i); |
|
1265 |
} |
|
1266 |
} |
|
1058 | 1267 |
async_complete(dev); |
1059 | 1268 |
dev->closing = 0; |
1060 | 1269 |
usb_device_detach(&dev->dev); |
Also available in: Unified diff