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