Add SAMD21 and SAMD51 support for CircuitPython.

The ProtoThreads style subtasks were removed because it led to
extremely unclear control flow. RTOSes can be used if threading is
needed.

Also added some additional functionality to MSC to support dynamic
LUNs and read-only LUNs.
This commit is contained in:
Scott Shawcroft 2018-10-24 23:55:10 -07:00
parent cb9bcce6a2
commit c582c0fda9
No known key found for this signature in database
GPG Key ID: FD0EDC4B6C53CA59
16 changed files with 1051 additions and 208 deletions

View File

@ -289,8 +289,6 @@ tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface
tusb_error_t cdcd_control_request_st(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 TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
@ -301,7 +299,7 @@ tusb_error_t cdcd_control_request_st(uint8_t rhport, tusb_control_request_t cons
if ( (CDC_REQUEST_GET_LINE_CODING == p_request->bRequest) || (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);
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, (uint8_t*) &p_cdc->line_coding, len);
// Invoke callback
if (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest)
@ -327,8 +325,7 @@ tusb_error_t cdcd_control_request_st(uint8_t rhport, tusb_control_request_t cons
{
dcd_control_stall(rhport); // 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

@ -407,8 +407,6 @@ tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t cons
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)
{
@ -419,7 +417,7 @@ 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 );
TU_ASSERT ( p_hid->desc_len <= CFG_TUD_CTRL_BUFSIZE );
memcpy(_usbd_ctrl_buf, p_hid->desc_report, p_hid->desc_len);
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, _usbd_ctrl_buf, p_hid->desc_len);
@ -447,7 +445,7 @@ tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t cons
xferlen = p_request->wLength;
}
STASK_ASSERT( xferlen > 0 );
TU_ASSERT( xferlen > 0 );
usbd_control_xfer_st(rhport, p_request->bmRequestType_bit.direction, p_hid->report_buf, xferlen);
}
else if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest )
@ -492,8 +490,7 @@ tusb_error_t hidd_control_request_st(uint8_t rhport, tusb_control_request_t cons
{
dcd_control_stall(rhport);
}
OSAL_SUBTASK_END
return TUSB_ERROR_NONE;
}
tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes)

View File

@ -279,11 +279,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;

View File

@ -59,31 +59,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];
//--------------------------------------------------------------------+
@ -172,8 +148,6 @@ tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf,
tusb_error_t mscd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request)
{
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)
@ -189,10 +163,19 @@ tusb_error_t mscd_control_request_st(uint8_t rhport, tusb_control_request_t cons
{
dcd_control_stall(rhport); // stall unsupported request
}
OSAL_SUBTASK_END
return TUSB_ERROR_NONE;
}
// 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 +185,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 +203,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 +242,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 +290,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 +424,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);
/** @} */
/** @} */
@ -185,4 +209,3 @@ void mscd_reset(uint8_t rhport);
#endif
#endif /* _TUSB_MSC_DEVICE_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);
/*------------------------------------------------------------------*/
@ -167,7 +148,7 @@ static inline bool dcd_control_status(uint8_t rhport, uint8_t dir)
static inline void dcd_control_stall(uint8_t rhport)
{
dcd_edpt_stall(rhport, 0);
dcd_edpt_stall(rhport, 0 | TUSB_DIR_IN_MASK);
}
#ifdef __cplusplus

View File

@ -239,25 +239,25 @@ void usbd_task( void* param)
OSAL_TASK_END
}
extern uint32_t setup_count;
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 );
proc_control_request_st(event.rhport, &event.setup_received);
}
else if (DCD_EVENT_XFER_COMPLETE == event.event_id)
{
@ -267,7 +267,7 @@ 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)
@ -304,7 +304,7 @@ static tusb_error_t usbd_main_st(void)
}
}
OSAL_SUBTASK_END
return err;
}
//--------------------------------------------------------------------+
@ -312,10 +312,7 @@ static tusb_error_t usbd_main_st(void)
//--------------------------------------------------------------------+
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;
tusb_error_t error = TUSB_ERROR_NONE;
//------------- Standard Request e.g in enumeration -------------//
if( TUSB_REQ_RCPT_DEVICE == p_request->bmRequestType_bit.recipient &&
@ -326,9 +323,10 @@ static tusb_error_t proc_control_request_st(uint8_t rhport, tusb_control_request
uint8_t const * buffer = NULL;
uint16_t const len = get_descriptor(rhport, p_request, &buffer);
if ( len )
{
STASK_ASSERT( len <= CFG_TUD_CTRL_BUFSIZE );
TU_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
@ -365,7 +363,7 @@ static tusb_error_t proc_control_request_st(uint8_t rhport, tusb_control_request
{
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 );
error = usbd_class_drivers[ _usbd_dev.itf2drv[ tu_u16_low(p_request->wIndex) ] ].control_req_st(rhport, p_request);
}else
{
dcd_control_stall(rhport); // Stall unsupported request
@ -406,8 +404,10 @@ static tusb_error_t proc_control_request_st(uint8_t rhport, tusb_control_request
{
dcd_control_stall(rhport); // Stall unsupported request
}
OSAL_SUBTASK_END
if (error != TUSB_ERROR_NONE) {
dcd_control_stall(rhport); // Stall errored requests
}
return error;
}
// Process Set Configure Request
@ -548,8 +548,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:
@ -590,9 +588,49 @@ 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
//--------------------------------------------------------------------+
uint32_t usbd_control_xfer_st(uint8_t _rhport, uint8_t _dir, uint8_t* _buffer, uint16_t _len) {
uint32_t err = TUSB_ERROR_NONE;
if (_len) {
dcd_control_xfer(_rhport, _dir, (uint8_t*) _buffer, _len);
}
dcd_control_status(_rhport, _dir);
return err;
}
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

@ -64,20 +64,7 @@ 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)
uint32_t usbd_control_xfer_st(uint8_t _rhport, uint8_t _dir, uint8_t* _buffer, uint16_t _len);
/*------------------------------------------------------------------*/
/* 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
@ -218,22 +170,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_SAMD51
#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

@ -203,7 +203,9 @@ static void xact_control_start(void)
bool dcd_control_xfer (uint8_t rhport, uint8_t dir, uint8_t * buffer, uint16_t length)
{
(void) rhport;
osal_semaphore_wait( _usbd_ctrl_sem, OSAL_TIMEOUT_CONTROL_XFER);
if ( length )
{
@ -216,9 +218,11 @@ bool dcd_control_xfer (uint8_t rhport, uint8_t dir, uint8_t * buffer, uint16_t l
xact_control_start();
}else
{
NRF_USBD->EPIN[0].PTR = 0;
NRF_USBD->EPIN[0].MAXCNT = 0;
// Status Phase also require Easy DMA has to be free as well !!!!
edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
edpt_dma_end();
NRF_USBD->TASKS_EP0STATUS = 1;
osal_semaphore_post(_usbd_ctrl_sem, false);
}
return true;
@ -434,7 +438,7 @@ void USBD_IRQHandler(void)
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);
dcd_event_setup_received(0, setup, true);
}
if ( int_status & USBD_INTEN_EP0DATADONE_Msk )

View File

@ -147,6 +147,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