Merge pull request #7 from tannewt/tinyusb_samd
Add SAMD support and simplify OS_NONE
This commit is contained in:
		@@ -50,6 +50,10 @@
 | 
			
		||||
 extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wpacked"
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wattributes"
 | 
			
		||||
 | 
			
		||||
/** \defgroup ClassDriver_CDC_Common Common Definitions
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
@@ -86,7 +90,8 @@ typedef enum
 | 
			
		||||
/// Communication Interface Protocol Codes
 | 
			
		||||
typedef enum
 | 
			
		||||
{
 | 
			
		||||
  CDC_COMM_PROTOCOL_ATCOMMAND              = 0x01 , ///< AT Commands: V.250 etc
 | 
			
		||||
  CDC_COMM_PROTOCOL_NONE                   = 0x00 , ///< No specific protocol
 | 
			
		||||
  CDC_COMM_PROTOCOL_ATCOMMAND                     , ///< AT Commands: V.250 etc
 | 
			
		||||
  CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101            , ///< AT Commands defined by PCCA-101
 | 
			
		||||
  CDC_COMM_PROTOCOL_ATCOMMAND_PCCA_101_AND_ANNEXO , ///< AT Commands defined by PCCA-101 & Annex O
 | 
			
		||||
  CDC_COMM_PROTOCOL_ATCOMMAND_GSM_707             , ///< AT Commands defined by GSM 07.07
 | 
			
		||||
@@ -401,6 +406,8 @@ typedef struct ATTR_PACKED
 | 
			
		||||
 | 
			
		||||
TU_VERIFY_STATIC(sizeof(cdc_line_control_state_t) == 2, "size is not correct");
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 
 | 
			
		||||
@@ -45,6 +45,7 @@
 | 
			
		||||
// INCLUDE
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
#include "cdc_device.h"
 | 
			
		||||
#include "device/control.h"
 | 
			
		||||
#include "device/usbd_pvt.h"
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
@@ -235,8 +236,10 @@ tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface
 | 
			
		||||
{
 | 
			
		||||
  if ( CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL != p_interface_desc->bInterfaceSubClass) return TUSB_ERROR_CDC_UNSUPPORTED_SUBCLASS;
 | 
			
		||||
 | 
			
		||||
  // Only support AT commands, no protocol and vendor specific commands.
 | 
			
		||||
  if ( !(tu_within(CDC_COMM_PROTOCOL_ATCOMMAND, p_interface_desc->bInterfaceProtocol, CDC_COMM_PROTOCOL_ATCOMMAND_CDMA) ||
 | 
			
		||||
         0xff == p_interface_desc->bInterfaceProtocol) )
 | 
			
		||||
         p_interface_desc->bInterfaceProtocol == CDC_COMM_PROTOCOL_NONE ||
 | 
			
		||||
         p_interface_desc->bInterfaceProtocol == 0xff ) )
 | 
			
		||||
  {
 | 
			
		||||
    return TUSB_ERROR_CDC_UNSUPPORTED_PROTOCOL;
 | 
			
		||||
  }
 | 
			
		||||
@@ -296,10 +299,23 @@ tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t cdcd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
 | 
			
		||||
void cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
 | 
			
		||||
{
 | 
			
		||||
  OSAL_SUBTASK_BEGIN
 | 
			
		||||
  //------------- Class Specific Request -------------//
 | 
			
		||||
  if (p_request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) return;
 | 
			
		||||
 | 
			
		||||
  // TODO Support multiple interfaces
 | 
			
		||||
  uint8_t const itf = 0;
 | 
			
		||||
  cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
 | 
			
		||||
 | 
			
		||||
  // Invoke callback
 | 
			
		||||
  if (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) {
 | 
			
		||||
    if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t cdcd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent)
 | 
			
		||||
{
 | 
			
		||||
  //------------- Class Specific Request -------------//
 | 
			
		||||
  if (p_request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
 | 
			
		||||
 | 
			
		||||
@@ -307,21 +323,18 @@ tusb_error_t cdcd_control_request_st(uint8_t rhport, tusb_control_request_t cons
 | 
			
		||||
  uint8_t const itf = 0;
 | 
			
		||||
  cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
 | 
			
		||||
 | 
			
		||||
  if ( (CDC_REQUEST_GET_LINE_CODING == p_request->bRequest) || (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) )
 | 
			
		||||
  if ((CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) )
 | 
			
		||||
  {
 | 
			
		||||
    uint16_t len = tu_min16(sizeof(cdc_line_coding_t), p_request->wLength);
 | 
			
		||||
    usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, &p_cdc->line_coding, len);
 | 
			
		||||
 | 
			
		||||
    // Invoke callback
 | 
			
		||||
    if (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest)
 | 
			
		||||
    {
 | 
			
		||||
      if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
 | 
			
		||||
    }
 | 
			
		||||
    dcd_edpt_xfer(rhport, 0, (uint8_t*) &p_cdc->line_coding, len);
 | 
			
		||||
  }
 | 
			
		||||
  else if ( (CDC_REQUEST_GET_LINE_CODING == p_request->bRequest))
 | 
			
		||||
  {
 | 
			
		||||
    uint16_t len = tu_min16(sizeof(cdc_line_coding_t), p_request->wLength);
 | 
			
		||||
    dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, (uint8_t*) &p_cdc->line_coding, len);
 | 
			
		||||
  }
 | 
			
		||||
  else if (CDC_REQUEST_SET_CONTROL_LINE_STATE == p_request->bRequest )
 | 
			
		||||
  {
 | 
			
		||||
    dcd_control_status(rhport, p_request->bmRequestType_bit.direction); // ACK control request
 | 
			
		||||
 | 
			
		||||
    // CDC PSTN v1.2 section 6.3.12
 | 
			
		||||
    // Bit 0: Indicates if DTE is present or not.
 | 
			
		||||
    //        This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready)
 | 
			
		||||
@@ -334,10 +347,9 @@ tusb_error_t cdcd_control_request_st(uint8_t rhport, tusb_control_request_t cons
 | 
			
		||||
  }
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dcd_control_stall(rhport); // stall unsupported request
 | 
			
		||||
    return TUSB_ERROR_FAILED; // stall unsupported request
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OSAL_SUBTASK_END
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes)
 | 
			
		||||
 
 | 
			
		||||
@@ -114,7 +114,8 @@ ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_li
 | 
			
		||||
 | 
			
		||||
void         cdcd_init               (void);
 | 
			
		||||
tusb_error_t cdcd_open               (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
 | 
			
		||||
tusb_error_t cdcd_control_request_st (uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
tusb_error_t cdcd_control_request (uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent);
 | 
			
		||||
void cdcd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
tusb_error_t cdcd_xfer_cb            (uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
 | 
			
		||||
void         cdcd_reset              (uint8_t rhport);
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf,
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
 | 
			
		||||
tusb_error_t cusd_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
 | 
			
		||||
{
 | 
			
		||||
  return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -65,6 +65,7 @@
 | 
			
		||||
void cusd_init(void);
 | 
			
		||||
tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
 | 
			
		||||
tusb_error_t cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
void cusd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
tusb_error_t cusd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
 | 
			
		||||
void cusd_reset(uint8_t rhport);
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -49,6 +49,10 @@
 | 
			
		||||
 extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wpacked"
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wattributes"
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// Common Definitions
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
@@ -609,6 +613,7 @@ enum
 | 
			
		||||
  HID_USAGE_CONSUMER_AC_PAN                            = 0x0238,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
@@ -46,6 +46,7 @@
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
#include "common/tusb_common.h"
 | 
			
		||||
#include "hid_device.h"
 | 
			
		||||
#include "device/control.h"
 | 
			
		||||
#include "device/usbd_pvt.h"
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
@@ -402,13 +403,11 @@ tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, u
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
 | 
			
		||||
tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent)
 | 
			
		||||
{
 | 
			
		||||
  hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex );
 | 
			
		||||
  TU_ASSERT(p_hid, TUSB_ERROR_FAILED);
 | 
			
		||||
 | 
			
		||||
  OSAL_SUBTASK_BEGIN
 | 
			
		||||
 | 
			
		||||
  //------------- STD Request -------------//
 | 
			
		||||
  if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
 | 
			
		||||
  {
 | 
			
		||||
@@ -418,14 +417,17 @@ tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t cons
 | 
			
		||||
 | 
			
		||||
    if (p_request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT)
 | 
			
		||||
    {
 | 
			
		||||
      // use device control buffer
 | 
			
		||||
      STASK_ASSERT ( p_hid->desc_len <= CFG_TUD_CTRL_BUFSIZE );
 | 
			
		||||
      memcpy(_usbd_ctrl_buf, p_hid->desc_report, p_hid->desc_len);
 | 
			
		||||
      // TODO: Handle zero length packet.
 | 
			
		||||
      uint16_t remaining_bytes = p_hid->desc_len - bytes_already_sent;
 | 
			
		||||
      if (remaining_bytes > 64) {
 | 
			
		||||
          remaining_bytes = 64;
 | 
			
		||||
      }
 | 
			
		||||
      memcpy(_shared_control_buffer, p_hid->desc_report + bytes_already_sent, remaining_bytes);
 | 
			
		||||
 | 
			
		||||
      usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, p_hid->desc_len);
 | 
			
		||||
      dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, remaining_bytes);
 | 
			
		||||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      dcd_control_stall(rhport);
 | 
			
		||||
      return TUSB_ERROR_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
  //------------- Class Specific Request -------------//
 | 
			
		||||
@@ -447,53 +449,64 @@ tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t cons
 | 
			
		||||
        xferlen = p_request->wLength;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      STASK_ASSERT( xferlen > 0 );
 | 
			
		||||
      usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, p_hid->report_buf, xferlen);
 | 
			
		||||
      TU_ASSERT( xferlen > 0 );
 | 
			
		||||
      dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, xferlen);
 | 
			
		||||
    }
 | 
			
		||||
    else if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, p_request->wLength);
 | 
			
		||||
      dcd_edpt_xfer(rhport, 0, _shared_control_buffer, p_request->wLength);
 | 
			
		||||
    }
 | 
			
		||||
    else if (HID_REQ_CONTROL_SET_IDLE == p_request->bRequest)
 | 
			
		||||
    {
 | 
			
		||||
      // TODO idle rate of report
 | 
			
		||||
      p_hid->idle_rate = tu_u16_high(p_request->wValue);
 | 
			
		||||
    }
 | 
			
		||||
    else if (HID_REQ_CONTROL_GET_IDLE == p_request->bRequest)
 | 
			
		||||
    {
 | 
			
		||||
      // TODO idle rate of report
 | 
			
		||||
      _shared_control_buffer[0] = p_hid->idle_rate;
 | 
			
		||||
      dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1);
 | 
			
		||||
    }
 | 
			
		||||
    else if (HID_REQ_CONTROL_GET_PROTOCOL == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      _shared_control_buffer[0] = 1-p_hid->boot_protocol;   // 0 is Boot, 1 is Report protocol
 | 
			
		||||
      dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1);
 | 
			
		||||
    }
 | 
			
		||||
    else if (HID_REQ_CONTROL_SET_PROTOCOL == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      p_hid->boot_protocol = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol
 | 
			
		||||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      return TUSB_ERROR_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    return TUSB_ERROR_FAILED;
 | 
			
		||||
  }
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
 | 
			
		||||
{
 | 
			
		||||
  hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex );
 | 
			
		||||
  if (p_hid == NULL) {
 | 
			
		||||
      return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
 | 
			
		||||
  {
 | 
			
		||||
    if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      // wValue = Report Type | Report ID
 | 
			
		||||
      uint8_t const report_type = tu_u16_high(p_request->wValue);
 | 
			
		||||
      uint8_t const report_id   = tu_u16_low(p_request->wValue);
 | 
			
		||||
 | 
			
		||||
      if ( p_hid->set_report_cb )
 | 
			
		||||
      {
 | 
			
		||||
        p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, _usbd_ctrl_buf, p_request->wLength);
 | 
			
		||||
        p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, _shared_control_buffer, p_request->wLength);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if (HID_REQ_CONTROL_SET_IDLE == p_request->bRequest)
 | 
			
		||||
    {
 | 
			
		||||
      // TODO idle rate of report
 | 
			
		||||
      p_hid->idle_rate = tu_u16_high(p_request->wValue);
 | 
			
		||||
      dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
    }
 | 
			
		||||
    else if (HID_REQ_CONTROL_GET_IDLE == p_request->bRequest)
 | 
			
		||||
    {
 | 
			
		||||
      // TODO idle rate of report
 | 
			
		||||
      _usbd_ctrl_buf[0] = p_hid->idle_rate;
 | 
			
		||||
      usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, 1);
 | 
			
		||||
    }
 | 
			
		||||
    else if (HID_REQ_CONTROL_GET_PROTOCOL == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      _usbd_ctrl_buf[0] = 1-p_hid->boot_protocol;   // 0 is Boot, 1 is Report protocol
 | 
			
		||||
      usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, 1);
 | 
			
		||||
    }
 | 
			
		||||
    else if (HID_REQ_CONTROL_SET_PROTOCOL == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      p_hid->boot_protocol = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol
 | 
			
		||||
      dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      dcd_control_stall(rhport);
 | 
			
		||||
    }
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    dcd_control_stall(rhport);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OSAL_SUBTASK_END
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes)
 | 
			
		||||
 
 | 
			
		||||
@@ -378,7 +378,8 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t
 | 
			
		||||
 | 
			
		||||
void hidd_init(void);
 | 
			
		||||
tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
 | 
			
		||||
tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent);
 | 
			
		||||
void hidd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
 | 
			
		||||
void hidd_reset(uint8_t rhport);
 | 
			
		||||
 | 
			
		||||
@@ -389,5 +390,3 @@ void hidd_reset(uint8_t rhport);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _TUSB_HID_DEVICE_H_ */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -52,6 +52,10 @@
 | 
			
		||||
 extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wpacked"
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wattributes"
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// Mass Storage Class Constant
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
@@ -279,11 +283,13 @@ typedef struct ATTR_PACKED
 | 
			
		||||
 | 
			
		||||
TU_VERIFY_STATIC( sizeof(scsi_mode_sense6_t) == 6, "size is not correct");
 | 
			
		||||
 | 
			
		||||
// This is only a Mode parameter header(6).
 | 
			
		||||
typedef struct ATTR_PACKED
 | 
			
		||||
{
 | 
			
		||||
  uint8_t data_len;
 | 
			
		||||
  uint8_t medium_type;
 | 
			
		||||
  uint8_t device_specific_para;
 | 
			
		||||
  bool write_protected : 1;
 | 
			
		||||
  uint8_t reserved : 7;
 | 
			
		||||
  uint8_t block_descriptor_len;
 | 
			
		||||
} scsi_mode_sense6_resp_t;
 | 
			
		||||
 | 
			
		||||
@@ -390,6 +396,8 @@ typedef struct ATTR_PACKED
 | 
			
		||||
TU_VERIFY_STATIC(sizeof(scsi_read10_t) == 10, "size is not correct");
 | 
			
		||||
TU_VERIFY_STATIC(sizeof(scsi_write10_t) == 10, "size is not correct");
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 }
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -47,6 +47,7 @@
 | 
			
		||||
 | 
			
		||||
#include "common/tusb_common.h"
 | 
			
		||||
#include "msc_device.h"
 | 
			
		||||
#include "device/control.h"
 | 
			
		||||
#include "device/usbd_pvt.h"
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
@@ -59,31 +60,7 @@ enum
 | 
			
		||||
  MSC_STAGE_STATUS
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  CFG_TUSB_MEM_ALIGN msc_cbw_t  cbw;
 | 
			
		||||
 | 
			
		||||
//#if defined (__ICCARM__) && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13UXX)
 | 
			
		||||
//  uint8_t padding1[64-sizeof(msc_cbw_t)]; // IAR cannot align struct's member
 | 
			
		||||
//#endif
 | 
			
		||||
 | 
			
		||||
  CFG_TUSB_MEM_ALIGN msc_csw_t csw;
 | 
			
		||||
 | 
			
		||||
  uint8_t  itf_num;
 | 
			
		||||
  uint8_t  ep_in;
 | 
			
		||||
  uint8_t  ep_out;
 | 
			
		||||
 | 
			
		||||
  // Bulk Only Transfer (BOT) Protocol
 | 
			
		||||
  uint8_t  stage;
 | 
			
		||||
  uint32_t total_len;
 | 
			
		||||
  uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage
 | 
			
		||||
 | 
			
		||||
  // Sense Response Data
 | 
			
		||||
  uint8_t sense_key;
 | 
			
		||||
  uint8_t add_sense_code;
 | 
			
		||||
  uint8_t add_sense_qualifier;
 | 
			
		||||
}mscd_interface_t;
 | 
			
		||||
 | 
			
		||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf;
 | 
			
		||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN mscd_interface_t _mscd_itf;
 | 
			
		||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_BUFSIZE];
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
@@ -170,29 +147,41 @@ tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf,
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t mscd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
 | 
			
		||||
tusb_error_t mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent)
 | 
			
		||||
{
 | 
			
		||||
  OSAL_SUBTASK_BEGIN
 | 
			
		||||
 | 
			
		||||
  TU_ASSERT(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS, TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT);
 | 
			
		||||
 | 
			
		||||
  if(MSC_REQ_RESET == p_request->bRequest)
 | 
			
		||||
  {
 | 
			
		||||
    dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
    // TODO: Actually reset.
 | 
			
		||||
  }
 | 
			
		||||
  else if (MSC_REQ_GET_MAX_LUN == p_request->bRequest)
 | 
			
		||||
  {
 | 
			
		||||
    // returned MAX LUN is minus 1 by specs
 | 
			
		||||
    _usbd_ctrl_buf[0] = CFG_TUD_MSC_MAXLUN-1;
 | 
			
		||||
    usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, 1);
 | 
			
		||||
    _shared_control_buffer[0] = CFG_TUD_MSC_MAXLUN-1;
 | 
			
		||||
    dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1);
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    dcd_control_stall(rhport); // stall unsupported request
 | 
			
		||||
    return TUSB_ERROR_FAILED; // stall unsupported request
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OSAL_SUBTASK_END
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
 | 
			
		||||
{
 | 
			
		||||
  return;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// For backwards compatibility we support static block counts.
 | 
			
		||||
#if defined(CFG_TUD_MSC_BLOCK_NUM) && defined(CFG_TUD_MSC_BLOCK_SZ)
 | 
			
		||||
ATTR_WEAK bool tud_lun_capacity_cb(uint8_t lun, uint32_t* last_valid_sector, uint16_t* block_size) {
 | 
			
		||||
    (void) lun;
 | 
			
		||||
    *last_valid_sector = CFG_TUD_MSC_BLOCK_NUM-1;
 | 
			
		||||
    *block_size = CFG_TUD_MSC_BLOCK_SZ;
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// return length of response (copied to buffer), -1 if it is not an built-in commands
 | 
			
		||||
int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t bufsize)
 | 
			
		||||
{
 | 
			
		||||
@@ -202,11 +191,13 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
 | 
			
		||||
  {
 | 
			
		||||
    case SCSI_CMD_READ_CAPACITY_10:
 | 
			
		||||
    {
 | 
			
		||||
      scsi_read_capacity10_resp_t read_capa10 =
 | 
			
		||||
      {
 | 
			
		||||
          .last_lba   = ENDIAN_BE(CFG_TUD_MSC_BLOCK_NUM-1), // read capacity
 | 
			
		||||
          .block_size = ENDIAN_BE(CFG_TUD_MSC_BLOCK_SZ)
 | 
			
		||||
      };
 | 
			
		||||
      scsi_read_capacity10_resp_t read_capa10;
 | 
			
		||||
 | 
			
		||||
      uint32_t last_valid_sector;
 | 
			
		||||
      uint16_t block_size;
 | 
			
		||||
      tud_lun_capacity_cb(p_cbw->lun, &last_valid_sector, &block_size);
 | 
			
		||||
      read_capa10.last_lba = ENDIAN_BE(last_valid_sector); // read capacity
 | 
			
		||||
      read_capa10.block_size = ENDIAN_BE(block_size);
 | 
			
		||||
 | 
			
		||||
      ret = sizeof(read_capa10);
 | 
			
		||||
      memcpy(buffer, &read_capa10, ret);
 | 
			
		||||
@@ -218,11 +209,17 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
 | 
			
		||||
      scsi_read_format_capacity_data_t read_fmt_capa =
 | 
			
		||||
      {
 | 
			
		||||
          .list_length     = 8,
 | 
			
		||||
          .block_num       = ENDIAN_BE(CFG_TUD_MSC_BLOCK_NUM),  // write capacity
 | 
			
		||||
          .block_num       = 0,
 | 
			
		||||
          .descriptor_type = 2,                                 // formatted media
 | 
			
		||||
          .block_size_u16  = ENDIAN_BE16(CFG_TUD_MSC_BLOCK_SZ)
 | 
			
		||||
          .block_size_u16  = 0
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      uint32_t last_valid_sector;
 | 
			
		||||
      uint16_t block_size;
 | 
			
		||||
      tud_lun_capacity_cb(p_cbw->lun, &last_valid_sector, &block_size);
 | 
			
		||||
      read_fmt_capa.block_num = ENDIAN_BE(last_valid_sector+1);
 | 
			
		||||
      read_fmt_capa.block_size_u16 = ENDIAN_BE16(block_size);
 | 
			
		||||
 | 
			
		||||
      ret = sizeof(read_fmt_capa);
 | 
			
		||||
      memcpy(buffer, &read_fmt_capa, ret);
 | 
			
		||||
    }
 | 
			
		||||
@@ -251,13 +248,21 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
 | 
			
		||||
 | 
			
		||||
    case SCSI_CMD_MODE_SENSE_6:
 | 
			
		||||
    {
 | 
			
		||||
      scsi_mode_sense6_resp_t const mode_resp = {
 | 
			
		||||
        .data_len = 3,
 | 
			
		||||
        .medium_type = 0,
 | 
			
		||||
        .device_specific_para = 0,
 | 
			
		||||
        .block_descriptor_len = 0    // no block descriptor are included
 | 
			
		||||
      scsi_mode_sense6_resp_t mode_resp =
 | 
			
		||||
      {
 | 
			
		||||
          .data_len = 3,
 | 
			
		||||
          .medium_type = 0,
 | 
			
		||||
          .write_protected = false,
 | 
			
		||||
          .reserved = 0,
 | 
			
		||||
          .block_descriptor_len = 0  // no block descriptor are included
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      bool writable = true;
 | 
			
		||||
      if (tud_msc_is_writable_cb) {
 | 
			
		||||
          writable = tud_msc_is_writable_cb(p_cbw->lun);
 | 
			
		||||
      }
 | 
			
		||||
      mode_resp.write_protected = !writable;
 | 
			
		||||
 | 
			
		||||
      ret = sizeof(mode_resp);
 | 
			
		||||
      memcpy(buffer, &mode_resp, ret);
 | 
			
		||||
    }
 | 
			
		||||
@@ -291,7 +296,7 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
 | 
			
		||||
  return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes)
 | 
			
		||||
tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, uint8_t event, uint32_t xferred_bytes)
 | 
			
		||||
{
 | 
			
		||||
  mscd_interface_t* p_msc = &_mscd_itf;
 | 
			
		||||
  msc_cbw_t const * p_cbw = &p_msc->cbw;
 | 
			
		||||
@@ -425,7 +430,7 @@ tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, u
 | 
			
		||||
          }else
 | 
			
		||||
          {
 | 
			
		||||
            // Application consume less than what we got (including zero)
 | 
			
		||||
            if ( nbytes < xferred_bytes )
 | 
			
		||||
            if ( nbytes < (int32_t) xferred_bytes )
 | 
			
		||||
            {
 | 
			
		||||
              if ( nbytes > 0 )
 | 
			
		||||
              {
 | 
			
		||||
 
 | 
			
		||||
@@ -55,14 +55,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
 | 
			
		||||
  #error MSC Device: Incorrect setting of MAX LUN
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef CFG_TUD_MSC_BLOCK_NUM
 | 
			
		||||
  #error CFG_TUD_MSC_BLOCK_NUM must be defined
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef CFG_TUD_MSC_BLOCK_SZ
 | 
			
		||||
  #error CFG_TUD_MSC_BLOCK_SZ must be defined
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifndef CFG_TUD_MSC_BUFSIZE
 | 
			
		||||
  #error CFG_TUD_MSC_BUFSIZE must be defined, value of CFG_TUD_MSC_BLOCK_SZ should work well, the more the better
 | 
			
		||||
#endif
 | 
			
		||||
@@ -89,6 +81,32 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
 | 
			
		||||
 extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
  CFG_TUSB_MEM_ALIGN msc_cbw_t  cbw;
 | 
			
		||||
 | 
			
		||||
//#if defined (__ICCARM__) && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13UXX)
 | 
			
		||||
//  uint8_t padding1[64-sizeof(msc_cbw_t)]; // IAR cannot align struct's member
 | 
			
		||||
//#endif
 | 
			
		||||
 | 
			
		||||
  CFG_TUSB_MEM_ALIGN msc_csw_t csw;
 | 
			
		||||
 | 
			
		||||
  uint8_t  itf_num;
 | 
			
		||||
  uint8_t  ep_in;
 | 
			
		||||
  uint8_t  ep_out;
 | 
			
		||||
 | 
			
		||||
  // Bulk Only Transfer (BOT) Protocol
 | 
			
		||||
  uint8_t  stage;
 | 
			
		||||
  uint32_t total_len;
 | 
			
		||||
  uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage
 | 
			
		||||
 | 
			
		||||
  // Sense Response Data
 | 
			
		||||
  uint8_t sense_key;
 | 
			
		||||
  uint8_t add_sense_code;
 | 
			
		||||
  uint8_t add_sense_qualifier;
 | 
			
		||||
}mscd_interface_t;
 | 
			
		||||
 | 
			
		||||
extern mscd_interface_t _mscd_itf;
 | 
			
		||||
 | 
			
		||||
/** \addtogroup ClassDriver_MSC
 | 
			
		||||
 *  @{
 | 
			
		||||
 * \defgroup MSC_Device Device
 | 
			
		||||
@@ -138,7 +156,7 @@ int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buf
 | 
			
		||||
 * \retval      negative    Indicate error writing disk I/O. Tinyusb will \b STALL the corresponding
 | 
			
		||||
 *                          endpoint and return failed status in command status wrapper phase.
 | 
			
		||||
 */
 | 
			
		||||
int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
 | 
			
		||||
int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Callback invoked when received an SCSI command not in built-in list below.
 | 
			
		||||
@@ -164,6 +182,12 @@ ATTR_WEAK void tud_msc_read10_complete_cb(uint8_t lun);
 | 
			
		||||
ATTR_WEAK void tud_msc_write10_complete_cb(uint8_t lun);
 | 
			
		||||
ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16]);
 | 
			
		||||
 | 
			
		||||
// Hook to make a mass storage device read-only.
 | 
			
		||||
ATTR_WEAK bool tud_msc_is_writable_cb(uint8_t lun);
 | 
			
		||||
 | 
			
		||||
// Override for dynamic LUN sizes.
 | 
			
		||||
ATTR_WEAK bool tud_lun_capacity_cb(uint8_t lun, uint32_t* last_valid_sector, uint16_t* block_size);
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
@@ -174,7 +198,8 @@ ATTR_WEAK void tud_msc_scsi_complete_cb(uint8_t lun, uint8_t const scsi_cmd[16])
 | 
			
		||||
 | 
			
		||||
void mscd_init(void);
 | 
			
		||||
tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
 | 
			
		||||
tusb_error_t mscd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
tusb_error_t mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent);
 | 
			
		||||
void mscd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
 | 
			
		||||
void mscd_reset(uint8_t rhport);
 | 
			
		||||
 | 
			
		||||
@@ -185,4 +210,3 @@ void mscd_reset(uint8_t rhport);
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _TUSB_MSC_DEVICE_H_ */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -51,6 +51,10 @@
 | 
			
		||||
 extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic push
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wpacked"
 | 
			
		||||
#pragma GCC diagnostic ignored "-Wattributes"
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* CONSTANTS
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
@@ -422,6 +426,8 @@ static inline uint8_t descriptor_len(uint8_t const p_desc[])
 | 
			
		||||
// Convert comma-separated string to descriptor unicode format
 | 
			
		||||
#define TUD_DESC_STRCONV( ... )     (const uint16_t[]) { TUD_DESC_STR_HEADER(VA_ARGS_NUM_(__VA_ARGS__)), __VA_ARGS__ }
 | 
			
		||||
 | 
			
		||||
#pragma GCC diagnostic pop
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 }
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										262
									
								
								src/device/control.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										262
									
								
								src/device/control.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,262 @@
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
/*!
 | 
			
		||||
    @file     usbd.c
 | 
			
		||||
    @author   hathach (tinyusb.org)
 | 
			
		||||
 | 
			
		||||
    @section LICENSE
 | 
			
		||||
 | 
			
		||||
    Software License Agreement (BSD License)
 | 
			
		||||
 | 
			
		||||
    Copyright (c) 2013, hathach (tinyusb.org)
 | 
			
		||||
    All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
    documentation and/or other materials provided with the distribution.
 | 
			
		||||
    3. Neither the name of the copyright holders nor the
 | 
			
		||||
    names of its contributors may be used to endorse or promote products
 | 
			
		||||
    derived from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 | 
			
		||||
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 | 
			
		||||
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
			
		||||
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
    This file is part of the tinyusb stack.
 | 
			
		||||
*/
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "tusb_option.h"
 | 
			
		||||
 | 
			
		||||
#if TUSB_OPT_DEVICE_ENABLED
 | 
			
		||||
 | 
			
		||||
#define _TINY_USB_SOURCE_FILE_
 | 
			
		||||
 | 
			
		||||
#include "tusb.h"
 | 
			
		||||
#include "control.h"
 | 
			
		||||
#include "device/usbd_pvt.h"
 | 
			
		||||
 | 
			
		||||
control_t control_state;
 | 
			
		||||
 | 
			
		||||
void controld_reset(uint8_t rhport) {
 | 
			
		||||
    control_state.current_stage = CONTROL_STAGE_SETUP;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void controld_init(void) {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper to send STATUS (zero length) packet
 | 
			
		||||
// Note dir is value of direction bit in setup packet (i.e DATA stage direction)
 | 
			
		||||
static inline bool dcd_control_status(uint8_t rhport, uint8_t dir)
 | 
			
		||||
{
 | 
			
		||||
  uint8_t ep_addr = 0;
 | 
			
		||||
  // Invert the direction.
 | 
			
		||||
  if (dir == TUSB_DIR_OUT) {
 | 
			
		||||
    ep_addr |= TUSB_DIR_IN_MASK;
 | 
			
		||||
  }
 | 
			
		||||
  // status direction is reversed to one in the setup packet
 | 
			
		||||
  return dcd_edpt_xfer(rhport, ep_addr, NULL, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dcd_control_stall(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  dcd_edpt_stall(rhport, 0 | TUSB_DIR_IN_MASK);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
// return len of descriptor and change pointer to descriptor's buffer
 | 
			
		||||
static uint16_t get_descriptor(uint8_t rhport, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
 | 
			
		||||
  uint8_t const desc_index = tu_u16_low( p_request->wValue );
 | 
			
		||||
 | 
			
		||||
  uint8_t const * desc_data = NULL ;
 | 
			
		||||
  uint16_t len = 0;
 | 
			
		||||
 | 
			
		||||
  switch(desc_type)
 | 
			
		||||
  {
 | 
			
		||||
    case TUSB_DESC_DEVICE:
 | 
			
		||||
      desc_data = (uint8_t const *) usbd_desc_set->device;
 | 
			
		||||
      len       = sizeof(tusb_desc_device_t);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    case TUSB_DESC_CONFIGURATION:
 | 
			
		||||
      desc_data = (uint8_t const *) usbd_desc_set->config;
 | 
			
		||||
      len       = ((tusb_desc_configuration_t const*) desc_data)->wTotalLength;
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    case TUSB_DESC_STRING:
 | 
			
		||||
      // String Descriptor always uses the desc set from user
 | 
			
		||||
      if ( desc_index < tud_desc_set.string_count )
 | 
			
		||||
      {
 | 
			
		||||
        desc_data = tud_desc_set.string_arr[desc_index];
 | 
			
		||||
        TU_VERIFY( desc_data != NULL, 0 );
 | 
			
		||||
 | 
			
		||||
        len  = desc_data[0];  // first byte of descriptor is its size
 | 
			
		||||
      }else
 | 
			
		||||
      {
 | 
			
		||||
        // out of range
 | 
			
		||||
        /* The 0xee string is indeed a Microsoft USB extension.
 | 
			
		||||
         * It can be used to tell Windows what driver it should use for the device !!!
 | 
			
		||||
         */
 | 
			
		||||
        return 0;
 | 
			
		||||
      }
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    case TUSB_DESC_DEVICE_QUALIFIER:
 | 
			
		||||
      // TODO If not highspeed capable stall this request otherwise
 | 
			
		||||
      // return the descriptor that could work in highspeed
 | 
			
		||||
      return 0;
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    default: return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TU_ASSERT( desc_data != NULL, 0);
 | 
			
		||||
 | 
			
		||||
  // up to Host's length
 | 
			
		||||
  len = tu_min16(p_request->wLength, len );
 | 
			
		||||
  (*pp_buffer) = desc_data;
 | 
			
		||||
 | 
			
		||||
  return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
tusb_error_t controld_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes) {
 | 
			
		||||
    if (control_state.current_stage == CONTROL_STAGE_STATUS && xferred_bytes == 0) {
 | 
			
		||||
        control_state.current_stage = CONTROL_STAGE_SETUP;
 | 
			
		||||
        return TUSB_ERROR_NONE;
 | 
			
		||||
    }
 | 
			
		||||
    tusb_error_t error = TUSB_ERROR_NONE;
 | 
			
		||||
    control_state.total_transferred += xferred_bytes;
 | 
			
		||||
    tusb_control_request_t const *p_request = &control_state.current_request;
 | 
			
		||||
 | 
			
		||||
    if (p_request->wLength == control_state.total_transferred || xferred_bytes < 64) {
 | 
			
		||||
        control_state.current_stage = CONTROL_STAGE_STATUS;
 | 
			
		||||
        dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
 | 
			
		||||
        // Do the user callback after queueing the STATUS packet because the callback could be slow.
 | 
			
		||||
        if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient )
 | 
			
		||||
        {
 | 
			
		||||
          tud_control_interface_control_complete_cb(rhport, tu_u16_low(p_request->wIndex), p_request);
 | 
			
		||||
        }
 | 
			
		||||
    } else {
 | 
			
		||||
        if (TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient) {
 | 
			
		||||
          error = tud_control_interface_control_cb(rhport, tu_u16_low(p_request->wIndex), p_request, control_state.total_transferred);
 | 
			
		||||
        } else {
 | 
			
		||||
          error = controld_process_control_request(rhport, p_request, control_state.total_transferred);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This tracks the state of a control request.
 | 
			
		||||
tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * p_request) {
 | 
			
		||||
  tusb_error_t error = TUSB_ERROR_NONE;
 | 
			
		||||
  memcpy(&control_state.current_request, p_request, sizeof(tusb_control_request_t));
 | 
			
		||||
  if (p_request->wLength == 0) {
 | 
			
		||||
      control_state.current_stage = CONTROL_STAGE_STATUS;
 | 
			
		||||
  } else {
 | 
			
		||||
      control_state.current_stage = CONTROL_STAGE_DATA;
 | 
			
		||||
      control_state.total_transferred = 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient )
 | 
			
		||||
  {
 | 
			
		||||
    error = tud_control_interface_control_cb(rhport, tu_u16_low(p_request->wIndex), p_request, 0);
 | 
			
		||||
  } else {
 | 
			
		||||
    error = controld_process_control_request(rhport, p_request, 0);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if (error != TUSB_ERROR_NONE) {
 | 
			
		||||
    dcd_control_stall(rhport); // Stall errored requests
 | 
			
		||||
  } else if (control_state.current_stage == CONTROL_STAGE_STATUS) {
 | 
			
		||||
    dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
  }
 | 
			
		||||
  return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// This handles the actual request and its response.
 | 
			
		||||
tusb_error_t controld_process_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent)
 | 
			
		||||
{
 | 
			
		||||
  tusb_error_t error = TUSB_ERROR_NONE;
 | 
			
		||||
  uint8_t ep_addr = 0;
 | 
			
		||||
  if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) {
 | 
			
		||||
      ep_addr |= TUSB_DIR_IN_MASK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //------------- Standard Request e.g in enumeration -------------//
 | 
			
		||||
  if( TUSB_REQ_RCPT_DEVICE    == p_request->bmRequestType_bit.recipient &&
 | 
			
		||||
      TUSB_REQ_TYPE_STANDARD  == p_request->bmRequestType_bit.type ) {
 | 
			
		||||
    switch (p_request->bRequest) {
 | 
			
		||||
      case TUSB_REQ_GET_DESCRIPTOR: {
 | 
			
		||||
        uint8_t  const * buffer = NULL;
 | 
			
		||||
        uint16_t const   len    = get_descriptor(rhport, p_request, &buffer);
 | 
			
		||||
 | 
			
		||||
        if (len) {
 | 
			
		||||
          uint16_t remaining_bytes = len - bytes_already_sent;
 | 
			
		||||
          if (remaining_bytes > 64) {
 | 
			
		||||
              remaining_bytes = 64;
 | 
			
		||||
          }
 | 
			
		||||
          memcpy(_shared_control_buffer, buffer + bytes_already_sent, remaining_bytes);
 | 
			
		||||
          dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, remaining_bytes);
 | 
			
		||||
        } else {
 | 
			
		||||
          return TUSB_ERROR_FAILED;
 | 
			
		||||
        }
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case TUSB_REQ_GET_CONFIGURATION:
 | 
			
		||||
        memcpy(_shared_control_buffer, &control_state.config, 1);
 | 
			
		||||
        dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, 1);
 | 
			
		||||
        break;
 | 
			
		||||
      case TUSB_REQ_SET_ADDRESS:
 | 
			
		||||
        dcd_set_address(rhport, (uint8_t) p_request->wValue);
 | 
			
		||||
        break;
 | 
			
		||||
      case TUSB_REQ_SET_CONFIGURATION:
 | 
			
		||||
        control_state.config = p_request->wValue;
 | 
			
		||||
        tud_control_set_config_cb (rhport, control_state.config);
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        return TUSB_ERROR_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
  } else if (p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT &&
 | 
			
		||||
             p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
 | 
			
		||||
    //------------- Endpoint Request -------------//
 | 
			
		||||
    switch (p_request->bRequest) {
 | 
			
		||||
      case TUSB_REQ_GET_STATUS: {
 | 
			
		||||
        uint16_t status = dcd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000;
 | 
			
		||||
        memcpy(_shared_control_buffer, &status, 2);
 | 
			
		||||
 | 
			
		||||
        dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, 2);
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
      case TUSB_REQ_CLEAR_FEATURE:
 | 
			
		||||
        // only endpoint feature is halted/stalled
 | 
			
		||||
        dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
 | 
			
		||||
        break;
 | 
			
		||||
      case TUSB_REQ_SET_FEATURE:
 | 
			
		||||
        // only endpoint feature is halted/stalled
 | 
			
		||||
        dcd_edpt_stall(rhport, tu_u16_low(p_request->wIndex));
 | 
			
		||||
        break;
 | 
			
		||||
      default:
 | 
			
		||||
        return TUSB_ERROR_FAILED;
 | 
			
		||||
    }
 | 
			
		||||
  } else {
 | 
			
		||||
    //------------- Unsupported Request -------------//
 | 
			
		||||
    return TUSB_ERROR_FAILED;
 | 
			
		||||
  }
 | 
			
		||||
  return error;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										98
									
								
								src/device/control.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/device/control.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,98 @@
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
/*!
 | 
			
		||||
    @file     usbd.h
 | 
			
		||||
    @author   hathach (tinyusb.org)
 | 
			
		||||
 | 
			
		||||
    @section LICENSE
 | 
			
		||||
 | 
			
		||||
    Software License Agreement (BSD License)
 | 
			
		||||
 | 
			
		||||
    Copyright (c) 2013, hathach (tinyusb.org)
 | 
			
		||||
    All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
    documentation and/or other materials provided with the distribution.
 | 
			
		||||
    3. Neither the name of the copyright holders nor the
 | 
			
		||||
    names of its contributors may be used to endorse or promote products
 | 
			
		||||
    derived from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 | 
			
		||||
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 | 
			
		||||
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
			
		||||
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
    This file is part of the tinyusb stack.
 | 
			
		||||
*/
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
 | 
			
		||||
/** \ingroup group_usbd
 | 
			
		||||
 *  @{ */
 | 
			
		||||
 | 
			
		||||
#ifndef _TUSB_CONTROL_H_
 | 
			
		||||
#define _TUSB_CONTROL_H_
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "tusb.h"
 | 
			
		||||
 | 
			
		||||
typedef enum {
 | 
			
		||||
    CONTROL_STAGE_SETUP, // Waiting for a setup token.
 | 
			
		||||
    CONTROL_STAGE_DATA, // In the process of sending or receiving data.
 | 
			
		||||
    CONTROL_STAGE_STATUS // In the process of transmitting the STATUS ZLP.
 | 
			
		||||
} control_stage_t;
 | 
			
		||||
 | 
			
		||||
typedef struct {
 | 
			
		||||
    control_stage_t current_stage;
 | 
			
		||||
    tusb_control_request_t current_request;
 | 
			
		||||
    uint16_t total_transferred;
 | 
			
		||||
    uint8_t config;
 | 
			
		||||
} control_t;
 | 
			
		||||
 | 
			
		||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _shared_control_buffer[64];
 | 
			
		||||
 | 
			
		||||
tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * const p_request);
 | 
			
		||||
 | 
			
		||||
// Callback when the configuration of the device is changed.
 | 
			
		||||
tusb_error_t tud_control_set_config_cb(uint8_t rhport, uint8_t config_number);
 | 
			
		||||
 | 
			
		||||
// Called when the DATA stage of a control transaction is complete.
 | 
			
		||||
void tud_control_interface_control_complete_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request);
 | 
			
		||||
 | 
			
		||||
tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request, uint16_t bytes_already_sent);
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// INTERNAL API
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
 | 
			
		||||
void controld_init(void);
 | 
			
		||||
tusb_error_t controld_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
 | 
			
		||||
 | 
			
		||||
// This tracks the state of a control request.
 | 
			
		||||
tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * p_request);
 | 
			
		||||
 | 
			
		||||
// This handles the actual request and its response.
 | 
			
		||||
tusb_error_t controld_process_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent);
 | 
			
		||||
 | 
			
		||||
tusb_error_t controld_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
 | 
			
		||||
void controld_reset(uint8_t rhport);
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#endif /* _TUSB_CONTROL_H_ */
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
@@ -113,32 +113,13 @@ void dcd_disconnect       (uint8_t rhport) ATTR_WEAK;
 | 
			
		||||
void dcd_event_handler(dcd_event_t const * event, bool in_isr);
 | 
			
		||||
 | 
			
		||||
// helper to send bus signal event
 | 
			
		||||
static inline void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr)
 | 
			
		||||
{
 | 
			
		||||
  dcd_event_t event = { .rhport = 0, .event_id = eid, };
 | 
			
		||||
  dcd_event_handler(&event, in_isr);
 | 
			
		||||
}
 | 
			
		||||
void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr);
 | 
			
		||||
 | 
			
		||||
// helper to send setup received
 | 
			
		||||
static inline void dcd_event_setup_recieved(uint8_t rhport, uint8_t const * setup, bool in_isr)
 | 
			
		||||
{
 | 
			
		||||
  dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_SETUP_RECEIVED };
 | 
			
		||||
  memcpy(&event.setup_received, setup, 8);
 | 
			
		||||
 | 
			
		||||
  dcd_event_handler(&event, true);
 | 
			
		||||
}
 | 
			
		||||
void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr);
 | 
			
		||||
 | 
			
		||||
// helper to send transfer complete event
 | 
			
		||||
static inline void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
 | 
			
		||||
{
 | 
			
		||||
  dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
 | 
			
		||||
 | 
			
		||||
  event.xfer_complete.ep_addr = ep_addr;
 | 
			
		||||
  event.xfer_complete.len     = xferred_bytes;
 | 
			
		||||
  event.xfer_complete.result  = result;
 | 
			
		||||
 | 
			
		||||
  dcd_event_handler(&event, in_isr);
 | 
			
		||||
}
 | 
			
		||||
void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
@@ -154,22 +135,6 @@ void dcd_edpt_stall       (uint8_t rhport, uint8_t ep_addr);
 | 
			
		||||
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr);
 | 
			
		||||
bool dcd_edpt_stalled     (uint8_t rhport, uint8_t ep_addr);
 | 
			
		||||
 | 
			
		||||
//------------- Control Endpoint -------------//
 | 
			
		||||
bool dcd_control_xfer     (uint8_t rhport, uint8_t dir, uint8_t * buffer, uint16_t length);
 | 
			
		||||
 | 
			
		||||
// Helper to send STATUS (zero length) packet
 | 
			
		||||
// Note dir is value of direction bit in setup packet (i.e DATA stage direction)
 | 
			
		||||
static inline bool dcd_control_status(uint8_t rhport, uint8_t dir)
 | 
			
		||||
{
 | 
			
		||||
  // status direction is reversed to one in the setup packet
 | 
			
		||||
  return dcd_control_xfer(rhport, 1-dir, NULL, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static inline void dcd_control_stall(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  dcd_edpt_stall(rhport, 0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 }
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
@@ -36,12 +36,15 @@
 | 
			
		||||
*/
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
 | 
			
		||||
// This top level class manages the bus state and delegates events to class-specific drivers.
 | 
			
		||||
 | 
			
		||||
#include "tusb_option.h"
 | 
			
		||||
 | 
			
		||||
#if TUSB_OPT_DEVICE_ENABLED
 | 
			
		||||
 | 
			
		||||
#define _TINY_USB_SOURCE_FILE_
 | 
			
		||||
 | 
			
		||||
#include "control.h"
 | 
			
		||||
#include "tusb.h"
 | 
			
		||||
#include "usbd.h"
 | 
			
		||||
#include "device/usbd_pvt.h"
 | 
			
		||||
@@ -72,7 +75,6 @@ typedef struct {
 | 
			
		||||
  uint8_t ep2drv[2][8];
 | 
			
		||||
}usbd_device_t;
 | 
			
		||||
 | 
			
		||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _usbd_ctrl_buf[CFG_TUD_CTRL_BUFSIZE];
 | 
			
		||||
static usbd_device_t _usbd_dev;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -92,7 +94,9 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
  void         (* init           ) (void);
 | 
			
		||||
  tusb_error_t (* open           ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t* p_length);
 | 
			
		||||
  tusb_error_t (* control_req_st ) (uint8_t rhport, tusb_control_request_t const *);
 | 
			
		||||
  // Control request is called one or more times for a request and can queue multiple data packets.
 | 
			
		||||
  tusb_error_t (* control_request ) (uint8_t rhport, tusb_control_request_t const *, uint16_t bytes_already_sent);
 | 
			
		||||
  void (* control_request_complete ) (uint8_t rhport, tusb_control_request_t const *);
 | 
			
		||||
  tusb_error_t (* xfer_cb        ) (uint8_t rhport, uint8_t ep_addr, tusb_event_t, uint32_t);
 | 
			
		||||
  void         (* sof            ) (uint8_t rhport);
 | 
			
		||||
  void         (* reset          ) (uint8_t);
 | 
			
		||||
@@ -100,52 +104,66 @@ typedef struct {
 | 
			
		||||
 | 
			
		||||
static usbd_class_driver_t const usbd_class_drivers[] =
 | 
			
		||||
{
 | 
			
		||||
    {
 | 
			
		||||
        .class_code      = TUSB_CLASS_UNSPECIFIED,
 | 
			
		||||
        .init            = controld_init,
 | 
			
		||||
        .open            = NULL,
 | 
			
		||||
        .control_request = NULL,
 | 
			
		||||
        .control_request_complete = NULL,
 | 
			
		||||
        .xfer_cb         = controld_xfer_cb,
 | 
			
		||||
        .sof             = NULL,
 | 
			
		||||
        .reset           = controld_reset
 | 
			
		||||
    },
 | 
			
		||||
  #if CFG_TUD_CDC
 | 
			
		||||
    {
 | 
			
		||||
        .class_code     = TUSB_CLASS_CDC,
 | 
			
		||||
        .init           = cdcd_init,
 | 
			
		||||
        .open           = cdcd_open,
 | 
			
		||||
        .control_req_st = cdcd_control_request_st,
 | 
			
		||||
        .xfer_cb        = cdcd_xfer_cb,
 | 
			
		||||
        .sof            = NULL,
 | 
			
		||||
        .reset          = cdcd_reset
 | 
			
		||||
        .class_code      = TUSB_CLASS_CDC,
 | 
			
		||||
        .init            = cdcd_init,
 | 
			
		||||
        .open            = cdcd_open,
 | 
			
		||||
        .control_request = cdcd_control_request,
 | 
			
		||||
        .control_request_complete = cdcd_control_request_complete,
 | 
			
		||||
        .xfer_cb         = cdcd_xfer_cb,
 | 
			
		||||
        .sof             = NULL,
 | 
			
		||||
        .reset           = cdcd_reset
 | 
			
		||||
    },
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #if CFG_TUD_MSC
 | 
			
		||||
    {
 | 
			
		||||
        .class_code     = TUSB_CLASS_MSC,
 | 
			
		||||
        .init           = mscd_init,
 | 
			
		||||
        .open           = mscd_open,
 | 
			
		||||
        .control_req_st = mscd_control_request_st,
 | 
			
		||||
        .xfer_cb        = mscd_xfer_cb,
 | 
			
		||||
        .sof            = NULL,
 | 
			
		||||
        .reset          = mscd_reset
 | 
			
		||||
        .class_code      = TUSB_CLASS_MSC,
 | 
			
		||||
        .init            = mscd_init,
 | 
			
		||||
        .open            = mscd_open,
 | 
			
		||||
        .control_request = mscd_control_request,
 | 
			
		||||
        .control_request_complete = mscd_control_request_complete,
 | 
			
		||||
        .xfer_cb         = mscd_xfer_cb,
 | 
			
		||||
        .sof             = NULL,
 | 
			
		||||
        .reset           = mscd_reset
 | 
			
		||||
    },
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
  #if CFG_TUD_HID
 | 
			
		||||
    {
 | 
			
		||||
        .class_code     = TUSB_CLASS_HID,
 | 
			
		||||
        .init           = hidd_init,
 | 
			
		||||
        .open           = hidd_open,
 | 
			
		||||
        .control_req_st = hidd_control_request_st,
 | 
			
		||||
        .xfer_cb        = hidd_xfer_cb,
 | 
			
		||||
        .sof            = NULL,
 | 
			
		||||
        .reset          = hidd_reset
 | 
			
		||||
        .class_code      = TUSB_CLASS_HID,
 | 
			
		||||
        .init            = hidd_init,
 | 
			
		||||
        .open            = hidd_open,
 | 
			
		||||
        .control_request = hidd_control_request,
 | 
			
		||||
        .control_request_complete = hidd_control_request_complete,
 | 
			
		||||
        .xfer_cb         = hidd_xfer_cb,
 | 
			
		||||
        .sof             = NULL,
 | 
			
		||||
        .reset           = hidd_reset
 | 
			
		||||
    },
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #if CFG_TUD_CUSTOM_CLASS
 | 
			
		||||
    {
 | 
			
		||||
        .class_code     = TUSB_CLASS_VENDOR_SPECIFIC,
 | 
			
		||||
        .init           = cusd_init,
 | 
			
		||||
        .open           = cusd_open,
 | 
			
		||||
        .control_req_st = cusd_control_request_st,
 | 
			
		||||
        .xfer_cb        = cusd_xfer_cb,
 | 
			
		||||
        .sof            = NULL,
 | 
			
		||||
        .reset          = cusd_reset
 | 
			
		||||
        .class_code      = TUSB_CLASS_VENDOR_SPECIFIC,
 | 
			
		||||
        .init            = cusd_init,
 | 
			
		||||
        .open            = cusd_open,
 | 
			
		||||
        .control_request = cusd_control_request,
 | 
			
		||||
        .control_request_complete = cusd_control_request_complete,
 | 
			
		||||
        .xfer_cb         = cusd_xfer_cb,
 | 
			
		||||
        .sof             = NULL,
 | 
			
		||||
        .reset           = cusd_reset
 | 
			
		||||
    },
 | 
			
		||||
  #endif
 | 
			
		||||
};
 | 
			
		||||
@@ -162,16 +180,10 @@ OSAL_TASK_DEF(_usbd_task_def, "usbd", usbd_task, CFG_TUD_TASK_PRIO, CFG_TUD_TASK
 | 
			
		||||
OSAL_QUEUE_DEF(_usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
 | 
			
		||||
static osal_queue_t _usbd_q;
 | 
			
		||||
 | 
			
		||||
/*------------- control transfer semaphore -------------*/
 | 
			
		||||
static osal_semaphore_def_t _usbd_sem_def;
 | 
			
		||||
osal_semaphore_t _usbd_ctrl_sem;
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// INTERNAL FUNCTION
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
 | 
			
		||||
static tusb_error_t proc_set_config_req(uint8_t rhport, uint8_t config_number);
 | 
			
		||||
static uint16_t get_descriptor(uint8_t rhport, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer);
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// APPLICATION API
 | 
			
		||||
@@ -184,7 +196,6 @@ bool tud_mounted(void)
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// IMPLEMENTATION
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
static tusb_error_t proc_control_request_st(uint8_t rhport, tusb_control_request_t const * const p_request);
 | 
			
		||||
static tusb_error_t usbd_main_st(void);
 | 
			
		||||
 | 
			
		||||
tusb_error_t usbd_init (void)
 | 
			
		||||
@@ -201,9 +212,6 @@ tusb_error_t usbd_init (void)
 | 
			
		||||
  _usbd_q = osal_queue_create(&_usbd_qdef);
 | 
			
		||||
  TU_VERIFY(_usbd_q, TUSB_ERROR_OSAL_QUEUE_FAILED);
 | 
			
		||||
 | 
			
		||||
  _usbd_ctrl_sem = osal_semaphore_create(&_usbd_sem_def);
 | 
			
		||||
  TU_VERIFY(_usbd_q, TUSB_ERROR_OSAL_SEMAPHORE_FAILED);
 | 
			
		||||
 | 
			
		||||
  osal_task_create(&_usbd_task_def);
 | 
			
		||||
 | 
			
		||||
  //------------- class init -------------//
 | 
			
		||||
@@ -217,6 +225,9 @@ static void usbd_reset(uint8_t rhport)
 | 
			
		||||
  tu_varclr(&_usbd_dev);
 | 
			
		||||
  memset(_usbd_dev.itf2drv, 0xff, sizeof(_usbd_dev.itf2drv)); // invalid mapping
 | 
			
		||||
  memset(_usbd_dev.ep2drv , 0xff, sizeof(_usbd_dev.ep2drv )); // invalid mapping
 | 
			
		||||
  // Always map the 0th endpoint to the control driver.
 | 
			
		||||
  _usbd_dev.ep2drv[TUSB_DIR_IN][0] = 0;
 | 
			
		||||
  _usbd_dev.ep2drv[TUSB_DIR_OUT][0] = 0;
 | 
			
		||||
 | 
			
		||||
  for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
 | 
			
		||||
  {
 | 
			
		||||
@@ -241,23 +252,22 @@ void usbd_task( void* param)
 | 
			
		||||
 | 
			
		||||
static tusb_error_t usbd_main_st(void)
 | 
			
		||||
{
 | 
			
		||||
  static dcd_event_t event;
 | 
			
		||||
 | 
			
		||||
  OSAL_SUBTASK_BEGIN
 | 
			
		||||
 | 
			
		||||
  dcd_event_t event;
 | 
			
		||||
  tusb_error_t err = TUSB_ERROR_NONE;
 | 
			
		||||
  // Loop until there is no more events in the queue
 | 
			
		||||
  while (1)
 | 
			
		||||
  while (_usbd_q->count > 0)
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t err;
 | 
			
		||||
 | 
			
		||||
    err = TUSB_ERROR_NONE;
 | 
			
		||||
    tu_memclr(&event, sizeof(dcd_event_t));
 | 
			
		||||
 | 
			
		||||
    osal_queue_receive(_usbd_q, &event, OSAL_TIMEOUT_WAIT_FOREVER, &err);
 | 
			
		||||
    err = osal_queue_receive(_usbd_q, &event);
 | 
			
		||||
    if (err != TUSB_ERROR_NONE) {
 | 
			
		||||
        break;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if ( DCD_EVENT_SETUP_RECEIVED == event.event_id )
 | 
			
		||||
    {
 | 
			
		||||
      STASK_INVOKE( proc_control_request_st(event.rhport, &event.setup_received), err );
 | 
			
		||||
      // Setup tokens are unique to the Control endpointso we delegate to it directly.
 | 
			
		||||
      controld_process_setup_request(event.rhport, &event.setup_received);
 | 
			
		||||
    }
 | 
			
		||||
    else if (DCD_EVENT_XFER_COMPLETE == event.event_id)
 | 
			
		||||
    {
 | 
			
		||||
@@ -267,20 +277,18 @@ static tusb_error_t usbd_main_st(void)
 | 
			
		||||
 | 
			
		||||
      if (drv_id < USBD_CLASS_DRIVER_COUNT)
 | 
			
		||||
      {
 | 
			
		||||
        usbd_class_drivers[drv_id].xfer_cb( event.rhport, ep_addr, (tusb_event_t) event.xfer_complete.result, event.xfer_complete.len);
 | 
			
		||||
        usbd_class_drivers[drv_id].xfer_cb( event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if (DCD_EVENT_BUS_RESET == event.event_id)
 | 
			
		||||
    {
 | 
			
		||||
      usbd_reset(event.rhport);
 | 
			
		||||
      osal_queue_reset(_usbd_q);
 | 
			
		||||
      osal_semaphore_reset(_usbd_ctrl_sem);
 | 
			
		||||
    }
 | 
			
		||||
    else if (DCD_EVENT_UNPLUGGED == event.event_id)
 | 
			
		||||
    {
 | 
			
		||||
      usbd_reset(event.rhport);
 | 
			
		||||
      osal_queue_reset(_usbd_q);
 | 
			
		||||
      osal_semaphore_reset(_usbd_ctrl_sem);
 | 
			
		||||
 | 
			
		||||
      tud_umount_cb(); // invoke callback
 | 
			
		||||
    }
 | 
			
		||||
@@ -304,116 +312,31 @@ static tusb_error_t usbd_main_st(void)
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OSAL_SUBTASK_END
 | 
			
		||||
    return err;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// CONTROL REQUEST
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
static tusb_error_t proc_control_request_st(uint8_t rhport, tusb_control_request_t const * const p_request)
 | 
			
		||||
{
 | 
			
		||||
  OSAL_SUBTASK_BEGIN
 | 
			
		||||
 | 
			
		||||
  ATTR_UNUSED tusb_error_t error;
 | 
			
		||||
  error = TUSB_ERROR_NONE;
 | 
			
		||||
 | 
			
		||||
  //------------- Standard Request e.g in enumeration -------------//
 | 
			
		||||
  if( TUSB_REQ_RCPT_DEVICE    == p_request->bmRequestType_bit.recipient &&
 | 
			
		||||
      TUSB_REQ_TYPE_STANDARD  == p_request->bmRequestType_bit.type )
 | 
			
		||||
  {
 | 
			
		||||
    if ( TUSB_REQ_GET_DESCRIPTOR == p_request->bRequest )
 | 
			
		||||
void tud_control_interface_control_complete_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request) {
 | 
			
		||||
    if (_usbd_dev.itf2drv[ interface ] < USBD_CLASS_DRIVER_COUNT)
 | 
			
		||||
    {
 | 
			
		||||
      uint8_t  const * buffer = NULL;
 | 
			
		||||
      uint16_t const   len    = get_descriptor(rhport, p_request, &buffer);
 | 
			
		||||
 | 
			
		||||
      if ( len )
 | 
			
		||||
      {
 | 
			
		||||
        STASK_ASSERT( len <= CFG_TUD_CTRL_BUFSIZE );
 | 
			
		||||
        memcpy(_usbd_ctrl_buf, buffer, len);
 | 
			
		||||
        usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, len);
 | 
			
		||||
      }else
 | 
			
		||||
      {
 | 
			
		||||
        dcd_control_stall(rhport); // stall unsupported descriptor
 | 
			
		||||
      const usbd_class_driver_t *driver = &usbd_class_drivers[_usbd_dev.itf2drv[interface]];
 | 
			
		||||
      if (driver->control_request_complete != NULL) {
 | 
			
		||||
        driver->control_request_complete(rhport, p_request);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
    else if (TUSB_REQ_GET_CONFIGURATION == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      memcpy(_usbd_ctrl_buf, &_usbd_dev.config_num, 1);
 | 
			
		||||
      usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, 1);
 | 
			
		||||
    }
 | 
			
		||||
    else if ( TUSB_REQ_SET_ADDRESS == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      dcd_set_address(rhport, (uint8_t) p_request->wValue);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
      #if CFG_TUSB_MCU != OPT_MCU_NRF5X // nrf5x auto handle set address, we must not return status
 | 
			
		||||
      dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
      #endif
 | 
			
		||||
    }
 | 
			
		||||
    else if ( TUSB_REQ_SET_CONFIGURATION == p_request->bRequest )
 | 
			
		||||
tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request, uint16_t bytes_already_sent) {
 | 
			
		||||
    if (_usbd_dev.itf2drv[ interface ] < USBD_CLASS_DRIVER_COUNT)
 | 
			
		||||
    {
 | 
			
		||||
      proc_set_config_req(rhport, (uint8_t) p_request->wValue);
 | 
			
		||||
      dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
      return usbd_class_drivers[_usbd_dev.itf2drv[interface]].control_request(rhport, p_request, bytes_already_sent);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      dcd_control_stall(rhport); // Stall unsupported request
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //------------- Class/Interface Specific Request -------------//
 | 
			
		||||
  else if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient )
 | 
			
		||||
  {
 | 
			
		||||
    if (_usbd_dev.itf2drv[ tu_u16_low(p_request->wIndex) ] < USBD_CLASS_DRIVER_COUNT)
 | 
			
		||||
    {
 | 
			
		||||
      STASK_INVOKE( usbd_class_drivers[ _usbd_dev.itf2drv[ tu_u16_low(p_request->wIndex) ] ].control_req_st(rhport, p_request), error );
 | 
			
		||||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      dcd_control_stall(rhport); // Stall unsupported request
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //------------- Endpoint Request -------------//
 | 
			
		||||
  else if ( TUSB_REQ_RCPT_ENDPOINT == p_request->bmRequestType_bit.recipient &&
 | 
			
		||||
            TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type)
 | 
			
		||||
  {
 | 
			
		||||
    if (TUSB_REQ_GET_STATUS == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      uint16_t status = dcd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000;
 | 
			
		||||
      memcpy(_usbd_ctrl_buf, &status, 2);
 | 
			
		||||
 | 
			
		||||
      usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, 2);
 | 
			
		||||
    }
 | 
			
		||||
    else if (TUSB_REQ_CLEAR_FEATURE == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      // only endpoint feature is halted/stalled
 | 
			
		||||
      dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
 | 
			
		||||
      dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
    }
 | 
			
		||||
    else if (TUSB_REQ_SET_FEATURE == p_request->bRequest )
 | 
			
		||||
    {
 | 
			
		||||
      // only endpoint feature is halted/stalled
 | 
			
		||||
      dcd_edpt_stall(rhport, tu_u16_low(p_request->wIndex));
 | 
			
		||||
      dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
      dcd_control_stall(rhport); // Stall unsupported request
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  //------------- Unsupported Request -------------//
 | 
			
		||||
  else
 | 
			
		||||
  {
 | 
			
		||||
    dcd_control_stall(rhport); // Stall unsupported request
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  OSAL_SUBTASK_END
 | 
			
		||||
    return TUSB_ERROR_FAILED;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Process Set Configure Request
 | 
			
		||||
// TODO Host (windows) can get HID report descriptor before set configured
 | 
			
		||||
// may need to open interface before set configured
 | 
			
		||||
static tusb_error_t proc_set_config_req(uint8_t rhport, uint8_t config_number)
 | 
			
		||||
tusb_error_t tud_control_set_config_cb(uint8_t rhport, uint8_t config_number)
 | 
			
		||||
{
 | 
			
		||||
  dcd_set_config(rhport, config_number);
 | 
			
		||||
 | 
			
		||||
@@ -465,65 +388,6 @@ static tusb_error_t proc_set_config_req(uint8_t rhport, uint8_t config_number)
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// return len of descriptor and change pointer to descriptor's buffer
 | 
			
		||||
static uint16_t get_descriptor(uint8_t rhport, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
 | 
			
		||||
  uint8_t const desc_index = tu_u16_low( p_request->wValue );
 | 
			
		||||
 | 
			
		||||
  uint8_t const * desc_data = NULL ;
 | 
			
		||||
  uint16_t len = 0;
 | 
			
		||||
 | 
			
		||||
  switch(desc_type)
 | 
			
		||||
  {
 | 
			
		||||
    case TUSB_DESC_DEVICE:
 | 
			
		||||
      desc_data = (uint8_t const *) usbd_desc_set->device;
 | 
			
		||||
      len       = sizeof(tusb_desc_device_t);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    case TUSB_DESC_CONFIGURATION:
 | 
			
		||||
      desc_data = (uint8_t const *) usbd_desc_set->config;
 | 
			
		||||
      len       = ((tusb_desc_configuration_t const*) desc_data)->wTotalLength;
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    case TUSB_DESC_STRING:
 | 
			
		||||
      // String Descriptor always uses the desc set from user
 | 
			
		||||
      if ( desc_index < tud_desc_set.string_count )
 | 
			
		||||
      {
 | 
			
		||||
        desc_data = tud_desc_set.string_arr[desc_index];
 | 
			
		||||
        TU_VERIFY( desc_data != NULL, 0 );
 | 
			
		||||
 | 
			
		||||
        len  = desc_data[0];  // first byte of descriptor is its size
 | 
			
		||||
      }else
 | 
			
		||||
      {
 | 
			
		||||
        // out of range
 | 
			
		||||
        /* The 0xee string is indeed a Microsoft USB extension.
 | 
			
		||||
         * It can be used to tell Windows what driver it should use for the device !!!
 | 
			
		||||
         */
 | 
			
		||||
        return 0;
 | 
			
		||||
      }
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    case TUSB_DESC_DEVICE_QUALIFIER:
 | 
			
		||||
      // TODO If not highspeed capable stall this request otherwise
 | 
			
		||||
      // return the descriptor that could work in highspeed
 | 
			
		||||
      return 0;
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    default: return 0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  TU_ASSERT( desc_data != NULL, 0);
 | 
			
		||||
 | 
			
		||||
  // up to Host's length
 | 
			
		||||
  len = tu_min16(p_request->wLength, len );
 | 
			
		||||
  (*pp_buffer) = desc_data;
 | 
			
		||||
 | 
			
		||||
  return len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Helper marking endpoint of interface belongs to class driver
 | 
			
		||||
static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id)
 | 
			
		||||
{
 | 
			
		||||
@@ -548,8 +412,6 @@ static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, ui
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
void dcd_event_handler(dcd_event_t const * event, bool in_isr)
 | 
			
		||||
{
 | 
			
		||||
  uint8_t const rhport = event->rhport;
 | 
			
		||||
 | 
			
		||||
  switch (event->event_id)
 | 
			
		||||
  {
 | 
			
		||||
    case DCD_EVENT_BUS_RESET:
 | 
			
		||||
@@ -571,18 +433,7 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
    case DCD_EVENT_XFER_COMPLETE:
 | 
			
		||||
      if (event->xfer_complete.ep_addr == 0)
 | 
			
		||||
      {
 | 
			
		||||
        // only signal data stage, skip status (zero byte)
 | 
			
		||||
        if (event->xfer_complete.len)
 | 
			
		||||
        {
 | 
			
		||||
          (void) event->xfer_complete.result; // TODO handle control error/stalled
 | 
			
		||||
          osal_semaphore_post( _usbd_ctrl_sem, in_isr);
 | 
			
		||||
        }
 | 
			
		||||
      }else
 | 
			
		||||
      {
 | 
			
		||||
        osal_queue_send(_usbd_q, event, in_isr);
 | 
			
		||||
      }
 | 
			
		||||
      osal_queue_send(_usbd_q, event, in_isr);
 | 
			
		||||
      TU_ASSERT(event->xfer_complete.result == DCD_XFER_SUCCESS,);
 | 
			
		||||
    break;
 | 
			
		||||
 | 
			
		||||
@@ -590,9 +441,40 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_event_handler(dcd_event_t const * event, bool in_isr);
 | 
			
		||||
 | 
			
		||||
// helper to send bus signal event
 | 
			
		||||
void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr)
 | 
			
		||||
{
 | 
			
		||||
  dcd_event_t event = { .rhport = 0, .event_id = eid, };
 | 
			
		||||
  dcd_event_handler(&event, in_isr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// helper to send setup received
 | 
			
		||||
void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr)
 | 
			
		||||
{
 | 
			
		||||
  dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_SETUP_RECEIVED };
 | 
			
		||||
  memcpy(&event.setup_received, setup, 8);
 | 
			
		||||
 | 
			
		||||
  dcd_event_handler(&event, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// helper to send transfer complete event
 | 
			
		||||
void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
 | 
			
		||||
{
 | 
			
		||||
  dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
 | 
			
		||||
 | 
			
		||||
  event.xfer_complete.ep_addr = ep_addr;
 | 
			
		||||
  event.xfer_complete.len     = xferred_bytes;
 | 
			
		||||
  event.xfer_complete.result  = result;
 | 
			
		||||
 | 
			
		||||
  dcd_event_handler(&event, in_isr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// Helper
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
 | 
			
		||||
tusb_error_t usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* p_desc_ep, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in)
 | 
			
		||||
{
 | 
			
		||||
  for(int i=0; i<2; i++)
 | 
			
		||||
 
 | 
			
		||||
@@ -45,10 +45,6 @@
 | 
			
		||||
 extern "C" {
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
// for used by usbd_control_xfer_st() only, must not be used directly
 | 
			
		||||
extern osal_semaphore_t _usbd_ctrl_sem;
 | 
			
		||||
extern uint8_t _usbd_ctrl_buf[CFG_TUD_CTRL_BUFSIZE];
 | 
			
		||||
 | 
			
		||||
// Either point to tud_desc_set or usbd_auto_desc_set depending on CFG_TUD_DESC_AUTO
 | 
			
		||||
extern tud_desc_set_t const* usbd_desc_set;
 | 
			
		||||
 | 
			
		||||
@@ -64,21 +60,6 @@ void         usbd_task (void* param);
 | 
			
		||||
// helper to parse an pair of In and Out endpoint descriptors. They must be consecutive
 | 
			
		||||
tusb_error_t usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* p_desc_ep, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in);
 | 
			
		||||
 | 
			
		||||
// Carry out Data and Status stage of control transfer
 | 
			
		||||
// Must be call in a subtask (_st) function
 | 
			
		||||
#define usbd_control_xfer_st(_rhport, _dir, _buffer, _len)                    \
 | 
			
		||||
  do {                                                                        \
 | 
			
		||||
    if (_len) {                                                               \
 | 
			
		||||
      uint32_t err;                                                           \
 | 
			
		||||
      dcd_control_xfer(_rhport, _dir, (uint8_t*) _buffer, _len);              \
 | 
			
		||||
      osal_semaphore_wait( _usbd_ctrl_sem, OSAL_TIMEOUT_CONTROL_XFER, &err ); \
 | 
			
		||||
      STASK_ASSERT_ERR( err );                                                \
 | 
			
		||||
    }                                                                         \
 | 
			
		||||
    dcd_control_status(_rhport, _dir);                                        \
 | 
			
		||||
    /* No need to wait for status phase to complete */                        \
 | 
			
		||||
  }while(0)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* Other Helpers
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
 
 | 
			
		||||
@@ -183,4 +183,3 @@ static inline void osal_queue_reset(osal_queue_t const queue_hdl)
 | 
			
		||||
 | 
			
		||||
/** @} */
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -60,8 +60,6 @@
 | 
			
		||||
//
 | 
			
		||||
//   OSAL_TASK_LOOP_ENG
 | 
			
		||||
// }
 | 
			
		||||
//
 | 
			
		||||
// NOTE: no switch statement is allowed in Task and subtask
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
#define OSAL_TASK_DEF(_name, _str, _func, _prio, _stack_sz)  osal_task_def_t _name;
 | 
			
		||||
 | 
			
		||||
@@ -73,52 +71,8 @@ static inline bool osal_task_create(osal_task_def_t* taskdef)
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define TASK_RESTART                             \
 | 
			
		||||
  _state = 0
 | 
			
		||||
 | 
			
		||||
#define osal_task_delay(_msec)                      \
 | 
			
		||||
  do {                                              \
 | 
			
		||||
    _timeout = tusb_hal_millis();                   \
 | 
			
		||||
    _state = __LINE__; case __LINE__:               \
 | 
			
		||||
      if ( _timeout + (_msec) > tusb_hal_millis() ) \
 | 
			
		||||
        return TUSB_ERROR_OSAL_WAITING;             \
 | 
			
		||||
  }while(0)
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// SUBTASK (a sub function that uses OS blocking services & called by a task
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
#define OSAL_SUBTASK_BEGIN                       \
 | 
			
		||||
  static uint16_t _state = 0;                    \
 | 
			
		||||
  ATTR_UNUSED static uint32_t _timeout = 0;      \
 | 
			
		||||
  (void) _timeout;                               \
 | 
			
		||||
  switch(_state) {                               \
 | 
			
		||||
    case 0: {
 | 
			
		||||
 | 
			
		||||
#define OSAL_SUBTASK_END                         \
 | 
			
		||||
  default: TASK_RESTART; break;                  \
 | 
			
		||||
  }}                                             \
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
 | 
			
		||||
#define STASK_INVOKE(_subtask, _status)                                         \
 | 
			
		||||
  do {                                                                          \
 | 
			
		||||
    _state = __LINE__; case __LINE__:                                           \
 | 
			
		||||
    {                                                                           \
 | 
			
		||||
      (_status) = _subtask; /* invoke sub task */                               \
 | 
			
		||||
      if (TUSB_ERROR_OSAL_WAITING == (_status)) return TUSB_ERROR_OSAL_WAITING; \
 | 
			
		||||
    }                                                                           \
 | 
			
		||||
  }while(0)
 | 
			
		||||
 | 
			
		||||
//------------- Sub Task Assert -------------//
 | 
			
		||||
#define STASK_RETURN(error)     do { TASK_RESTART; return error; } while(0)
 | 
			
		||||
 | 
			
		||||
#define STASK_ASSERT_ERR(_err)                TU_VERIFY_ERR_HDLR(_err, TU_BREAKPOINT(); TASK_RESTART, TUSB_ERROR_FAILED)
 | 
			
		||||
#define STASK_ASSERT_ERR_HDLR(_err, _func)    TU_VERIFY_ERR_HDLR(_err, TU_BREAKPOINT(); _func; TASK_RESTART, TUSB_ERROR_FAILED )
 | 
			
		||||
 | 
			
		||||
#define STASK_ASSERT(_cond)                   TU_VERIFY_HDLR(_cond, TU_BREAKPOINT(); TASK_RESTART, TUSB_ERROR_FAILED)
 | 
			
		||||
#define STASK_ASSERT_HDLR(_cond, _func)       TU_VERIFY_HDLR(_cond, TU_BREAKPOINT(); _func; TASK_RESTART, TUSB_ERROR_FAILED)
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// Semaphore API
 | 
			
		||||
// Binary Semaphore API
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
typedef struct
 | 
			
		||||
{
 | 
			
		||||
@@ -135,7 +89,6 @@ static inline osal_semaphore_t osal_semaphore_create(osal_semaphore_def_t* semde
 | 
			
		||||
 | 
			
		||||
static inline bool osal_semaphore_post(osal_semaphore_t sem_hdl, bool in_isr)
 | 
			
		||||
{
 | 
			
		||||
  (void) in_isr;
 | 
			
		||||
  sem_hdl->count++;
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
@@ -145,22 +98,21 @@ static inline void osal_semaphore_reset(osal_semaphore_t sem_hdl)
 | 
			
		||||
  sem_hdl->count = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define osal_semaphore_wait(_sem_hdl, _msec, _err)                                               \
 | 
			
		||||
  do {                                                                                           \
 | 
			
		||||
    _timeout = tusb_hal_millis();                                                                \
 | 
			
		||||
    _state = __LINE__; case __LINE__:                                                            \
 | 
			
		||||
    if( (_sem_hdl)->count == 0 ) {                                                               \
 | 
			
		||||
      if ( ((_msec) != OSAL_TIMEOUT_WAIT_FOREVER) && (_timeout + (_msec) <= tusb_hal_millis()) ) \
 | 
			
		||||
        *(_err) = TUSB_ERROR_OSAL_TIMEOUT;                                                       \
 | 
			
		||||
      else                                                                                       \
 | 
			
		||||
        return TUSB_ERROR_OSAL_WAITING;                                                          \
 | 
			
		||||
    } else{                                                                                      \
 | 
			
		||||
      /* Enter critical ? */                                                                     \
 | 
			
		||||
      (_sem_hdl)->count--;                                                                       \
 | 
			
		||||
      /* Exit critical ? */                                                                      \
 | 
			
		||||
      *(_err) = TUSB_ERROR_NONE;                                                                 \
 | 
			
		||||
    }                                                                                            \
 | 
			
		||||
  }while(0)
 | 
			
		||||
static inline tusb_error_t osal_semaphore_wait(osal_semaphore_t sem_hdl, uint32_t msec) {
 | 
			
		||||
  (void) msec;
 | 
			
		||||
  while (true) {
 | 
			
		||||
      while (sem_hdl->count == 0) {
 | 
			
		||||
      }
 | 
			
		||||
      // tusb_hal_int_disable_all();
 | 
			
		||||
      if (sem_hdl->count == 0) {
 | 
			
		||||
          sem_hdl->count--;
 | 
			
		||||
          // tusb_hal_int_enable_all();
 | 
			
		||||
          break;
 | 
			
		||||
      }
 | 
			
		||||
      // tusb_hal_int_enable_all();
 | 
			
		||||
  }
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//--------------------------------------------------------------------+
 | 
			
		||||
// MUTEX API
 | 
			
		||||
@@ -205,22 +157,13 @@ static inline void osal_queue_reset(osal_queue_t const queue_hdl)
 | 
			
		||||
  queue_hdl->count = queue_hdl->rd_idx = queue_hdl->wr_idx = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#define osal_queue_receive(_q_hdl, p_data, _msec, _err)                                           \
 | 
			
		||||
  do {                                                                                            \
 | 
			
		||||
    _timeout = tusb_hal_millis();                                                                 \
 | 
			
		||||
    _state = __LINE__; case __LINE__:                                                             \
 | 
			
		||||
    if( (_q_hdl)->count == 0 ) {                                                                  \
 | 
			
		||||
      if ( ((_msec) != OSAL_TIMEOUT_WAIT_FOREVER) && ( _timeout + (_msec) <= tusb_hal_millis()) ) \
 | 
			
		||||
        *(_err) = TUSB_ERROR_OSAL_TIMEOUT;                                                        \
 | 
			
		||||
      else                                                                                        \
 | 
			
		||||
        return TUSB_ERROR_OSAL_WAITING;                                                           \
 | 
			
		||||
    } else{                                                                                       \
 | 
			
		||||
      /* Enter critical ? */                                                                      \
 | 
			
		||||
      tu_fifo_read(_q_hdl, p_data);                                                               \
 | 
			
		||||
      /* Exit critical ? */                                                                       \
 | 
			
		||||
      *(_err) = TUSB_ERROR_NONE;                                                                  \
 | 
			
		||||
    }                                                                                             \
 | 
			
		||||
  }while(0)
 | 
			
		||||
static inline tusb_error_t osal_queue_receive(osal_queue_t const queue_hdl, void* data) {
 | 
			
		||||
  if (!tu_fifo_read(queue_hdl, data)) {
 | 
			
		||||
    return TUSB_ERROR_OSAL_WAITING;
 | 
			
		||||
  }
 | 
			
		||||
  return TUSB_ERROR_NONE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#ifdef __cplusplus
 | 
			
		||||
 }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										341
									
								
								src/portable/microchip/samd21/dcd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										341
									
								
								src/portable/microchip/samd21/dcd.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,341 @@
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
/*!
 | 
			
		||||
    @file     dcd_nrf5x.c
 | 
			
		||||
    @author   hathach
 | 
			
		||||
 | 
			
		||||
    @section LICENSE
 | 
			
		||||
 | 
			
		||||
    Software License Agreement (BSD License)
 | 
			
		||||
 | 
			
		||||
    Copyright (c) 2018, Scott Shawcroft for Adafruit Industries
 | 
			
		||||
    All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
    documentation and/or other materials provided with the distribution.
 | 
			
		||||
    3. Neither the name of the copyright holders nor the
 | 
			
		||||
    names of its contributors may be used to endorse or promote products
 | 
			
		||||
    derived from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 | 
			
		||||
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 | 
			
		||||
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
			
		||||
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
    This file is part of the tinyusb stack.
 | 
			
		||||
*/
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "tusb_option.h"
 | 
			
		||||
 | 
			
		||||
#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMD21
 | 
			
		||||
 | 
			
		||||
#include "device/dcd.h"
 | 
			
		||||
 | 
			
		||||
#include "device/usbd.h"
 | 
			
		||||
#include "device/usbd_pvt.h" // to use defer function helper
 | 
			
		||||
 | 
			
		||||
#include "class/msc/msc_device.h"
 | 
			
		||||
 | 
			
		||||
#include "sam.h"
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* MACRO TYPEDEF CONSTANT ENUM
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  // Max allowed by USB specs
 | 
			
		||||
  MAX_PACKET_SIZE   = 64,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
UsbDeviceDescBank sram_registers[8][2];
 | 
			
		||||
ATTR_ALIGNED(4) uint8_t control_out_buffer[64];
 | 
			
		||||
ATTR_ALIGNED(4) uint8_t control_in_buffer[64];
 | 
			
		||||
 | 
			
		||||
volatile uint32_t setup_count = 0;
 | 
			
		||||
 | 
			
		||||
// Setup the control endpoint 0.
 | 
			
		||||
static void bus_reset(void) {
 | 
			
		||||
    // Max size of packets is 64 bytes.
 | 
			
		||||
    UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT];
 | 
			
		||||
    bank_out->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
    UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN];
 | 
			
		||||
    bank_in->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
 | 
			
		||||
    UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0];
 | 
			
		||||
    ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1);
 | 
			
		||||
    ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
 | 
			
		||||
 | 
			
		||||
    dcd_edpt_xfer(0, 0, control_out_buffer, 64);
 | 
			
		||||
    setup_count = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* Controller API
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
bool dcd_init (uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  USB->DEVICE.DESCADD.reg = (uint32_t) &sram_registers;
 | 
			
		||||
  USB->DEVICE.CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_FS;
 | 
			
		||||
  USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE;
 | 
			
		||||
  USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST;
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_connect (uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
void dcd_disconnect (uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  dcd_edpt_xfer (0, TUSB_DIR_IN_MASK, NULL, 0);
 | 
			
		||||
  // Wait for EP0 to finish before switching the address.
 | 
			
		||||
  while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
 | 
			
		||||
  USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  (void) config_num;
 | 
			
		||||
  // Nothing to do
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* Control
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
bool dcd_control_xfer (uint8_t rhport, uint8_t dir, uint8_t * buffer, uint16_t length)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  uint8_t ep_addr = 0;
 | 
			
		||||
  if (dir == TUSB_DIR_IN) {
 | 
			
		||||
      ep_addr |= TUSB_DIR_IN_MASK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return dcd_edpt_xfer (rhport, ep_addr, buffer, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(desc_edpt->bEndpointAddress);
 | 
			
		||||
  uint8_t const dir   = edpt_dir(desc_edpt->bEndpointAddress);
 | 
			
		||||
 | 
			
		||||
  UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
 | 
			
		||||
  uint32_t size_value = 0;
 | 
			
		||||
  while (size_value < 7) {
 | 
			
		||||
    if (1 << (size_value + 3) == desc_edpt->wMaxPacketSize.size) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    size_value++;
 | 
			
		||||
  }
 | 
			
		||||
  bank->PCKSIZE.bit.SIZE = size_value;
 | 
			
		||||
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  if ( dir == TUSB_DIR_OUT )
 | 
			
		||||
  {
 | 
			
		||||
    ep->EPCFG.bit.EPTYPE0 = desc_edpt->bmAttributes.xfer + 1;
 | 
			
		||||
    ep->EPINTENSET.bit.TRCPT0 = true;
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    ep->EPCFG.bit.EPTYPE1 = desc_edpt->bmAttributes.xfer + 1;
 | 
			
		||||
    ep->EPINTENSET.bit.TRCPT1 = true;
 | 
			
		||||
  }
 | 
			
		||||
  __ISB(); __DSB();
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  uint8_t const dir   = edpt_dir(ep_addr);
 | 
			
		||||
 | 
			
		||||
  UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  bank->ADDR.reg = (uint32_t) buffer;
 | 
			
		||||
  if ( dir == TUSB_DIR_OUT )
 | 
			
		||||
  {
 | 
			
		||||
    bank->PCKSIZE.bit.MULTI_PACKET_SIZE = total_bytes;
 | 
			
		||||
    bank->PCKSIZE.bit.BYTE_COUNT = 0;
 | 
			
		||||
    ep->EPSTATUSCLR.reg |= USB_DEVICE_EPSTATUSCLR_BK0RDY;
 | 
			
		||||
    ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL0;
 | 
			
		||||
  } else
 | 
			
		||||
  {
 | 
			
		||||
    bank->PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
 | 
			
		||||
    bank->PCKSIZE.bit.BYTE_COUNT = total_bytes;
 | 
			
		||||
    // bank->PCKSIZE.bit.AUTO_ZLP = 1;
 | 
			
		||||
    ep->EPSTATUSSET.reg |= USB_DEVICE_EPSTATUSSET_BK1RDY;
 | 
			
		||||
    ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_stalled (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  // control is never got halted
 | 
			
		||||
  if ( ep_addr == 0 ) {
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
  return (edpt_dir(ep_addr) == TUSB_DIR_IN ) ? ep->EPINTFLAG.bit.STALL1 : ep->EPINTFLAG.bit.STALL0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  if (edpt_dir(ep_addr) == TUSB_DIR_IN) {
 | 
			
		||||
      ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1;
 | 
			
		||||
  } else {
 | 
			
		||||
      ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  __ISB(); __DSB();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  if (edpt_dir(ep_addr) == TUSB_DIR_IN) {
 | 
			
		||||
    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1;
 | 
			
		||||
  } else {
 | 
			
		||||
    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  // USBD shouldn't check control endpoint state
 | 
			
		||||
  if ( 0 == ep_addr ) return false;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  if (edpt_dir(ep_addr) == TUSB_DIR_IN) {
 | 
			
		||||
    return ep->EPINTFLAG.bit.TRCPT1 == 0 && ep->EPSTATUS.bit.BK1RDY == 1;
 | 
			
		||||
  }
 | 
			
		||||
  return ep->EPINTFLAG.bit.TRCPT0 == 0 && ep->EPSTATUS.bit.BK0RDY == 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
static bool maybe_handle_setup_packet(void) {
 | 
			
		||||
    if (USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP)
 | 
			
		||||
    {
 | 
			
		||||
        USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP;
 | 
			
		||||
 | 
			
		||||
        // This copies the data elsewhere so we can reuse the buffer.
 | 
			
		||||
        dcd_event_setup_received(0, (uint8_t*) sram_registers[0][0].ADDR.reg, true);
 | 
			
		||||
        dcd_edpt_xfer(0, 0, control_out_buffer, 64);
 | 
			
		||||
        setup_count += 1;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void maybe_transfer_complete(void) {
 | 
			
		||||
    uint32_t epints = USB->DEVICE.EPINTSMRY.reg;
 | 
			
		||||
    for (uint8_t epnum = 0; epnum < USB_EPT_NUM; epnum++) {
 | 
			
		||||
        if ((epints & (1 << epnum)) == 0) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (maybe_handle_setup_packet()) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
        uint32_t epintflag = ep->EPINTFLAG.reg;
 | 
			
		||||
 | 
			
		||||
        // Handle IN completions
 | 
			
		||||
        if ((epintflag & USB_DEVICE_EPINTFLAG_TRCPT1) != 0) {
 | 
			
		||||
            ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1;
 | 
			
		||||
 | 
			
		||||
            UsbDeviceDescBank* bank = &sram_registers[epnum][TUSB_DIR_IN];
 | 
			
		||||
            uint16_t total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
 | 
			
		||||
 | 
			
		||||
            uint8_t ep_addr = epnum | TUSB_DIR_IN_MASK;
 | 
			
		||||
            dcd_event_xfer_complete(0, ep_addr, total_transfer_size, DCD_XFER_SUCCESS, true);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // Handle OUT completions
 | 
			
		||||
        if ((epintflag & USB_DEVICE_EPINTFLAG_TRCPT0) != 0) {
 | 
			
		||||
            ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT0;
 | 
			
		||||
 | 
			
		||||
            UsbDeviceDescBank* bank = &sram_registers[epnum][TUSB_DIR_OUT];
 | 
			
		||||
            uint16_t total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
 | 
			
		||||
 | 
			
		||||
            uint8_t ep_addr = epnum;
 | 
			
		||||
            dcd_event_xfer_complete(0, ep_addr, total_transfer_size, DCD_XFER_SUCCESS, true);
 | 
			
		||||
            if (epnum == 0) {
 | 
			
		||||
                dcd_edpt_xfer(0, 0, control_out_buffer, 64);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void USB_Handler(void) {
 | 
			
		||||
  uint32_t int_status = USB->DEVICE.INTFLAG.reg;
 | 
			
		||||
 | 
			
		||||
  /*------------- Interrupt Processing -------------*/
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_EORST )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_EORST;
 | 
			
		||||
    bus_reset();
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_SOF )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Setup packet received.
 | 
			
		||||
  maybe_handle_setup_packet();
 | 
			
		||||
 | 
			
		||||
  // Handle complete transfer
 | 
			
		||||
  maybe_transfer_complete();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										82
									
								
								src/portable/microchip/samd21/hal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								src/portable/microchip/samd21/hal.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,82 @@
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
/*!
 | 
			
		||||
    @file     hal_nrf5x.c
 | 
			
		||||
    @author   hathach
 | 
			
		||||
 | 
			
		||||
    @section LICENSE
 | 
			
		||||
 | 
			
		||||
    Software License Agreement (BSD License)
 | 
			
		||||
 | 
			
		||||
    Copyright (c) 2018, hathach (tinyusb.org)
 | 
			
		||||
    All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
    documentation and/or other materials provided with the distribution.
 | 
			
		||||
    3. Neither the name of the copyright holders nor the
 | 
			
		||||
    names of its contributors may be used to endorse or promote products
 | 
			
		||||
    derived from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 | 
			
		||||
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 | 
			
		||||
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
			
		||||
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
    This file is part of the tinyusb stack.
 | 
			
		||||
*/
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "tusb_option.h"
 | 
			
		||||
 | 
			
		||||
#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMD21
 | 
			
		||||
 | 
			
		||||
#include "sam.h"
 | 
			
		||||
 | 
			
		||||
#include "tusb_hal.h"
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* MACRO TYPEDEF CONSTANT ENUM
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
#define USB_NVIC_PRIO   7
 | 
			
		||||
 | 
			
		||||
void tusb_hal_nrf_power_event(uint32_t event);
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* TUSB HAL
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
bool tusb_hal_init(void)
 | 
			
		||||
{
 | 
			
		||||
  USB->DEVICE.PADCAL.bit.TRANSP = (*((uint32_t*) USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
 | 
			
		||||
  USB->DEVICE.PADCAL.bit.TRANSN = (*((uint32_t*) USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
 | 
			
		||||
  USB->DEVICE.PADCAL.bit.TRIM = (*((uint32_t*) USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
 | 
			
		||||
 | 
			
		||||
  USB->DEVICE.QOSCTRL.bit.CQOS = USB_QOSCTRL_CQOS_HIGH_Val;
 | 
			
		||||
  USB->DEVICE.QOSCTRL.bit.DQOS = USB_QOSCTRL_DQOS_HIGH_Val;
 | 
			
		||||
 | 
			
		||||
  tusb_hal_int_enable(0);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tusb_hal_int_enable(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  NVIC_EnableIRQ(USB_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tusb_hal_int_disable(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  NVIC_DisableIRQ(USB_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										360
									
								
								src/portable/microchip/samd51/dcd.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										360
									
								
								src/portable/microchip/samd51/dcd.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,360 @@
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
/*!
 | 
			
		||||
    @file     dcd_nrf5x.c
 | 
			
		||||
    @author   hathach
 | 
			
		||||
 | 
			
		||||
    @section LICENSE
 | 
			
		||||
 | 
			
		||||
    Software License Agreement (BSD License)
 | 
			
		||||
 | 
			
		||||
    Copyright (c) 2018, Scott Shawcroft for Adafruit Industries
 | 
			
		||||
    All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
    documentation and/or other materials provided with the distribution.
 | 
			
		||||
    3. Neither the name of the copyright holders nor the
 | 
			
		||||
    names of its contributors may be used to endorse or promote products
 | 
			
		||||
    derived from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 | 
			
		||||
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 | 
			
		||||
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
			
		||||
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
    This file is part of the tinyusb stack.
 | 
			
		||||
*/
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "tusb_option.h"
 | 
			
		||||
 | 
			
		||||
#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMD51
 | 
			
		||||
 | 
			
		||||
#include "device/dcd.h"
 | 
			
		||||
 | 
			
		||||
#include "device/usbd.h"
 | 
			
		||||
#include "device/usbd_pvt.h" // to use defer function helper
 | 
			
		||||
 | 
			
		||||
#include "sam.h"
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* MACRO TYPEDEF CONSTANT ENUM
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
enum
 | 
			
		||||
{
 | 
			
		||||
  // Max allowed by USB specs
 | 
			
		||||
  MAX_PACKET_SIZE   = 64,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
UsbDeviceDescBank sram_registers[8][2];
 | 
			
		||||
ATTR_ALIGNED(4) uint8_t control_out_buffer[64];
 | 
			
		||||
ATTR_ALIGNED(4) uint8_t control_in_buffer[64];
 | 
			
		||||
 | 
			
		||||
volatile uint32_t setup_count = 0;
 | 
			
		||||
 | 
			
		||||
// Setup the control endpoint 0.
 | 
			
		||||
static void bus_reset(void) {
 | 
			
		||||
    // Max size of packets is 64 bytes.
 | 
			
		||||
    UsbDeviceDescBank* bank_out = &sram_registers[0][TUSB_DIR_OUT];
 | 
			
		||||
    bank_out->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
    UsbDeviceDescBank* bank_in = &sram_registers[0][TUSB_DIR_IN];
 | 
			
		||||
    bank_in->PCKSIZE.bit.SIZE = 0x3;
 | 
			
		||||
 | 
			
		||||
    UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[0];
 | 
			
		||||
    ep->EPCFG.reg = USB_DEVICE_EPCFG_EPTYPE0(0x1) | USB_DEVICE_EPCFG_EPTYPE1(0x1);
 | 
			
		||||
    ep->EPINTENSET.reg = USB_DEVICE_EPINTENSET_TRCPT0 | USB_DEVICE_EPINTENSET_TRCPT1 | USB_DEVICE_EPINTENSET_RXSTP;
 | 
			
		||||
 | 
			
		||||
    dcd_edpt_xfer(0, 0, control_out_buffer, 64);
 | 
			
		||||
    setup_count = 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* Controller API
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
bool dcd_init (uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  USB->DEVICE.DESCADD.reg = (uint32_t) &sram_registers;
 | 
			
		||||
  USB->DEVICE.CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_FS;
 | 
			
		||||
  USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE;
 | 
			
		||||
  USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST;
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_connect (uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
void dcd_disconnect (uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  dcd_edpt_xfer (0, TUSB_DIR_IN_MASK, NULL, 0);
 | 
			
		||||
  // Wait for EP0 to finish before switching the address.
 | 
			
		||||
  while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
 | 
			
		||||
  USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  (void) config_num;
 | 
			
		||||
  // Nothing to do
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* Control
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
bool dcd_control_xfer (uint8_t rhport, uint8_t dir, uint8_t * buffer, uint16_t length)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  uint8_t ep_addr = 0;
 | 
			
		||||
  if (dir == TUSB_DIR_IN) {
 | 
			
		||||
      ep_addr |= TUSB_DIR_IN_MASK;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return dcd_edpt_xfer (rhport, ep_addr, buffer, length);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(desc_edpt->bEndpointAddress);
 | 
			
		||||
  uint8_t const dir   = edpt_dir(desc_edpt->bEndpointAddress);
 | 
			
		||||
 | 
			
		||||
  UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
 | 
			
		||||
  uint32_t size_value = 0;
 | 
			
		||||
  while (size_value < 7) {
 | 
			
		||||
    if (1 << (size_value + 3) == desc_edpt->wMaxPacketSize.size) {
 | 
			
		||||
      break;
 | 
			
		||||
    }
 | 
			
		||||
    size_value++;
 | 
			
		||||
  }
 | 
			
		||||
  bank->PCKSIZE.bit.SIZE = size_value;
 | 
			
		||||
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  if ( dir == TUSB_DIR_OUT )
 | 
			
		||||
  {
 | 
			
		||||
    ep->EPCFG.bit.EPTYPE0 = desc_edpt->bmAttributes.xfer + 1;
 | 
			
		||||
    ep->EPINTENSET.bit.TRCPT0 = true;
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    ep->EPCFG.bit.EPTYPE1 = desc_edpt->bmAttributes.xfer + 1;
 | 
			
		||||
    ep->EPINTENSET.bit.TRCPT1 = true;
 | 
			
		||||
  }
 | 
			
		||||
  __ISB(); __DSB();
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  uint8_t const dir   = edpt_dir(ep_addr);
 | 
			
		||||
 | 
			
		||||
  UsbDeviceDescBank* bank = &sram_registers[epnum][dir];
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  bank->ADDR.reg = (uint32_t) buffer;
 | 
			
		||||
  if ( dir == TUSB_DIR_OUT )
 | 
			
		||||
  {
 | 
			
		||||
    bank->PCKSIZE.bit.MULTI_PACKET_SIZE = total_bytes;
 | 
			
		||||
    bank->PCKSIZE.bit.BYTE_COUNT = 0;
 | 
			
		||||
    ep->EPSTATUSCLR.reg |= USB_DEVICE_EPSTATUSCLR_BK0RDY;
 | 
			
		||||
    ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL0;
 | 
			
		||||
  } else
 | 
			
		||||
  {
 | 
			
		||||
    bank->PCKSIZE.bit.MULTI_PACKET_SIZE = 0;
 | 
			
		||||
    bank->PCKSIZE.bit.BYTE_COUNT = total_bytes;
 | 
			
		||||
    ep->EPSTATUSSET.reg |= USB_DEVICE_EPSTATUSSET_BK1RDY;
 | 
			
		||||
    ep->EPINTFLAG.reg |= USB_DEVICE_EPINTFLAG_TRFAIL1;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_stalled (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  // control is never got halted
 | 
			
		||||
  if ( ep_addr == 0 ) {
 | 
			
		||||
      return false;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
  return (edpt_dir(ep_addr) == TUSB_DIR_IN ) ? ep->EPINTFLAG.bit.STALL1 : ep->EPINTFLAG.bit.STALL0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  if (edpt_dir(ep_addr) == TUSB_DIR_IN) {
 | 
			
		||||
      ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ1;
 | 
			
		||||
  } else {
 | 
			
		||||
      ep->EPSTATUSSET.reg = USB_DEVICE_EPSTATUSSET_STALLRQ0;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  __ISB(); __DSB();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  if (edpt_dir(ep_addr) == TUSB_DIR_IN) {
 | 
			
		||||
    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ1;
 | 
			
		||||
  } else {
 | 
			
		||||
    ep->EPSTATUSCLR.reg = USB_DEVICE_EPSTATUSCLR_STALLRQ0;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  // USBD shouldn't check control endpoint state
 | 
			
		||||
  if ( 0 == ep_addr ) return false;
 | 
			
		||||
 | 
			
		||||
  uint8_t const epnum = edpt_number(ep_addr);
 | 
			
		||||
  UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
  if (edpt_dir(ep_addr) == TUSB_DIR_IN) {
 | 
			
		||||
    return ep->EPINTFLAG.bit.TRCPT1 == 0 && ep->EPSTATUS.bit.BK1RDY == 1;
 | 
			
		||||
  }
 | 
			
		||||
  return ep->EPINTFLAG.bit.TRCPT0 == 0 && ep->EPSTATUS.bit.BK0RDY == 1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
static bool maybe_handle_setup_packet(void) {
 | 
			
		||||
    if (USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.bit.RXSTP)
 | 
			
		||||
    {
 | 
			
		||||
        USB->DEVICE.DeviceEndpoint[0].EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_RXSTP;
 | 
			
		||||
        // uint8_t* buf = (uint8_t*) sram_registers[0][0].ADDR.reg;
 | 
			
		||||
        //
 | 
			
		||||
        // if (buf[6] == 0x12) asm("bkpt");
 | 
			
		||||
        // This copies the data elsewhere so we can reuse the buffer.
 | 
			
		||||
        dcd_event_setup_received(0, (uint8_t*) sram_registers[0][0].ADDR.reg, true);
 | 
			
		||||
        dcd_edpt_xfer(0, 0, control_out_buffer, 64);
 | 
			
		||||
        setup_count += 1;
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
/* USB_EORSM_DNRSM, USB_EORST_RST, USB_LPMSUSP_DDISC, USB_LPM_DCONN,
 | 
			
		||||
USB_MSOF, USB_RAMACER, USB_RXSTP_TXSTP_0, USB_RXSTP_TXSTP_1,
 | 
			
		||||
USB_RXSTP_TXSTP_2, USB_RXSTP_TXSTP_3, USB_RXSTP_TXSTP_4,
 | 
			
		||||
USB_RXSTP_TXSTP_5, USB_RXSTP_TXSTP_6, USB_RXSTP_TXSTP_7,
 | 
			
		||||
USB_STALL0_STALL_0, USB_STALL0_STALL_1, USB_STALL0_STALL_2,
 | 
			
		||||
USB_STALL0_STALL_3, USB_STALL0_STALL_4, USB_STALL0_STALL_5,
 | 
			
		||||
USB_STALL0_STALL_6, USB_STALL0_STALL_7, USB_STALL1_0, USB_STALL1_1,
 | 
			
		||||
USB_STALL1_2, USB_STALL1_3, USB_STALL1_4, USB_STALL1_5, USB_STALL1_6,
 | 
			
		||||
USB_STALL1_7, USB_SUSPEND, USB_TRFAIL0_TRFAIL_0, USB_TRFAIL0_TRFAIL_1,
 | 
			
		||||
USB_TRFAIL0_TRFAIL_2, USB_TRFAIL0_TRFAIL_3, USB_TRFAIL0_TRFAIL_4,
 | 
			
		||||
USB_TRFAIL0_TRFAIL_5, USB_TRFAIL0_TRFAIL_6, USB_TRFAIL0_TRFAIL_7,
 | 
			
		||||
USB_TRFAIL1_PERR_0, USB_TRFAIL1_PERR_1, USB_TRFAIL1_PERR_2,
 | 
			
		||||
USB_TRFAIL1_PERR_3, USB_TRFAIL1_PERR_4, USB_TRFAIL1_PERR_5,
 | 
			
		||||
USB_TRFAIL1_PERR_6, USB_TRFAIL1_PERR_7, USB_UPRSM, USB_WAKEUP */
 | 
			
		||||
void USB_0_Handler(void) {
 | 
			
		||||
  uint32_t int_status = USB->DEVICE.INTFLAG.reg;
 | 
			
		||||
 | 
			
		||||
  /*------------- Interrupt Processing -------------*/
 | 
			
		||||
  if ( int_status & USB_DEVICE_INTFLAG_EORST )
 | 
			
		||||
  {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_EORST;
 | 
			
		||||
    bus_reset();
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Setup packet received.
 | 
			
		||||
  maybe_handle_setup_packet();
 | 
			
		||||
}
 | 
			
		||||
/* USB_SOF_HSOF */
 | 
			
		||||
void USB_1_Handler(void) {
 | 
			
		||||
    USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
 | 
			
		||||
    dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void transfer_complete(uint8_t direction) {
 | 
			
		||||
        // uint8_t* buf = (uint8_t*) sram_registers[0][0].ADDR.reg;
 | 
			
		||||
        //
 | 
			
		||||
        // if (buf[6] == 0x12 || setup_count == 2) asm("bkpt");
 | 
			
		||||
    uint32_t epints = USB->DEVICE.EPINTSMRY.reg;
 | 
			
		||||
    for (uint8_t epnum = 0; epnum < USB_EPT_NUM; epnum++) {
 | 
			
		||||
        if ((epints & (1 << epnum)) == 0) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (direction == TUSB_DIR_OUT && maybe_handle_setup_packet()) {
 | 
			
		||||
            continue;
 | 
			
		||||
        }
 | 
			
		||||
        UsbDeviceEndpoint* ep = &USB->DEVICE.DeviceEndpoint[epnum];
 | 
			
		||||
 | 
			
		||||
        UsbDeviceDescBank* bank = &sram_registers[epnum][direction];
 | 
			
		||||
        uint16_t total_transfer_size = bank->PCKSIZE.bit.BYTE_COUNT;
 | 
			
		||||
 | 
			
		||||
        uint8_t ep_addr = epnum;
 | 
			
		||||
        if (direction == TUSB_DIR_IN) {
 | 
			
		||||
            ep_addr |= TUSB_DIR_IN_MASK;
 | 
			
		||||
        }
 | 
			
		||||
        dcd_event_xfer_complete(0, ep_addr, total_transfer_size, DCD_XFER_SUCCESS, true);
 | 
			
		||||
        if (epnum == 0 && direction == TUSB_DIR_OUT) {
 | 
			
		||||
            dcd_edpt_xfer(0, 0, control_out_buffer, 64);
 | 
			
		||||
        }
 | 
			
		||||
        if (direction == TUSB_DIR_IN) {
 | 
			
		||||
            ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT1;
 | 
			
		||||
        } else {
 | 
			
		||||
            ep->EPINTFLAG.reg = USB_DEVICE_EPINTFLAG_TRCPT0;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Bank zero is for OUT and SETUP transactions.
 | 
			
		||||
/* USB_TRCPT0_0, USB_TRCPT0_1, USB_TRCPT0_2,
 | 
			
		||||
USB_TRCPT0_3, USB_TRCPT0_4, USB_TRCPT0_5,
 | 
			
		||||
USB_TRCPT0_6, USB_TRCPT0_7 */
 | 
			
		||||
void USB_2_Handler(void) {
 | 
			
		||||
    transfer_complete(TUSB_DIR_OUT);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Bank one is used for IN transactions.
 | 
			
		||||
/* USB_TRCPT1_0, USB_TRCPT1_1, USB_TRCPT1_2,
 | 
			
		||||
USB_TRCPT1_3, USB_TRCPT1_4, USB_TRCPT1_5,
 | 
			
		||||
USB_TRCPT1_6, USB_TRCPT1_7 */
 | 
			
		||||
void USB_3_Handler(void) {
 | 
			
		||||
    transfer_complete(TUSB_DIR_IN);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
							
								
								
									
										88
									
								
								src/portable/microchip/samd51/hal.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								src/portable/microchip/samd51/hal.c
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,88 @@
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
/*!
 | 
			
		||||
    @file     hal_nrf5x.c
 | 
			
		||||
    @author   hathach
 | 
			
		||||
 | 
			
		||||
    @section LICENSE
 | 
			
		||||
 | 
			
		||||
    Software License Agreement (BSD License)
 | 
			
		||||
 | 
			
		||||
    Copyright (c) 2018, hathach (tinyusb.org)
 | 
			
		||||
    All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions are met:
 | 
			
		||||
    1. Redistributions of source code must retain the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer.
 | 
			
		||||
    2. Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
    notice, this list of conditions and the following disclaimer in the
 | 
			
		||||
    documentation and/or other materials provided with the distribution.
 | 
			
		||||
    3. Neither the name of the copyright holders nor the
 | 
			
		||||
    names of its contributors may be used to endorse or promote products
 | 
			
		||||
    derived from this software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
 | 
			
		||||
    EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 | 
			
		||||
    WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 | 
			
		||||
    DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
 | 
			
		||||
    DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 | 
			
		||||
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 | 
			
		||||
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 | 
			
		||||
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 | 
			
		||||
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
    This file is part of the tinyusb stack.
 | 
			
		||||
*/
 | 
			
		||||
/**************************************************************************/
 | 
			
		||||
 | 
			
		||||
#include "tusb_option.h"
 | 
			
		||||
 | 
			
		||||
#if TUSB_OPT_DEVICE_ENABLED && CFG_TUSB_MCU == OPT_MCU_SAMD51
 | 
			
		||||
 | 
			
		||||
#include "sam.h"
 | 
			
		||||
 | 
			
		||||
#include "tusb_hal.h"
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* MACRO TYPEDEF CONSTANT ENUM
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
#define USB_NVIC_PRIO   7
 | 
			
		||||
 | 
			
		||||
void tusb_hal_nrf_power_event(uint32_t event);
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/* TUSB HAL
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
bool tusb_hal_init(void)
 | 
			
		||||
{
 | 
			
		||||
  USB->DEVICE.PADCAL.bit.TRANSP = (*((uint32_t*) USB_FUSES_TRANSP_ADDR) & USB_FUSES_TRANSP_Msk) >> USB_FUSES_TRANSP_Pos;
 | 
			
		||||
  USB->DEVICE.PADCAL.bit.TRANSN = (*((uint32_t*) USB_FUSES_TRANSN_ADDR) & USB_FUSES_TRANSN_Msk) >> USB_FUSES_TRANSN_Pos;
 | 
			
		||||
  USB->DEVICE.PADCAL.bit.TRIM = (*((uint32_t*) USB_FUSES_TRIM_ADDR) & USB_FUSES_TRIM_Msk) >> USB_FUSES_TRIM_Pos;
 | 
			
		||||
 | 
			
		||||
  USB->DEVICE.QOSCTRL.bit.CQOS = 3;
 | 
			
		||||
  USB->DEVICE.QOSCTRL.bit.DQOS = 3;
 | 
			
		||||
 | 
			
		||||
  tusb_hal_int_enable(0);
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tusb_hal_int_enable(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  NVIC_EnableIRQ(USB_0_IRQn);
 | 
			
		||||
  NVIC_EnableIRQ(USB_1_IRQn);
 | 
			
		||||
  NVIC_EnableIRQ(USB_2_IRQn);
 | 
			
		||||
  NVIC_EnableIRQ(USB_3_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void tusb_hal_int_disable(uint8_t rhport)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
  NVIC_DisableIRQ(USB_3_IRQn);
 | 
			
		||||
  NVIC_DisableIRQ(USB_2_IRQn);
 | 
			
		||||
  NVIC_DisableIRQ(USB_1_IRQn);
 | 
			
		||||
  NVIC_DisableIRQ(USB_0_IRQn);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
@@ -82,17 +82,8 @@ typedef struct
 | 
			
		||||
 | 
			
		||||
/*static*/ struct
 | 
			
		||||
{
 | 
			
		||||
  struct
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t* buffer;
 | 
			
		||||
    uint16_t total_len;
 | 
			
		||||
    volatile uint16_t actual_len;
 | 
			
		||||
 | 
			
		||||
    uint8_t  dir;
 | 
			
		||||
  }control;
 | 
			
		||||
 | 
			
		||||
  // Non control: 7 endpoints IN & OUT (offset 1)
 | 
			
		||||
  nom_xfer_t xfer[7][2];
 | 
			
		||||
  // All 8 endpoints including control IN & OUT (offset 1)
 | 
			
		||||
  nom_xfer_t xfer[8][2];
 | 
			
		||||
 | 
			
		||||
  volatile bool dma_running;
 | 
			
		||||
}_dcd;
 | 
			
		||||
@@ -109,6 +100,8 @@ void bus_reset(void)
 | 
			
		||||
  NRF_USBD->TASKS_STARTISOOUT = 0;
 | 
			
		||||
 | 
			
		||||
  tu_varclr(&_dcd);
 | 
			
		||||
  _dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE;
 | 
			
		||||
  _dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
@@ -176,61 +169,13 @@ static void edpt_dma_end(void)
 | 
			
		||||
  _dcd.dma_running = false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void xact_control_start(void)
 | 
			
		||||
{
 | 
			
		||||
  // Each transaction is up to 64 bytes
 | 
			
		||||
  uint8_t const xact_len = tu_min16(_dcd.control.total_len-_dcd.control.actual_len, MAX_PACKET_SIZE);
 | 
			
		||||
 | 
			
		||||
  if ( _dcd.control.dir == TUSB_DIR_OUT )
 | 
			
		||||
  {
 | 
			
		||||
    // TODO control out
 | 
			
		||||
    NRF_USBD->EPOUT[0].PTR    = (uint32_t) _dcd.control.buffer;
 | 
			
		||||
    NRF_USBD->EPOUT[0].MAXCNT = xact_len;
 | 
			
		||||
 | 
			
		||||
    NRF_USBD->TASKS_EP0RCVOUT = 1;
 | 
			
		||||
    __ISB(); __DSB();
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    NRF_USBD->EPIN[0].PTR        = (uint32_t) _dcd.control.buffer;
 | 
			
		||||
    NRF_USBD->EPIN[0].MAXCNT     = xact_len;
 | 
			
		||||
 | 
			
		||||
    edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[0]);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  _dcd.control.buffer     += xact_len;
 | 
			
		||||
  _dcd.control.actual_len += xact_len;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_control_xfer (uint8_t rhport, uint8_t dir, uint8_t * buffer, uint16_t length)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
 | 
			
		||||
  if ( length )
 | 
			
		||||
  {
 | 
			
		||||
    // Data Phase
 | 
			
		||||
    _dcd.control.total_len  = length;
 | 
			
		||||
    _dcd.control.actual_len = 0;
 | 
			
		||||
    _dcd.control.buffer     = buffer;
 | 
			
		||||
    _dcd.control.dir        = dir;
 | 
			
		||||
 | 
			
		||||
    xact_control_start();
 | 
			
		||||
  }else
 | 
			
		||||
  {
 | 
			
		||||
    // Status Phase also require Easy DMA has to be free as well !!!!
 | 
			
		||||
    edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
 | 
			
		||||
    edpt_dma_end();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------------------------------------------------------------*/
 | 
			
		||||
/*
 | 
			
		||||
 *------------------------------------------------------------------*/
 | 
			
		||||
 | 
			
		||||
static inline nom_xfer_t* get_td(uint8_t epnum, uint8_t dir)
 | 
			
		||||
{
 | 
			
		||||
  return &_dcd.xfer[epnum-1][dir];
 | 
			
		||||
  return &_dcd.xfer[epnum][dir];
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*------------- Bulk/Int OUT transfer -------------*/
 | 
			
		||||
@@ -292,7 +237,7 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
 | 
			
		||||
  uint8_t const epnum = edpt_number(desc_edpt->bEndpointAddress);
 | 
			
		||||
  uint8_t const dir   = edpt_dir(desc_edpt->bEndpointAddress);
 | 
			
		||||
 | 
			
		||||
  _dcd.xfer[epnum-1][dir].mps = desc_edpt->wMaxPacketSize.size;
 | 
			
		||||
  _dcd.xfer[epnum][dir].mps = desc_edpt->wMaxPacketSize.size;
 | 
			
		||||
 | 
			
		||||
  if ( dir == TUSB_DIR_OUT )
 | 
			
		||||
  {
 | 
			
		||||
@@ -308,6 +253,16 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void control_status_token(uint8_t addr) {
 | 
			
		||||
  NRF_USBD->EPIN[0].PTR        = 0;
 | 
			
		||||
  NRF_USBD->EPIN[0].MAXCNT     = 0;
 | 
			
		||||
  // Status Phase also require Easy DMA has to be free as well !!!!
 | 
			
		||||
  NRF_USBD->TASKS_EP0STATUS = 1;
 | 
			
		||||
 | 
			
		||||
  // The nRF doesn't interrupt on status transmit so we queue up a success response.
 | 
			
		||||
  dcd_event_xfer_complete(0, addr, 0, DCD_XFER_SUCCESS, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
 | 
			
		||||
{
 | 
			
		||||
  (void) rhport;
 | 
			
		||||
@@ -321,7 +276,10 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
 | 
			
		||||
  xfer->total_len  = total_bytes;
 | 
			
		||||
  xfer->actual_len = 0;
 | 
			
		||||
 | 
			
		||||
  if ( dir == TUSB_DIR_OUT )
 | 
			
		||||
  // How does the control endpoint handle a ZLP in the data phase?
 | 
			
		||||
  if (epnum == 0 && total_bytes == 0) {
 | 
			
		||||
      control_status_token(ep_addr);
 | 
			
		||||
  } else if ( dir == TUSB_DIR_OUT )
 | 
			
		||||
  {
 | 
			
		||||
    if ( xfer->data_received )
 | 
			
		||||
    {
 | 
			
		||||
@@ -427,47 +385,15 @@ void USBD_IRQHandler(void)
 | 
			
		||||
    edpt_dma_end();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /*------------- Control Transfer -------------*/
 | 
			
		||||
  // Setup tokens are specific to the Control endpoint.
 | 
			
		||||
  if ( int_status & USBD_INTEN_EP0SETUP_Msk )
 | 
			
		||||
  {
 | 
			
		||||
    uint8_t setup[8] = {
 | 
			
		||||
        NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH,
 | 
			
		||||
        NRF_USBD->WINDEXL       , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
 | 
			
		||||
    };
 | 
			
		||||
    dcd_event_setup_recieved(0, setup, true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( int_status & USBD_INTEN_EP0DATADONE_Msk )
 | 
			
		||||
  {
 | 
			
		||||
    if ( _dcd.control.dir == TUSB_DIR_OUT )
 | 
			
		||||
    {
 | 
			
		||||
      // Control OUT: data from Host -> Endpoint
 | 
			
		||||
      // Trigger DMA to move Endpoint -> SRAM
 | 
			
		||||
      edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[0]);
 | 
			
		||||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      // Control IN: data transferred from Endpoint -> Host
 | 
			
		||||
      if ( _dcd.control.actual_len < _dcd.control.total_len )
 | 
			
		||||
      {
 | 
			
		||||
        xact_control_start();
 | 
			
		||||
      }else
 | 
			
		||||
      {
 | 
			
		||||
        // Control IN complete
 | 
			
		||||
        dcd_event_xfer_complete(0, 0, _dcd.control.actual_len, DCD_XFER_SUCCESS, true);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // Control OUT: data from Endpoint -> SRAM
 | 
			
		||||
  if ( int_status & USBD_INTEN_ENDEPOUT0_Msk)
 | 
			
		||||
  {
 | 
			
		||||
    if ( _dcd.control.actual_len < _dcd.control.total_len )
 | 
			
		||||
    {
 | 
			
		||||
      xact_control_start();
 | 
			
		||||
    }else
 | 
			
		||||
    {
 | 
			
		||||
      // Control OUT complete
 | 
			
		||||
      dcd_event_xfer_complete(0, 0, _dcd.control.actual_len, DCD_XFER_SUCCESS, true);
 | 
			
		||||
    if (setup[1] != TUSB_REQ_SET_ADDRESS) {
 | 
			
		||||
      dcd_event_setup_received(0, setup, true);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -478,9 +404,9 @@ void USBD_IRQHandler(void)
 | 
			
		||||
   * We must handle this stage before Host -> Endpoint just in case
 | 
			
		||||
   * 2 event happens at once
 | 
			
		||||
   */
 | 
			
		||||
  for(uint8_t epnum=1; epnum<8; epnum++)
 | 
			
		||||
  for(uint8_t epnum=0; epnum<8; epnum++)
 | 
			
		||||
  {
 | 
			
		||||
    if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum) )
 | 
			
		||||
    if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum))
 | 
			
		||||
    {
 | 
			
		||||
      nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
 | 
			
		||||
 | 
			
		||||
@@ -505,16 +431,16 @@ void USBD_IRQHandler(void)
 | 
			
		||||
    // Ended event for Bulk/Int : nothing to do
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  if ( int_status & USBD_INTEN_EPDATA_Msk)
 | 
			
		||||
  if ( int_status & USBD_INTEN_EPDATA_Msk || int_status & USBD_INTEN_EP0DATADONE_Msk)
 | 
			
		||||
  {
 | 
			
		||||
    uint32_t data_status = NRF_USBD->EPDATASTATUS;
 | 
			
		||||
 | 
			
		||||
    nrf_usbd_epdatastatus_clear(data_status);
 | 
			
		||||
 | 
			
		||||
    // Bulk/Int In: data from Endpoint -> Host
 | 
			
		||||
    for(uint8_t epnum=1; epnum<8; epnum++)
 | 
			
		||||
    for(uint8_t epnum=0; epnum<8; epnum++)
 | 
			
		||||
    {
 | 
			
		||||
      if ( BIT_TEST_(data_status, epnum ) )
 | 
			
		||||
      if ( BIT_TEST_(data_status, epnum ) || (epnum == 0 && BIT_TEST_(int_status, USBD_INTEN_EP0DATADONE_Pos)))
 | 
			
		||||
      {
 | 
			
		||||
        nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN);
 | 
			
		||||
 | 
			
		||||
@@ -533,7 +459,7 @@ void USBD_IRQHandler(void)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Bulk/Int OUT: data from Host -> Endpoint
 | 
			
		||||
    for(uint8_t epnum=1; epnum<8; epnum++)
 | 
			
		||||
    for(uint8_t epnum=0; epnum<8; epnum++)
 | 
			
		||||
    {
 | 
			
		||||
      if ( BIT_TEST_(data_status, 16+epnum ) )
 | 
			
		||||
      {
 | 
			
		||||
 
 | 
			
		||||
@@ -57,6 +57,9 @@
 | 
			
		||||
#define OPT_MCU_LPC43XX        7 ///< NXP LPC43xx series
 | 
			
		||||
 | 
			
		||||
#define OPT_MCU_NRF5X        100 ///< Nordic nRF5x series
 | 
			
		||||
 | 
			
		||||
#define OPT_MCU_SAMD21        200 ///< MicroChip SAMD21
 | 
			
		||||
#define OPT_MCU_SAMD51        201 ///< MicroChip SAMD51
 | 
			
		||||
/** @} */
 | 
			
		||||
 | 
			
		||||
/** \defgroup group_supported_os Supported RTOS
 | 
			
		||||
@@ -147,6 +150,8 @@
 | 
			
		||||
 | 
			
		||||
  #ifndef CFG_TUD_ENUM_BUFFER_SIZE
 | 
			
		||||
    #define CFG_TUD_CTRL_BUFSIZE 256
 | 
			
		||||
  #else
 | 
			
		||||
    #define CFG_TUD_CTRL_BUFSIZE CFG_TUD_ENUM_BUFFER_SIZE
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #ifndef CFG_TUD_DESC_AUTO
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user