Revision 4d611c9a hw/usb-uhci.c

b/hw/usb-uhci.c
76 76
    uint8_t status2; /* bit 0 and 1 are used to generate UHCI_STS_USBINT */
77 77
    QEMUTimer *frame_timer;
78 78
    UHCIPort ports[NB_PORTS];
79

  
80
    /* Interrupts that should be raised at the end of the current frame.  */
81
    uint32_t pending_int_mask;
82
    /* For simplicity of implementation we only allow a single pending USB
83
       request.  This means all usb traffic on this controller is effectively
84
       suspended until that transfer completes.  When the transfer completes
85
       the next transfer from that queue will be processed.  However 
86
       other queues will not be processed until the next frame.  The solution
87
       is to allow multiple pending requests.  */
88
    uint32_t async_qh;
89
    USBPacket usb_packet;
90
    uint8_t usb_buf[1280];
79 91
} UHCIState;
80 92

  
81 93
typedef struct UHCI_TD {
......
188 200
                port = &s->ports[i];
189 201
                dev = port->port.dev;
190 202
                if (dev) {
191
                    dev->handle_packet(dev, 
192
                                       USB_MSG_RESET, 0, 0, NULL, 0);
203
                    usb_send_msg(dev, USB_MSG_RESET);
193 204
                }
194 205
            }
195 206
            uhci_reset(s);
......
232 243
                /* port reset */
233 244
                if ( (val & UHCI_PORT_RESET) && 
234 245
                     !(port->ctrl & UHCI_PORT_RESET) ) {
235
                    dev->handle_packet(dev, 
236
                                       USB_MSG_RESET, 0, 0, NULL, 0);
246
                    usb_send_msg(dev, USB_MSG_RESET);
237 247
                }
238 248
            }
239 249
            port->ctrl = (port->ctrl & 0x01fb) | (val & ~0x01fb);
......
336 346
            port->ctrl &= ~UHCI_PORT_LSDA;
337 347
        port->port.dev = dev;
338 348
        /* send the attach message */
339
        dev->handle_packet(dev, 
340
                           USB_MSG_ATTACH, 0, 0, NULL, 0);
349
        usb_send_msg(dev, USB_MSG_ATTACH);
341 350
    } else {
342 351
        /* set connect status */
343 352
        if (port->ctrl & UHCI_PORT_CCS) {
......
352 361
        dev = port->port.dev;
353 362
        if (dev) {
354 363
            /* send the detach message */
355
            dev->handle_packet(dev, 
356
                               USB_MSG_DETACH, 0, 0, NULL, 0);
364
            usb_send_msg(dev, USB_MSG_DETACH);
357 365
        }
358 366
        port->port.dev = NULL;
359 367
    }
360 368
}
361 369

  
362
static int uhci_broadcast_packet(UHCIState *s, uint8_t pid, 
363
                                 uint8_t devaddr, uint8_t devep,
364
                                 uint8_t *data, int len)
370
static int uhci_broadcast_packet(UHCIState *s, USBPacket *p)
365 371
{
366 372
    UHCIPort *port;
367 373
    USBDevice *dev;
......
370 376
#ifdef DEBUG_PACKET
371 377
    {
372 378
        const char *pidstr;
373
        switch(pid) {
379
        switch(p->pid) {
374 380
        case USB_TOKEN_SETUP: pidstr = "SETUP"; break;
375 381
        case USB_TOKEN_IN: pidstr = "IN"; break;
376 382
        case USB_TOKEN_OUT: pidstr = "OUT"; break;
377 383
        default: pidstr = "?"; break;
378 384
        }
379 385
        printf("frame %d: pid=%s addr=0x%02x ep=%d len=%d\n",
380
               s->frnum, pidstr, devaddr, devep, len);
381
        if (pid != USB_TOKEN_IN) {
386
               s->frnum, pidstr, p->devaddr, p->devep, p->len);
387
        if (p->pid != USB_TOKEN_IN) {
382 388
            printf("     data_out=");
383
            for(i = 0; i < len; i++) {
384
                printf(" %02x", data[i]);
389
            for(i = 0; i < p->len; i++) {
390
                printf(" %02x", p->data[i]);
385 391
            }
386 392
            printf("\n");
387 393
        }
......
391 397
        port = &s->ports[i];
392 398
        dev = port->port.dev;
393 399
        if (dev && (port->ctrl & UHCI_PORT_EN)) {
394
            ret = dev->handle_packet(dev, pid, 
395
                                     devaddr, devep,
396
                                     data, len);
400
            ret = dev->handle_packet(dev, p);
397 401
            if (ret != USB_RET_NODEV) {
398 402
#ifdef DEBUG_PACKET
399
                {
403
                if (ret == USB_RET_ASYNC) {
404
                    printf("usb-uhci: Async packet\n");
405
                } else {
400 406
                    printf("     ret=%d ", ret);
401
                    if (pid == USB_TOKEN_IN && ret > 0) {
407
                    if (p->pid == USB_TOKEN_IN && ret > 0) {
402 408
                        printf("data_in=");
403 409
                        for(i = 0; i < ret; i++) {
404
                            printf(" %02x", data[i]);
410
                            printf(" %02x", p->data[i]);
405 411
                        }
406 412
                    }
407 413
                    printf("\n");
......
414 420
    return USB_RET_NODEV;
415 421
}
416 422

  
423
static void uhci_async_complete_packet(USBPacket * packet, void *opaque);
424

  
417 425
/* return -1 if fatal error (frame must be stopped)
418 426
          0 if TD successful
419 427
          1 if TD unsuccessful or inactive
......
421 429
static int uhci_handle_td(UHCIState *s, UHCI_TD *td, int *int_mask)
422 430
{
423 431
    uint8_t pid;
424
    uint8_t buf[1280];
425 432
    int len, max_len, err, ret;
426 433

  
434
    /* ??? This is wrong for async completion.  */
427 435
    if (td->ctrl & TD_CTRL_IOC) {
428 436
        *int_mask |= 0x01;
429 437
    }
......
434 442
    /* TD is active */
435 443
    max_len = ((td->token >> 21) + 1) & 0x7ff;
436 444
    pid = td->token & 0xff;
437
    switch(pid) {
438
    case USB_TOKEN_OUT:
439
    case USB_TOKEN_SETUP:
440
        cpu_physical_memory_read(td->buffer, buf, max_len);
441
        ret = uhci_broadcast_packet(s, pid, 
442
                                    (td->token >> 8) & 0x7f,
443
                                    (td->token >> 15) & 0xf,
444
                                    buf, max_len);
445
        len = max_len;
446
        break;
447
    case USB_TOKEN_IN:
448
        ret = uhci_broadcast_packet(s, pid, 
449
                                    (td->token >> 8) & 0x7f,
450
                                    (td->token >> 15) & 0xf,
451
                                    buf, max_len);
445
    if (s->async_qh) {
446
        ret = s->usb_packet.len;
452 447
        if (ret >= 0) {
453 448
            len = ret;
454 449
            if (len > max_len) {
......
457 452
            }
458 453
            if (len > 0) {
459 454
                /* write the data back */
460
                cpu_physical_memory_write(td->buffer, buf, len);
455
                cpu_physical_memory_write(td->buffer, s->usb_buf, len);
461 456
            }
462 457
        } else {
463 458
            len = 0;
464 459
        }
465
        break;
466
    default:
467
        /* invalid pid : frame interrupted */
468
        s->status |= UHCI_STS_HCPERR;
469
        uhci_update_irq(s);
470
        return -1;
460
        s->async_qh = 0;
461
    } else {
462
        s->usb_packet.pid = pid;
463
        s->usb_packet.devaddr = (td->token >> 8) & 0x7f;
464
        s->usb_packet.devep = (td->token >> 15) & 0xf;
465
        s->usb_packet.data = s->usb_buf;
466
        s->usb_packet.len = max_len;
467
        s->usb_packet.complete_cb = uhci_async_complete_packet;
468
        s->usb_packet.complete_opaque = s;
469
        switch(pid) {
470
        case USB_TOKEN_OUT:
471
        case USB_TOKEN_SETUP:
472
            cpu_physical_memory_read(td->buffer, s->usb_buf, max_len);
473
            ret = uhci_broadcast_packet(s, &s->usb_packet);
474
            len = max_len;
475
            break;
476
        case USB_TOKEN_IN:
477
            ret = uhci_broadcast_packet(s, &s->usb_packet);
478
            if (ret >= 0) {
479
                len = ret;
480
                if (len > max_len) {
481
                    len = max_len;
482
                    ret = USB_RET_BABBLE;
483
                }
484
                if (len > 0) {
485
                    /* write the data back */
486
                    cpu_physical_memory_write(td->buffer, s->usb_buf, len);
487
                }
488
            } else {
489
                len = 0;
490
            }
491
            break;
492
        default:
493
            /* invalid pid : frame interrupted */
494
            s->status |= UHCI_STS_HCPERR;
495
            uhci_update_irq(s);
496
            return -1;
497
        }
498
    }
499
    if (ret == USB_RET_ASYNC) {
500
        return 2;
471 501
    }
472 502
    if (td->ctrl & TD_CTRL_IOS)
473 503
        td->ctrl &= ~TD_CTRL_ACTIVE;
......
520 550
    }
521 551
}
522 552

  
553
static void uhci_async_complete_packet(USBPacket * packet, void *opaque)
554
{
555
    UHCIState *s = opaque;
556
    UHCI_QH qh;
557
    UHCI_TD td;
558
    uint32_t link;
559
    uint32_t old_td_ctrl;
560
    uint32_t val;
561
    int ret;
562

  
563
    link = s->async_qh;
564
    if (!link) {
565
        /* This should never happen. It means a TD somehow got removed
566
           without cancelling the associated async IO request.  */
567
        return;
568
    }
569
    cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));
570
    le32_to_cpus(&qh.link);
571
    le32_to_cpus(&qh.el_link);
572
    /* Re-process the queue containing the async packet.  */
573
    while (1) {
574
        cpu_physical_memory_read(qh.el_link & ~0xf, 
575
                                 (uint8_t *)&td, sizeof(td));
576
        le32_to_cpus(&td.link);
577
        le32_to_cpus(&td.ctrl);
578
        le32_to_cpus(&td.token);
579
        le32_to_cpus(&td.buffer);
580
        old_td_ctrl = td.ctrl;
581
        ret = uhci_handle_td(s, &td, &s->pending_int_mask);
582
        /* update the status bits of the TD */
583
        if (old_td_ctrl != td.ctrl) {
584
            val = cpu_to_le32(td.ctrl);
585
            cpu_physical_memory_write((qh.el_link & ~0xf) + 4, 
586
                                      (const uint8_t *)&val, 
587
                                      sizeof(val));
588
        }
589
        if (ret < 0)
590
            break; /* interrupted frame */
591
        if (ret == 2) {
592
            s->async_qh = link;
593
            break;
594
        } else if (ret == 0) {
595
            /* update qh element link */
596
            qh.el_link = td.link;
597
            val = cpu_to_le32(qh.el_link);
598
            cpu_physical_memory_write((link & ~0xf) + 4, 
599
                                      (const uint8_t *)&val, 
600
                                      sizeof(val));
601
            if (!(qh.el_link & 4))
602
                break;
603
        }
604
        break;
605
    }
606
}
607

  
523 608
static void uhci_frame_timer(void *opaque)
524 609
{
525 610
    UHCIState *s = opaque;
......
528 613
    int int_mask, cnt, ret;
529 614
    UHCI_TD td;
530 615
    UHCI_QH qh;
616
    uint32_t old_async_qh;
531 617

  
532 618
    if (!(s->cmd & UHCI_CMD_RS)) {
533 619
        qemu_del_timer(s->frame_timer);
......
535 621
        s->status |= UHCI_STS_HCHALTED;
536 622
        return;
537 623
    }
624
    /* Complete the previous frame.  */
625
    s->frnum = (s->frnum + 1) & 0x7ff;
626
    if (s->pending_int_mask) {
627
        s->status2 |= s->pending_int_mask;
628
        s->status |= UHCI_STS_USBINT;
629
        uhci_update_irq(s);
630
    }
631
    old_async_qh = s->async_qh;
538 632
    frame_addr = s->fl_base_addr + ((s->frnum & 0x3ff) << 2);
539 633
    cpu_physical_memory_read(frame_addr, (uint8_t *)&link, 4);
540 634
    le32_to_cpus(&link);
......
546 640
        /* valid frame */
547 641
        if (link & 2) {
548 642
            /* QH */
643
            if (link == s->async_qh) {
644
                /* We've found a previously issues packet.
645
                   Nothing else to do.  */
646
                old_async_qh = 0;
647
                break;
648
            }
549 649
            cpu_physical_memory_read(link & ~0xf, (uint8_t *)&qh, sizeof(qh));
550 650
            le32_to_cpus(&qh.link);
551 651
            le32_to_cpus(&qh.el_link);
......
556 656
            } else if (qh.el_link & 2) {
557 657
                /* QH */
558 658
                link = qh.el_link;
659
            } else if (s->async_qh) {
660
                /* We can only cope with one pending packet.  Keep looking
661
                   for the previously issued packet.  */
662
                link = qh.link;
559 663
            } else {
560 664
                /* TD */
561 665
                if (--cnt == 0)
......
577 681
                }
578 682
                if (ret < 0)
579 683
                    break; /* interrupted frame */
580
                if (ret == 0) {
684
                if (ret == 2) {
685
                    s->async_qh = link;
686
                } else if (ret == 0) {
581 687
                    /* update qh element link */
582 688
                    qh.el_link = td.link;
583 689
                    val = cpu_to_le32(qh.el_link);
......
599 705
            le32_to_cpus(&td.ctrl);
600 706
            le32_to_cpus(&td.token);
601 707
            le32_to_cpus(&td.buffer);
602
            old_td_ctrl = td.ctrl;
603
            ret = uhci_handle_td(s, &td, &int_mask);
604
            /* update the status bits of the TD */
605
            if (old_td_ctrl != td.ctrl) {
606
                val = cpu_to_le32(td.ctrl);
607
                cpu_physical_memory_write((link & ~0xf) + 4, 
608
                                          (const uint8_t *)&val, 
609
                                          sizeof(val));
708
            /* Ignore isochonous transfers while there is an async packet
709
               pending.  This is wrong, but we don't implement isochronous
710
               transfers anyway.  */
711
            if (s->async_qh == 0) {
712
                old_td_ctrl = td.ctrl;
713
                ret = uhci_handle_td(s, &td, &int_mask);
714
                /* update the status bits of the TD */
715
                if (old_td_ctrl != td.ctrl) {
716
                    val = cpu_to_le32(td.ctrl);
717
                    cpu_physical_memory_write((link & ~0xf) + 4, 
718
                                              (const uint8_t *)&val, 
719
                                              sizeof(val));
720
                }
721
                if (ret < 0)
722
                    break; /* interrupted frame */
723
                if (ret == 2) {
724
                    /* We can't handle async isochronous transfers.
725
                       Cancel The packet.  */
726
                    fprintf(stderr, "usb-uhci: Unimplemented async packet\n");
727
                    usb_cancel_packet(&s->usb_packet);
728
                }
610 729
            }
611
            if (ret < 0)
612
                break; /* interrupted frame */
613 730
            link = td.link;
614 731
        }
615 732
    }
616
    s->frnum = (s->frnum + 1) & 0x7ff;
617
    if (int_mask) {
618
        s->status2 |= int_mask;
619
        s->status |= UHCI_STS_USBINT;
620
        uhci_update_irq(s);
733
    s->pending_int_mask = int_mask;
734
    if (old_async_qh) {
735
        /* A previously started transfer has disappeared from the transfer
736
           list.  There's nothing useful we can do with it now, so just
737
           discard the packet and hope it wasn't too important.  */
738
#ifdef DEBUG
739
        printf("Discarding USB packet\n");
740
#endif
741
        usb_cancel_packet(&s->usb_packet);
742
        s->async_qh = 0;
621 743
    }
622 744
    /* prepare the timer for the next frame */
623 745
    expire_time = qemu_get_clock(vm_clock) + 

Also available in: Unified diff