diff options
Diffstat (limited to 'firmware/target/arm/as3525')
-rw-r--r-- | firmware/target/arm/as3525/usb-drv-as3525v2.c | 119 |
1 files changed, 74 insertions, 45 deletions
diff --git a/firmware/target/arm/as3525/usb-drv-as3525v2.c b/firmware/target/arm/as3525/usb-drv-as3525v2.c index 36791e8dc9..24487c0981 100644 --- a/firmware/target/arm/as3525/usb-drv-as3525v2.c +++ b/firmware/target/arm/as3525/usb-drv-as3525v2.c | |||
@@ -43,17 +43,30 @@ static int __out_ep_list_ep0[NUM_OUT_EP + 1] = {0, OUT_EP_LIST}; | |||
43 | 43 | ||
44 | /* iterate through each in/out ep except EP0 | 44 | /* iterate through each in/out ep except EP0 |
45 | * 'counter' is the counter, 'ep' is the actual value */ | 45 | * 'counter' is the counter, 'ep' is the actual value */ |
46 | #define FOR_EACH_EP(list, size, counter, ep) \ | ||
47 | for(counter = 0, ep = (list)[0]; \ | ||
48 | counter < (size); \ | ||
49 | counter++, ep = (list)[counter]) | ||
50 | |||
51 | #define FOR_EACH_IN_EP_EX(include_ep0, counter, ep) \ | ||
52 | FOR_EACH_EP(include_ep0 ? __in_ep_list_ep0 : __in_ep_list, \ | ||
53 | include_ep0 ? NUM_IN_EP : NUM_IN_EP + 1, counter, ep) | ||
54 | |||
55 | #define FOR_EACH_OUT_EP_EX(include_ep0, counter, ep) \ | ||
56 | FOR_EACH_EP(include_ep0 ? __out_ep_list_ep0 : __out_ep_list, \ | ||
57 | include_ep0 ? NUM_OUT_EP : NUM_OUT_EP + 1, counter, ep) | ||
58 | |||
46 | #define FOR_EACH_IN_EP(counter, ep) \ | 59 | #define FOR_EACH_IN_EP(counter, ep) \ |
47 | for(counter = 0, ep = __in_ep_list[0]; counter < NUM_IN_EP; counter++, ep = __in_ep_list[counter]) | 60 | FOR_EACH_IN_EP_EX(false, counter, ep) |
48 | 61 | ||
49 | #define FOR_EACH_IN_EP_AND_EP0(counter, ep) \ | 62 | #define FOR_EACH_IN_EP_AND_EP0(counter, ep) \ |
50 | for(counter = 0, ep = __in_ep_list_ep0[0]; counter <= NUM_IN_EP; counter++, ep = __in_ep_list_ep0[counter]) | 63 | FOR_EACH_IN_EP_EX(true, counter, ep) |
51 | 64 | ||
52 | #define FOR_EACH_OUT_EP(counter, ep) \ | 65 | #define FOR_EACH_OUT_EP(counter, ep) \ |
53 | for(counter = 0, ep = __out_ep_list[0]; counter < NUM_OUT_EP; counter++, ep = __out_ep_list[counter]) | 66 | FOR_EACH_OUT_EP_EX(false, counter, ep) |
54 | 67 | ||
55 | #define FOR_EACH_OUT_EP_AND_EP0(counter, ep) \ | 68 | #define FOR_EACH_OUT_EP_AND_EP0(counter, ep) \ |
56 | for(counter = 0, ep = __out_ep_list_ep0[0]; counter <= NUM_OUT_EP; counter++, ep = __out_ep_list_ep0[counter]) | 69 | FOR_EACH_OUT_EP_EX(true, counter, ep) |
57 | 70 | ||
58 | struct usb_endpoint | 71 | struct usb_endpoint |
59 | { | 72 | { |
@@ -222,6 +235,31 @@ static void reset_endpoints(void) | |||
222 | prepare_setup_ep0(); | 235 | prepare_setup_ep0(); |
223 | } | 236 | } |
224 | 237 | ||
238 | static void cancel_all_transfers(bool cancel_ep0) | ||
239 | { | ||
240 | logf("usb-drv: cancel all transfers"); | ||
241 | int flags = disable_irq_save(); | ||
242 | unsigned i, ep; | ||
243 | FOR_EACH_IN_EP_EX(cancel_ep0, i, ep) | ||
244 | { | ||
245 | endpoints[ep][DIR_IN].status = 1; | ||
246 | endpoints[ep][DIR_IN].wait = false; | ||
247 | endpoints[ep][DIR_IN].busy = false; | ||
248 | wakeup_signal(&endpoints[ep][DIR_IN].complete); | ||
249 | DIEPCTL(ep) = (DIEPCTL(ep) & ~DEPCTL_usbactep) | DEPCTL_epdis; | ||
250 | } | ||
251 | FOR_EACH_OUT_EP_EX(cancel_ep0, i, ep) | ||
252 | { | ||
253 | endpoints[ep][DIR_OUT].status = 1; | ||
254 | endpoints[ep][DIR_OUT].wait = false; | ||
255 | endpoints[ep][DIR_OUT].busy = false; | ||
256 | wakeup_signal(&endpoints[ep][DIR_OUT].complete); | ||
257 | DOEPCTL(ep) = (DOEPCTL(ep) & ~DEPCTL_usbactep) | DEPCTL_epdis; | ||
258 | } | ||
259 | |||
260 | restore_irq(flags); | ||
261 | } | ||
262 | |||
225 | static void core_dev_init(void) | 263 | static void core_dev_init(void) |
226 | { | 264 | { |
227 | unsigned int i, ep; | 265 | unsigned int i, ep; |
@@ -383,7 +421,6 @@ static void handle_ep_int(int ep, bool dir_in) | |||
383 | * so we setup EP0 to receive next setup */ | 421 | * so we setup EP0 to receive next setup */ |
384 | if(ep == 0 && endpoint->len == 0) | 422 | if(ep == 0 && endpoint->len == 0) |
385 | prepare_setup_ep0(); | 423 | prepare_setup_ep0(); |
386 | DIEPCTL(ep) |= DEPCTL_snak; | ||
387 | usb_core_transfer_complete(ep, USB_DIR_IN, 0, transfered); | 424 | usb_core_transfer_complete(ep, USB_DIR_IN, 0, transfered); |
388 | wakeup_signal(&endpoint->complete); | 425 | wakeup_signal(&endpoint->complete); |
389 | } | 426 | } |
@@ -435,12 +472,12 @@ static void handle_ep_int(int ep, bool dir_in) | |||
435 | if(DOEPINT(ep) & DOEPINT_setup) | 472 | if(DOEPINT(ep) & DOEPINT_setup) |
436 | { | 473 | { |
437 | logf("usb-drv: setup on EP%d OUT", ep); | 474 | logf("usb-drv: setup on EP%d OUT", ep); |
438 | logf("rt=%x r=%x", ep0_setup_pkt.bRequestType, ep0_setup_pkt.bRequest); | ||
439 | if(ep != 0) | 475 | if(ep != 0) |
440 | panicf("usb-drv: setup not on EP0, this is impossible"); | 476 | panicf("usb-drv: setup not on EP0, this is impossible"); |
441 | DOEPCTL(ep) |= DEPCTL_snak; | 477 | DOEPCTL(ep) |= DEPCTL_snak; |
442 | /* handle the set address here because of a bug in the usb core */ | 478 | /* handle the set address here because of a bug in the usb core */ |
443 | invalidate_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */ | 479 | invalidate_dcache_range((void*)&ep0_setup_pkt, sizeof ep0_setup_pkt); /* force write back */ |
480 | logf(" rt=%x r=%x", ep0_setup_pkt.bRequestType, ep0_setup_pkt.bRequest); | ||
444 | if(ep0_setup_pkt.bRequestType == USB_TYPE_STANDARD && | 481 | if(ep0_setup_pkt.bRequestType == USB_TYPE_STANDARD && |
445 | ep0_setup_pkt.bRequest == USB_REQ_SET_ADDRESS) | 482 | ep0_setup_pkt.bRequest == USB_REQ_SET_ADDRESS) |
446 | usb_drv_set_address(ep0_setup_pkt.wValue); | 483 | usb_drv_set_address(ep0_setup_pkt.wValue); |
@@ -484,6 +521,7 @@ void INT_USB(void) | |||
484 | /* Clear the Remote Wakeup Signalling */ | 521 | /* Clear the Remote Wakeup Signalling */ |
485 | //DCTL &= ~DCTL_rmtwkupsig; | 522 | //DCTL &= ~DCTL_rmtwkupsig; |
486 | 523 | ||
524 | cancel_all_transfers(true); | ||
487 | /* Flush FIFOs */ | 525 | /* Flush FIFOs */ |
488 | flush_tx_fifos(0x10); | 526 | flush_tx_fifos(0x10); |
489 | flush_rx_fifos(); | 527 | flush_rx_fifos(); |
@@ -501,18 +539,10 @@ void INT_USB(void) | |||
501 | logf("usb-drv: enum done"); | 539 | logf("usb-drv: enum done"); |
502 | 540 | ||
503 | /* read speed */ | 541 | /* read speed */ |
504 | switch(extract(DSTS, enumspd)) | 542 | if(usb_drv_port_speed()) |
505 | { | 543 | logf("usb-drv: HS"); |
506 | case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: | 544 | else |
507 | logf("usb-drv: HS"); | 545 | logf("usb-drv: FS"); |
508 | break; | ||
509 | case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: | ||
510 | case DSTS_ENUMSPD_FS_PHY_48MHZ: | ||
511 | logf("usb-drv: FS"); | ||
512 | break; | ||
513 | case DSTS_ENUMSPD_LS_PHY_6MHZ: | ||
514 | panicf("usb-drv: LS is not supported"); | ||
515 | } | ||
516 | 546 | ||
517 | /* fixme: change EP0 mps here */ | 547 | /* fixme: change EP0 mps here */ |
518 | } | 548 | } |
@@ -523,14 +553,32 @@ void INT_USB(void) | |||
523 | } | 553 | } |
524 | 554 | ||
525 | if(sts & GINTMSK_disconnect) | 555 | if(sts & GINTMSK_disconnect) |
556 | { | ||
526 | panicf("usb-drv: disconnect"); | 557 | panicf("usb-drv: disconnect"); |
558 | cancel_all_transfers(true); | ||
559 | usb_enable(false); | ||
560 | } | ||
527 | 561 | ||
528 | GINTSTS = GINTSTS; | 562 | GINTSTS = GINTSTS; |
529 | } | 563 | } |
530 | 564 | ||
531 | int usb_drv_port_speed(void) | 565 | int usb_drv_port_speed(void) |
532 | { | 566 | { |
533 | return 0; | 567 | switch(extract(DSTS, enumspd)) |
568 | { | ||
569 | case DSTS_ENUMSPD_HS_PHY_30MHZ_OR_60MHZ: | ||
570 | return 1; | ||
571 | case DSTS_ENUMSPD_FS_PHY_30MHZ_OR_60MHZ: | ||
572 | case DSTS_ENUMSPD_FS_PHY_48MHZ: | ||
573 | return 0; | ||
574 | break; | ||
575 | case DSTS_ENUMSPD_LS_PHY_6MHZ: | ||
576 | panicf("usb-drv: LS is not supported"); | ||
577 | return 0; | ||
578 | default: | ||
579 | panicf("usb-drv: wtf is this speed ?"); | ||
580 | return 0; | ||
581 | } | ||
534 | } | 582 | } |
535 | 583 | ||
536 | int usb_drv_request_endpoint(int type, int dir) | 584 | int usb_drv_request_endpoint(int type, int dir) |
@@ -547,29 +595,9 @@ void usb_drv_release_endpoint(int ep) | |||
547 | endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; | 595 | endpoints[EP_NUM(ep)][EP_DIR(ep)].active = false; |
548 | } | 596 | } |
549 | 597 | ||
550 | void usb_drv_cancel_all_transfers(void) | 598 | void usb_drv_cancel_all_transfers() |
551 | { | 599 | { |
552 | logf("usb-drv: cancel all transfers"); | 600 | cancel_all_transfers(false); |
553 | int flags = disable_irq_save(); | ||
554 | unsigned i, ep; | ||
555 | FOR_EACH_IN_EP(i, ep) | ||
556 | { | ||
557 | endpoints[ep][DIR_IN].status = 1; | ||
558 | endpoints[ep][DIR_IN].wait = false; | ||
559 | endpoints[ep][DIR_IN].busy = false; | ||
560 | wakeup_signal(&endpoints[ep][DIR_IN].complete); | ||
561 | DIEPCTL(ep) = (DIEPCTL(ep) & ~DEPCTL_usbactep) | DEPCTL_epdis; | ||
562 | } | ||
563 | FOR_EACH_OUT_EP(i, ep) | ||
564 | { | ||
565 | endpoints[ep][DIR_OUT].status = 1; | ||
566 | endpoints[ep][DIR_OUT].wait = false; | ||
567 | endpoints[ep][DIR_OUT].busy = false; | ||
568 | wakeup_signal(&endpoints[ep][DIR_OUT].complete); | ||
569 | DOEPCTL(ep) = (DOEPCTL(ep) & ~DEPCTL_usbactep) | DEPCTL_epdis; | ||
570 | } | ||
571 | |||
572 | restore_irq(flags); | ||
573 | } | 601 | } |
574 | 602 | ||
575 | static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocking) | 603 | static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocking) |
@@ -586,14 +614,15 @@ static int usb_drv_transfer(int ep, void *ptr, int len, bool dir_in, bool blocki | |||
586 | #define DEPTSIZ *eptsiz | 614 | #define DEPTSIZ *eptsiz |
587 | #define DEPDMA *epdma | 615 | #define DEPDMA *epdma |
588 | 616 | ||
589 | if(endpoint->busy) | ||
590 | panicf("usb-drv: EP%d %s is already busy", ep, dir_in ? "IN" : "OUT"); | ||
591 | |||
592 | if(DEPCTL & DEPCTL_stall) | 617 | if(DEPCTL & DEPCTL_stall) |
593 | { | 618 | { |
594 | logf("usb-drv: cannot receive on a stalled endpoint"); | 619 | logf("usb-drv: cannot receive/send on a stalled endpoint"); |
595 | return -1; | 620 | return -1; |
596 | } | 621 | } |
622 | |||
623 | if(endpoint->busy) | ||
624 | logf("usb-drv: EP%d %s is already busy", ep, dir_in ? "IN" : "OUT"); | ||
625 | |||
597 | endpoint->busy = true; | 626 | endpoint->busy = true; |
598 | endpoint->len = len; | 627 | endpoint->len = len; |
599 | endpoint->wait = blocking; | 628 | endpoint->wait = blocking; |