diff options
author | Solomon Peachy <pizza@shaftnet.org> | 2018-09-20 16:14:36 -0400 |
---|---|---|
committer | Solomon Peachy <pizza@shaftnet.org> | 2018-09-20 21:11:40 -0400 |
commit | a454b7f9efe1f935f37b1e91c0aba2fd9190aed5 (patch) | |
tree | f82390e8cda7c7755083c4077bd24c8de4a86326 | |
parent | a26c1c14599e0f67674c58b214ff9901fe7169ed (diff) | |
download | rockbox-a454b7f9efe1f935f37b1e91c0aba2fd9190aed5.tar.gz rockbox-a454b7f9efe1f935f37b1e91c0aba2fd9190aed5.zip |
jz4760: Lots of stability fixes to the USB driver.
It actually works for transferring data now!
Igor Poretsky gets full credit for this patch.
Change-Id: I247c70fdf45e590b4699b9b8668bbdab7bc3ef03
-rw-r--r-- | docs/CREDITS | 1 | ||||
-rw-r--r-- | firmware/target/mips/ingenic_jz47xx/usb-jz4760.c | 376 |
2 files changed, 293 insertions, 84 deletions
diff --git a/docs/CREDITS b/docs/CREDITS index 7743ba0af8..03ba132b39 100644 --- a/docs/CREDITS +++ b/docs/CREDITS | |||
@@ -666,6 +666,7 @@ Alessandro Stoppani | |||
666 | Alexander Yurenin | 666 | Alexander Yurenin |
667 | Roman Stolyarov | 667 | Roman Stolyarov |
668 | Solomon Peachy | 668 | Solomon Peachy |
669 | Igor Poretsky | ||
669 | 670 | ||
670 | The libmad team | 671 | The libmad team |
671 | The wavpack team | 672 | The wavpack team |
diff --git a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c index bc2158fb6f..3c7bb80f2c 100644 --- a/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c +++ b/firmware/target/mips/ingenic_jz47xx/usb-jz4760.c | |||
@@ -53,14 +53,14 @@ enum ep_type | |||
53 | 53 | ||
54 | struct usb_endpoint | 54 | struct usb_endpoint |
55 | { | 55 | { |
56 | void *buf; | 56 | volatile void *buf; |
57 | size_t length; | 57 | volatile size_t length; |
58 | union | 58 | union |
59 | { | 59 | { |
60 | size_t sent; | 60 | volatile size_t sent; |
61 | size_t received; | 61 | volatile size_t received; |
62 | }; | 62 | }; |
63 | bool busy; | 63 | volatile bool busy; |
64 | 64 | ||
65 | const enum ep_type type; | 65 | const enum ep_type type; |
66 | const bool use_dma; | 66 | const bool use_dma; |
@@ -68,23 +68,35 @@ struct usb_endpoint | |||
68 | const long fifo_addr; | 68 | const long fifo_addr; |
69 | unsigned short fifo_size; | 69 | unsigned short fifo_size; |
70 | 70 | ||
71 | bool wait; | 71 | volatile bool wait; |
72 | struct semaphore complete; | 72 | struct semaphore complete; |
73 | |||
74 | volatile int rc; | ||
75 | bool allocated; | ||
73 | }; | 76 | }; |
74 | 77 | ||
75 | #define EP_INIT(_type, _fifo_addr, _fifo_size, _buf, _use_dma) \ | 78 | #define EP_INIT(_type, _fifo_addr, _fifo_size, _buf, _use_dma) \ |
76 | { .type = (_type), .fifo_addr = (_fifo_addr), .fifo_size = (_fifo_size), \ | 79 | { .type = (_type), .fifo_addr = (_fifo_addr), .fifo_size = (_fifo_size), \ |
77 | .buf = (_buf), .use_dma = (_use_dma), .length = 0, .busy = false, .wait = false } | 80 | .buf = (_buf), .use_dma = (_use_dma), \ |
81 | .length = 0, .busy = false, .wait = false, .allocated = false } | ||
82 | |||
83 | static union | ||
84 | { | ||
85 | int buf[64 / sizeof(int)]; | ||
86 | struct usb_ctrlrequest request; | ||
87 | } ep0_rx; | ||
88 | |||
89 | static volatile bool ep0_data_supplied = false; | ||
90 | static volatile bool ep0_data_requested = false; | ||
78 | 91 | ||
79 | static unsigned char ep0_rx_buf[64]; | ||
80 | static struct usb_endpoint endpoints[] = | 92 | static struct usb_endpoint endpoints[] = |
81 | { | 93 | { |
82 | EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL, false), | 94 | EP_INIT(ep_control, USB_FIFO_EP(0), 64, NULL, false), |
83 | EP_INIT(ep_control, USB_FIFO_EP(0), 64, &ep0_rx_buf, false), | 95 | EP_INIT(ep_control, USB_FIFO_EP(0), 64, &ep0_rx.buf, false), |
84 | EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false), | 96 | EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false), |
85 | EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false), | 97 | EP_INIT(ep_bulk, USB_FIFO_EP(1), 512, NULL, false), |
86 | EP_INIT(ep_interrupt, USB_FIFO_EP(2), 64, NULL, false), | 98 | EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL, false), |
87 | EP_INIT(ep_interrupt, USB_FIFO_EP(2), 64, NULL, false), | 99 | EP_INIT(ep_interrupt, USB_FIFO_EP(2), 512, NULL, false), |
88 | }; | 100 | }; |
89 | 101 | ||
90 | static inline void select_endpoint(int ep) | 102 | static inline void select_endpoint(int ep) |
@@ -133,16 +145,32 @@ static void writeFIFO(struct usb_endpoint *ep, size_t size) | |||
133 | logf("%s(EP%d, %d)", __func__, EP_NUMBER2(ep), size); | 145 | logf("%s(EP%d, %d)", __func__, EP_NUMBER2(ep), size); |
134 | 146 | ||
135 | register unsigned int *d32 = (unsigned int *)EP_PTR(ep); | 147 | register unsigned int *d32 = (unsigned int *)EP_PTR(ep); |
148 | register unsigned char *d8 = (unsigned char *)d32; | ||
136 | register size_t s = size >> 2; | 149 | register size_t s = size >> 2; |
150 | register unsigned int x; | ||
137 | 151 | ||
138 | if(size > 0) | 152 | if(size > 0) |
139 | { | 153 | { |
140 | while (s--) | 154 | if( ((unsigned int)d8 & 3) == 0 ) |
141 | REG32(ep->fifo_addr) = *d32++; | 155 | { |
156 | while (s--) | ||
157 | REG32(ep->fifo_addr) = *d32++; | ||
158 | d8 = (unsigned char *)d32; | ||
159 | } | ||
160 | else | ||
161 | { | ||
162 | while (s--) | ||
163 | { | ||
164 | x = (unsigned int)(*d8++) & 0xff; | ||
165 | x |= ((unsigned int)(*d8++) & 0xff) << 8; | ||
166 | x |= ((unsigned int)(*d8++) & 0xff) << 16; | ||
167 | x |= ((unsigned int)(*d8++) & 0xff) << 24; | ||
168 | REG32(ep->fifo_addr) = x; | ||
169 | } | ||
170 | } | ||
142 | 171 | ||
143 | if( (s = size & 3) ) | 172 | if( (s = size & 3) ) |
144 | { | 173 | { |
145 | register unsigned char *d8 = (unsigned char *)d32; | ||
146 | while (s--) | 174 | while (s--) |
147 | REG8(ep->fifo_addr) = *d8++; | 175 | REG8(ep->fifo_addr) = *d8++; |
148 | } | 176 | } |
@@ -183,13 +211,16 @@ static void EP0_send(void) | |||
183 | { | 211 | { |
184 | struct usb_endpoint* ep = &endpoints[0]; | 212 | struct usb_endpoint* ep = &endpoints[0]; |
185 | unsigned int length; | 213 | unsigned int length; |
186 | unsigned char csr0; | 214 | unsigned short csr0; |
187 | 215 | ||
188 | select_endpoint(0); | 216 | select_endpoint(0); |
189 | csr0 = REG_USB_CSR0; | 217 | csr0 = REG_USB_CSR0; |
190 | 218 | ||
191 | if(ep->sent == 0) | 219 | if(ep->sent == 0) |
220 | { | ||
192 | length = MIN(ep->length, ep->fifo_size); | 221 | length = MIN(ep->length, ep->fifo_size); |
222 | REG_USB_CSR0 = (csr0 | USB_CSR0_FLUSHFIFO); | ||
223 | } | ||
193 | else | 224 | else |
194 | length = MIN(EP_BUF_LEFT(ep), ep->fifo_size); | 225 | length = MIN(EP_BUF_LEFT(ep), ep->fifo_size); |
195 | 226 | ||
@@ -199,7 +230,9 @@ static void EP0_send(void) | |||
199 | if(ep->sent >= ep->length) | 230 | if(ep->sent >= ep->length) |
200 | { | 231 | { |
201 | REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY | USB_CSR0_DATAEND); /* Set data end! */ | 232 | REG_USB_CSR0 = (csr0 | USB_CSR0_INPKTRDY | USB_CSR0_DATAEND); /* Set data end! */ |
202 | usb_core_transfer_complete(0, USB_DIR_IN, 0, ep->sent); | 233 | if (!ep->wait) |
234 | usb_core_transfer_complete(0, USB_DIR_IN, 0, ep->sent); | ||
235 | ep->rc = 0; | ||
203 | ep_transfer_completed(ep); | 236 | ep_transfer_completed(ep); |
204 | } | 237 | } |
205 | else | 238 | else |
@@ -208,9 +241,7 @@ static void EP0_send(void) | |||
208 | 241 | ||
209 | static void EP0_handler(void) | 242 | static void EP0_handler(void) |
210 | { | 243 | { |
211 | logf("%s()", __func__); | 244 | unsigned short csr0; |
212 | |||
213 | unsigned char csr0; | ||
214 | struct usb_endpoint *ep_send = &endpoints[0]; | 245 | struct usb_endpoint *ep_send = &endpoints[0]; |
215 | struct usb_endpoint *ep_recv = &endpoints[1]; | 246 | struct usb_endpoint *ep_recv = &endpoints[1]; |
216 | 247 | ||
@@ -218,6 +249,8 @@ static void EP0_handler(void) | |||
218 | select_endpoint(0); | 249 | select_endpoint(0); |
219 | csr0 = REG_USB_CSR0; | 250 | csr0 = REG_USB_CSR0; |
220 | 251 | ||
252 | logf("%s(): 0x%x", __func__, csr0); | ||
253 | |||
221 | /* Check for SentStall: | 254 | /* Check for SentStall: |
222 | This bit is set when a STALL handshake is transmitted. The CPU should clear this bit. | 255 | This bit is set when a STALL handshake is transmitted. The CPU should clear this bit. |
223 | */ | 256 | */ |
@@ -234,19 +267,66 @@ static void EP0_handler(void) | |||
234 | */ | 267 | */ |
235 | if(csr0 & USB_CSR0_SETUPEND) | 268 | if(csr0 & USB_CSR0_SETUPEND) |
236 | { | 269 | { |
237 | REG_USB_CSR0 = csr0 | USB_CSR0_SVDSETUPEND; | 270 | csr0 |= USB_CSR0_SVDSETUPEND; |
238 | return; | 271 | REG_USB_CSR0 = csr0; |
272 | ep0_data_supplied = false; | ||
273 | ep0_data_requested = false; | ||
274 | if (ep_send->busy) | ||
275 | { | ||
276 | if (!ep_send->wait) | ||
277 | usb_core_transfer_complete(0, USB_DIR_IN, -1, 0); | ||
278 | ep_transfer_completed(ep_send); | ||
279 | } | ||
280 | if (ep_recv->busy) | ||
281 | { | ||
282 | usb_core_transfer_complete(0, USB_DIR_OUT, -1, 0); | ||
283 | ep_transfer_completed(ep_recv); | ||
284 | } | ||
239 | } | 285 | } |
240 | 286 | ||
241 | /* Call relevant routines for endpoint 0 state */ | 287 | /* Call relevant routines for endpoint 0 state */ |
242 | if(ep_send->busy) | 288 | if(csr0 & USB_CSR0_OUTPKTRDY) /* There is a packet in the fifo */ |
243 | EP0_send(); | ||
244 | else if(csr0 & USB_CSR0_OUTPKTRDY) /* There is a packet in the fifo */ | ||
245 | { | 289 | { |
246 | readFIFO(ep_recv, REG_USB_COUNT0); | 290 | if (ep_send->busy) |
247 | REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */ | 291 | { |
248 | usb_core_control_request((struct usb_ctrlrequest*)ep_recv->buf); | 292 | if (!ep_send->wait) |
293 | usb_core_transfer_complete(0, USB_DIR_IN, -1, 0); | ||
294 | ep_transfer_completed(ep_send); | ||
295 | } | ||
296 | if (ep_recv->busy && ep_recv->buf && ep_recv->length) | ||
297 | { | ||
298 | unsigned int size = REG_USB_COUNT0; | ||
299 | readFIFO(ep_recv, size); | ||
300 | ep_recv->received += size; | ||
301 | if (size < ep_recv->fifo_size || ep_recv->received >= ep_recv->length) | ||
302 | { | ||
303 | REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY | USB_CSR0_DATAEND; /* Set data end! */ | ||
304 | usb_core_transfer_complete(0, USB_DIR_OUT, 0, ep_recv->received); | ||
305 | ep_transfer_completed(ep_recv); | ||
306 | } | ||
307 | else REG_USB_CSR0 = csr0 | USB_CSR0_SVDOUTPKTRDY; /* clear OUTPKTRDY bit */ | ||
308 | } | ||
309 | else if (!ep0_data_supplied) | ||
310 | { | ||
311 | ep_recv->buf = ep0_rx.buf; | ||
312 | readFIFO(ep_recv, REG_USB_COUNT0); | ||
313 | csr0 |= USB_CSR0_SVDOUTPKTRDY; | ||
314 | if (!ep0_rx.request.wLength) | ||
315 | { | ||
316 | csr0 |= USB_CSR0_DATAEND; /* Set data end! */ | ||
317 | ep0_data_requested = false; | ||
318 | ep0_data_supplied = false; | ||
319 | } | ||
320 | else if (ep0_rx.request.bRequestType & USB_DIR_IN) | ||
321 | ep0_data_requested = true; | ||
322 | else ep0_data_supplied = true; | ||
323 | REG_USB_CSR0 = csr0; | ||
324 | usb_core_control_request(&ep0_rx.request); | ||
325 | ep_transfer_completed(ep_recv); | ||
326 | } | ||
249 | } | 327 | } |
328 | else if (ep_send->busy) | ||
329 | EP0_send(); | ||
250 | } | 330 | } |
251 | 331 | ||
252 | static void EPIN_handler(unsigned int endpoint) | 332 | static void EPIN_handler(unsigned int endpoint) |
@@ -292,7 +372,9 @@ static void EPIN_handler(unsigned int endpoint) | |||
292 | 372 | ||
293 | if(ep->sent >= ep->length) | 373 | if(ep->sent >= ep->length) |
294 | { | 374 | { |
295 | usb_core_transfer_complete(endpoint, USB_DIR_IN, 0, ep->sent); | 375 | if (!ep->wait) |
376 | usb_core_transfer_complete(endpoint, USB_DIR_IN, 0, ep->sent); | ||
377 | ep->rc = 0; | ||
296 | ep_transfer_completed(ep); | 378 | ep_transfer_completed(ep); |
297 | logf("sent complete"); | 379 | logf("sent complete"); |
298 | } | 380 | } |
@@ -352,20 +434,23 @@ static void EPDMA_handler(int number) | |||
352 | { | 434 | { |
353 | int endpoint = -1; | 435 | int endpoint = -1; |
354 | unsigned int size = 0; | 436 | unsigned int size = 0; |
437 | struct usb_endpoint* ep = NULL; | ||
355 | 438 | ||
356 | if(number == USB_INTR_DMA_BULKIN) | 439 | if(number == USB_INTR_DMA_BULKIN) |
440 | { | ||
357 | endpoint = (REG_USB_CNTL(0) >> 4) & 0xF; | 441 | endpoint = (REG_USB_CNTL(0) >> 4) & 0xF; |
442 | ep = &endpoints[endpoint*2]; | ||
443 | size = (unsigned int)ep->buf - REG_USB_ADDR(0); | ||
444 | } | ||
358 | else if(number == USB_INTR_DMA_BULKOUT) | 445 | else if(number == USB_INTR_DMA_BULKOUT) |
446 | { | ||
359 | endpoint = (REG_USB_CNTL(1) >> 4) & 0xF; | 447 | endpoint = (REG_USB_CNTL(1) >> 4) & 0xF; |
448 | ep = &endpoints[endpoint*2+1]; | ||
449 | size = (unsigned int)ep->buf - REG_USB_ADDR(1); | ||
450 | } | ||
360 | 451 | ||
361 | struct usb_endpoint* ep = &endpoints[endpoint]; | ||
362 | logf("DMA_BULK%d %d", number, endpoint); | 452 | logf("DMA_BULK%d %d", number, endpoint); |
363 | 453 | ||
364 | if(number == USB_INTR_DMA_BULKIN) | ||
365 | size = (unsigned int)ep->buf - REG_USB_ADDR(0); | ||
366 | else if(number == USB_INTR_DMA_BULKOUT) | ||
367 | size = (unsigned int)ep->buf - REG_USB_ADDR(1); | ||
368 | |||
369 | if(number == USB_INTR_DMA_BULKOUT) | 454 | if(number == USB_INTR_DMA_BULKOUT) |
370 | { | 455 | { |
371 | /* Disable DMA */ | 456 | /* Disable DMA */ |
@@ -389,29 +474,41 @@ static void EPDMA_handler(int number) | |||
389 | REG_USB_INCSR |= USB_INCSR_INPKTRDY; | 474 | REG_USB_INCSR |= USB_INCSR_INPKTRDY; |
390 | } | 475 | } |
391 | 476 | ||
392 | usb_core_transfer_complete(endpoint, EP_IS_IN(ep) ? USB_DIR_IN : USB_DIR_OUT, | 477 | if (ep) |
393 | 0, ep->length); | 478 | { |
394 | ep_transfer_completed(ep); | 479 | int dir = EP_IS_IN(ep) ? USB_DIR_IN : USB_DIR_OUT; |
480 | if ((dir == USB_DIR_OUT) || !ep->wait) | ||
481 | usb_core_transfer_complete(endpoint, dir, 0, ep->length); | ||
482 | ep->rc = 0; | ||
483 | ep_transfer_completed(ep); | ||
484 | } | ||
395 | } | 485 | } |
396 | 486 | ||
397 | static void setup_endpoint(struct usb_endpoint *ep) | 487 | static void setup_endpoint(struct usb_endpoint *ep) |
398 | { | 488 | { |
399 | int csr, csrh; | 489 | int endpoint = EP_NUMBER2(ep); |
490 | unsigned char csr, csrh; | ||
491 | |||
492 | select_endpoint(endpoint); | ||
400 | 493 | ||
401 | select_endpoint(EP_NUMBER2(ep)); | 494 | if (ep->busy) |
495 | { | ||
496 | if(EP_IS_IN(ep)) | ||
497 | { | ||
498 | if (ep->wait) | ||
499 | semaphore_release(&ep->complete); | ||
500 | else usb_core_transfer_complete(endpoint, USB_DIR_IN, -1, 0); | ||
501 | } | ||
502 | else usb_core_transfer_complete(endpoint, USB_DIR_OUT, -1, 0); | ||
503 | } | ||
402 | 504 | ||
403 | ep->busy = false; | 505 | ep->busy = false; |
404 | ep->wait = false; | 506 | ep->wait = false; |
405 | ep->sent = 0; | 507 | ep->sent = 0; |
406 | ep->length = 0; | 508 | ep->length = 0; |
407 | 509 | ||
408 | if(ep->type == ep_bulk) | 510 | if(ep->type != ep_control) |
409 | { | 511 | ep->fifo_size = usb_drv_port_speed() ? 512 : 64; |
410 | if(REG_USB_POWER & USB_POWER_HSMODE) | ||
411 | ep->fifo_size = 512; | ||
412 | else | ||
413 | ep->fifo_size = 64; | ||
414 | } | ||
415 | 512 | ||
416 | if(EP_IS_IN(ep)) | 513 | if(EP_IS_IN(ep)) |
417 | { | 514 | { |
@@ -427,7 +524,9 @@ static void setup_endpoint(struct usb_endpoint *ep) | |||
427 | REG_USB_INMAXP = ep->fifo_size; | 524 | REG_USB_INMAXP = ep->fifo_size; |
428 | REG_USB_INCSR = csr; | 525 | REG_USB_INCSR = csr; |
429 | REG_USB_INCSRH = csrh; | 526 | REG_USB_INCSRH = csrh; |
430 | REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep)); | 527 | |
528 | if (ep->allocated) | ||
529 | REG_USB_INTRINE |= USB_INTR_EP(EP_NUMBER2(ep)); | ||
431 | } | 530 | } |
432 | else | 531 | else |
433 | { | 532 | { |
@@ -443,7 +542,9 @@ static void setup_endpoint(struct usb_endpoint *ep) | |||
443 | REG_USB_OUTMAXP = ep->fifo_size; | 542 | REG_USB_OUTMAXP = ep->fifo_size; |
444 | REG_USB_OUTCSR = csr; | 543 | REG_USB_OUTCSR = csr; |
445 | REG_USB_OUTCSRH = csrh; | 544 | REG_USB_OUTCSRH = csrh; |
446 | REG_USB_INTROUTE |= USB_INTR_EP(EP_NUMBER2(ep)); | 545 | |
546 | if (ep->allocated) | ||
547 | REG_USB_INTROUTE |= USB_INTR_EP(EP_NUMBER2(ep)); | ||
447 | } | 548 | } |
448 | } | 549 | } |
449 | 550 | ||
@@ -483,10 +584,35 @@ static void udc_reset(void) | |||
483 | select_endpoint(0); | 584 | select_endpoint(0); |
484 | REG_USB_CSR0 = (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_SVDSETUPEND | USB_CSR0_FLUSHFIFO); | 585 | REG_USB_CSR0 = (USB_CSR0_SVDOUTPKTRDY | USB_CSR0_SVDSETUPEND | USB_CSR0_FLUSHFIFO); |
485 | 586 | ||
587 | if (endpoints[0].busy) | ||
588 | { | ||
589 | if (endpoints[0].wait) | ||
590 | semaphore_release(&endpoints[0].complete); | ||
591 | else usb_core_transfer_complete(0, USB_DIR_IN, -1, 0); | ||
592 | } | ||
593 | |||
594 | endpoints[0].busy = false; | ||
595 | endpoints[0].wait = false; | ||
596 | endpoints[0].sent = 0; | ||
597 | endpoints[0].length = 0; | ||
598 | endpoints[0].allocated = true; | ||
599 | |||
600 | if (endpoints[1].busy) | ||
601 | usb_core_transfer_complete(0, USB_DIR_OUT, -1, 0); | ||
602 | |||
603 | endpoints[1].busy = false; | ||
604 | endpoints[1].wait = false; | ||
605 | endpoints[1].received = 0; | ||
606 | endpoints[1].length = 0; | ||
607 | endpoints[1].allocated = true; | ||
608 | |||
486 | /* Reset other endpoints */ | 609 | /* Reset other endpoints */ |
487 | for(i=2; i<TOTAL_EP(); i++) | 610 | for(i=2; i<TOTAL_EP(); i++) |
488 | setup_endpoint(&endpoints[i]); | 611 | setup_endpoint(&endpoints[i]); |
489 | 612 | ||
613 | ep0_data_supplied = false; | ||
614 | ep0_data_requested = false; | ||
615 | |||
490 | /* Enable interrupts */ | 616 | /* Enable interrupts */ |
491 | REG_USB_INTRINE |= USB_INTR_EP(0); | 617 | REG_USB_INTRINE |= USB_INTR_EP(0); |
492 | REG_USB_INTRUSBE |= USB_INTR_RESET; | 618 | REG_USB_INTRUSBE |= USB_INTR_RESET; |
@@ -498,7 +624,7 @@ static void udc_reset(void) | |||
498 | void OTG(void) | 624 | void OTG(void) |
499 | { | 625 | { |
500 | /* Read interrupt registers */ | 626 | /* Read interrupt registers */ |
501 | unsigned char intrUSB = REG_USB_INTRUSB & 0x07; /* Mask SOF */ | 627 | unsigned char intrUSB = REG_USB_INTRUSB; |
502 | unsigned short intrIn = REG_USB_INTRIN; | 628 | unsigned short intrIn = REG_USB_INTRIN; |
503 | unsigned short intrOut = REG_USB_INTROUT; | 629 | unsigned short intrOut = REG_USB_INTROUT; |
504 | unsigned char intrDMA = REG_USB_INTR; | 630 | unsigned char intrDMA = REG_USB_INTR; |
@@ -689,17 +815,28 @@ void usb_drv_set_address(int address) | |||
689 | 815 | ||
690 | static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length, bool blocking) | 816 | static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length, bool blocking) |
691 | { | 817 | { |
692 | if(ep->type == ep_control && ptr == NULL && length == 0) | ||
693 | return; /* ACK request, handled in the ISR */ | ||
694 | |||
695 | int flags = disable_irq_save(); | 818 | int flags = disable_irq_save(); |
696 | 819 | ||
820 | if(ep->type == ep_control) | ||
821 | { | ||
822 | if ((ptr == NULL && length == 0) || !ep0_data_requested) | ||
823 | { | ||
824 | restore_irq(flags); | ||
825 | return; | ||
826 | } | ||
827 | ep0_data_requested = false; | ||
828 | } | ||
829 | |||
697 | ep->buf = ptr; | 830 | ep->buf = ptr; |
698 | ep->sent = 0; | 831 | ep->sent = 0; |
699 | ep->length = length; | 832 | ep->length = length; |
700 | ep->busy = true; | 833 | ep->busy = true; |
701 | if(blocking) | 834 | if(blocking) |
835 | { | ||
836 | ep->rc = -1; | ||
702 | ep->wait = true; | 837 | ep->wait = true; |
838 | } | ||
839 | else ep->rc = 0; | ||
703 | 840 | ||
704 | if(ep->type == ep_control) | 841 | if(ep->type == ep_control) |
705 | { | 842 | { |
@@ -725,27 +862,39 @@ static void usb_drv_send_internal(struct usb_endpoint* ep, void* ptr, int length | |||
725 | 862 | ||
726 | if(blocking) | 863 | if(blocking) |
727 | { | 864 | { |
728 | semaphore_wait(&ep->complete, TIMEOUT_BLOCK); | 865 | semaphore_wait(&ep->complete, HZ); |
729 | ep->wait = false; | 866 | ep->wait = false; |
730 | } | 867 | } |
731 | } | 868 | } |
732 | 869 | ||
733 | int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) | 870 | int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) |
734 | { | 871 | { |
872 | struct usb_endpoint *ep = &endpoints[(endpoint & 0x7F)*2]; | ||
873 | |||
735 | logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); | 874 | logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); |
736 | 875 | ||
737 | usb_drv_send_internal(&endpoints[(endpoint & 0x7F)*2], ptr, length, false); | 876 | if (ep->allocated) |
877 | { | ||
878 | usb_drv_send_internal(ep, ptr, length, false); | ||
879 | return 0; | ||
880 | } | ||
738 | 881 | ||
739 | return 0; | 882 | return -1; |
740 | } | 883 | } |
741 | 884 | ||
742 | int usb_drv_send(int endpoint, void* ptr, int length) | 885 | int usb_drv_send(int endpoint, void* ptr, int length) |
743 | { | 886 | { |
887 | struct usb_endpoint *ep = &endpoints[(endpoint & 0x7F)*2]; | ||
888 | |||
744 | logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); | 889 | logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); |
745 | 890 | ||
746 | usb_drv_send_internal(&endpoints[(endpoint & 0x7F)*2], ptr, length, true); | 891 | if (ep->allocated) |
892 | { | ||
893 | usb_drv_send_internal(ep, ptr, length, true); | ||
894 | return ep->rc; | ||
895 | } | ||
747 | 896 | ||
748 | return 0; | 897 | return -1; |
749 | } | 898 | } |
750 | 899 | ||
751 | int usb_drv_recv(int endpoint, void* ptr, int length) | 900 | int usb_drv_recv(int endpoint, void* ptr, int length) |
@@ -756,33 +905,42 @@ int usb_drv_recv(int endpoint, void* ptr, int length) | |||
756 | 905 | ||
757 | logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); | 906 | logf("%s(%d, 0x%x, %d)", __func__, endpoint, (int)ptr, length); |
758 | 907 | ||
759 | if(endpoint == EP_CONTROL) | 908 | if (ptr == NULL || length == 0) |
760 | return 0; /* all EP0 OUT transactions are handled within the ISR */ | 909 | return 0; |
910 | |||
911 | ep = &endpoints[endpoint*2+1]; | ||
912 | |||
913 | if (!ep->allocated) | ||
914 | return -1; | ||
915 | |||
916 | flags = disable_irq_save(); | ||
917 | |||
918 | ep->buf = ptr; | ||
919 | ep->received = 0; | ||
920 | ep->length = length; | ||
921 | ep->busy = true; | ||
922 | if(ep->use_dma) | ||
923 | { | ||
924 | //dma_cache_wback_inv((unsigned long)ptr, length); | ||
925 | __dcache_writeback_all(); | ||
926 | REG_USB_ADDR(1) = PHYSADDR((unsigned long)ptr); | ||
927 | REG_USB_COUNT(1) = length; | ||
928 | REG_USB_CNTL(1) = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | | ||
929 | USB_CNTL_ENA | USB_CNTL_EP(endpoint) | | ||
930 | USB_CNTL_BURST_16); | ||
931 | } | ||
761 | else | 932 | else |
762 | { | 933 | { |
763 | flags = disable_irq_save(); | 934 | if (endpoint == EP_CONTROL) |
764 | ep = &endpoints[endpoint*2+1]; | ||
765 | |||
766 | ep->buf = ptr; | ||
767 | ep->received = 0; | ||
768 | ep->length = length; | ||
769 | ep->busy = true; | ||
770 | if(ep->use_dma) | ||
771 | { | 935 | { |
772 | //dma_cache_wback_inv((unsigned long)ptr, length); | 936 | ep0_data_supplied = false; |
773 | __dcache_writeback_all(); | 937 | EP0_handler(); |
774 | REG_USB_ADDR(1) = PHYSADDR((unsigned long)ptr); | ||
775 | REG_USB_COUNT(1) = length; | ||
776 | REG_USB_CNTL(1) = (USB_CNTL_INTR_EN | USB_CNTL_MODE_1 | | ||
777 | USB_CNTL_ENA | USB_CNTL_EP(endpoint) | | ||
778 | USB_CNTL_BURST_16); | ||
779 | } | 938 | } |
780 | else | 939 | else EPOUT_handler(endpoint); |
781 | EPOUT_handler(endpoint); | ||
782 | |||
783 | restore_irq(flags); | ||
784 | return 0; | ||
785 | } | 940 | } |
941 | |||
942 | restore_irq(flags); | ||
943 | return 0; | ||
786 | } | 944 | } |
787 | 945 | ||
788 | void usb_drv_set_test_mode(int mode) | 946 | void usb_drv_set_test_mode(int mode) |
@@ -818,11 +976,19 @@ void usb_drv_cancel_all_transfers(void) | |||
818 | { | 976 | { |
819 | logf("%s()", __func__); | 977 | logf("%s()", __func__); |
820 | 978 | ||
821 | unsigned int i, flags; | 979 | unsigned int i, flags = disable_irq_save(); |
822 | flags = disable_irq_save(); | ||
823 | 980 | ||
824 | for(i=0; i<TOTAL_EP(); i++) | 981 | for(i=0; i<TOTAL_EP(); i++) |
825 | { | 982 | { |
983 | if (endpoints[i].busy) | ||
984 | { | ||
985 | if (i & 1) | ||
986 | usb_core_transfer_complete(i >> 1, USB_DIR_OUT, -1, 0); | ||
987 | else if (endpoints[i].wait) | ||
988 | semaphore_release(&endpoints[i].complete); | ||
989 | else usb_core_transfer_complete(i >> 1, USB_DIR_IN, -1, 0); | ||
990 | } | ||
991 | |||
826 | if(i != 1) /* ep0 out needs special handling */ | 992 | if(i != 1) /* ep0 out needs special handling */ |
827 | endpoints[i].buf = NULL; | 993 | endpoints[i].buf = NULL; |
828 | 994 | ||
@@ -835,11 +1001,27 @@ void usb_drv_cancel_all_transfers(void) | |||
835 | restore_irq(flags); | 1001 | restore_irq(flags); |
836 | } | 1002 | } |
837 | 1003 | ||
838 | |||
839 | void usb_drv_release_endpoint(int ep) | 1004 | void usb_drv_release_endpoint(int ep) |
840 | { | 1005 | { |
841 | (void)ep; | 1006 | int n = ep & 0x7f; |
1007 | |||
842 | logf("%s(%d, %s)", __func__, (ep & 0x7F), (ep >> 7) ? "IN" : "OUT"); | 1008 | logf("%s(%d, %s)", __func__, (ep & 0x7F), (ep >> 7) ? "IN" : "OUT"); |
1009 | |||
1010 | if (n) | ||
1011 | { | ||
1012 | int dir = ep & USB_ENDPOINT_DIR_MASK; | ||
1013 | |||
1014 | if(dir == USB_DIR_IN) | ||
1015 | { | ||
1016 | REG_USB_INTRINE &= ~USB_INTR_EP(n); | ||
1017 | endpoints[n << 1].allocated = false; | ||
1018 | } | ||
1019 | else | ||
1020 | { | ||
1021 | REG_USB_INTROUTE &= ~USB_INTR_EP(n); | ||
1022 | endpoints[(n << 1) + 1].allocated = false; | ||
1023 | } | ||
1024 | } | ||
843 | } | 1025 | } |
844 | 1026 | ||
845 | int usb_drv_request_endpoint(int type, int dir) | 1027 | int usb_drv_request_endpoint(int type, int dir) |
@@ -854,17 +1036,43 @@ int usb_drv_request_endpoint(int type, int dir) | |||
854 | { | 1036 | { |
855 | case USB_ENDPOINT_XFER_BULK: | 1037 | case USB_ENDPOINT_XFER_BULK: |
856 | if(dir == USB_DIR_IN) | 1038 | if(dir == USB_DIR_IN) |
1039 | { | ||
1040 | if (endpoints[2].allocated) | ||
1041 | break; | ||
1042 | endpoints[2].allocated = true; | ||
1043 | REG_USB_INTRINE |= USB_INTR_EP(1); | ||
857 | return (1 | USB_DIR_IN); | 1044 | return (1 | USB_DIR_IN); |
1045 | } | ||
858 | else | 1046 | else |
1047 | { | ||
1048 | if (endpoints[3].allocated) | ||
1049 | break; | ||
1050 | endpoints[3].allocated = true; | ||
1051 | REG_USB_INTROUTE |= USB_INTR_EP(1); | ||
859 | return (1 | USB_DIR_OUT); | 1052 | return (1 | USB_DIR_OUT); |
1053 | } | ||
860 | 1054 | ||
861 | case USB_ENDPOINT_XFER_INT: | 1055 | case USB_ENDPOINT_XFER_INT: |
862 | if(dir == USB_DIR_IN) | 1056 | if(dir == USB_DIR_IN) |
1057 | { | ||
1058 | if (endpoints[4].allocated) | ||
1059 | break; | ||
1060 | endpoints[4].allocated = true; | ||
1061 | REG_USB_INTRINE |= USB_INTR_EP(2); | ||
863 | return (2 | USB_DIR_IN); | 1062 | return (2 | USB_DIR_IN); |
1063 | } | ||
864 | else | 1064 | else |
1065 | { | ||
1066 | if (endpoints[5].allocated) | ||
1067 | break; | ||
1068 | endpoints[5].allocated = true; | ||
1069 | REG_USB_INTROUTE |= USB_INTR_EP(2); | ||
865 | return (2 | USB_DIR_OUT); | 1070 | return (2 | USB_DIR_OUT); |
1071 | } | ||
866 | 1072 | ||
867 | default: | 1073 | default: |
868 | return -1; | 1074 | break; |
869 | } | 1075 | } |
1076 | |||
1077 | return -1; | ||
870 | } | 1078 | } |