@@ -78,8 +78,10 @@ typedef struct {
7878
7979// Max nbytes for each control/bulk/interrupt transfer
8080enum {
81- NBYTES_CBI_FULLSPEED_MAX = 64 ,
82- NBYTES_CBI_HIGHSPEED_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
81+ NBYTES_ISO_FS_MAX = 1023 , // FS ISO
82+ NBYTES_ISO_HS_MAX = 1024 , // HS ISO
83+ NBYTES_CBI_FS_MAX = 64 , // FS control/bulk/interrupt
84+ NBYTES_CBI_HS_MAX = 32767 // can be up to all 15-bit, but only tested with 4096
8385};
8486
8587enum {
@@ -112,6 +114,8 @@ enum {
112114typedef union TU_ATTR_PACKED
113115{
114116 // Full and High speed has different bit layout for buffer_offset and nbytes
117+ // TODO FS/HS layout depends on the max speed of controller e.g
118+ // lpc55s69 PORT0 is only FS but actually has the same layout as HS on port1
115119
116120 // Buffer (aligned 64) = DATABUFSTART [31:22] | buffer_offset [21:6]
117121 volatile struct {
@@ -175,6 +179,9 @@ typedef struct
175179// Use CFG_TUSB_MEM_SECTION to place it accordingly.
176180CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED (256 ) static dcd_data_t _dcd ;
177181
182+ // Dummy buffer to fix ZLPs overwriting the buffer (probably an USB/DMA controller bug)
183+ CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED (64 ) static uint8_t dummy [8 ];
184+
178185//--------------------------------------------------------------------+
179186// Multiple Controllers
180187//--------------------------------------------------------------------+
@@ -225,8 +232,36 @@ static inline uint8_t ep_addr2id(uint8_t ep_addr)
225232//--------------------------------------------------------------------+
226233// CONTROLLER API
227234//--------------------------------------------------------------------+
235+
236+ static void prepare_setup_packet (uint8_t rhport )
237+ {
238+ if (_dcd_controller [rhport ].max_speed == TUSB_SPEED_FULL )
239+ {
240+ _dcd .ep [0 ][1 ].buffer_fs .offset = get_buf_offset (_dcd .setup_packet );
241+ }else
242+ {
243+ _dcd .ep [0 ][1 ].buffer_hs .offset = get_buf_offset (_dcd .setup_packet );
244+ }
245+ }
246+
247+ static void edpt_reset (uint8_t rhport , uint8_t ep_id )
248+ {
249+ (void ) rhport ;
250+ tu_memclr (& _dcd .ep [ep_id ], sizeof (_dcd .ep [ep_id ]));
251+ }
252+
253+ static void edpt_reset_all (uint8_t rhport )
254+ {
255+ for (uint8_t ep_id = 0 ; ep_id < 2 * _dcd_controller [rhport ].ep_pairs ; ++ ep_id )
256+ {
257+ edpt_reset (rhport , ep_id );
258+ }
259+ prepare_setup_packet (rhport );
260+ }
228261void dcd_init (uint8_t rhport )
229262{
263+ edpt_reset_all (rhport );
264+
230265 dcd_registers_t * dcd_reg = _dcd_controller [rhport ].regs ;
231266
232267 dcd_reg -> EPLISTSTART = (uint32_t ) _dcd .ep ;
@@ -310,18 +345,13 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
310345
311346bool dcd_edpt_open (uint8_t rhport , tusb_desc_endpoint_t const * p_endpoint_desc )
312347{
313- (void ) rhport ;
314-
315- // TODO not support ISO yet
316- TU_VERIFY (p_endpoint_desc -> bmAttributes .xfer != TUSB_XFER_ISOCHRONOUS );
317-
318348 //------------- Prepare Queue Head -------------//
319349 uint8_t ep_id = ep_addr2id (p_endpoint_desc -> bEndpointAddress );
320350
321351 // Check if endpoint is available
322352 TU_ASSERT ( _dcd .ep [ep_id ][0 ].disable && _dcd .ep [ep_id ][1 ].disable );
323353
324- tu_memclr ( _dcd . ep [ ep_id ], 2 * sizeof ( ep_cmd_sts_t ) );
354+ edpt_reset ( rhport , ep_id );
325355 _dcd .ep [ep_id ][0 ].is_iso = (p_endpoint_desc -> bmAttributes .xfer == TUSB_XFER_ISOCHRONOUS );
326356
327357 // Enable EP interrupt
@@ -333,19 +363,20 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
333363
334364void dcd_edpt_close_all (uint8_t rhport )
335365{
336- (void ) rhport ;
337- // TODO implement dcd_edpt_close_all()
366+ for (uint8_t ep_id = 0 ; ep_id < 2 * _dcd_controller [rhport ].ep_pairs ; ++ ep_id )
367+ {
368+ _dcd .ep [ep_id ][0 ].active = _dcd .ep [ep_id ][0 ].active = 0 ; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
369+ _dcd .ep [ep_id ][0 ].disable = _dcd .ep [ep_id ][1 ].disable = 1 ;
370+ }
338371}
339372
340- static void prepare_setup_packet (uint8_t rhport )
373+ void dcd_edpt_close (uint8_t rhport , uint8_t ep_addr )
341374{
342- if (_dcd_controller [rhport ].max_speed == TUSB_SPEED_FULL )
343- {
344- _dcd .ep [0 ][1 ].buffer_fs .offset = get_buf_offset (_dcd .setup_packet );;
345- }else
346- {
347- _dcd .ep [0 ][1 ].buffer_hs .offset = get_buf_offset (_dcd .setup_packet );;
348- }
375+ (void ) rhport ;
376+
377+ uint8_t ep_id = ep_addr2id (ep_addr );
378+ _dcd .ep [ep_id ][0 ].active = _dcd .ep [ep_id ][0 ].active = 0 ; // TODO proper way is to EPSKIP then wait ep[][].active then write ep[][].disable (see table 778 in LPC55S69 Use Manual)
379+ _dcd .ep [ep_id ][0 ].disable = _dcd .ep [ep_id ][1 ].disable = 1 ;
349380}
350381
351382static void prepare_ep_xfer (uint8_t rhport , uint8_t ep_id , uint16_t buf_offset , uint16_t total_bytes )
@@ -354,13 +385,12 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset,
354385
355386 if (_dcd_controller [rhport ].max_speed == TUSB_SPEED_FULL )
356387 {
357- // TODO ISO FullSpeed can have up to 1023 bytes
358- nbytes = tu_min16 (total_bytes , NBYTES_CBI_FULLSPEED_MAX );
388+ nbytes = tu_min16 (total_bytes , _dcd .ep [ep_id ][0 ].is_iso ? NBYTES_ISO_FS_MAX : NBYTES_CBI_FS_MAX );
359389 _dcd .ep [ep_id ][0 ].buffer_fs .offset = buf_offset ;
360390 _dcd .ep [ep_id ][0 ].buffer_fs .nbytes = nbytes ;
361391 }else
362392 {
363- nbytes = tu_min16 (total_bytes , NBYTES_CBI_HIGHSPEED_MAX );
393+ nbytes = tu_min16 (total_bytes , NBYTES_CBI_HS_MAX );
364394 _dcd .ep [ep_id ][0 ].buffer_hs .offset = buf_offset ;
365395 _dcd .ep [ep_id ][0 ].buffer_hs .nbytes = nbytes ;
366396 }
@@ -372,13 +402,19 @@ static void prepare_ep_xfer(uint8_t rhport, uint8_t ep_id, uint16_t buf_offset,
372402
373403bool dcd_edpt_xfer (uint8_t rhport , uint8_t ep_addr , uint8_t * buffer , uint16_t total_bytes )
374404{
375- (void ) rhport ;
376-
377405 uint8_t const ep_id = ep_addr2id (ep_addr );
378406
379407 tu_memclr (& _dcd .dma [ep_id ], sizeof (xfer_dma_t ));
380408 _dcd .dma [ep_id ].total_bytes = total_bytes ;
381409
410+ if (!buffer )
411+ {
412+ // Although having no data, ZLPs can cause buffer overwritten to zeroes.
413+ // Probably due to USB/DMA controller side effect/bug.
414+ // Assigned buffer offset to (valid) dummy to prevent overwriting to DATABUFSTART
415+ buffer = (uint8_t * )(uint32_t )dummy ;
416+ }
417+
382418 prepare_ep_xfer (rhport , ep_id , get_buf_offset (buffer ), total_bytes );
383419
384420 return true;
@@ -390,15 +426,14 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t to
390426static void bus_reset (uint8_t rhport )
391427{
392428 tu_memclr (& _dcd , sizeof (dcd_data_t ));
429+ edpt_reset_all (rhport );
393430
394- // disable all non-control endpoints on bus reset
395- for (uint8_t ep_id = 2 ; ep_id < 2 * MAX_EP_PAIRS ; ep_id ++ )
431+ // disable all endpoints as specified by LPC55S69 UM Table 778
432+ for (uint8_t ep_id = 0 ; ep_id < 2 * MAX_EP_PAIRS ; ep_id ++ )
396433 {
397434 _dcd .ep [ep_id ][0 ].disable = _dcd .ep [ep_id ][1 ].disable = 1 ;
398435 }
399436
400- prepare_setup_packet (rhport );
401-
402437 dcd_registers_t * dcd_reg = _dcd_controller [rhport ].regs ;
403438
404439 dcd_reg -> EPINUSE = 0 ;
@@ -506,23 +541,15 @@ void dcd_int_handler(uint8_t rhport)
506541 }
507542 }
508543
509- // TODO support suspend & resume
510544 if (cmd_stat & CMDSTAT_SUSPEND_CHANGE_MASK )
511545 {
512- if (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK )
513- { // suspend signal, bus idle for more than 3ms
514- // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
515- if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK )
516- {
517- dcd_event_bus_signal (rhport , DCD_EVENT_SUSPEND , true);
518- }
546+ // suspend signal, bus idle for more than 3ms
547+ // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
548+ if (cmd_stat & CMDSTAT_DEVICE_ADDR_MASK )
549+ {
550+ dcd_event_bus_signal (rhport , (cmd_stat & CMDSTAT_DEVICE_SUSPEND_MASK ) ? DCD_EVENT_SUSPEND : DCD_EVENT_RESUME , true);
519551 }
520552 }
521- // else
522- // { // resume signal
523- // dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
524- // }
525- // }
526553 }
527554
528555 // Setup Receive
0 commit comments