5252#endif
5353static_assert (PICO_USB_HOST_INTERRUPT_ENDPOINTS <= USB_MAX_ENDPOINTS , "" );
5454
55- // Host mode uses one shared endpoint register for non-interrupt endpoint
56- static struct hw_endpoint ep_pool [1 + PICO_USB_HOST_INTERRUPT_ENDPOINTS ];
57- #define epx (ep_pool[0])
55+ /* Information about an endpoint to be copied into a struct hw_endpoint, e. g.
56+ * for epx. */
57+ struct sw_endpoint {
58+ bool configured ;
59+ uint8_t dev_addr ;
60+ uint8_t ep_addr ;
61+ uint16_t wMaxPacketSize ;
62+ uint8_t transfer_type ;
63+ uint8_t bmInterval ; /* probably useless because this is not for interrupt endpoints? */
64+ uint8_t next_pid ;
65+ };
66+
67+ // Host mode uses one shared endpoint register for non-interrupt endpoint, but
68+ // we need to store the endpoint type somewhere.
69+ static struct hw_endpoint epx = {
70+ .buffer_control = & usbh_dpram -> epx_buf_ctrl ,
71+ .endpoint_control = & usbh_dpram -> epx_ctrl ,
72+ .hw_data_buf = & usbh_dpram -> epx_data [0 ]
73+ };
74+ static struct sw_endpoint sw_ep_pool [USB_MAX_ENDPOINTS ];
75+
76+ static struct sw_endpoint sw_ep_ctrl = {
77+ .configured = true,
78+ .dev_addr = 0 , /* dynamic */
79+ .ep_addr = 0 , /* dynamic */
80+ .wMaxPacketSize = 64 ,
81+ .transfer_type = TUSB_XFER_CONTROL ,
82+ .bmInterval = 0 ,
83+ .next_pid = 1
84+ };
85+
86+ // pool for interrupt endpoints
87+ static struct hw_endpoint ep_pool [PICO_USB_HOST_INTERRUPT_ENDPOINTS ];
5888
5989#define usb_hw_set hw_set_alias(usb_hw)
6090#define usb_hw_clear hw_clear_alias(usb_hw)
@@ -65,12 +95,29 @@ enum {
6595 USB_SIE_CTRL_PULLDOWN_EN_BITS | USB_SIE_CTRL_EP0_INT_1BUF_BITS
6696};
6797
68- static struct hw_endpoint * get_dev_ep (uint8_t dev_addr , uint8_t ep_addr )
98+ static struct sw_endpoint * get_dev_sw_ep (uint8_t dev_addr , uint8_t ep_addr )
6999{
70- uint8_t num = tu_edpt_number (ep_addr );
71- if ( num == 0 ) return & epx ;
100+ uint8_t num = tu_edpt_number (ep_addr );
101+
102+ if (num == 0 ) {
103+ sw_ep_ctrl .dev_addr = dev_addr ;
104+ sw_ep_ctrl .ep_addr = ep_addr ;
105+ return & sw_ep_ctrl ;
106+ }
107+
108+ for (uint32_t i = 0 ; i < TU_ARRAY_SIZE (sw_ep_pool ); i ++ ) {
109+ struct sw_endpoint * ep = & sw_ep_pool [i ];
110+ if (ep -> configured && ep -> dev_addr == dev_addr && ep -> ep_addr == ep_addr ) {
111+ return ep ;
112+ }
113+ }
114+
115+ return NULL ;
116+ }
72117
73- for ( uint32_t i = 1 ; i < TU_ARRAY_SIZE (ep_pool ); i ++ )
118+ static struct hw_endpoint * get_dev_hw_ep (uint8_t dev_addr , uint8_t ep_addr )
119+ {
120+ for ( uint32_t i = 0 ; i < TU_ARRAY_SIZE (ep_pool ); i ++ )
74121 {
75122 struct hw_endpoint * ep = & ep_pool [i ];
76123 if ( ep -> configured && (ep -> dev_addr == dev_addr ) && (ep -> ep_addr == ep_addr ) ) return ep ;
@@ -273,31 +320,44 @@ static struct hw_endpoint *_hw_endpoint_allocate(uint8_t transfer_type)
273320{
274321 struct hw_endpoint * ep = NULL ;
275322
276- if (transfer_type == TUSB_XFER_INTERRUPT )
277- {
278- ep = _next_free_interrupt_ep ();
279- pico_info ("Allocate interrupt ep %d\n" , ep -> interrupt_num );
280- assert (ep );
281- ep -> buffer_control = & usbh_dpram -> int_ep_buffer_ctrl [ep -> interrupt_num ].ctrl ;
282- ep -> endpoint_control = & usbh_dpram -> int_ep_ctrl [ep -> interrupt_num ].ctrl ;
283- // 0 for epx (double buffered): TODO increase to 1024 for ISO
284- // 2x64 for intep0
285- // 3x64 for intep1
286- // etc
287- ep -> hw_data_buf = & usbh_dpram -> epx_data [64 * (ep -> interrupt_num + 2 )];
288- }
289- else
290- {
291- ep = & epx ;
292- ep -> buffer_control = & usbh_dpram -> epx_buf_ctrl ;
293- ep -> endpoint_control = & usbh_dpram -> epx_ctrl ;
294- ep -> hw_data_buf = & usbh_dpram -> epx_data [0 ];
295- }
323+ ep = _next_free_interrupt_ep ();
324+ pico_info ("Allocate interrupt ep %d\n" , ep -> interrupt_num );
325+ assert (ep );
326+ ep -> buffer_control = & usbh_dpram -> int_ep_buffer_ctrl [ep -> interrupt_num ].ctrl ;
327+ ep -> endpoint_control = & usbh_dpram -> int_ep_ctrl [ep -> interrupt_num ].ctrl ;
328+ // 0 for epx (double buffered): TODO increase to 1024 for ISO
329+ // 2x64 for intep0
330+ // 3x64 for intep1
331+ // etc
332+ ep -> hw_data_buf = & usbh_dpram -> epx_data [64 * (ep -> interrupt_num + 2 )];
296333
297334 return ep ;
298335}
299336
300- static void _hw_endpoint_init (struct hw_endpoint * ep , uint8_t dev_addr , uint8_t ep_addr , uint16_t wMaxPacketSize , uint8_t transfer_type , uint8_t bmInterval )
337+ static struct sw_endpoint * _sw_endpoint_allocate (void )
338+ {
339+ for (uint i = 0 ; i < TU_ARRAY_SIZE (sw_ep_pool ); i ++ ) {
340+ if (!sw_ep_pool [i ].configured ) {
341+ return & sw_ep_pool [i ];
342+ }
343+ }
344+ return NULL ;
345+ }
346+
347+ static void _sw_endpoint_restore_epx (void ) {
348+ uint8_t const num_old = tu_edpt_number (epx .ep_addr );
349+
350+ if (num_old != 0 ) {
351+ /* previous use of epx was not for control transfer: save next_pid
352+ * toggle state in sw endpoint */
353+ struct sw_endpoint * eps = get_dev_sw_ep (epx .dev_addr , epx .ep_addr );
354+ if (eps != NULL ) {
355+ eps -> next_pid = epx .next_pid ;
356+ }
357+ }
358+ }
359+
360+ static void _hw_endpoint_init (struct hw_endpoint * ep , uint8_t dev_addr , uint8_t ep_addr , uint16_t wMaxPacketSize , uint8_t transfer_type , uint8_t bmInterval , uint8_t next_pid )
301361{
302362 // Already has data buffer, endpoint control, and buffer control allocated at this point
303363 assert (ep -> endpoint_control );
@@ -313,8 +373,7 @@ static void _hw_endpoint_init(struct hw_endpoint *ep, uint8_t dev_addr, uint8_t
313373 // For host, IN to host == RX, anything else rx == false
314374 ep -> rx = (dir == TUSB_DIR_IN );
315375
316- // Response to a setup packet on EP0 starts with pid of 1
317- ep -> next_pid = (num == 0 ? 1u : 0u );
376+ ep -> next_pid = next_pid ;
318377 ep -> wMaxPacketSize = wMaxPacketSize ;
319378 ep -> transfer_type = transfer_type ;
320379
@@ -462,6 +521,12 @@ void hcd_device_close(uint8_t rhport, uint8_t dev_addr)
462521 hw_endpoint_reset_transfer (ep );
463522 }
464523 }
524+
525+ for (size_t i = 1 ; i < TU_ARRAY_SIZE (sw_ep_pool ); i ++ ) {
526+ if (sw_ep_pool [i ].dev_addr == dev_addr ) {
527+ sw_ep_pool [i ].configured = false;
528+ }
529+ }
465530}
466531
467532uint32_t hcd_frame_number (uint8_t rhport )
@@ -491,20 +556,39 @@ void hcd_int_disable(uint8_t rhport)
491556
492557bool hcd_edpt_open (uint8_t rhport , uint8_t dev_addr , tusb_desc_endpoint_t const * ep_desc )
493558{
559+ uint8_t transfer_type ;
494560 (void ) rhport ;
495561
496562 pico_trace ("hcd_edpt_open dev_addr %d, ep_addr %d\n" , dev_addr , ep_desc -> bEndpointAddress );
497563
498564 // Allocated differently based on if it's an interrupt endpoint or not
499- struct hw_endpoint * ep = _hw_endpoint_allocate (ep_desc -> bmAttributes .xfer );
500- TU_ASSERT (ep );
501-
502- _hw_endpoint_init (ep ,
503- dev_addr ,
504- ep_desc -> bEndpointAddress ,
505- tu_edpt_packet_size (ep_desc ),
506- ep_desc -> bmAttributes .xfer ,
507- ep_desc -> bInterval );
565+ transfer_type = ep_desc -> bmAttributes .xfer ;
566+ if (transfer_type == TUSB_XFER_INTERRUPT ) {
567+ struct hw_endpoint * ep = _hw_endpoint_allocate (ep_desc -> bmAttributes .xfer );
568+ TU_ASSERT (ep );
569+
570+ _hw_endpoint_init (ep ,
571+ dev_addr ,
572+ ep_desc -> bEndpointAddress ,
573+ tu_edpt_packet_size (ep_desc ),
574+ transfer_type ,
575+ ep_desc -> bInterval ,
576+ 0 );
577+ } else if (transfer_type != TUSB_XFER_CONTROL ) {
578+ struct sw_endpoint * ep = _sw_endpoint_allocate ();
579+ TU_ASSERT (ep );
580+
581+ /* Only remember information about endpoint, will be configured into HW
582+ * epx for each transfer. */
583+ ep -> configured = true;
584+ ep -> dev_addr = dev_addr ;
585+ ep -> ep_addr = ep_desc -> bEndpointAddress ;
586+ ep -> wMaxPacketSize = tu_edpt_packet_size (ep_desc );
587+ ep -> transfer_type = transfer_type ;
588+ ep -> bmInterval = ep_desc -> bInterval ;
589+ } else {
590+ /* control endpoint is implicitly open (sw_ep_ctrl) */
591+ }
508592
509593 return true;
510594}
@@ -514,48 +598,65 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
514598 (void ) rhport ;
515599
516600 pico_trace ("hcd_edpt_xfer dev_addr %d, ep_addr 0x%x, len %d\n" , dev_addr , ep_addr , buflen );
517-
601+
518602 uint8_t const ep_num = tu_edpt_number (ep_addr );
519603 tusb_dir_t const ep_dir = tu_edpt_dir (ep_addr );
520604
521- // Get appropriate ep. Either EPX or interrupt endpoint
522- struct hw_endpoint * ep = get_dev_ep (dev_addr , ep_addr );
523- TU_ASSERT (ep );
605+ // Get appropriate ep
606+ struct hw_endpoint * ep = get_dev_hw_ep (dev_addr , ep_addr );
607+ if (ep != NULL ) {
608+ // EP should be inactive
609+ assert (!ep -> active );
524610
525- // EP should be inactive
526- assert (!ep -> active );
611+ // Interrupt ep registers should already be configured
612+ hw_endpoint_xfer_start (ep , buffer , buflen );
613+ return true;
614+ }
527615
528- // Control endpoint can change direction 0x00 <-> 0x80
529- if ( ep_addr != ep -> ep_addr )
530- {
531- assert (ep_num == 0 );
532616
533- // Direction has flipped on endpoint control so re init it but with same properties
534- _hw_endpoint_init (ep , dev_addr , ep_addr , ep -> wMaxPacketSize , ep -> transfer_type , 0 );
535- }
617+ struct sw_endpoint * eps = get_dev_sw_ep (dev_addr , ep_addr );
618+ if (eps != NULL ) {
619+ ep = & epx ;
620+
621+ /* TODO: Handle multiple outstanding requests to different sw
622+ * endpoints. */
623+ assert (!ep -> active );
624+
625+ /* configure shared epx hw endpoint with sw values */
626+ if (ep -> dev_addr != eps -> dev_addr || ep -> ep_addr != eps -> ep_addr ) {
627+ _sw_endpoint_restore_epx ();
628+ _hw_endpoint_init (
629+ ep ,
630+ dev_addr ,
631+ ep_addr ,
632+ eps -> wMaxPacketSize ,
633+ eps -> transfer_type ,
634+ eps -> bmInterval ,
635+ eps -> next_pid
636+ );
637+ }
536638
537- // If a normal transfer (non-interrupt) then initiate using
538- // sie ctrl registers. Otherwise interrupt ep registers should
539- // already be configured
540- if (ep == & epx ) {
541639 hw_endpoint_xfer_start (ep , buffer , buflen );
542640
543641 // That has set up buffer control, endpoint control etc
544642 // for host we have to initiate the transfer
545643 usb_hw -> dev_addr_ctrl = (uint32_t ) (dev_addr | (ep_num << USB_ADDR_ENDP_ENDPOINT_LSB ));
546644
547- uint32_t flags = USB_SIE_CTRL_START_TRANS_BITS | SIE_CTRL_BASE |
548- ( ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS ) ;
645+ uint32_t flags = SIE_CTRL_BASE ;
646+ flags |= ep_dir ? USB_SIE_CTRL_RECEIVE_DATA_BITS : USB_SIE_CTRL_SEND_DATA_BITS ;
549647 // Set pre if we are a low speed device on full speed hub
550648 flags |= need_pre (dev_addr ) ? USB_SIE_CTRL_PREAMBLE_EN_BITS : 0 ;
551649
650+ /* This seems to be required because otherwise the controller sometimes
651+ * ignores the request to start our transaction (or starts the wrong
652+ * kind of transaction, who knows). */
552653 usb_hw -> sie_ctrl = flags ;
553- } else
554- {
555- hw_endpoint_xfer_start ( ep , buffer , buflen ) ;
654+
655+ usb_hw -> sie_ctrl = flags | USB_SIE_CTRL_START_TRANS_BITS ;
656+ return true ;
556657 }
557658
558- return true ;
659+ return false ;
559660}
560661
561662bool hcd_setup_send (uint8_t rhport , uint8_t dev_addr , uint8_t const setup_packet [8 ])
@@ -568,15 +669,16 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet
568669 usbh_dpram -> setup_packet [i ] = setup_packet [i ];
569670 }
570671
571- // Configure EP0 struct with setup info for the trans complete
572- struct hw_endpoint * ep = _hw_endpoint_allocate (0 );
672+ struct hw_endpoint * ep = & epx ;
573673 TU_ASSERT (ep );
574674
575675 // EPX should be inactive
576676 assert (!ep -> active );
577677
578678 // EP0 out
579- _hw_endpoint_init (ep , dev_addr , 0x00 , ep -> wMaxPacketSize , 0 , 0 );
679+ // Response to a setup packet on EP0 starts with pid of 1
680+ _sw_endpoint_restore_epx ();
681+ _hw_endpoint_init (ep , dev_addr , 0x00 , ep -> wMaxPacketSize , 0 , 0 , 1 );
580682 assert (ep -> configured );
581683
582684 ep -> remaining_len = 8 ;
0 commit comments