hcd-uhci.c (50dcc0f85da5d2a74760af4b67c040c4d0c8b939) | hcd-uhci.c (60e1b2a6ddf1fd9cc93ad81d8ba7d8ac4369cc78) |
---|---|
1/* 2 * USB UHCI controller emulation 3 * 4 * Copyright (c) 2005 Fabrice Bellard 5 * 6 * Copyright (c) 2008 Max Krasnyansky 7 * Magor rewrite of the UHCI data structures parser and frame processor 8 * Support for fully async operation and multiple outstanding transactions --- 63 unchanged lines hidden (view full) --- 72#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC) 73 74#define FRAME_TIMER_FREQ 1000 75 76#define FRAME_MAX_LOOPS 256 77 78#define NB_PORTS 2 79 | 1/* 2 * USB UHCI controller emulation 3 * 4 * Copyright (c) 2005 Fabrice Bellard 5 * 6 * Copyright (c) 2008 Max Krasnyansky 7 * Magor rewrite of the UHCI data structures parser and frame processor 8 * Support for fully async operation and multiple outstanding transactions --- 63 unchanged lines hidden (view full) --- 72#define UHCI_PORT_WRITE_CLEAR (UHCI_PORT_CSC | UHCI_PORT_ENC) 73 74#define FRAME_TIMER_FREQ 1000 75 76#define FRAME_MAX_LOOPS 256 77 78#define NB_PORTS 2 79 |
80enum { 81 TD_RESULT_STOP_FRAME = -1, 82 TD_RESULT_COMPLETE = 0, 83 TD_RESULT_NEXT_QH = 1, 84 TD_RESULT_ASYNC = 2, 85}; 86 |
|
80typedef struct UHCIState UHCIState; 81typedef struct UHCIAsync UHCIAsync; 82typedef struct UHCIQueue UHCIQueue; 83 84/* 85 * Pending async transaction. 86 * 'packet' must be the first field because completion 87 * handler does "(UHCIAsync *) pkt" cast. --- 628 unchanged lines hidden (view full) --- 716 goto out; 717 } 718 719 if ((td->ctrl & TD_CTRL_SPD) && len < max_len) { 720 *int_mask |= 0x02; 721 /* short packet: do not update QH */ 722 trace_usb_uhci_packet_complete_shortxfer(async->queue->token, 723 async->td); | 87typedef struct UHCIState UHCIState; 88typedef struct UHCIAsync UHCIAsync; 89typedef struct UHCIQueue UHCIQueue; 90 91/* 92 * Pending async transaction. 93 * 'packet' must be the first field because completion 94 * handler does "(UHCIAsync *) pkt" cast. --- 628 unchanged lines hidden (view full) --- 723 goto out; 724 } 725 726 if ((td->ctrl & TD_CTRL_SPD) && len < max_len) { 727 *int_mask |= 0x02; 728 /* short packet: do not update QH */ 729 trace_usb_uhci_packet_complete_shortxfer(async->queue->token, 730 async->td); |
724 return 1; | 731 return TD_RESULT_NEXT_QH; |
725 } 726 } 727 728 /* success */ 729 trace_usb_uhci_packet_complete_success(async->queue->token, async->td); | 732 } 733 } 734 735 /* success */ 736 trace_usb_uhci_packet_complete_success(async->queue->token, async->td); |
730 return 0; | 737 return TD_RESULT_COMPLETE; |
731 732out: 733 switch(ret) { 734 case USB_RET_STALL: 735 td->ctrl |= TD_CTRL_STALL; 736 td->ctrl &= ~TD_CTRL_ACTIVE; 737 s->status |= UHCI_STS_USBERR; 738 if (td->ctrl & TD_CTRL_IOC) { 739 *int_mask |= 0x01; 740 } 741 uhci_update_irq(s); 742 trace_usb_uhci_packet_complete_stall(async->queue->token, async->td); | 738 739out: 740 switch(ret) { 741 case USB_RET_STALL: 742 td->ctrl |= TD_CTRL_STALL; 743 td->ctrl &= ~TD_CTRL_ACTIVE; 744 s->status |= UHCI_STS_USBERR; 745 if (td->ctrl & TD_CTRL_IOC) { 746 *int_mask |= 0x01; 747 } 748 uhci_update_irq(s); 749 trace_usb_uhci_packet_complete_stall(async->queue->token, async->td); |
743 return 1; | 750 return TD_RESULT_NEXT_QH; |
744 745 case USB_RET_BABBLE: 746 td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; 747 td->ctrl &= ~TD_CTRL_ACTIVE; 748 s->status |= UHCI_STS_USBERR; 749 if (td->ctrl & TD_CTRL_IOC) { 750 *int_mask |= 0x01; 751 } 752 uhci_update_irq(s); 753 /* frame interrupted */ 754 trace_usb_uhci_packet_complete_babble(async->queue->token, async->td); | 751 752 case USB_RET_BABBLE: 753 td->ctrl |= TD_CTRL_BABBLE | TD_CTRL_STALL; 754 td->ctrl &= ~TD_CTRL_ACTIVE; 755 s->status |= UHCI_STS_USBERR; 756 if (td->ctrl & TD_CTRL_IOC) { 757 *int_mask |= 0x01; 758 } 759 uhci_update_irq(s); 760 /* frame interrupted */ 761 trace_usb_uhci_packet_complete_babble(async->queue->token, async->td); |
755 return -1; | 762 return TD_RESULT_STOP_FRAME; |
756 757 case USB_RET_NAK: 758 td->ctrl |= TD_CTRL_NAK; 759 if (pid == USB_TOKEN_SETUP) 760 break; | 763 764 case USB_RET_NAK: 765 td->ctrl |= TD_CTRL_NAK; 766 if (pid == USB_TOKEN_SETUP) 767 break; |
761 return 1; | 768 return TD_RESULT_NEXT_QH; |
762 763 case USB_RET_IOERROR: 764 case USB_RET_NODEV: 765 default: 766 break; 767 } 768 769 /* Retry the TD if error count is not zero */ --- 9 unchanged lines hidden (view full) --- 779 *int_mask |= 0x01; 780 uhci_update_irq(s); 781 trace_usb_uhci_packet_complete_error(async->queue->token, 782 async->td); 783 } 784 } 785 td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | 786 (err << TD_CTRL_ERROR_SHIFT); | 769 770 case USB_RET_IOERROR: 771 case USB_RET_NODEV: 772 default: 773 break; 774 } 775 776 /* Retry the TD if error count is not zero */ --- 9 unchanged lines hidden (view full) --- 786 *int_mask |= 0x01; 787 uhci_update_irq(s); 788 trace_usb_uhci_packet_complete_error(async->queue->token, 789 async->td); 790 } 791 } 792 td->ctrl = (td->ctrl & ~(3 << TD_CTRL_ERROR_SHIFT)) | 793 (err << TD_CTRL_ERROR_SHIFT); |
787 return 1; | 794 return TD_RESULT_NEXT_QH; |
788} 789 790static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask) 791{ 792 UHCIAsync *async; 793 int len = 0, max_len; 794 uint8_t pid; 795 USBDevice *dev; 796 USBEndpoint *ep; 797 798 /* Is active ? */ 799 if (!(td->ctrl & TD_CTRL_ACTIVE)) | 795} 796 797static int uhci_handle_td(UHCIState *s, uint32_t addr, UHCI_TD *td, uint32_t *int_mask) 798{ 799 UHCIAsync *async; 800 int len = 0, max_len; 801 uint8_t pid; 802 USBDevice *dev; 803 USBEndpoint *ep; 804 805 /* Is active ? */ 806 if (!(td->ctrl & TD_CTRL_ACTIVE)) |
800 return 1; | 807 return TD_RESULT_NEXT_QH; |
801 802 async = uhci_async_find_td(s, addr, td); 803 if (async) { 804 /* Already submitted */ 805 async->queue->valid = 32; 806 807 if (!async->done) | 808 809 async = uhci_async_find_td(s, addr, td); 810 if (async) { 811 /* Already submitted */ 812 async->queue->valid = 32; 813 814 if (!async->done) |
808 return 1; | 815 return TD_RESULT_NEXT_QH; |
809 810 uhci_async_unlink(async); 811 goto done; 812 } 813 814 /* Allocate new packet */ 815 async = uhci_async_alloc(uhci_queue_get(s, td), addr); 816 if (!async) | 816 817 uhci_async_unlink(async); 818 goto done; 819 } 820 821 /* Allocate new packet */ 822 async = uhci_async_alloc(uhci_queue_get(s, td), addr); 823 if (!async) |
817 return 1; | 824 return TD_RESULT_NEXT_QH; |
818 819 /* valid needs to be large enough to handle 10 frame delay 820 * for initial isochronous requests 821 */ 822 async->queue->valid = 32; 823 async->isoc = td->ctrl & TD_CTRL_IOS; 824 825 max_len = ((td->token >> 21) + 1) & 0x7ff; --- 17 unchanged lines hidden (view full) --- 843 len = usb_handle_packet(dev, &async->packet); 844 break; 845 846 default: 847 /* invalid pid : frame interrupted */ 848 uhci_async_free(async); 849 s->status |= UHCI_STS_HCPERR; 850 uhci_update_irq(s); | 825 826 /* valid needs to be large enough to handle 10 frame delay 827 * for initial isochronous requests 828 */ 829 async->queue->valid = 32; 830 async->isoc = td->ctrl & TD_CTRL_IOS; 831 832 max_len = ((td->token >> 21) + 1) & 0x7ff; --- 17 unchanged lines hidden (view full) --- 850 len = usb_handle_packet(dev, &async->packet); 851 break; 852 853 default: 854 /* invalid pid : frame interrupted */ 855 uhci_async_free(async); 856 s->status |= UHCI_STS_HCPERR; 857 uhci_update_irq(s); |
851 return -1; | 858 return TD_RESULT_STOP_FRAME; |
852 } 853 854 if (len == USB_RET_ASYNC) { 855 uhci_async_link(async); | 859 } 860 861 if (len == USB_RET_ASYNC) { 862 uhci_async_link(async); |
856 return 2; | 863 return TD_RESULT_ASYNC; |
857 } 858 859 async->packet.result = len; 860 861done: 862 len = uhci_complete_td(s, td, async, int_mask); 863 usb_packet_unmap(&async->packet); 864 uhci_async_free(async); --- 89 unchanged lines hidden (view full) --- 954 if (!(ptd.ctrl & TD_CTRL_ACTIVE)) { 955 break; 956 } 957 if (uhci_queue_token(&ptd) != token) { 958 break; 959 } 960 trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token); 961 ret = uhci_handle_td(s, plink, &ptd, &int_mask); | 864 } 865 866 async->packet.result = len; 867 868done: 869 len = uhci_complete_td(s, td, async, int_mask); 870 usb_packet_unmap(&async->packet); 871 uhci_async_free(async); --- 89 unchanged lines hidden (view full) --- 961 if (!(ptd.ctrl & TD_CTRL_ACTIVE)) { 962 break; 963 } 964 if (uhci_queue_token(&ptd) != token) { 965 break; 966 } 967 trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token); 968 ret = uhci_handle_td(s, plink, &ptd, &int_mask); |
962 assert(ret == 2); /* got USB_RET_ASYNC */ | 969 assert(ret == TD_RESULT_ASYNC); |
963 assert(int_mask == 0); 964 plink = ptd.link; 965 } 966} 967 968static void uhci_process_frame(UHCIState *s) 969{ 970 uint32_t frame_addr, link, old_td_ctrl, val, int_mask; --- 71 unchanged lines hidden (view full) --- 1042 ret = uhci_handle_td(s, link, &td, &int_mask); 1043 if (old_td_ctrl != td.ctrl) { 1044 /* update the status bits of the TD */ 1045 val = cpu_to_le32(td.ctrl); 1046 pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); 1047 } 1048 1049 switch (ret) { | 970 assert(int_mask == 0); 971 plink = ptd.link; 972 } 973} 974 975static void uhci_process_frame(UHCIState *s) 976{ 977 uint32_t frame_addr, link, old_td_ctrl, val, int_mask; --- 71 unchanged lines hidden (view full) --- 1049 ret = uhci_handle_td(s, link, &td, &int_mask); 1050 if (old_td_ctrl != td.ctrl) { 1051 /* update the status bits of the TD */ 1052 val = cpu_to_le32(td.ctrl); 1053 pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); 1054 } 1055 1056 switch (ret) { |
1050 case -1: /* interrupted frame */ | 1057 case TD_RESULT_STOP_FRAME: /* interrupted frame */ |
1051 goto out; 1052 | 1058 goto out; 1059 |
1053 case 1: /* goto next queue */ | 1060 case TD_RESULT_NEXT_QH: |
1054 trace_usb_uhci_td_nextqh(curr_qh & ~0xf, link & ~0xf); 1055 link = curr_qh ? qh.link : td.link; 1056 continue; 1057 | 1061 trace_usb_uhci_td_nextqh(curr_qh & ~0xf, link & ~0xf); 1062 link = curr_qh ? qh.link : td.link; 1063 continue; 1064 |
1058 case 2: /* got USB_RET_ASYNC */ | 1065 case TD_RESULT_ASYNC: |
1059 trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); 1060 if (is_valid(td.link)) { 1061 uhci_fill_queue(s, &td); 1062 } 1063 link = curr_qh ? qh.link : td.link; 1064 continue; 1065 | 1066 trace_usb_uhci_td_async(curr_qh & ~0xf, link & ~0xf); 1067 if (is_valid(td.link)) { 1068 uhci_fill_queue(s, &td); 1069 } 1070 link = curr_qh ? qh.link : td.link; 1071 continue; 1072 |
1066 case 0: /* completed TD */ | 1073 case TD_RESULT_COMPLETE: |
1067 trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf); 1068 link = td.link; 1069 td_count++; 1070 bytes_count += (td.ctrl & 0x7ff) + 1; 1071 1072 if (curr_qh) { 1073 /* update QH element link */ 1074 qh.el_link = link; --- 297 unchanged lines hidden --- | 1074 trace_usb_uhci_td_complete(curr_qh & ~0xf, link & ~0xf); 1075 link = td.link; 1076 td_count++; 1077 bytes_count += (td.ctrl & 0x7ff) + 1; 1078 1079 if (curr_qh) { 1080 /* update QH element link */ 1081 qh.el_link = link; --- 297 unchanged lines hidden --- |