hcd-uhci.c (5ad23e873c858292dc58b9296261365312b8f683) | hcd-uhci.c (66a08cbe6ad1aebec8eecf58b3ba042e19dd1649) |
---|---|
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 --- 91 unchanged lines hidden (view full) --- 100 QEMUSGList sgl; 101 UHCIQueue *queue; 102 QTAILQ_ENTRY(UHCIAsync) next; 103 uint32_t td_addr; 104 uint8_t done; 105}; 106 107struct UHCIQueue { | 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 --- 91 unchanged lines hidden (view full) --- 100 QEMUSGList sgl; 101 UHCIQueue *queue; 102 QTAILQ_ENTRY(UHCIAsync) next; 103 uint32_t td_addr; 104 uint8_t done; 105}; 106 107struct UHCIQueue { |
108 uint32_t qh_addr; |
|
108 uint32_t token; 109 UHCIState *uhci; 110 USBEndpoint *ep; 111 QTAILQ_ENTRY(UHCIQueue) next; 112 QTAILQ_HEAD(, UHCIAsync) asyncs; 113 int8_t valid; 114}; 115 --- 49 unchanged lines hidden (view full) --- 165static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td); 166 167static inline int32_t uhci_queue_token(UHCI_TD *td) 168{ 169 /* covers ep, dev, pid -> identifies the endpoint */ 170 return td->token & 0x7ffff; 171} 172 | 109 uint32_t token; 110 UHCIState *uhci; 111 USBEndpoint *ep; 112 QTAILQ_ENTRY(UHCIQueue) next; 113 QTAILQ_HEAD(, UHCIAsync) asyncs; 114 int8_t valid; 115}; 116 --- 49 unchanged lines hidden (view full) --- 166static void uhci_queue_fill(UHCIQueue *q, UHCI_TD *td); 167 168static inline int32_t uhci_queue_token(UHCI_TD *td) 169{ 170 /* covers ep, dev, pid -> identifies the endpoint */ 171 return td->token & 0x7ffff; 172} 173 |
173static UHCIQueue *uhci_queue_get(UHCIState *s, UHCI_TD *td, USBEndpoint *ep) | 174static UHCIQueue *uhci_queue_new(UHCIState *s, uint32_t qh_addr, UHCI_TD *td, 175 USBEndpoint *ep) |
174{ | 176{ |
175 uint32_t token = uhci_queue_token(td); | |
176 UHCIQueue *queue; 177 | 177 UHCIQueue *queue; 178 |
178 QTAILQ_FOREACH(queue, &s->queues, next) { 179 if (queue->token == token) { 180 return queue; 181 } 182 } 183 | |
184 queue = g_new0(UHCIQueue, 1); 185 queue->uhci = s; | 179 queue = g_new0(UHCIQueue, 1); 180 queue->uhci = s; |
186 queue->token = token; | 181 queue->qh_addr = qh_addr; 182 queue->token = uhci_queue_token(td); |
187 queue->ep = ep; 188 QTAILQ_INIT(&queue->asyncs); 189 QTAILQ_INSERT_HEAD(&s->queues, queue, next); 190 trace_usb_uhci_queue_add(queue->token); 191 return queue; 192} 193 | 183 queue->ep = ep; 184 QTAILQ_INIT(&queue->asyncs); 185 QTAILQ_INSERT_HEAD(&s->queues, queue, next); 186 trace_usb_uhci_queue_add(queue->token); 187 return queue; 188} 189 |
194static void uhci_queue_free(UHCIQueue *queue) | 190static void uhci_queue_free(UHCIQueue *queue, const char *reason) |
195{ 196 UHCIState *s = queue->uhci; 197 UHCIAsync *async; 198 199 while (!QTAILQ_EMPTY(&queue->asyncs)) { 200 async = QTAILQ_FIRST(&queue->asyncs); 201 uhci_async_cancel(async); 202 } 203 | 191{ 192 UHCIState *s = queue->uhci; 193 UHCIAsync *async; 194 195 while (!QTAILQ_EMPTY(&queue->asyncs)) { 196 async = QTAILQ_FIRST(&queue->asyncs); 197 uhci_async_cancel(async); 198 } 199 |
204 trace_usb_uhci_queue_del(queue->token); | 200 trace_usb_uhci_queue_del(queue->token, reason); |
205 QTAILQ_REMOVE(&s->queues, queue, next); 206 g_free(queue); 207} 208 | 201 QTAILQ_REMOVE(&s->queues, queue, next); 202 g_free(queue); 203} 204 |
205static UHCIQueue *uhci_queue_find(UHCIState *s, UHCI_TD *td) 206{ 207 uint32_t token = uhci_queue_token(td); 208 UHCIQueue *queue; 209 210 QTAILQ_FOREACH(queue, &s->queues, next) { 211 if (queue->token == token) { 212 return queue; 213 } 214 } 215 return NULL; 216} 217 218static bool uhci_queue_verify(UHCIQueue *queue, uint32_t qh_addr, UHCI_TD *td, 219 uint32_t td_addr, bool queuing) 220{ 221 UHCIAsync *first = QTAILQ_FIRST(&queue->asyncs); 222 223 return queue->qh_addr == qh_addr && 224 queue->token == uhci_queue_token(td) && 225 (queuing || !(td->ctrl & TD_CTRL_ACTIVE) || first == NULL || 226 first->td_addr == td_addr); 227} 228 |
|
209static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr) 210{ 211 UHCIAsync *async = g_new0(UHCIAsync, 1); 212 213 async->queue = queue; 214 async->td_addr = td_addr; 215 usb_packet_init(&async->packet); 216 pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1); --- 52 unchanged lines hidden (view full) --- 269 * Cancel async packets that are no longer valid 270 */ 271static void uhci_async_validate_end(UHCIState *s) 272{ 273 UHCIQueue *queue, *n; 274 275 QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) { 276 if (!queue->valid) { | 229static UHCIAsync *uhci_async_alloc(UHCIQueue *queue, uint32_t td_addr) 230{ 231 UHCIAsync *async = g_new0(UHCIAsync, 1); 232 233 async->queue = queue; 234 async->td_addr = td_addr; 235 usb_packet_init(&async->packet); 236 pci_dma_sglist_init(&async->sgl, &queue->uhci->dev, 1); --- 52 unchanged lines hidden (view full) --- 289 * Cancel async packets that are no longer valid 290 */ 291static void uhci_async_validate_end(UHCIState *s) 292{ 293 UHCIQueue *queue, *n; 294 295 QTAILQ_FOREACH_SAFE(queue, &s->queues, next, n) { 296 if (!queue->valid) { |
277 uhci_queue_free(queue); | 297 uhci_queue_free(queue, "validate-end"); |
278 } 279 } 280} 281 282static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev) 283{ 284 UHCIQueue *queue, *n; 285 --- 4 unchanged lines hidden (view full) --- 290 } 291} 292 293static void uhci_async_cancel_all(UHCIState *s) 294{ 295 UHCIQueue *queue, *nq; 296 297 QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) { | 298 } 299 } 300} 301 302static void uhci_async_cancel_device(UHCIState *s, USBDevice *dev) 303{ 304 UHCIQueue *queue, *n; 305 --- 4 unchanged lines hidden (view full) --- 310 } 311} 312 313static void uhci_async_cancel_all(UHCIState *s) 314{ 315 UHCIQueue *queue, *nq; 316 317 QTAILQ_FOREACH_SAFE(queue, &s->queues, next, nq) { |
298 uhci_queue_free(queue); | 318 uhci_queue_free(queue, "cancel-all"); |
299 } 300} 301 302static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t td_addr, 303 UHCI_TD *td) 304{ 305 uint32_t token = uhci_queue_token(td); 306 UHCIQueue *queue; --- 470 unchanged lines hidden (view full) --- 777 s->status |= UHCI_STS_USBERR; 778 if (td->ctrl & TD_CTRL_IOC) { 779 *int_mask |= 0x01; 780 } 781 uhci_update_irq(s); 782 return err; 783} 784 | 319 } 320} 321 322static UHCIAsync *uhci_async_find_td(UHCIState *s, uint32_t td_addr, 323 UHCI_TD *td) 324{ 325 uint32_t token = uhci_queue_token(td); 326 UHCIQueue *queue; --- 470 unchanged lines hidden (view full) --- 797 s->status |= UHCI_STS_USBERR; 798 if (td->ctrl & TD_CTRL_IOC) { 799 *int_mask |= 0x01; 800 } 801 uhci_update_irq(s); 802 return err; 803} 804 |
785static int uhci_handle_td(UHCIState *s, UHCIQueue *q, | 805static int uhci_handle_td(UHCIState *s, UHCIQueue *q, uint32_t qh_addr, |
786 UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask) 787{ 788 UHCIAsync *async; 789 int len = 0, max_len; 790 bool spd; 791 bool queuing = (q != NULL); 792 uint8_t pid = td->token & 0xff; 793 | 806 UHCI_TD *td, uint32_t td_addr, uint32_t *int_mask) 807{ 808 UHCIAsync *async; 809 int len = 0, max_len; 810 bool spd; 811 bool queuing = (q != NULL); 812 uint8_t pid = td->token & 0xff; 813 |
814 if (q == NULL) { 815 q = uhci_queue_find(s, td); 816 if (q && !uhci_queue_verify(q, qh_addr, td, td_addr, queuing)) { 817 uhci_queue_free(q, "guest re-used qh"); 818 q = NULL; 819 } 820 } 821 |
|
794 /* Is active ? */ 795 if (!(td->ctrl & TD_CTRL_ACTIVE)) { 796 /* 797 * ehci11d spec page 22: "Even if the Active bit in the TD is already 798 * cleared when the TD is fetched ... an IOC interrupt is generated" 799 */ 800 if (td->ctrl & TD_CTRL_IOC) { 801 *int_mask |= 0x01; --- 18 unchanged lines hidden (view full) --- 820 uhci_async_unlink(async); 821 goto done; 822 } 823 824 /* Allocate new packet */ 825 if (q == NULL) { 826 USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f); 827 USBEndpoint *ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); | 822 /* Is active ? */ 823 if (!(td->ctrl & TD_CTRL_ACTIVE)) { 824 /* 825 * ehci11d spec page 22: "Even if the Active bit in the TD is already 826 * cleared when the TD is fetched ... an IOC interrupt is generated" 827 */ 828 if (td->ctrl & TD_CTRL_IOC) { 829 *int_mask |= 0x01; --- 18 unchanged lines hidden (view full) --- 848 uhci_async_unlink(async); 849 goto done; 850 } 851 852 /* Allocate new packet */ 853 if (q == NULL) { 854 USBDevice *dev = uhci_find_device(s, (td->token >> 8) & 0x7f); 855 USBEndpoint *ep = usb_ep_get(dev, pid, (td->token >> 15) & 0xf); |
828 q = uhci_queue_get(s, td, ep); | 856 q = uhci_queue_new(s, qh_addr, td, ep); |
829 } 830 async = uhci_async_alloc(q, td_addr); 831 832 /* valid needs to be large enough to handle 10 frame delay 833 * for initial isochronous requests 834 */ 835 async->queue->valid = 32; 836 --- 112 unchanged lines hidden (view full) --- 949 uhci_read_td(q->uhci, &ptd, plink); 950 if (!(ptd.ctrl & TD_CTRL_ACTIVE)) { 951 break; 952 } 953 if (uhci_queue_token(&ptd) != q->token) { 954 break; 955 } 956 trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token); | 857 } 858 async = uhci_async_alloc(q, td_addr); 859 860 /* valid needs to be large enough to handle 10 frame delay 861 * for initial isochronous requests 862 */ 863 async->queue->valid = 32; 864 --- 112 unchanged lines hidden (view full) --- 977 uhci_read_td(q->uhci, &ptd, plink); 978 if (!(ptd.ctrl & TD_CTRL_ACTIVE)) { 979 break; 980 } 981 if (uhci_queue_token(&ptd) != q->token) { 982 break; 983 } 984 trace_usb_uhci_td_queue(plink & ~0xf, ptd.ctrl, ptd.token); |
957 ret = uhci_handle_td(q->uhci, q, &ptd, plink, &int_mask); | 985 ret = uhci_handle_td(q->uhci, q, q->qh_addr, &ptd, plink, &int_mask); |
958 if (ret == TD_RESULT_ASYNC_CONT) { 959 break; 960 } 961 assert(ret == TD_RESULT_ASYNC_START); 962 assert(int_mask == 0); 963 plink = ptd.link; 964 } 965 usb_device_flush_ep_queue(q->ep->dev, q->ep); --- 64 unchanged lines hidden (view full) --- 1030 continue; 1031 } 1032 1033 /* TD */ 1034 uhci_read_td(s, &td, link); 1035 trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token); 1036 1037 old_td_ctrl = td.ctrl; | 986 if (ret == TD_RESULT_ASYNC_CONT) { 987 break; 988 } 989 assert(ret == TD_RESULT_ASYNC_START); 990 assert(int_mask == 0); 991 plink = ptd.link; 992 } 993 usb_device_flush_ep_queue(q->ep->dev, q->ep); --- 64 unchanged lines hidden (view full) --- 1058 continue; 1059 } 1060 1061 /* TD */ 1062 uhci_read_td(s, &td, link); 1063 trace_usb_uhci_td_load(curr_qh & ~0xf, link & ~0xf, td.ctrl, td.token); 1064 1065 old_td_ctrl = td.ctrl; |
1038 ret = uhci_handle_td(s, NULL, &td, link, &int_mask); | 1066 ret = uhci_handle_td(s, NULL, curr_qh, &td, link, &int_mask); |
1039 if (old_td_ctrl != td.ctrl) { 1040 /* update the status bits of the TD */ 1041 val = cpu_to_le32(td.ctrl); 1042 pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); 1043 } 1044 1045 switch (ret) { 1046 case TD_RESULT_STOP_FRAME: /* interrupted frame */ --- 344 unchanged lines hidden --- | 1067 if (old_td_ctrl != td.ctrl) { 1068 /* update the status bits of the TD */ 1069 val = cpu_to_le32(td.ctrl); 1070 pci_dma_write(&s->dev, (link & ~0xf) + 4, &val, sizeof(val)); 1071 } 1072 1073 switch (ret) { 1074 case TD_RESULT_STOP_FRAME: /* interrupted frame */ --- 344 unchanged lines hidden --- |