Commit 7bfe5777023bb88e8f63a3e80a836f3eb7b13fdc
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; | ... | ... |