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
	 hathach
					hathach