Merge pull request #7 from tannewt/tinyusb_samd

Add SAMD support and simplify OS_NONE
This commit is contained in:
hathach 2018-11-14 15:36:12 +07:00 committed by GitHub
commit 983225ae60
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 1601 additions and 588 deletions

View File

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

View File

@ -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)

View File

@ -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);

View File

@ -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;
}

View File

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

View File

@ -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
}

View File

@ -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)

View File

@ -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_ */

View File

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

View File

@ -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 )
{

View File

@ -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_ */

View File

@ -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
View 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
View 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_ */
/** @} */

View File

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

View File

@ -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++)

View File

@ -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
*------------------------------------------------------------------*/

View File

@ -183,4 +183,3 @@ static inline void osal_queue_reset(osal_queue_t const queue_hdl)
/** @} */
/** @} */

View File

@ -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
}

View 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

View 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

View 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

View 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

View File

@ -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 ) )
{

View File

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