summaryrefslogtreecommitdiff
path: root/firmware/target/arm
diff options
context:
space:
mode:
authorFrank Gevaerts <frank@gevaerts.be>2009-05-16 15:30:09 +0000
committerFrank Gevaerts <frank@gevaerts.be>2009-05-16 15:30:09 +0000
commit69a4117c1d15d91836de91abe5f8f93b868ec808 (patch)
treea3d47f51a0998506ef7b0f5332ddecae3e2106d2 /firmware/target/arm
parente435e4d976757f8436484a5b4d158ab7545fcdb6 (diff)
downloadrockbox-69a4117c1d15d91836de91abe5f8f93b868ec808.tar.gz
rockbox-69a4117c1d15d91836de91abe5f8f93b868ec808.zip
Add working USB HID driver, by Tomer Shalev (part of his GSoC work).
This needs support for usb interrupt transfers, so there are some changes in various USB drivers as well (only usb-drv-arc supports it at this point, others won't have working HID yet). HID is disabled for now, as the apps/ part is not included yet. git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20962 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'firmware/target/arm')
-rw-r--r--firmware/target/arm/usb-drv-arc.c185
-rw-r--r--firmware/target/arm/usb-tcc.c5
2 files changed, 122 insertions, 68 deletions
diff --git a/firmware/target/arm/usb-drv-arc.c b/firmware/target/arm/usb-drv-arc.c
index 200601eb24..8a10c5fbd6 100644
--- a/firmware/target/arm/usb-drv-arc.c
+++ b/firmware/target/arm/usb-drv-arc.c
@@ -248,10 +248,6 @@
248#define EPCTRL_RX_EP_STALL (0x00000001) 248#define EPCTRL_RX_EP_STALL (0x00000001)
249 249
250/* bit 19-18 and 3-2 are endpoint type */ 250/* bit 19-18 and 3-2 are endpoint type */
251#define EPCTRL_EP_TYPE_CONTROL (0)
252#define EPCTRL_EP_TYPE_ISO (1)
253#define EPCTRL_EP_TYPE_BULK (2)
254#define EPCTRL_EP_TYPE_INTERRUPT (3)
255#define EPCTRL_TX_EP_TYPE_SHIFT (18) 251#define EPCTRL_TX_EP_TYPE_SHIFT (18)
256#define EPCTRL_RX_EP_TYPE_SHIFT (2) 252#define EPCTRL_RX_EP_TYPE_SHIFT (2)
257 253
@@ -312,6 +308,14 @@
312 transfer size, so it seems like a good size */ 308 transfer size, so it seems like a good size */
313#define NUM_TDS_PER_EP 4 309#define NUM_TDS_PER_EP 4
314 310
311typedef struct usb_endpoint
312{
313 bool allocated[2];
314 short type[2];
315 short max_pkt_size[2];
316} usb_endpoint_t;
317static usb_endpoint_t endpoints[USB_NUM_ENDPOINTS];
318
315/* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */ 319/* manual: 32.13.2 Endpoint Transfer Descriptor (dTD) */
316struct transfer_descriptor { 320struct transfer_descriptor {
317 unsigned int next_td_ptr; /* Next TD pointer(31-5), T(0) set 321 unsigned int next_td_ptr; /* Next TD pointer(31-5), T(0) set
@@ -356,16 +360,12 @@ static const unsigned int pipe2mask[] = {
356 0x10, 0x100000, 360 0x10, 0x100000,
357}; 361};
358 362
359static char ep_allocation[USB_NUM_ENDPOINTS];
360
361/*-------------------------------------------------------------------------*/ 363/*-------------------------------------------------------------------------*/
362static void transfer_completed(void); 364static void transfer_completed(void);
363static void control_received(void); 365static void control_received(void);
364static int prime_transfer(int endpoint, void* ptr, 366static int prime_transfer(int ep_num, void* ptr, int len, bool send, bool wait);
365 int len, bool send, bool wait);
366static void prepare_td(struct transfer_descriptor* td, 367static void prepare_td(struct transfer_descriptor* td,
367 struct transfer_descriptor* previous_td, 368 struct transfer_descriptor* previous_td, void *ptr, int len,int pipe);
368 void *ptr, int len,int pipe);
369static void bus_reset(void); 369static void bus_reset(void);
370static void init_control_queue_heads(void); 370static void init_control_queue_heads(void);
371static void init_bulk_queue_heads(void); 371static void init_bulk_queue_heads(void);
@@ -394,7 +394,7 @@ void usb_drv_reset(void)
394 while (REG_USBCMD & USBCMD_CTRL_RESET); 394 while (REG_USBCMD & USBCMD_CTRL_RESET);
395 395
396#if CONFIG_CPU == PP5022 || CONFIG_CPU == PP5024 396#if CONFIG_CPU == PP5022 || CONFIG_CPU == PP5024
397 /* On a CPU which identifies as a PP5022, this 397 /* On a CPU which identifies as a PP5022, this
398 initialization must be done after USB is reset. 398 initialization must be done after USB is reset.
399 */ 399 */
400 outl(inl(0x70000060) | 0xF, 0x70000060); 400 outl(inl(0x70000060) | 0xF, 0x70000060);
@@ -475,6 +475,27 @@ static void _usb_drv_init(bool attach)
475 (void)attach; 475 (void)attach;
476} 476}
477 477
478#ifdef LOGF_ENABLE
479#define XFER_DIR_STR(dir) ((dir) ? "IN" : "OUT")
480#define XFER_TYPE_STR(type) \
481 ((type) == USB_ENDPOINT_XFER_CONTROL ? "CTRL" : \
482 ((type) == USB_ENDPOINT_XFER_ISOC ? "ISOC" : \
483 ((type) == USB_ENDPOINT_XFER_BULK ? "BULK" : \
484 ((type) == USB_ENDPOINT_XFER_INT ? "INTR" : "INVL"))))
485
486static void log_ep(int ep_num, int ep_dir, char* prefix)
487{
488 usb_endpoint_t* endpoint = &endpoints[ep_num];
489
490 logf("%s: ep%d %s %s %d", prefix, ep_num, XFER_DIR_STR(ep_dir),
491 XFER_TYPE_STR(endpoint->type[ep_dir]),
492 endpoint->max_pkt_size[ep_dir]);
493}
494#else
495#undef log_ep
496#define log_ep(...)
497#endif
498
478void usb_drv_init(void) 499void usb_drv_init(void)
479{ 500{
480 _usb_drv_init(false); 501 _usb_drv_init(false);
@@ -483,6 +504,7 @@ void usb_drv_init(void)
483/* fully enable driver */ 504/* fully enable driver */
484void usb_drv_attach(void) 505void usb_drv_attach(void)
485{ 506{
507 logf("usb_drv_attach");
486 sleep(HZ/10); 508 sleep(HZ/10);
487 _usb_drv_init(true); 509 _usb_drv_init(true);
488} 510}
@@ -555,49 +577,51 @@ void usb_drv_int(void)
555bool usb_drv_stalled(int endpoint,bool in) 577bool usb_drv_stalled(int endpoint,bool in)
556{ 578{
557 if(in) { 579 if(in) {
558 return ((REG_ENDPTCTRL(endpoint&0x7f) & EPCTRL_TX_EP_STALL)!=0); 580 return ((REG_ENDPTCTRL(EP_NUM(endpoint)) & EPCTRL_TX_EP_STALL)!=0);
559 } 581 }
560 else { 582 else {
561 return ((REG_ENDPTCTRL(endpoint&0x7f) & EPCTRL_RX_EP_STALL)!=0); 583 return ((REG_ENDPTCTRL(EP_NUM(endpoint)) & EPCTRL_RX_EP_STALL)!=0);
562 } 584 }
563 585
564} 586}
565void usb_drv_stall(int endpoint, bool stall,bool in) 587void usb_drv_stall(int endpoint, bool stall, bool in)
566{ 588{
567 logf("%sstall %d", stall?"":"un", endpoint&0x7f); 589 int ep_num = EP_NUM(endpoint);
590
591 logf("%sstall %d", stall ? "" : "un", ep_num);
568 592
569 if(in) { 593 if(in) {
570 if (stall) { 594 if (stall) {
571 REG_ENDPTCTRL(endpoint&0x7f) |= EPCTRL_TX_EP_STALL; 595 REG_ENDPTCTRL(ep_num) |= EPCTRL_TX_EP_STALL;
572 } 596 }
573 else { 597 else {
574 REG_ENDPTCTRL(endpoint&0x7f) &= ~EPCTRL_TX_EP_STALL; 598 REG_ENDPTCTRL(ep_num) &= ~EPCTRL_TX_EP_STALL;
575 } 599 }
576 } 600 }
577 else { 601 else {
578 if (stall) { 602 if (stall) {
579 REG_ENDPTCTRL(endpoint) |= EPCTRL_RX_EP_STALL; 603 REG_ENDPTCTRL(ep_num) |= EPCTRL_RX_EP_STALL;
580 } 604 }
581 else { 605 else {
582 REG_ENDPTCTRL(endpoint) &= ~EPCTRL_RX_EP_STALL; 606 REG_ENDPTCTRL(ep_num) &= ~EPCTRL_RX_EP_STALL;
583 } 607 }
584 } 608 }
585} 609}
586 610
587int usb_drv_send_nonblocking(int endpoint, void* ptr, int length) 611int usb_drv_send_nonblocking(int endpoint, void* ptr, int length)
588{ 612{
589 return prime_transfer(endpoint&0x7f, ptr, length, true, false); 613 return prime_transfer(EP_NUM(endpoint), ptr, length, true, false);
590} 614}
591 615
592int usb_drv_send(int endpoint, void* ptr, int length) 616int usb_drv_send(int endpoint, void* ptr, int length)
593{ 617{
594 return prime_transfer(endpoint&0x7f, ptr, length, true, true); 618 return prime_transfer(EP_NUM(endpoint), ptr, length, true, true);
595} 619}
596 620
597int usb_drv_recv(int endpoint, void* ptr, int length) 621int usb_drv_recv(int endpoint, void* ptr, int length)
598{ 622{
599 //logf("usbrecv(%x, %d)", ptr, length); 623 //logf("usbrecv(%x, %d)", ptr, length);
600 return prime_transfer(endpoint&0x7f, ptr, length, false, false); 624 return prime_transfer(EP_NUM(endpoint), ptr, length, false, false);
601} 625}
602 626
603int usb_drv_port_speed(void) 627int usb_drv_port_speed(void)
@@ -627,7 +651,7 @@ void usb_drv_set_address(int address)
627 651
628void usb_drv_reset_endpoint(int endpoint, bool send) 652void usb_drv_reset_endpoint(int endpoint, bool send)
629{ 653{
630 int pipe = (endpoint&0x7f) * 2 + (send ? 1 : 0); 654 int pipe = EP_NUM(endpoint) * 2 + (send ? 1 : 0);
631 unsigned int mask = pipe2mask[pipe]; 655 unsigned int mask = pipe2mask[pipe];
632 REG_ENDPTFLUSH = mask; 656 REG_ENDPTFLUSH = mask;
633 while (REG_ENDPTFLUSH & mask); 657 while (REG_ENDPTFLUSH & mask);
@@ -662,23 +686,23 @@ void usb_drv_set_test_mode(int mode)
662/*-------------------------------------------------------------------------*/ 686/*-------------------------------------------------------------------------*/
663 687
664/* manual: 32.14.5.2 */ 688/* manual: 32.14.5.2 */
665static int prime_transfer(int endpoint, void* ptr, int len, bool send, bool wait) 689static int prime_transfer(int ep_num, void* ptr, int len, bool send, bool wait)
666{ 690{
667 int rc = 0; 691 int rc = 0;
668 int pipe = endpoint * 2 + (send ? 1 : 0); 692 int pipe = ep_num * 2 + (send ? 1 : 0);
669 unsigned int mask = pipe2mask[pipe]; 693 unsigned int mask = pipe2mask[pipe];
670 struct queue_head* qh = &qh_array[pipe]; 694 struct queue_head* qh = &qh_array[pipe];
671 static long last_tick; 695 static long last_tick;
672 struct transfer_descriptor* new_td,*cur_td,*prev_td; 696 struct transfer_descriptor *new_td, *cur_td, *prev_td;
673 697
674 int oldlevel = disable_irq_save(); 698 int oldlevel = disable_irq_save();
675/* 699/*
676 if (send && endpoint > EP_CONTROL) { 700 if (send && ep_num > EP_CONTROL) {
677 logf("usb: sent %d bytes", len); 701 logf("usb: sent %d bytes", len);
678 } 702 }
679*/ 703*/
680 qh->status = 0; 704 qh->status = 0;
681 qh->wait = wait; 705 qh->wait = wait;
682 706
683 new_td=&td_array[pipe*NUM_TDS_PER_EP]; 707 new_td=&td_array[pipe*NUM_TDS_PER_EP];
684 cur_td=new_td; 708 cur_td=new_td;
@@ -694,15 +718,15 @@ static int prime_transfer(int endpoint, void* ptr, int len, bool send, bool wait
694 cur_td++; 718 cur_td++;
695 len-=tdlen; 719 len-=tdlen;
696 } 720 }
697 while(len>0 ); 721 while(len>0);
698 //logf("starting ep %d %s",endpoint,send?"send":"receive"); 722 //logf("starting ep %d %s",ep_num,send?"send":"receive");
699 723
700 qh->dtd.next_td_ptr = (unsigned int)new_td; 724 qh->dtd.next_td_ptr = (unsigned int)new_td;
701 qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE); 725 qh->dtd.size_ioc_sts &= ~(QH_STATUS_HALT | QH_STATUS_ACTIVE);
702 726
703 REG_ENDPTPRIME |= mask; 727 REG_ENDPTPRIME |= mask;
704 728
705 if(endpoint == EP_CONTROL && (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0)) { 729 if(ep_num == EP_CONTROL && (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0)) {
706 /* 32.14.3.2.2 */ 730 /* 32.14.3.2.2 */
707 logf("new setup arrived"); 731 logf("new setup arrived");
708 rc = -4; 732 rc = -4;
@@ -724,11 +748,11 @@ static int prime_transfer(int endpoint, void* ptr, int len, bool send, bool wait
724 } 748 }
725 749
726 if (!(REG_ENDPTSTATUS & mask)) { 750 if (!(REG_ENDPTSTATUS & mask)) {
727 logf("no prime! %d %d %x", endpoint, pipe, qh->dtd.size_ioc_sts & 0xff ); 751 logf("no prime! %d %d %x", ep_num, pipe, qh->dtd.size_ioc_sts & 0xff);
728 rc = -3; 752 rc = -3;
729 goto pt_error; 753 goto pt_error;
730 } 754 }
731 if(endpoint == EP_CONTROL && (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0)) { 755 if(ep_num == EP_CONTROL && (REG_ENDPTSETUPSTAT & EPSETUP_STATUS_EP0)) {
732 /* 32.14.3.2.2 */ 756 /* 32.14.3.2.2 */
733 logf("new setup arrived"); 757 logf("new setup arrived");
734 rc = -4; 758 rc = -4;
@@ -780,17 +804,38 @@ void usb_drv_cancel_all_transfers(void)
780 } 804 }
781} 805}
782 806
783int usb_drv_request_endpoint(int dir) 807int usb_drv_request_endpoint(int type, int dir)
784{ 808{
785 int i, bit; 809 int ep_num, ep_dir;
810 short ep_type;
811
812 /* Safety */
813 ep_dir = EP_DIR(dir);
814 ep_type = type & USB_ENDPOINT_XFERTYPE_MASK;
786 815
787 bit=(dir & USB_DIR_IN)? 2:1; 816 logf("req: %s %s", XFER_DIR_STR(ep_dir), XFER_TYPE_STR(ep_type));
788 817
789 for (i=1; i < USB_NUM_ENDPOINTS; i++) { 818 /* Find an available ep/dir pair */
790 if((ep_allocation[i] & bit)!=0) 819 for (ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) {
820 usb_endpoint_t* endpoint=&endpoints[ep_num];
821 int other_dir=(ep_dir ? 0:1);
822
823 if (endpoint->allocated[ep_dir])
791 continue; 824 continue;
792 ep_allocation[i] |= bit; 825
793 return i | dir; 826 if (endpoint->allocated[other_dir] &&
827 endpoint->type[other_dir] != ep_type) {
828 logf("ep of different type!");
829 return -1;
830 }
831
832 log_ep(ep_num, ep_dir, "add");
833
834 endpoint->allocated[ep_dir] = 1;
835 endpoint->type[ep_dir] = ep_type;
836
837 log_ep(ep_num, ep_dir, "got");
838 return (ep_num | (dir & USB_ENDPOINT_DIR_MASK));
794 } 839 }
795 840
796 return -1; 841 return -1;
@@ -798,8 +843,11 @@ int usb_drv_request_endpoint(int dir)
798 843
799void usb_drv_release_endpoint(int ep) 844void usb_drv_release_endpoint(int ep)
800{ 845{
801 int mask = (ep & USB_DIR_IN)? ~2:~1; 846 int ep_num = EP_NUM(ep);
802 ep_allocation[ep & 0x7f] &= mask; 847 int ep_dir = EP_DIR(ep);
848
849 log_ep(ep_num, ep_dir, "rel");
850 endpoints[ep_num].allocated[ep_dir] = 0;
803} 851}
804 852
805 853
@@ -870,11 +918,12 @@ static void transfer_completed(void)
870 struct transfer_descriptor* td=&td_array[pipe*NUM_TDS_PER_EP]; 918 struct transfer_descriptor* td=&td_array[pipe*NUM_TDS_PER_EP];
871 while(td!=(struct transfer_descriptor*)DTD_NEXT_TERMINATE && td!=0) 919 while(td!=(struct transfer_descriptor*)DTD_NEXT_TERMINATE && td!=0)
872 { 920 {
873 length += ((td->reserved & DTD_RESERVED_LENGTH_MASK) - 921 length += ((td->reserved & DTD_RESERVED_LENGTH_MASK) -
874 ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS)); 922 ((td->size_ioc_sts & DTD_PACKET_SIZE) >> DTD_LENGTH_BIT_POS));
875 td=(struct transfer_descriptor*) td->next_td_ptr; 923 td=(struct transfer_descriptor*) td->next_td_ptr;
876 } 924 }
877 usb_core_transfer_complete(ep, dir?USB_DIR_IN:USB_DIR_OUT, qh->status, length); 925 usb_core_transfer_complete(ep, dir?USB_DIR_IN:USB_DIR_OUT,
926 qh->status, length);
878 } 927 }
879 } 928 }
880 } 929 }
@@ -906,7 +955,7 @@ static void bus_reset(void)
906 } 955 }
907 956
908 usb_drv_cancel_all_transfers(); 957 usb_drv_cancel_all_transfers();
909 958
910 if (!(REG_PORTSC1 & PORTSCX_PORT_RESET)) { 959 if (!(REG_PORTSC1 & PORTSCX_PORT_RESET)) {
911 logf("usb: slow reset!"); 960 logf("usb: slow reset!");
912 } 961 }
@@ -926,39 +975,41 @@ static void init_control_queue_heads(void)
926/* manual: 32.14.4.1 Queue Head Initialization */ 975/* manual: 32.14.4.1 Queue Head Initialization */
927static void init_bulk_queue_heads(void) 976static void init_bulk_queue_heads(void)
928{ 977{
929 int tx_packetsize; 978 int packetsize = (usb_drv_port_speed() ? 512 : 64);
930 int rx_packetsize;
931 int i; 979 int i;
932 980
933 if (usb_drv_port_speed()) {
934 rx_packetsize = 512;
935 tx_packetsize = 512;
936 }
937 else {
938 rx_packetsize = 64;
939 tx_packetsize = 64;
940 }
941 /* TODO: this should take ep_allocation into account */ 981 /* TODO: this should take ep_allocation into account */
942 982 for (i=1;i<USB_NUM_ENDPOINTS;i++) {
943 /*** bulk ***/ 983 qh_array[i*2].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS |
944 for(i=1;i<USB_NUM_ENDPOINTS;i++) { 984 QH_ZLT_SEL;
945 qh_array[i*2].max_pkt_length = rx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL;
946 qh_array[i*2].dtd.next_td_ptr = QH_NEXT_TERMINATE; 985 qh_array[i*2].dtd.next_td_ptr = QH_NEXT_TERMINATE;
947 qh_array[i*2+1].max_pkt_length = tx_packetsize << QH_MAX_PKT_LEN_POS | QH_ZLT_SEL; 986 qh_array[i*2+1].max_pkt_length = packetsize << QH_MAX_PKT_LEN_POS |
987 QH_ZLT_SEL;
948 qh_array[i*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE; 988 qh_array[i*2+1].dtd.next_td_ptr = QH_NEXT_TERMINATE;
949 } 989 }
950} 990}
951 991
952static void init_endpoints(void) 992static void init_endpoints(void)
953{ 993{
954 int i; 994 int ep_num;
955 /* TODO: this should take ep_allocation into account */ 995
956 /* bulk */ 996 logf("init_endpoints");
957 for(i=1;i<USB_NUM_ENDPOINTS;i++) { 997 /* RX/TX from the device POV: OUT/IN, respectively */
958 REG_ENDPTCTRL(i) = 998 for(ep_num=1;ep_num<USB_NUM_ENDPOINTS;ep_num++) {
999 usb_endpoint_t *endpoint = &endpoints[ep_num];
1000
1001 /* manual: 32.9.5.18 (Caution) */
1002 if (!endpoint->allocated[DIR_OUT]) {
1003 endpoint->type[DIR_OUT] = USB_ENDPOINT_XFER_BULK;
1004 }
1005 if (!endpoint->allocated[DIR_IN]) {
1006 endpoint->type[DIR_IN] = USB_ENDPOINT_XFER_BULK;
1007 }
1008
1009 REG_ENDPTCTRL(ep_num) =
959 EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE | 1010 EPCTRL_RX_DATA_TOGGLE_RST | EPCTRL_RX_ENABLE |
960 EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE | 1011 EPCTRL_TX_DATA_TOGGLE_RST | EPCTRL_TX_ENABLE |
961 (EPCTRL_EP_TYPE_BULK << EPCTRL_RX_EP_TYPE_SHIFT) | 1012 (endpoint->type[DIR_OUT] << EPCTRL_RX_EP_TYPE_SHIFT) |
962 (EPCTRL_EP_TYPE_BULK << EPCTRL_TX_EP_TYPE_SHIFT); 1013 (endpoint->type[DIR_IN] << EPCTRL_TX_EP_TYPE_SHIFT);
963 } 1014 }
964} 1015}
diff --git a/firmware/target/arm/usb-tcc.c b/firmware/target/arm/usb-tcc.c
index 611e4be195..2538efd12e 100644
--- a/firmware/target/arm/usb-tcc.c
+++ b/firmware/target/arm/usb-tcc.c
@@ -94,12 +94,15 @@ static struct tcc_ep tcc_endpoints[] = {
94static bool usb_drv_write_ep(struct tcc_ep *ep); 94static bool usb_drv_write_ep(struct tcc_ep *ep);
95static void usb_set_speed(int); 95static void usb_set_speed(int);
96 96
97int usb_drv_request_endpoint(int dir) 97int usb_drv_request_endpoint(int type, int dir)
98{ 98{
99 int flags = disable_irq_save(); 99 int flags = disable_irq_save();
100 size_t ep; 100 size_t ep;
101 int ret = 0; 101 int ret = 0;
102 102
103 if (type != USB_ENDPOINT_XFER_BULK)
104 return -1;
105
103 if (dir == USB_DIR_IN) 106 if (dir == USB_DIR_IN)
104 ep = 1; 107 ep = 1;
105 else 108 else