Commit 7bfe5777023bb88e8f63a3e80a836f3eb7b13fdc

Authored by balrog
1 parent 046833ea

OHCI USB isochronous transfers support (Arnon Gilboa).


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3493 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 340 additions and 17 deletions
hw/usb-ohci.c
... ... @@ -32,6 +32,7 @@
32 32 //#define DEBUG_OHCI
33 33 /* Dump packet contents. */
34 34 //#define DEBUG_PACKET
  35 +//#define DEBUG_ISOCH
35 36 /* This causes frames to occur 1000x slower */
36 37 //#define OHCI_TIME_WARP 1
37 38  
... ... @@ -132,8 +133,8 @@ static void ohci_bus_stop(OHCIState *ohci);
132 133 #define OHCI_ED_S (1<<13)
133 134 #define OHCI_ED_K (1<<14)
134 135 #define OHCI_ED_F (1<<15)
135   -#define OHCI_ED_MPS_SHIFT 7
136   -#define OHCI_ED_MPS_MASK (0xf<<OHCI_ED_FA_SHIFT)
  136 +#define OHCI_ED_MPS_SHIFT 16
  137 +#define OHCI_ED_MPS_MASK (0x7ff<<OHCI_ED_MPS_SHIFT)
137 138  
138 139 /* Flags in the head field of an Endpoint Desciptor. */
139 140 #define OHCI_ED_H 1
... ... @@ -152,6 +153,22 @@ static void ohci_bus_stop(OHCIState *ohci);
152 153 #define OHCI_TD_CC_SHIFT 28
153 154 #define OHCI_TD_CC_MASK (0xf<<OHCI_TD_CC_SHIFT)
154 155  
  156 +/* Bitfields for the first word of an Isochronous Transfer Desciptor. */
  157 +/* CC & DI - same as in the General Transfer Desciptor */
  158 +#define OHCI_TD_SF_SHIFT 0
  159 +#define OHCI_TD_SF_MASK (0xffff<<OHCI_TD_SF_SHIFT)
  160 +#define OHCI_TD_FC_SHIFT 24
  161 +#define OHCI_TD_FC_MASK (7<<OHCI_TD_FC_SHIFT)
  162 +
  163 +/* Isochronous Transfer Desciptor - Offset / PacketStatusWord */
  164 +#define OHCI_TD_PSW_CC_SHIFT 12
  165 +#define OHCI_TD_PSW_CC_MASK (0xf<<OHCI_TD_PSW_CC_SHIFT)
  166 +#define OHCI_TD_PSW_SIZE_SHIFT 0
  167 +#define OHCI_TD_PSW_SIZE_MASK (0xfff<<OHCI_TD_PSW_SIZE_SHIFT)
  168 +
  169 +#define OHCI_PAGE_MASK 0xfffff000
  170 +#define OHCI_OFFSET_MASK 0xfff
  171 +
155 172 #define OHCI_DPTR_MASK 0xfffffff0
156 173  
157 174 #define OHCI_BM(val, field) \
... ... @@ -178,6 +195,15 @@ struct ohci_td {
178 195 uint32_t be;
179 196 };
180 197  
  198 +/* Isochronous transfer descriptor */
  199 +struct ohci_iso_td {
  200 + uint32_t flags;
  201 + uint32_t bp;
  202 + uint32_t next;
  203 + uint32_t be;
  204 + uint16_t offset[8];
  205 +};
  206 +
181 207 #define USB_HZ 12000000
182 208  
183 209 /* OHCI Local stuff */
... ... @@ -421,6 +447,32 @@ static inline int put_dwords(uint32_t addr, uint32_t *buf, int num)
421 447 return 1;
422 448 }
423 449  
  450 +/* Get an array of words from main memory */
  451 +static inline int get_words(uint32_t addr, uint16_t *buf, int num)
  452 +{
  453 + int i;
  454 +
  455 + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
  456 + cpu_physical_memory_rw(addr, (uint8_t *)buf, sizeof(*buf), 0);
  457 + *buf = le16_to_cpu(*buf);
  458 + }
  459 +
  460 + return 1;
  461 +}
  462 +
  463 +/* Put an array of words in to main memory */
  464 +static inline int put_words(uint32_t addr, uint16_t *buf, int num)
  465 +{
  466 + int i;
  467 +
  468 + for (i = 0; i < num; i++, buf++, addr += sizeof(*buf)) {
  469 + uint16_t tmp = cpu_to_le16(*buf);
  470 + cpu_physical_memory_rw(addr, (uint8_t *)&tmp, sizeof(tmp), 1);
  471 + }
  472 +
  473 + return 1;
  474 +}
  475 +
424 476 static inline int ohci_read_ed(uint32_t addr, struct ohci_ed *ed)
425 477 {
426 478 return get_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
... ... @@ -431,6 +483,12 @@ static inline int ohci_read_td(uint32_t addr, struct ohci_td *td)
431 483 return get_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
432 484 }
433 485  
  486 +static inline int ohci_read_iso_td(uint32_t addr, struct ohci_iso_td *td)
  487 +{
  488 + return (get_dwords(addr, (uint32_t *)td, 4) &&
  489 + get_words(addr + 16, td->offset, 8));
  490 +}
  491 +
434 492 static inline int ohci_put_ed(uint32_t addr, struct ohci_ed *ed)
435 493 {
436 494 return put_dwords(addr, (uint32_t *)ed, sizeof(*ed) >> 2);
... ... @@ -441,6 +499,12 @@ static inline int ohci_put_td(uint32_t addr, struct ohci_td *td)
441 499 return put_dwords(addr, (uint32_t *)td, sizeof(*td) >> 2);
442 500 }
443 501  
  502 +static inline int ohci_put_iso_td(uint32_t addr, struct ohci_iso_td *td)
  503 +{
  504 + return (put_dwords(addr, (uint32_t *)td, 4) &&
  505 + put_words(addr + 16, td->offset, 8));
  506 +}
  507 +
444 508 /* Read/Write the contents of a TD from/to main memory. */
445 509 static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write)
446 510 {
... ... @@ -459,16 +523,270 @@ static void ohci_copy_td(struct ohci_td *td, uint8_t *buf, int len, int write)
459 523 cpu_physical_memory_rw(ptr, buf, len - n, write);
460 524 }
461 525  
462   -static void ohci_process_lists(OHCIState *ohci);
  526 +/* Read/Write the contents of an ISO TD from/to main memory. */
  527 +static void ohci_copy_iso_td(uint32_t start_addr, uint32_t end_addr,
  528 + uint8_t *buf, int len, int write)
  529 +{
  530 + uint32_t ptr;
  531 + uint32_t n;
463 532  
464   -static void ohci_async_complete_packet(USBPacket * packet, void *opaque)
  533 + ptr = start_addr;
  534 + n = 0x1000 - (ptr & 0xfff);
  535 + if (n > len)
  536 + n = len;
  537 + cpu_physical_memory_rw(ptr, buf, n, write);
  538 + if (n == len)
  539 + return;
  540 + ptr = end_addr & ~0xfffu;
  541 + buf += n;
  542 + cpu_physical_memory_rw(ptr, buf, len - n, write);
  543 +}
  544 +
  545 +static void ohci_process_lists(OHCIState *ohci, int completion);
  546 +
  547 +static void ohci_async_complete_packet(USBPacket *packet, void *opaque)
465 548 {
466 549 OHCIState *ohci = opaque;
467 550 #ifdef DEBUG_PACKET
468 551 dprintf("Async packet complete\n");
469 552 #endif
470 553 ohci->async_complete = 1;
471   - ohci_process_lists(ohci);
  554 + ohci_process_lists(ohci, 1);
  555 +}
  556 +
  557 +#define USUB(a, b) ((int16_t)((uint16_t)(a) - (uint16_t)(b)))
  558 +
  559 +static int ohci_service_iso_td(OHCIState *ohci, struct ohci_ed *ed,
  560 + int completion)
  561 +{
  562 + int dir;
  563 + size_t len = 0;
  564 + char *str = NULL;
  565 + int pid;
  566 + int ret;
  567 + int i;
  568 + USBDevice *dev;
  569 + struct ohci_iso_td iso_td;
  570 + uint32_t addr;
  571 + uint16_t starting_frame;
  572 + int16_t relative_frame_number;
  573 + int frame_count;
  574 + uint32_t start_offset, next_offset, end_offset = 0;
  575 + uint32_t start_addr, end_addr;
  576 +
  577 + addr = ed->head & OHCI_DPTR_MASK;
  578 +
  579 + if (!ohci_read_iso_td(addr, &iso_td)) {
  580 + printf("usb-ohci: ISO_TD read error at %x\n", addr);
  581 + return 0;
  582 + }
  583 +
  584 + starting_frame = OHCI_BM(iso_td.flags, TD_SF);
  585 + frame_count = OHCI_BM(iso_td.flags, TD_FC);
  586 + relative_frame_number = USUB(ohci->frame_number, starting_frame);
  587 +
  588 +#ifdef DEBUG_ISOCH
  589 + printf("--- ISO_TD ED head 0x%.8x tailp 0x%.8x\n"
  590 + "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
  591 + "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
  592 + "0x%.8x 0x%.8x 0x%.8x 0x%.8x\n"
  593 + "frame_number 0x%.8x starting_frame 0x%.8x\n"
  594 + "frame_count 0x%.8x relative %d\n"
  595 + "di 0x%.8x cc 0x%.8x\n",
  596 + ed->head & OHCI_DPTR_MASK, ed->tail & OHCI_DPTR_MASK,
  597 + iso_td.flags, iso_td.bp, iso_td.next, iso_td.be,
  598 + iso_td.offset[0], iso_td.offset[1], iso_td.offset[2], iso_td.offset[3],
  599 + iso_td.offset[4], iso_td.offset[5], iso_td.offset[6], iso_td.offset[7],
  600 + ohci->frame_number, starting_frame,
  601 + frame_count, relative_frame_number,
  602 + OHCI_BM(iso_td.flags, TD_DI), OHCI_BM(iso_td.flags, TD_CC));
  603 +#endif
  604 +
  605 + if (relative_frame_number < 0) {
  606 + dprintf("usb-ohci: ISO_TD R=%d < 0\n", relative_frame_number);
  607 + return 1;
  608 + } else if (relative_frame_number > frame_count) {
  609 + /* ISO TD expired - retire the TD to the Done Queue and continue with
  610 + the next ISO TD of the same ED */
  611 + dprintf("usb-ohci: ISO_TD R=%d > FC=%d\n", relative_frame_number,
  612 + frame_count);
  613 + OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_DATAOVERRUN);
  614 + ed->head &= ~OHCI_DPTR_MASK;
  615 + ed->head |= (iso_td.next & OHCI_DPTR_MASK);
  616 + iso_td.next = ohci->done;
  617 + ohci->done = addr;
  618 + i = OHCI_BM(iso_td.flags, TD_DI);
  619 + if (i < ohci->done_count)
  620 + ohci->done_count = i;
  621 + ohci_put_iso_td(addr, &iso_td);
  622 + return 0;
  623 + }
  624 +
  625 + dir = OHCI_BM(ed->flags, ED_D);
  626 + switch (dir) {
  627 + case OHCI_TD_DIR_IN:
  628 + str = "in";
  629 + pid = USB_TOKEN_IN;
  630 + break;
  631 + case OHCI_TD_DIR_OUT:
  632 + str = "out";
  633 + pid = USB_TOKEN_OUT;
  634 + break;
  635 + case OHCI_TD_DIR_SETUP:
  636 + str = "setup";
  637 + pid = USB_TOKEN_SETUP;
  638 + break;
  639 + default:
  640 + printf("usb-ohci: Bad direction %d\n", dir);
  641 + return 1;
  642 + }
  643 +
  644 + if (!iso_td.bp || !iso_td.be) {
  645 + printf("usb-ohci: ISO_TD bp 0x%.8x be 0x%.8x\n", iso_td.bp, iso_td.be);
  646 + return 1;
  647 + }
  648 +
  649 + start_offset = iso_td.offset[relative_frame_number];
  650 + next_offset = iso_td.offset[relative_frame_number + 1];
  651 +
  652 + if (!(OHCI_BM(start_offset, TD_PSW_CC) & 0xe) ||
  653 + ((relative_frame_number < frame_count) &&
  654 + !(OHCI_BM(next_offset, TD_PSW_CC) & 0xe))) {
  655 + printf("usb-ohci: ISO_TD cc != not accessed 0x%.8x 0x%.8x\n",
  656 + start_offset, next_offset);
  657 + return 1;
  658 + }
  659 +
  660 + if ((relative_frame_number < frame_count) && (start_offset > next_offset)) {
  661 + printf("usb-ohci: ISO_TD start_offset=0x%.8x > next_offset=0x%.8x\n",
  662 + start_offset, next_offset);
  663 + return 1;
  664 + }
  665 +
  666 + if ((start_offset & 0x1000) == 0) {
  667 + start_addr = (iso_td.bp & OHCI_PAGE_MASK) |
  668 + (start_offset & OHCI_OFFSET_MASK);
  669 + } else {
  670 + start_addr = (iso_td.be & OHCI_PAGE_MASK) |
  671 + (start_offset & OHCI_OFFSET_MASK);
  672 + }
  673 +
  674 + if (relative_frame_number < frame_count) {
  675 + end_offset = next_offset - 1;
  676 + if ((end_offset & 0x1000) == 0) {
  677 + end_addr = (iso_td.bp & OHCI_PAGE_MASK) |
  678 + (end_offset & OHCI_OFFSET_MASK);
  679 + } else {
  680 + end_addr = (iso_td.be & OHCI_PAGE_MASK) |
  681 + (end_offset & OHCI_OFFSET_MASK);
  682 + }
  683 + } else {
  684 + /* Last packet in the ISO TD */
  685 + end_addr = iso_td.be;
  686 + }
  687 +
  688 + if ((start_addr & OHCI_PAGE_MASK) != (end_addr & OHCI_PAGE_MASK)) {
  689 + len = (end_addr & OHCI_OFFSET_MASK) + 0x1001
  690 + - (start_addr & OHCI_OFFSET_MASK);
  691 + } else {
  692 + len = end_addr - start_addr + 1;
  693 + }
  694 +
  695 + if (len && dir != OHCI_TD_DIR_IN) {
  696 + ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, len, 0);
  697 + }
  698 +
  699 + if (completion) {
  700 + ret = ohci->usb_packet.len;
  701 + } else {
  702 + ret = USB_RET_NODEV;
  703 + for (i = 0; i < ohci->num_ports; i++) {
  704 + dev = ohci->rhport[i].port.dev;
  705 + if ((ohci->rhport[i].ctrl & OHCI_PORT_PES) == 0)
  706 + continue;
  707 + ohci->usb_packet.pid = pid;
  708 + ohci->usb_packet.devaddr = OHCI_BM(ed->flags, ED_FA);
  709 + ohci->usb_packet.devep = OHCI_BM(ed->flags, ED_EN);
  710 + ohci->usb_packet.data = ohci->usb_buf;
  711 + ohci->usb_packet.len = len;
  712 + ohci->usb_packet.complete_cb = ohci_async_complete_packet;
  713 + ohci->usb_packet.complete_opaque = ohci;
  714 + ret = dev->handle_packet(dev, &ohci->usb_packet);
  715 + if (ret != USB_RET_NODEV)
  716 + break;
  717 + }
  718 +
  719 + if (ret == USB_RET_ASYNC) {
  720 + return 1;
  721 + }
  722 + }
  723 +
  724 +#ifdef DEBUG_ISOCH
  725 + printf("so 0x%.8x eo 0x%.8x\nsa 0x%.8x ea 0x%.8x\ndir %s len %zu ret %d\n",
  726 + start_offset, end_offset, start_addr, end_addr, str, len, ret);
  727 +#endif
  728 +
  729 + /* Writeback */
  730 + if (dir == OHCI_TD_DIR_IN && ret >= 0 && ret <= len) {
  731 + /* IN transfer succeeded */
  732 + ohci_copy_iso_td(start_addr, end_addr, ohci->usb_buf, ret, 1);
  733 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
  734 + OHCI_CC_NOERROR);
  735 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, ret);
  736 + } else if (dir == OHCI_TD_DIR_OUT && ret == len) {
  737 + /* OUT transfer succeeded */
  738 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
  739 + OHCI_CC_NOERROR);
  740 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE, 0);
  741 + } else {
  742 + if (ret > len) {
  743 + printf("usb-ohci: DataOverrun %d > %zu\n", ret, len);
  744 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
  745 + OHCI_CC_DATAOVERRUN);
  746 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
  747 + len);
  748 + } else if (ret >= 0) {
  749 + printf("usb-ohci: DataUnderrun %d\n", ret);
  750 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
  751 + OHCI_CC_DATAUNDERRUN);
  752 + } else {
  753 + switch (ret) {
  754 + case USB_RET_NODEV:
  755 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
  756 + OHCI_CC_DEVICENOTRESPONDING);
  757 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
  758 + 0);
  759 + break;
  760 + case USB_RET_NAK:
  761 + case USB_RET_STALL:
  762 + printf("usb-ohci: got NAK/STALL %d\n", ret);
  763 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
  764 + OHCI_CC_STALL);
  765 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_SIZE,
  766 + 0);
  767 + break;
  768 + default:
  769 + printf("usb-ohci: Bad device response %d\n", ret);
  770 + OHCI_SET_BM(iso_td.offset[relative_frame_number], TD_PSW_CC,
  771 + OHCI_CC_UNDEXPETEDPID);
  772 + break;
  773 + }
  774 + }
  775 + }
  776 +
  777 + if (relative_frame_number == frame_count) {
  778 + /* Last data packet of ISO TD - retire the TD to the Done Queue */
  779 + OHCI_SET_BM(iso_td.flags, TD_CC, OHCI_CC_NOERROR);
  780 + ed->head &= ~OHCI_DPTR_MASK;
  781 + ed->head |= (iso_td.next & OHCI_DPTR_MASK);
  782 + iso_td.next = ohci->done;
  783 + ohci->done = addr;
  784 + i = OHCI_BM(iso_td.flags, TD_DI);
  785 + if (i < ohci->done_count)
  786 + ohci->done_count = i;
  787 + }
  788 + ohci_put_iso_td(addr, &iso_td);
  789 + return 1;
472 790 }
473 791  
474 792 /* Service a transport descriptor.
... ... @@ -671,7 +989,7 @@ static int ohci_service_td(OHCIState *ohci, struct ohci_ed *ed)
671 989 }
672 990  
673 991 /* Service an endpoint list. Returns nonzero if active TD were found. */
674   -static int ohci_service_ed_list(OHCIState *ohci, uint32_t head)
  992 +static int ohci_service_ed_list(OHCIState *ohci, uint32_t head, int completion)
675 993 {
676 994 struct ohci_ed ed;
677 995 uint32_t next_ed;
... ... @@ -702,10 +1020,6 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head)
702 1020 continue;
703 1021 }
704 1022  
705   - /* Skip isochronous endpoints. */
706   - if (ed.flags & OHCI_ED_F)
707   - continue;
708   -
709 1023 while ((ed.head & OHCI_DPTR_MASK) != ed.tail) {
710 1024 #ifdef DEBUG_PACKET
711 1025 dprintf("ED @ 0x%.8x fa=%u en=%u d=%u s=%u k=%u f=%u mps=%u "
... ... @@ -719,8 +1033,14 @@ static int ohci_service_ed_list(OHCIState *ohci, uint32_t head)
719 1033 #endif
720 1034 active = 1;
721 1035  
722   - if (ohci_service_td(ohci, &ed))
723   - break;
  1036 + if ((ed.flags & OHCI_ED_F) == 0) {
  1037 + if (ohci_service_td(ohci, &ed))
  1038 + break;
  1039 + } else {
  1040 + /* Handle isochronous endpoints */
  1041 + if (ohci_service_iso_td(ohci, &ed, completion))
  1042 + break;
  1043 + }
724 1044 }
725 1045  
726 1046 ohci_put_ed(cur, &ed);
... ... @@ -738,19 +1058,19 @@ static void ohci_sof(OHCIState *ohci)
738 1058 }
739 1059  
740 1060 /* Process Control and Bulk lists. */
741   -static void ohci_process_lists(OHCIState *ohci)
  1061 +static void ohci_process_lists(OHCIState *ohci, int completion)
742 1062 {
743 1063 if ((ohci->ctl & OHCI_CTL_CLE) && (ohci->status & OHCI_STATUS_CLF)) {
744 1064 if (ohci->ctrl_cur && ohci->ctrl_cur != ohci->ctrl_head)
745 1065 dprintf("usb-ohci: head %x, cur %x\n", ohci->ctrl_head, ohci->ctrl_cur);
746   - if (!ohci_service_ed_list(ohci, ohci->ctrl_head)) {
  1066 + if (!ohci_service_ed_list(ohci, ohci->ctrl_head, completion)) {
747 1067 ohci->ctrl_cur = 0;
748 1068 ohci->status &= ~OHCI_STATUS_CLF;
749 1069 }
750 1070 }
751 1071  
752 1072 if ((ohci->ctl & OHCI_CTL_BLE) && (ohci->status & OHCI_STATUS_BLF)) {
753   - if (!ohci_service_ed_list(ohci, ohci->bulk_head)) {
  1073 + if (!ohci_service_ed_list(ohci, ohci->bulk_head, completion)) {
754 1074 ohci->bulk_cur = 0;
755 1075 ohci->status &= ~OHCI_STATUS_BLF;
756 1076 }
... ... @@ -770,7 +1090,7 @@ static void ohci_frame_boundary(void *opaque)
770 1090 int n;
771 1091  
772 1092 n = ohci->frame_number & 0x1f;
773   - ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]));
  1093 + ohci_service_ed_list(ohci, le32_to_cpu(hcca.intr[n]), 0);
774 1094 }
775 1095  
776 1096 /* Cancel all pending packets if either of the lists has been disabled. */
... ... @@ -780,7 +1100,7 @@ static void ohci_frame_boundary(void *opaque)
780 1100 ohci->async_td = 0;
781 1101 }
782 1102 ohci->old_ctl = ohci->ctl;
783   - ohci_process_lists(ohci);
  1103 + ohci_process_lists(ohci, 0);
784 1104  
785 1105 /* Frame boundary, so do EOF stuf here */
786 1106 ohci->frt = ohci->fit;
... ... @@ -1206,6 +1526,9 @@ static void ohci_mem_write(void *ptr, target_phys_addr_t addr, uint32_t val)
1206 1526 ohci_set_frame_interval(ohci, val);
1207 1527 break;
1208 1528  
  1529 + case 15: /* HcFmNumber */
  1530 + break;
  1531 +
1209 1532 case 16: /* HcPeriodicStart */
1210 1533 ohci->pstart = val & 0xffff;
1211 1534 break;
... ...