Kaynağa Gözat

added usbd_edpt_xfer/usbd_edpt_busy to replace dcd_edpt_transfer/dcd_edpt_busy()

- improve fifo write/read_n with only one lock
- use usbd_edpt_xfer/usbd_edpt_busy for hid/cdc/msc class driver
- replace cdc read's pending_read_from_host by usbd_edpt_busy()
hathach 6 yıl önce
ebeveyn
işleme
a0307bafda

+ 1 - 1
examples/device/cdc_msc_hid/src/main.c

@@ -201,7 +201,7 @@ void hid_task(void)
       tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0);
       tud_hid_mouse_report(REPORT_ID_MOUSE, 0x00, delta, delta, 0, 0);
 
 
       // delay a bit before attempt to send keyboard report
       // delay a bit before attempt to send keyboard report
-      board_delay(2);
+      board_delay(10);
     }
     }
   }
   }
 
 

+ 9 - 11
src/class/cdc/cdc_device.c

@@ -73,23 +73,21 @@ typedef struct
 //--------------------------------------------------------------------+
 //--------------------------------------------------------------------+
 CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
 CFG_TUSB_MEM_SECTION static cdcd_interface_t _cdcd_itf[CFG_TUD_CDC];
 
 
-// TODO will be replaced by dcd_edpt_busy()
-bool pending_read_from_host;
+//bool pending_read_from_host; TODO remove
 static void _prep_out_transaction (uint8_t itf)
 static void _prep_out_transaction (uint8_t itf)
 {
 {
   cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
   cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
 
 
   // skip if previous transfer not complete
   // skip if previous transfer not complete
-  // dcd_edpt_busy() doesn't work, probably transfer is complete but not properly handled by the stack
-//  if ( dcd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_out) ) return;
-  if (pending_read_from_host) return;
+  if ( usbd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_out) ) return;
+  //if (pending_read_from_host) return;
 
 
   // Prepare for incoming data but only allow what we can store in the ring buffer.
   // Prepare for incoming data but only allow what we can store in the ring buffer.
   uint16_t max_read = tu_fifo_remaining(&p_cdc->rx_ff);
   uint16_t max_read = tu_fifo_remaining(&p_cdc->rx_ff);
   if ( max_read >= CFG_TUD_CDC_EPSIZE )
   if ( max_read >= CFG_TUD_CDC_EPSIZE )
   {
   {
-    dcd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_out, p_cdc->epout_buf, CFG_TUD_CDC_EPSIZE);
-    pending_read_from_host = true;
+    usbd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_out, p_cdc->epout_buf, CFG_TUD_CDC_EPSIZE);
+//    pending_read_from_host = true;
   }
   }
 }
 }
 
 
@@ -183,13 +181,13 @@ uint32_t tud_cdc_n_write(uint8_t itf, void const* buffer, uint32_t bufsize)
 bool tud_cdc_n_write_flush (uint8_t itf)
 bool tud_cdc_n_write_flush (uint8_t itf)
 {
 {
   cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
   cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
-  TU_VERIFY( !dcd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_in) ); // skip if previous transfer not complete
+  TU_VERIFY( !usbd_edpt_busy(TUD_OPT_RHPORT, p_cdc->ep_in) ); // skip if previous transfer not complete
 
 
   uint16_t count = tu_fifo_read_n(&_cdcd_itf[itf].tx_ff, p_cdc->epin_buf, CFG_TUD_CDC_EPSIZE);
   uint16_t count = tu_fifo_read_n(&_cdcd_itf[itf].tx_ff, p_cdc->epin_buf, CFG_TUD_CDC_EPSIZE);
   if ( count )
   if ( count )
   {
   {
     TU_VERIFY( tud_cdc_n_connected(itf) ); // fifo is empty if not connected
     TU_VERIFY( tud_cdc_n_connected(itf) ); // fifo is empty if not connected
-    TU_ASSERT( dcd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_in, p_cdc->epin_buf, count) );
+    TU_ASSERT( usbd_edpt_xfer(TUD_OPT_RHPORT, p_cdc->ep_in, p_cdc->epin_buf, count) );
   }
   }
 
 
   return true;
   return true;
@@ -298,7 +296,7 @@ bool cdcd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t
   }
   }
 
 
   // Prepare for incoming data
   // Prepare for incoming data
-  pending_read_from_host = false;
+//  pending_read_from_host = false;
   _prep_out_transaction(cdc_id);
   _prep_out_transaction(cdc_id);
 
 
   return true;
   return true;
@@ -394,7 +392,7 @@ bool cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
     if (tud_cdc_rx_cb && tu_fifo_count(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf);
     if (tud_cdc_rx_cb && tu_fifo_count(&p_cdc->rx_ff) ) tud_cdc_rx_cb(itf);
 
 
     // prepare for OUT transaction
     // prepare for OUT transaction
-    pending_read_from_host = false;
+//    pending_read_from_host = false;
     _prep_out_transaction(itf);
     _prep_out_transaction(itf);
   }
   }
 
 

+ 9 - 6
src/class/hid/hid_device.c

@@ -73,28 +73,31 @@ bool tud_hid_ready(void)
 {
 {
   uint8_t itf = 0;
   uint8_t itf = 0;
   uint8_t const ep_in = _hidd_itf[itf].ep_in;
   uint8_t const ep_in = _hidd_itf[itf].ep_in;
-  return tud_ready() && (ep_in != 0) && !dcd_edpt_busy(TUD_OPT_RHPORT, ep_in);
+  return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(TUD_OPT_RHPORT, ep_in);
 }
 }
 
 
 bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len)
 bool tud_hid_report(uint8_t report_id, void const* report, uint8_t len)
 {
 {
-  TU_VERIFY( tud_hid_ready() && (len <= CFG_TUD_HID_BUFSIZE) );
+  TU_VERIFY( tud_hid_ready() );
 
 
   uint8_t itf = 0;
   uint8_t itf = 0;
   hidd_interface_t * p_hid = &_hidd_itf[itf];
   hidd_interface_t * p_hid = &_hidd_itf[itf];
 
 
-  // If report id = 0, skip ID field
   if (report_id)
   if (report_id)
   {
   {
+    len = tu_min8(len, CFG_TUD_HID_BUFSIZE-1);
+
     p_hid->epin_buf[0] = report_id;
     p_hid->epin_buf[0] = report_id;
     memcpy(p_hid->epin_buf+1, report, len);
     memcpy(p_hid->epin_buf+1, report, len);
     len++;
     len++;
   }else
   }else
   {
   {
+    // If report id = 0, skip ID field
+    len = tu_min8(len, CFG_TUD_HID_BUFSIZE);
     memcpy(p_hid->epin_buf, report, len);
     memcpy(p_hid->epin_buf, report, len);
   }
   }
 
 
-  return dcd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->epin_buf, len);
+  return usbd_edpt_xfer(TUD_OPT_RHPORT, p_hid->ep_in, p_hid->epin_buf, len);
 }
 }
 
 
 bool tud_hid_boot_mode(void)
 bool tud_hid_boot_mode(void)
@@ -180,7 +183,7 @@ bool hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t
   *p_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
   *p_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
 
 
   // Prepare for output endpoint
   // Prepare for output endpoint
-  if (p_hid->ep_out) TU_ASSERT(dcd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
+  if (p_hid->ep_out) TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
 
 
   return true;
   return true;
 }
 }
@@ -303,7 +306,7 @@ bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_
   if (ep_addr == p_hid->ep_out)
   if (ep_addr == p_hid->ep_out)
   {
   {
     tud_hid_set_report_cb(0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, xferred_bytes);
     tud_hid_set_report_cb(0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, xferred_bytes);
-    TU_ASSERT(dcd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
+    TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
   }
   }
 
 
   return true;
   return true;

+ 7 - 7
src/class/msc/msc_device.c

@@ -139,7 +139,7 @@ bool mscd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t
   (*p_len) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
   (*p_len) = sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t);
 
 
   // Prepare for Command Block Wrapper
   // Prepare for Command Block Wrapper
-  TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)) );
+  TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)) );
 
 
   return true;
   return true;
 }
 }
@@ -394,7 +394,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
         if ( (p_cbw->total_bytes > 0 ) && !tu_bit_test(p_cbw->dir, 7) )
         if ( (p_cbw->total_bytes > 0 ) && !tu_bit_test(p_cbw->dir, 7) )
         {
         {
           // queue transfer
           // queue transfer
-          TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
+          TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, p_msc->total_len) );
         }else
         }else
         {
         {
           int32_t resplen;
           int32_t resplen;
@@ -428,7 +428,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
             if (p_msc->total_len)
             if (p_msc->total_len)
             {
             {
               TU_ASSERT( p_cbw->total_bytes >= p_msc->total_len ); // cannot return more than host expect
               TU_ASSERT( p_cbw->total_bytes >= p_msc->total_len ); // cannot return more than host expect
-              TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
+              TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, p_msc->total_len) );
             }else
             }else
             {
             {
               p_msc->stage = MSC_STAGE_STATUS;
               p_msc->stage = MSC_STAGE_STATUS;
@@ -543,7 +543,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
       p_msc->stage = MSC_STAGE_CMD;
       p_msc->stage = MSC_STAGE_CMD;
 
 
       // Send SCSI Status
       // Send SCSI Status
-      TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)) );
+      TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in , (uint8_t*) &p_msc->csw, sizeof(msc_csw_t)) );
 
 
       // Invoke complete callback if defined
       // Invoke complete callback if defined
       if ( SCSI_CMD_READ_10 == p_cbw->command[0])
       if ( SCSI_CMD_READ_10 == p_cbw->command[0])
@@ -560,7 +560,7 @@ bool mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t
       }
       }
 
 
       // Queue for the next CBW
       // Queue for the next CBW
-      TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)) );
+      TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)) );
     }
     }
   }
   }
 
 
@@ -602,7 +602,7 @@ static void proc_read10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
   }
   }
   else
   else
   {
   {
-    TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, nbytes), );
+    TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_in, _mscd_buf, nbytes), );
   }
   }
 }
 }
 
 
@@ -627,7 +627,7 @@ static void proc_write10_cmd(uint8_t rhport, mscd_interface_t* p_msc)
   int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len);
   int32_t nbytes = (int32_t) tu_min32(sizeof(_mscd_buf), p_cbw->total_bytes-p_msc->xferred_len);
 
 
   // Write10 callback will be called later when usb transfer complete
   // Write10 callback will be called later when usb transfer complete
-  TU_ASSERT( dcd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), );
+  TU_ASSERT( usbd_edpt_xfer(rhport, p_msc->ep_out, _mscd_buf, nbytes), );
 }
 }
 
 
 #endif
 #endif

+ 61 - 39
src/common/tusb_fifo.c

@@ -71,6 +71,35 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si
   return true;
   return true;
 }
 }
 
 
+// retrieve data from fifo
+static void _tu_ff_pull(tu_fifo_t* f, void * buffer)
+{
+  memcpy(buffer,
+         f->buffer + (f->rd_idx * f->item_size),
+         f->item_size);
+
+  f->rd_idx = (f->rd_idx + 1) % f->depth;
+  f->count--;
+}
+
+// send data to fifo
+static void _tu_ff_push(tu_fifo_t* f, void const * data)
+{
+  memcpy( f->buffer + (f->wr_idx * f->item_size),
+          data,
+          f->item_size);
+
+  f->wr_idx = (f->wr_idx + 1) % f->depth;
+
+  if (tu_fifo_full(f))
+  {
+    f->rd_idx = f->wr_idx; // keep the full state (rd == wr && len = size)
+  }
+  else
+  {
+    f->count++;
+  }
+}
 
 
 /******************************************************************************/
 /******************************************************************************/
 /*!
 /*!
@@ -82,23 +111,19 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si
 
 
     @param[in]  f
     @param[in]  f
                 Pointer to the FIFO buffer to manipulate
                 Pointer to the FIFO buffer to manipulate
-    @param[in]  p_buffer
+    @param[in]  buffer
                 Pointer to the place holder for data read from the buffer
                 Pointer to the place holder for data read from the buffer
 
 
     @returns TRUE if the queue is not empty
     @returns TRUE if the queue is not empty
 */
 */
 /******************************************************************************/
 /******************************************************************************/
-bool tu_fifo_read(tu_fifo_t* f, void * p_buffer)
+bool tu_fifo_read(tu_fifo_t* f, void * buffer)
 {
 {
   if( tu_fifo_empty(f) ) return false;
   if( tu_fifo_empty(f) ) return false;
 
 
   tu_fifo_lock(f);
   tu_fifo_lock(f);
 
 
-  memcpy(p_buffer,
-         f->buffer + (f->rd_idx * f->item_size),
-         f->item_size);
-  f->rd_idx = (f->rd_idx + 1) % f->depth;
-  f->count--;
+  _tu_ff_pull(f, buffer);
 
 
   tu_fifo_unlock(f);
   tu_fifo_unlock(f);
 
 
@@ -113,7 +138,7 @@ bool tu_fifo_read(tu_fifo_t* f, void * p_buffer)
 
 
     @param[in]  f
     @param[in]  f
                 Pointer to the FIFO buffer to manipulate
                 Pointer to the FIFO buffer to manipulate
-    @param[in]  p_data
+    @param[in]  buffer
                 The pointer to data location
                 The pointer to data location
     @param[in]  count
     @param[in]  count
                 Number of element that buffer can afford
                 Number of element that buffer can afford
@@ -121,27 +146,28 @@ bool tu_fifo_read(tu_fifo_t* f, void * p_buffer)
     @returns number of items read from the FIFO
     @returns number of items read from the FIFO
 */
 */
 /******************************************************************************/
 /******************************************************************************/
-uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t count)
+uint16_t tu_fifo_read_n (tu_fifo_t* f, void * buffer, uint16_t count)
 {
 {
   if( tu_fifo_empty(f) ) return 0;
   if( tu_fifo_empty(f) ) return 0;
 
 
+  tu_fifo_lock(f);
+
   /* Limit up to fifo's count */
   /* Limit up to fifo's count */
   if ( count > f->count ) count = f->count;
   if ( count > f->count ) count = f->count;
 
 
-  /* Could copy up to 2 portions marked as 'x' if queue is wrapped around
-   * case 1: ....RxxxxW.......
-   * case 2: xxxxxW....Rxxxxxx
-   */
-//  uint16_t index2upper = tu_min16(count, f->count-f->rd_idx);
-
-  uint8_t* p_buf = (uint8_t*) p_buffer;
+  uint8_t* buf8 = (uint8_t*) buffer;
   uint16_t len = 0;
   uint16_t len = 0;
-  while( (len < count) && tu_fifo_read(f, p_buf) )
+
+  while (len < count)
   {
   {
+    _tu_ff_pull(f, buf8);
+
     len++;
     len++;
-    p_buf += f->item_size;
+    buf8 += f->item_size;
   }
   }
 
 
+  tu_fifo_unlock(f);
+
   return len;
   return len;
 }
 }
 
 
@@ -182,33 +208,20 @@ bool tu_fifo_peek_at(tu_fifo_t* f, uint16_t pos, void * p_buffer)
 
 
     @param[in]  f
     @param[in]  f
                 Pointer to the FIFO buffer to manipulate
                 Pointer to the FIFO buffer to manipulate
-    @param[in]  p_data
+    @param[in]  data
                 The byte to add to the FIFO
                 The byte to add to the FIFO
 
 
     @returns TRUE if the data was written to the FIFO (overwrittable
     @returns TRUE if the data was written to the FIFO (overwrittable
              FIFO will always return TRUE)
              FIFO will always return TRUE)
 */
 */
 /******************************************************************************/
 /******************************************************************************/
-bool tu_fifo_write (tu_fifo_t* f, const void * p_data)
+bool tu_fifo_write (tu_fifo_t* f, const void * data)
 {
 {
   if ( tu_fifo_full(f) && !f->overwritable ) return false;
   if ( tu_fifo_full(f) && !f->overwritable ) return false;
 
 
   tu_fifo_lock(f);
   tu_fifo_lock(f);
 
 
-  memcpy( f->buffer + (f->wr_idx * f->item_size),
-          p_data,
-          f->item_size);
-
-  f->wr_idx = (f->wr_idx + 1) % f->depth;
-
-  if (tu_fifo_full(f))
-  {
-    f->rd_idx = f->wr_idx; // keep the full state (rd == wr && len = size)
-  }
-  else
-  {
-    f->count++;
-  }
+  _tu_ff_push(f, data);
 
 
   tu_fifo_unlock(f);
   tu_fifo_unlock(f);
 
 
@@ -223,26 +236,35 @@ bool tu_fifo_write (tu_fifo_t* f, const void * p_data)
 
 
     @param[in]  f
     @param[in]  f
                 Pointer to the FIFO buffer to manipulate
                 Pointer to the FIFO buffer to manipulate
-    @param[in]  p_data
+    @param[in]  data
                 The pointer to data to add to the FIFO
                 The pointer to data to add to the FIFO
     @param[in]  count
     @param[in]  count
                 Number of element
                 Number of element
     @return Number of written elements
     @return Number of written elements
 */
 */
 /******************************************************************************/
 /******************************************************************************/
-uint16_t tu_fifo_write_n (tu_fifo_t* f, const void * p_data, uint16_t count)
+uint16_t tu_fifo_write_n (tu_fifo_t* f, const void * data, uint16_t count)
 {
 {
   if ( count == 0 ) return 0;
   if ( count == 0 ) return 0;
 
 
-  uint8_t const* p_buf = (uint8_t const*) p_data;
+  tu_fifo_lock(f);
+
+  // Not overwritable limit up to full
+  if (!f->overwritable) count = tu_min16(count, tu_fifo_remaining(f));
 
 
+  uint8_t const* buf8 = (uint8_t const*) data;
   uint16_t len = 0;
   uint16_t len = 0;
-  while( (len < count) && tu_fifo_write(f, p_buf) )
+
+  while (len < count)
   {
   {
+    _tu_ff_push(f, buf8);
+
     len++;
     len++;
-    p_buf += f->item_size;
+    buf8 += f->item_size;
   }
   }
 
 
+  tu_fifo_unlock(f);
+
   return len;
   return len;
 }
 }
 
 

+ 13 - 10
src/device/dcd.h

@@ -100,25 +100,28 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num);
 // Wake up host
 // Wake up host
 void dcd_remote_wakeup(uint8_t rhport);
 void dcd_remote_wakeup(uint8_t rhport);
 
 
-/*------------------------------------------------------------------*/
-/* Endpoint API
- *  - open        : Configure endpoint's registers
- *  - xfer        : Submit a transfer. When complete dcd_event_xfer_complete
- *                  must be called to notify the stack
- *  - busy        : Check if endpoint transferring is complete (TODO remove)
- *  - stall       : stall endpoint
- *  - clear_stall : clear stall, data toggle is also reset to DATA0
- *------------------------------------------------------------------*/
+//--------------------------------------------------------------------+
+// Endpoint API
+//--------------------------------------------------------------------+
+
+// Configure endpoint's registers according to descriptor
 bool dcd_edpt_open        (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
 bool dcd_edpt_open        (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
+
+// Submit a transfer, When complete dcd_event_xfer_complete() is invoked to notify the stack
 bool dcd_edpt_xfer        (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
 bool dcd_edpt_xfer        (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
+
+// Check if endpoint transferring is complete (TODO remove)
 bool dcd_edpt_busy        (uint8_t rhport, uint8_t ep_addr);
 bool dcd_edpt_busy        (uint8_t rhport, uint8_t ep_addr);
 
 
+// Stall endpoint
 void dcd_edpt_stall       (uint8_t rhport, uint8_t ep_addr);
 void dcd_edpt_stall       (uint8_t rhport, uint8_t ep_addr);
+
+// clear stall, data toggle is also reset to DATA0
 void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
 void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
 
 
 /*------------------------------------------------------------------*/
 /*------------------------------------------------------------------*/
 /* Event Function
 /* Event Function
- * Called by DCD to notify USBD
+ * Called by DCD to notify device stack
  *------------------------------------------------------------------*/
  *------------------------------------------------------------------*/
 void dcd_event_handler(dcd_event_t const * event, bool in_isr);
 void dcd_event_handler(dcd_event_t const * event, bool in_isr);
 
 

+ 36 - 7
src/device/usbd.c

@@ -51,8 +51,8 @@ typedef struct {
       uint8_t self_powered          : 1; // configuration descriptor's attribute
       uint8_t self_powered          : 1; // configuration descriptor's attribute
   };
   };
 
 
-//  uint8_t ep_busy_mask[2];  // bit mask for busy endpoint
-  uint8_t ep_stall_mask[2]; // bit mask for stalled endpoint
+  uint8_t ep_busy_map[2];  // bit mask for busy endpoint
+  uint8_t ep_stall_map[2]; // bit map for stalled endpoint
 
 
   uint8_t itf2drv[16];      // map interface number to driver (0xff is invalid)
   uint8_t itf2drv[16];      // map interface number to driver (0xff is invalid)
   uint8_t ep2drv[8][2];     // map endpoint to driver ( 0xff is invalid )
   uint8_t ep2drv[8][2];     // map endpoint to driver ( 0xff is invalid )
@@ -287,6 +287,10 @@ void tud_task (void)
         {
         {
           // Invoke the class callback associated with the endpoint address
           // Invoke the class callback associated with the endpoint address
           uint8_t const ep_addr = event.xfer_complete.ep_addr;
           uint8_t const ep_addr = event.xfer_complete.ep_addr;
+          uint8_t const epnum = tu_edpt_number(ep_addr);
+          uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+          _usbd_dev.ep_busy_map[dir] = (uint8_t) tu_bit_clear(_usbd_dev.ep_busy_map[dir], epnum);
 
 
           if ( 0 == tu_edpt_number(ep_addr) )
           if ( 0 == tu_edpt_number(ep_addr) )
           {
           {
@@ -621,7 +625,7 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
 
 
     case DCD_EVENT_SUSPEND:
     case DCD_EVENT_SUSPEND:
       // NOTE: When plugging/unplugging device, the D+/D- state are unstable and can accidentally meet the
       // NOTE: When plugging/unplugging device, the D+/D- state are unstable and can accidentally meet the
-      // SUSPEND condition ( Idle for 3ms ). Some MCUs such as samd don't distinguish suspend vs disconnect as well.
+      // SUSPEND condition ( Idle for 3ms ). Some MCUs such as SAMD doesn't distinguish suspend vs disconnect as well.
       // We will skip handling SUSPEND/RESUME event if not currently connected
       // We will skip handling SUSPEND/RESUME event if not currently connected
       if ( _usbd_dev.connected )
       if ( _usbd_dev.connected )
       {
       {
@@ -643,7 +647,8 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
     break;
     break;
 
 
     case DCD_EVENT_XFER_COMPLETE:
     case DCD_EVENT_XFER_COMPLETE:
-      // skip zero-length control status complete event, should dcd notifies us.
+      // skip zero-length control status complete event, should DCD notify us.
+      // TODO could cause issue with actual zero length data used by class such as DFU
       if ( (0 == tu_edpt_number(event->xfer_complete.ep_addr)) && (event->xfer_complete.len == 0) ) break;
       if ( (0 == tu_edpt_number(event->xfer_complete.ep_addr)) && (event->xfer_complete.len == 0) ) break;
 
 
       osal_queue_send(_usbd_q, event, in_isr);
       osal_queue_send(_usbd_q, event, in_isr);
@@ -733,13 +738,37 @@ void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr)
 //--------------------------------------------------------------------+
 //--------------------------------------------------------------------+
 // USBD Endpoint API
 // USBD Endpoint API
 //--------------------------------------------------------------------+
 //--------------------------------------------------------------------+
+
+bool usbd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
+{
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  TU_VERIFY( dcd_edpt_xfer(rhport, ep_addr, buffer, total_bytes) );
+
+  _usbd_dev.ep_busy_map[dir] = (uint8_t) tu_bit_set(_usbd_dev.ep_busy_map[dir], epnum);
+
+  return true;
+}
+
+bool usbd_edpt_busy(uint8_t rhport, uint8_t ep_addr)
+{
+  (void) rhport;
+
+  uint8_t const epnum = tu_edpt_number(ep_addr);
+  uint8_t const dir   = tu_edpt_dir(ep_addr);
+
+  return tu_bit_test(_usbd_dev.ep_busy_map[dir], epnum);
+}
+
+
 void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
 void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr)
 {
 {
   uint8_t const epnum = tu_edpt_number(ep_addr);
   uint8_t const epnum = tu_edpt_number(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
 
 
   dcd_edpt_stall(rhport, ep_addr);
   dcd_edpt_stall(rhport, ep_addr);
-  _usbd_dev.ep_stall_mask[dir] = (uint8_t) tu_bit_set(_usbd_dev.ep_stall_mask[dir], epnum);
+  _usbd_dev.ep_stall_map[dir] = (uint8_t) tu_bit_set(_usbd_dev.ep_stall_map[dir], epnum);
 }
 }
 
 
 void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
 void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
@@ -748,7 +777,7 @@ void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr)
   uint8_t const dir   = tu_edpt_dir(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
 
 
   dcd_edpt_clear_stall(rhport, ep_addr);
   dcd_edpt_clear_stall(rhport, ep_addr);
-  _usbd_dev.ep_stall_mask[dir] = (uint8_t) tu_bit_clear(_usbd_dev.ep_stall_mask[dir], epnum);
+  _usbd_dev.ep_stall_map[dir] = (uint8_t) tu_bit_clear(_usbd_dev.ep_stall_map[dir], epnum);
 }
 }
 
 
 bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr)
 bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr)
@@ -758,7 +787,7 @@ bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr)
   uint8_t const epnum = tu_edpt_number(ep_addr);
   uint8_t const epnum = tu_edpt_number(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
   uint8_t const dir   = tu_edpt_dir(ep_addr);
 
 
-  return tu_bit_test(_usbd_dev.ep_stall_mask[dir], epnum);
+  return tu_bit_test(_usbd_dev.ep_stall_map[dir], epnum);
 }
 }
 
 
 #endif
 #endif

+ 9 - 2
src/device/usbd_pvt.h

@@ -33,10 +33,11 @@
  extern "C" {
  extern "C" {
 #endif
 #endif
 
 
+bool usbd_init (void);
+
 //--------------------------------------------------------------------+
 //--------------------------------------------------------------------+
-// INTERNAL API for stack management
+// USBD Endpoint API
 //--------------------------------------------------------------------+
 //--------------------------------------------------------------------+
-bool usbd_init (void);
 
 
 // Carry out Data and Status stage of control transfer
 // Carry out Data and Status stage of control transfer
 // - If len = 0, it is equivalent to sending status only
 // - If len = 0, it is equivalent to sending status only
@@ -46,6 +47,12 @@ bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, v
 // Send STATUS (zero length) packet
 // Send STATUS (zero length) packet
 bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request);
 bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request);
 
 
+// Submit a usb transfer
+bool usbd_edpt_xfer        (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
+
+// Check if endpoint transferring is complete
+bool usbd_edpt_busy        (uint8_t rhport, uint8_t ep_addr);
+
 void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr);
 void usbd_edpt_stall(uint8_t rhport, uint8_t ep_addr);
 void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr);
 void usbd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr);
 bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr);
 bool usbd_edpt_stalled(uint8_t rhport, uint8_t ep_addr);