Merge branch 'master' of https://github.com/hathach/tinyusb into uac_interl
This commit is contained in:
@@ -43,16 +43,14 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
enum
|
||||
{
|
||||
enum {
|
||||
MSC_STAGE_IDLE = 0,
|
||||
MSC_STAGE_CMD,
|
||||
MSC_STAGE_DATA,
|
||||
MSC_STAGE_STATUS,
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
typedef struct {
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
@@ -69,13 +67,13 @@ typedef struct
|
||||
|
||||
//------------- SCSI -------------//
|
||||
uint8_t stage;
|
||||
void* buffer;
|
||||
void* buffer;
|
||||
tuh_msc_complete_cb_t complete_cb;
|
||||
uintptr_t complete_arg;
|
||||
|
||||
CFG_TUH_MEM_ALIGN msc_cbw_t cbw;
|
||||
CFG_TUH_MEM_ALIGN msc_csw_t csw;
|
||||
}msch_interface_t;
|
||||
} msch_interface_t;
|
||||
|
||||
CFG_TUH_MEM_SECTION static msch_interface_t _msch_itf[CFG_TUH_DEVICE_MAX];
|
||||
|
||||
@@ -86,40 +84,34 @@ static uint8_t _msch_buffer[sizeof(scsi_inquiry_resp_t)];
|
||||
|
||||
// FIXME potential nul reference
|
||||
TU_ATTR_ALWAYS_INLINE
|
||||
static inline msch_interface_t* get_itf(uint8_t dev_addr)
|
||||
{
|
||||
return &_msch_itf[dev_addr-1];
|
||||
static inline msch_interface_t* get_itf(uint8_t dev_addr) {
|
||||
return &_msch_itf[dev_addr - 1];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// PUBLIC API
|
||||
//--------------------------------------------------------------------+
|
||||
uint8_t tuh_msc_get_maxlun(uint8_t dev_addr)
|
||||
{
|
||||
uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
return p_msc->max_lun;
|
||||
}
|
||||
|
||||
uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun)
|
||||
{
|
||||
uint32_t tuh_msc_get_block_count(uint8_t dev_addr, uint8_t lun) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
return p_msc->capacity[lun].block_count;
|
||||
}
|
||||
|
||||
uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun)
|
||||
{
|
||||
uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
return p_msc->capacity[lun].block_size;
|
||||
}
|
||||
|
||||
bool tuh_msc_mounted(uint8_t dev_addr)
|
||||
{
|
||||
bool tuh_msc_mounted(uint8_t dev_addr) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
return p_msc->mounted;
|
||||
}
|
||||
|
||||
bool tuh_msc_ready(uint8_t dev_addr)
|
||||
{
|
||||
bool tuh_msc_ready(uint8_t dev_addr) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
return p_msc->mounted && !usbh_edpt_busy(dev_addr, p_msc->ep_in) && !usbh_edpt_busy(dev_addr, p_msc->ep_out);
|
||||
}
|
||||
@@ -127,20 +119,20 @@ bool tuh_msc_ready(uint8_t dev_addr)
|
||||
//--------------------------------------------------------------------+
|
||||
// PUBLIC API: SCSI COMMAND
|
||||
//--------------------------------------------------------------------+
|
||||
static inline void cbw_init(msc_cbw_t *cbw, uint8_t lun)
|
||||
{
|
||||
static inline void cbw_init(msc_cbw_t* cbw, uint8_t lun) {
|
||||
tu_memclr(cbw, sizeof(msc_cbw_t));
|
||||
cbw->signature = MSC_CBW_SIGNATURE;
|
||||
cbw->tag = 0x54555342; // TUSB
|
||||
cbw->lun = lun;
|
||||
}
|
||||
|
||||
bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
||||
{
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data,
|
||||
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||
msch_interface_t* p_msc = get_itf(daddr);
|
||||
TU_VERIFY(p_msc->configured);
|
||||
|
||||
// TODO claim endpoint
|
||||
// claim endpoint
|
||||
TU_VERIFY(usbh_edpt_claim(daddr, p_msc->ep_out));
|
||||
|
||||
p_msc->cbw = *cbw;
|
||||
p_msc->stage = MSC_STAGE_CMD;
|
||||
@@ -148,15 +140,18 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu
|
||||
p_msc->complete_cb = complete_cb;
|
||||
p_msc->complete_arg = arg;
|
||||
|
||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t)));
|
||||
if (!usbh_edpt_xfer(daddr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))) {
|
||||
usbh_edpt_release(daddr, p_msc->ep_out);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
||||
{
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
TU_VERIFY(p_msc->configured);
|
||||
bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response,
|
||||
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
TU_VERIFY(p_msc->configured);
|
||||
|
||||
msc_cbw_t cbw;
|
||||
cbw_init(&cbw, lun);
|
||||
@@ -169,8 +164,8 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r
|
||||
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
||||
}
|
||||
|
||||
bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
||||
{
|
||||
bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response,
|
||||
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
TU_VERIFY(p_msc->mounted);
|
||||
|
||||
@@ -181,18 +176,16 @@ bool tuh_msc_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* respons
|
||||
cbw.dir = TUSB_DIR_IN_MASK;
|
||||
cbw.cmd_len = sizeof(scsi_inquiry_t);
|
||||
|
||||
scsi_inquiry_t const cmd_inquiry =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_INQUIRY,
|
||||
.alloc_length = sizeof(scsi_inquiry_resp_t)
|
||||
scsi_inquiry_t const cmd_inquiry = {
|
||||
.cmd_code = SCSI_CMD_INQUIRY,
|
||||
.alloc_length = sizeof(scsi_inquiry_resp_t)
|
||||
};
|
||||
memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len);
|
||||
|
||||
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
||||
}
|
||||
|
||||
bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
||||
{
|
||||
bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
TU_VERIFY(p_msc->configured);
|
||||
|
||||
@@ -200,16 +193,16 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_
|
||||
cbw_init(&cbw, lun);
|
||||
|
||||
cbw.total_bytes = 0;
|
||||
cbw.dir = TUSB_DIR_OUT;
|
||||
cbw.cmd_len = sizeof(scsi_test_unit_ready_t);
|
||||
cbw.command[0] = SCSI_CMD_TEST_UNIT_READY;
|
||||
cbw.command[1] = lun; // according to wiki TODO need verification
|
||||
cbw.dir = TUSB_DIR_OUT;
|
||||
cbw.cmd_len = sizeof(scsi_test_unit_ready_t);
|
||||
cbw.command[0] = SCSI_CMD_TEST_UNIT_READY;
|
||||
cbw.command[1] = lun; // according to wiki TODO need verification
|
||||
|
||||
return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb, arg);
|
||||
}
|
||||
|
||||
bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
||||
{
|
||||
bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void* response,
|
||||
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||
msc_cbw_t cbw;
|
||||
cbw_init(&cbw, lun);
|
||||
|
||||
@@ -217,73 +210,64 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *response, tuh_ms
|
||||
cbw.dir = TUSB_DIR_IN_MASK;
|
||||
cbw.cmd_len = sizeof(scsi_request_sense_t);
|
||||
|
||||
scsi_request_sense_t const cmd_request_sense =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_REQUEST_SENSE,
|
||||
.alloc_length = 18
|
||||
scsi_request_sense_t const cmd_request_sense = {
|
||||
.cmd_code = SCSI_CMD_REQUEST_SENSE,
|
||||
.alloc_length = 18
|
||||
};
|
||||
|
||||
memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len);
|
||||
|
||||
return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb, arg);
|
||||
}
|
||||
|
||||
bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
||||
{
|
||||
bool tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void* buffer, uint32_t lba, uint16_t block_count,
|
||||
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
TU_VERIFY(p_msc->mounted);
|
||||
|
||||
msc_cbw_t cbw;
|
||||
cbw_init(&cbw, lun);
|
||||
|
||||
cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
|
||||
cbw.dir = TUSB_DIR_IN_MASK;
|
||||
cbw.cmd_len = sizeof(scsi_read10_t);
|
||||
cbw.total_bytes = block_count * p_msc->capacity[lun].block_size;
|
||||
cbw.dir = TUSB_DIR_IN_MASK;
|
||||
cbw.cmd_len = sizeof(scsi_read10_t);
|
||||
|
||||
scsi_read10_t const cmd_read10 =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_READ_10,
|
||||
.lba = tu_htonl(lba),
|
||||
.block_count = tu_htons(block_count)
|
||||
scsi_read10_t const cmd_read10 = {
|
||||
.cmd_code = SCSI_CMD_READ_10,
|
||||
.lba = tu_htonl(lba),
|
||||
.block_count = tu_htons(block_count)
|
||||
};
|
||||
|
||||
memcpy(cbw.command, &cmd_read10, cbw.cmd_len);
|
||||
|
||||
return tuh_msc_scsi_command(dev_addr, &cbw, buffer, complete_cb, arg);
|
||||
}
|
||||
|
||||
bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * buffer, uint32_t lba, uint16_t block_count, tuh_msc_complete_cb_t complete_cb, uintptr_t arg)
|
||||
{
|
||||
bool tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const* buffer, uint32_t lba, uint16_t block_count,
|
||||
tuh_msc_complete_cb_t complete_cb, uintptr_t arg) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
TU_VERIFY(p_msc->mounted);
|
||||
|
||||
msc_cbw_t cbw;
|
||||
cbw_init(&cbw, lun);
|
||||
|
||||
cbw.total_bytes = block_count*p_msc->capacity[lun].block_size;
|
||||
cbw.total_bytes = block_count * p_msc->capacity[lun].block_size;
|
||||
cbw.dir = TUSB_DIR_OUT;
|
||||
cbw.cmd_len = sizeof(scsi_write10_t);
|
||||
|
||||
scsi_write10_t const cmd_write10 =
|
||||
{
|
||||
.cmd_code = SCSI_CMD_WRITE_10,
|
||||
.lba = tu_htonl(lba),
|
||||
.block_count = tu_htons(block_count)
|
||||
scsi_write10_t const cmd_write10 = {
|
||||
.cmd_code = SCSI_CMD_WRITE_10,
|
||||
.lba = tu_htonl(lba),
|
||||
.block_count = tu_htons(block_count)
|
||||
};
|
||||
|
||||
memcpy(cbw.command, &cmd_write10, cbw.cmd_len);
|
||||
|
||||
return tuh_msc_scsi_command(dev_addr, &cbw, (void*)(uintptr_t) buffer, complete_cb, arg);
|
||||
return tuh_msc_scsi_command(dev_addr, &cbw, (void*) (uintptr_t) buffer, complete_cb, arg);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// MSC interface Reset (not used now)
|
||||
bool tuh_msc_reset(uint8_t dev_addr)
|
||||
{
|
||||
tusb_control_request_t const new_request =
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
bool tuh_msc_reset(uint8_t dev_addr) {
|
||||
tusb_control_request_t const new_request = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_OUT
|
||||
@@ -300,79 +284,71 @@ bool tuh_msc_reset(uint8_t dev_addr)
|
||||
//--------------------------------------------------------------------+
|
||||
// CLASS-USBH API
|
||||
//--------------------------------------------------------------------+
|
||||
void msch_init(void)
|
||||
{
|
||||
void msch_init(void) {
|
||||
tu_memclr(_msch_itf, sizeof(_msch_itf));
|
||||
}
|
||||
|
||||
void msch_close(uint8_t dev_addr)
|
||||
{
|
||||
TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX, );
|
||||
void msch_close(uint8_t dev_addr) {
|
||||
TU_VERIFY(dev_addr <= CFG_TUH_DEVICE_MAX,);
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
TU_VERIFY(p_msc->configured, );
|
||||
TU_VERIFY(p_msc->configured,);
|
||||
|
||||
TU_LOG_DRV(" MSCh close addr = %d\r\n", dev_addr);
|
||||
|
||||
// invoke Application Callback
|
||||
if (p_msc->mounted) {
|
||||
if(tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr);
|
||||
if (tuh_msc_umount_cb) tuh_msc_umount_cb(dev_addr);
|
||||
}
|
||||
|
||||
tu_memclr(p_msc, sizeof(msch_interface_t));
|
||||
}
|
||||
|
||||
bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) {
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
msc_cbw_t const * cbw = &p_msc->cbw;
|
||||
msc_csw_t * csw = &p_msc->csw;
|
||||
|
||||
switch (p_msc->stage)
|
||||
{
|
||||
switch (p_msc->stage) {
|
||||
case MSC_STAGE_CMD:
|
||||
// Must be Command Block
|
||||
TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t));
|
||||
TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t));
|
||||
|
||||
if ( cbw->total_bytes && p_msc->buffer )
|
||||
{
|
||||
if (cbw->total_bytes && p_msc->buffer) {
|
||||
// Data stage if any
|
||||
p_msc->stage = MSC_STAGE_DATA;
|
||||
|
||||
uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out;
|
||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, (uint16_t) cbw->total_bytes));
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
// Status stage
|
||||
p_msc->stage = MSC_STAGE_STATUS;
|
||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
case MSC_STAGE_DATA:
|
||||
// Status stage
|
||||
p_msc->stage = MSC_STAGE_STATUS;
|
||||
TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, (uint16_t) sizeof(msc_csw_t)));
|
||||
break;
|
||||
break;
|
||||
|
||||
case MSC_STAGE_STATUS:
|
||||
// SCSI op is complete
|
||||
p_msc->stage = MSC_STAGE_IDLE;
|
||||
|
||||
if (p_msc->complete_cb)
|
||||
{
|
||||
tuh_msc_complete_data_t const cb_data =
|
||||
{
|
||||
.cbw = cbw,
|
||||
.csw = csw,
|
||||
.scsi_data = p_msc->buffer,
|
||||
.user_arg = p_msc->complete_arg
|
||||
if (p_msc->complete_cb) {
|
||||
tuh_msc_complete_data_t const cb_data = {
|
||||
.cbw = cbw,
|
||||
.csw = csw,
|
||||
.scsi_data = p_msc->buffer,
|
||||
.user_arg = p_msc->complete_arg
|
||||
};
|
||||
p_msc->complete_cb(dev_addr, &cb_data);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
|
||||
// unknown state
|
||||
default: break;
|
||||
// unknown state
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -381,39 +357,35 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32
|
||||
//--------------------------------------------------------------------+
|
||||
// MSC Enumeration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
static void config_get_maxlun_complete (tuh_xfer_t* xfer);
|
||||
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data);
|
||||
static void config_get_maxlun_complete(tuh_xfer_t* xfer);
|
||||
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
||||
static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
||||
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data);
|
||||
|
||||
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
|
||||
{
|
||||
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const* desc_itf, uint16_t max_len) {
|
||||
(void) rhport;
|
||||
TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
|
||||
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
|
||||
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
|
||||
|
||||
// msc driver length is fixed
|
||||
uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
|
||||
uint16_t const drv_len = (uint16_t) (sizeof(tusb_desc_interface_t) +
|
||||
desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
|
||||
TU_ASSERT(drv_len <= max_len);
|
||||
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf);
|
||||
tusb_desc_endpoint_t const* ep_desc = (tusb_desc_endpoint_t const*) tu_desc_next(desc_itf);
|
||||
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
for (uint32_t i = 0; i < 2; i++) {
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
|
||||
TU_ASSERT(tuh_edpt_open(dev_addr, ep_desc));
|
||||
|
||||
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
|
||||
{
|
||||
if (TUSB_DIR_IN == tu_edpt_dir(ep_desc->bEndpointAddress)) {
|
||||
p_msc->ep_in = ep_desc->bEndpointAddress;
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
p_msc->ep_out = ep_desc->bEndpointAddress;
|
||||
}
|
||||
|
||||
ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(ep_desc);
|
||||
ep_desc = (tusb_desc_endpoint_t const*) tu_desc_next(ep_desc);
|
||||
}
|
||||
|
||||
p_msc->itf_num = desc_itf->bInterfaceNumber;
|
||||
@@ -430,32 +402,31 @@ bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) {
|
||||
//------------- Get Max Lun -------------//
|
||||
TU_LOG_DRV("MSC Get Max Lun\r\n");
|
||||
tusb_control_request_t const request = {
|
||||
.bmRequestType_bit = {
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_IN
|
||||
},
|
||||
.bRequest = MSC_REQ_GET_MAX_LUN,
|
||||
.wValue = 0,
|
||||
.wIndex = itf_num,
|
||||
.wLength = 1
|
||||
.bmRequestType_bit = {
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_CLASS,
|
||||
.direction = TUSB_DIR_IN
|
||||
},
|
||||
.bRequest = MSC_REQ_GET_MAX_LUN,
|
||||
.wValue = 0,
|
||||
.wIndex = itf_num,
|
||||
.wLength = 1
|
||||
};
|
||||
|
||||
tuh_xfer_t xfer = {
|
||||
.daddr = dev_addr,
|
||||
.ep_addr = 0,
|
||||
.setup = &request,
|
||||
.buffer = _msch_buffer,
|
||||
.complete_cb = config_get_maxlun_complete,
|
||||
.user_data = 0
|
||||
.daddr = dev_addr,
|
||||
.ep_addr = 0,
|
||||
.setup = &request,
|
||||
.buffer = _msch_buffer,
|
||||
.complete_cb = config_get_maxlun_complete,
|
||||
.user_data = 0
|
||||
};
|
||||
TU_ASSERT(tuh_control_xfer(&xfer));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void config_get_maxlun_complete (tuh_xfer_t* xfer)
|
||||
{
|
||||
static void config_get_maxlun_complete(tuh_xfer_t* xfer) {
|
||||
uint8_t const daddr = xfer->daddr;
|
||||
msch_interface_t* p_msc = get_itf(daddr);
|
||||
|
||||
@@ -471,18 +442,16 @@ static void config_get_maxlun_complete (tuh_xfer_t* xfer)
|
||||
tuh_msc_test_unit_ready(daddr, lun, config_test_unit_ready_complete, 0);
|
||||
}
|
||||
|
||||
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
|
||||
{
|
||||
static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
|
||||
msc_cbw_t const* cbw = cb_data->cbw;
|
||||
msc_csw_t const* csw = cb_data->csw;
|
||||
|
||||
if (csw->status == 0)
|
||||
{
|
||||
if (csw->status == 0) {
|
||||
// Unit is ready, read its capacity
|
||||
TU_LOG_DRV("SCSI Read Capacity\r\n");
|
||||
tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer), config_read_capacity_complete, 0);
|
||||
}else
|
||||
{
|
||||
tuh_msc_read_capacity(dev_addr, cbw->lun, (scsi_read_capacity10_resp_t*) ((void*) _msch_buffer),
|
||||
config_read_capacity_complete, 0);
|
||||
} else {
|
||||
// Note: During enumeration, some device fails Test Unit Ready and require a few retries
|
||||
// with Request Sense to start working !!
|
||||
// TODO limit number of retries
|
||||
@@ -493,8 +462,7 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, tuh_msc_complete_d
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
|
||||
{
|
||||
static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
|
||||
msc_cbw_t const* cbw = cb_data->cbw;
|
||||
msc_csw_t const* csw = cb_data->csw;
|
||||
|
||||
@@ -503,8 +471,7 @@ static bool config_request_sense_complete(uint8_t dev_addr, tuh_msc_complete_dat
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const * cb_data)
|
||||
{
|
||||
static bool config_read_capacity_complete(uint8_t dev_addr, tuh_msc_complete_data_t const* cb_data) {
|
||||
msc_cbw_t const* cbw = cb_data->cbw;
|
||||
msc_csw_t const* csw = cb_data->csw;
|
||||
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
#ifndef _TUSB_MSC_HOST_H_
|
||||
#define _TUSB_MSC_HOST_H_
|
||||
#ifndef TUSB_MSC_HOST_H_
|
||||
#define TUSB_MSC_HOST_H_
|
||||
|
||||
#include "msc.h"
|
||||
|
||||
@@ -73,7 +73,7 @@ uint32_t tuh_msc_get_block_size(uint8_t dev_addr, uint8_t lun);
|
||||
// Perform a full SCSI command (cbw, data, csw) in non-blocking manner.
|
||||
// Complete callback is invoked when SCSI op is complete.
|
||||
// return true if success, false if there is already pending operation.
|
||||
bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
|
||||
bool tuh_msc_scsi_command(uint8_t daddr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb, uintptr_t arg);
|
||||
|
||||
// Perform SCSI Inquiry command
|
||||
// Complete callback is invoked when SCSI op is complete.
|
||||
@@ -123,4 +123,4 @@ bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, ui
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_MSC_HOST_H_ */
|
||||
#endif
|
||||
|
||||
@@ -75,8 +75,6 @@
|
||||
#include "tusb_types.h"
|
||||
#include "tusb_debug.h"
|
||||
|
||||
#include "tusb_timeout.h" // TODO remove
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Optional API implemented by application if needed
|
||||
// TODO move to a more ovious place/file
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
/*
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 Ha Thach (tinyusb.org)
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* This file is part of the TinyUSB stack.
|
||||
*/
|
||||
|
||||
/** \ingroup Group_Common Common Files
|
||||
* \defgroup Group_TimeoutTimer timeout timer
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_TIMEOUT_H_
|
||||
#define _TUSB_TIMEOUT_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
uint32_t start;
|
||||
uint32_t interval;
|
||||
}tu_timeout_t;
|
||||
|
||||
#if 0
|
||||
|
||||
extern uint32_t tusb_hal_millis(void);
|
||||
|
||||
static inline void tu_timeout_set(tu_timeout_t* tt, uint32_t msec)
|
||||
{
|
||||
tt->interval = msec;
|
||||
tt->start = tusb_hal_millis();
|
||||
}
|
||||
|
||||
static inline bool tu_timeout_expired(tu_timeout_t* tt)
|
||||
{
|
||||
return ( tusb_hal_millis() - tt->start ) >= tt->interval;
|
||||
}
|
||||
|
||||
// For used with periodic event to prevent drift
|
||||
static inline void tu_timeout_reset(tu_timeout_t* tt)
|
||||
{
|
||||
tt->start += tt->interval;
|
||||
}
|
||||
|
||||
static inline void tu_timeout_restart(tu_timeout_t* tt)
|
||||
{
|
||||
tt->start = tusb_hal_millis();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_TIMEOUT_H_ */
|
||||
|
||||
/** @} */
|
||||
@@ -56,12 +56,8 @@
|
||||
* #define TU_VERIFY(cond) if(cond) return false;
|
||||
* #define TU_VERIFY(cond,ret) if(cond) return ret;
|
||||
*
|
||||
* #define TU_VERIFY_HDLR(cond,handler) if(cond) {handler; return false;}
|
||||
* #define TU_VERIFY_HDLR(cond,ret,handler) if(cond) {handler; return ret;}
|
||||
*
|
||||
* #define TU_ASSERT(cond) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return false;}
|
||||
* #define TU_ASSERT(cond,ret) if(cond) {_MESS_FAILED(); TU_BREAKPOINT(), return ret;}
|
||||
*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
@@ -97,40 +93,23 @@
|
||||
#define TU_BREAKPOINT() do {} while (0)
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Macro Generator
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
// Helper to implement optional parameter for TU_VERIFY Macro family
|
||||
#define _GET_3RD_ARG(arg1, arg2, arg3, ...) arg3
|
||||
#define _GET_4TH_ARG(arg1, arg2, arg3, arg4, ...) arg4
|
||||
|
||||
/*------------- Generator for TU_VERIFY and TU_VERIFY_HDLR -------------*/
|
||||
#define TU_VERIFY_DEFINE(_cond, _handler, _ret) do \
|
||||
{ \
|
||||
if ( !(_cond) ) { _handler; return _ret; } \
|
||||
} while(0)
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TU_VERIFY
|
||||
* - TU_VERIFY_1ARGS : return false if failed
|
||||
* - TU_VERIFY_2ARGS : return provided value if failed
|
||||
*------------------------------------------------------------------*/
|
||||
#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, , false)
|
||||
#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, , _ret)
|
||||
#define TU_VERIFY_DEFINE(_cond, _ret) \
|
||||
do { \
|
||||
if ( !(_cond) ) { return _ret; } \
|
||||
} while(0)
|
||||
|
||||
#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, UNUSED)(__VA_ARGS__)
|
||||
#define TU_VERIFY_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, false)
|
||||
#define TU_VERIFY_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _ret)
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TU_VERIFY WITH HANDLER
|
||||
* - TU_VERIFY_HDLR_2ARGS : execute handler, return false if failed
|
||||
* - TU_VERIFY_HDLR_3ARGS : execute handler, return provided error if failed
|
||||
*------------------------------------------------------------------*/
|
||||
#define TU_VERIFY_HDLR_2ARGS(_cond, _handler) TU_VERIFY_DEFINE(_cond, _handler, false)
|
||||
#define TU_VERIFY_HDLR_3ARGS(_cond, _handler, _ret) TU_VERIFY_DEFINE(_cond, _handler, _ret)
|
||||
|
||||
#define TU_VERIFY_HDLR(...) _GET_4TH_ARG(__VA_ARGS__, TU_VERIFY_HDLR_3ARGS, TU_VERIFY_HDLR_2ARGS,UNUSED)(__VA_ARGS__)
|
||||
#define TU_VERIFY(...) _GET_3RD_ARG(__VA_ARGS__, TU_VERIFY_2ARGS, TU_VERIFY_1ARGS, _dummy)(__VA_ARGS__)
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* ASSERT
|
||||
@@ -138,19 +117,20 @@
|
||||
* - 1 arg : return false if failed
|
||||
* - 2 arg : return error if failed
|
||||
*------------------------------------------------------------------*/
|
||||
#define ASSERT_1ARGS(_cond) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), false)
|
||||
#define ASSERT_2ARGS(_cond, _ret) TU_VERIFY_DEFINE(_cond, _MESS_FAILED(); TU_BREAKPOINT(), _ret)
|
||||
#define TU_ASSERT_DEFINE(_cond, _ret) \
|
||||
do { \
|
||||
if ( !(_cond) ) { _MESS_FAILED(); TU_BREAKPOINT(); return _ret; } \
|
||||
} while(0)
|
||||
|
||||
#define TU_ASSERT_1ARGS(_cond) TU_ASSERT_DEFINE(_cond, false)
|
||||
#define TU_ASSERT_2ARGS(_cond, _ret) TU_ASSERT_DEFINE(_cond, _ret)
|
||||
|
||||
#ifndef TU_ASSERT
|
||||
#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, ASSERT_2ARGS, ASSERT_1ARGS,UNUSED)(__VA_ARGS__)
|
||||
#define TU_ASSERT(...) _GET_3RD_ARG(__VA_ARGS__, TU_ASSERT_2ARGS, TU_ASSERT_1ARGS, _dummy)(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* ASSERT HDLR
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TUSB_VERIFY_H_ */
|
||||
#endif
|
||||
|
||||
@@ -131,7 +131,7 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) TU_AT
|
||||
bool hcd_init(uint8_t rhport);
|
||||
|
||||
// Interrupt Handler
|
||||
void hcd_int_handler(uint8_t rhport);
|
||||
void hcd_int_handler(uint8_t rhport, bool in_isr);
|
||||
|
||||
// Enable USB interrupt
|
||||
void hcd_int_enable (uint8_t rhport);
|
||||
|
||||
@@ -817,6 +817,7 @@ bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
||||
}
|
||||
|
||||
// Submit an transfer
|
||||
// TODO call usbh_edpt_release if failed
|
||||
bool usbh_edpt_xfer_with_callback(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes,
|
||||
tuh_xfer_cb_t complete_cb, uintptr_t user_data)
|
||||
{
|
||||
@@ -1713,19 +1714,16 @@ static bool _parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configur
|
||||
return true;
|
||||
}
|
||||
|
||||
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
||||
{
|
||||
void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) {
|
||||
usbh_device_t* dev = get_device(dev_addr);
|
||||
|
||||
for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++)
|
||||
{
|
||||
for(itf_num++; itf_num < CFG_TUH_INTERFACE_MAX; itf_num++) {
|
||||
// continue with next valid interface
|
||||
// IAD binding interface such as CDCs should return itf_num + 1 when complete
|
||||
// with usbh_driver_set_config_complete()
|
||||
uint8_t const drv_id = dev->itf2drv[itf_num];
|
||||
usbh_class_driver_t const * driver = get_driver(drv_id);
|
||||
if (driver)
|
||||
{
|
||||
if (driver) {
|
||||
TU_LOG_USBH("%s set config: itf = %u\r\n", driver->name, itf_num);
|
||||
driver->set_config(dev_addr, itf_num);
|
||||
break;
|
||||
@@ -1733,23 +1731,19 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
||||
}
|
||||
|
||||
// all interface are configured
|
||||
if (itf_num == CFG_TUH_INTERFACE_MAX)
|
||||
{
|
||||
if (itf_num == CFG_TUH_INTERFACE_MAX) {
|
||||
enum_full_complete();
|
||||
|
||||
if (is_hub_addr(dev_addr))
|
||||
{
|
||||
if (is_hub_addr(dev_addr)) {
|
||||
TU_LOG(CFG_TUH_LOG_LEVEL, "HUB address = %u is mounted\r\n", dev_addr);
|
||||
}else
|
||||
{
|
||||
}else {
|
||||
// Invoke callback if available
|
||||
if (tuh_mount_cb) tuh_mount_cb(dev_addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void enum_full_complete(void)
|
||||
{
|
||||
static void enum_full_complete(void) {
|
||||
// mark enumeration as complete
|
||||
_dev0.enumerating = 0;
|
||||
|
||||
|
||||
@@ -124,11 +124,16 @@ void tuh_task(void) {
|
||||
bool tuh_task_event_ready(void);
|
||||
|
||||
#ifndef _TUSB_HCD_H_
|
||||
extern void hcd_int_handler(uint8_t rhport);
|
||||
extern void hcd_int_handler(uint8_t rhport, bool in_isr);
|
||||
#endif
|
||||
|
||||
// Interrupt handler, name alias to HCD
|
||||
#define tuh_int_handler hcd_int_handler
|
||||
// Interrupt handler alias to HCD with in_isr as optional parameter
|
||||
// - tuh_int_handler(rhport) --> hcd_int_handler(rhport, true)
|
||||
// - tuh_int_handler(rhport, in_isr) --> hcd_int_handler(rhport, in_isr)
|
||||
// Note: this is similar to TU_VERIFY(), _GET_3RD_ARG() is defined in tusb_verify.h
|
||||
#define _tuh_int_handler_1arg(_rhport) hcd_int_handler(_rhport, true)
|
||||
#define _tuh_int_hanlder_2arg(_rhport, _in_isr) hcd_int_handler(_rhport, _in_isr)
|
||||
#define tuh_int_handler(...) _GET_3RD_ARG(__VA_ARGS__, _tuh_int_hanlder_2arg, _tuh_int_handler_1arg, _dummy)(__VA_ARGS__)
|
||||
|
||||
// Check if roothub port is initialized and active as a host
|
||||
bool tuh_rhport_is_active(uint8_t rhport);
|
||||
|
||||
@@ -210,16 +210,21 @@ static max3421_data_t _hcd_data;
|
||||
// API: SPI transfer with MAX3421E, must be implemented by application
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void tuh_max3421_spi_cs_api(uint8_t rhport, bool active);
|
||||
bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len);
|
||||
void tuh_max3421_int_api(uint8_t rhport, bool enabled);
|
||||
// API to control MAX3421 SPI CS
|
||||
extern void tuh_max3421_spi_cs_api(uint8_t rhport, bool active);
|
||||
|
||||
static void handle_connect_irq(uint8_t rhport, bool in_isr);
|
||||
static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr);
|
||||
// API to transfer data with MAX3421 SPI
|
||||
// Either tx_buf or rx_buf can be NULL, which means transfer is write or read only
|
||||
extern bool tuh_max3421_spi_xfer_api(uint8_t rhport, uint8_t const* tx_buf, uint8_t* rx_buf, size_t xfer_bytes);
|
||||
|
||||
// API to enable/disable MAX3421 INTR pin interrupt
|
||||
extern void tuh_max3421_int_api(uint8_t rhport, bool enabled);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// SPI Helper
|
||||
//--------------------------------------------------------------------+
|
||||
static void handle_connect_irq(uint8_t rhport, bool in_isr);
|
||||
static inline void hirq_write(uint8_t rhport, uint8_t data, bool in_isr);
|
||||
|
||||
static void max3421_spi_lock(uint8_t rhport, bool in_isr) {
|
||||
// disable interrupt and mutex lock (for pre-emptive RTOS) if not in_isr
|
||||
@@ -249,9 +254,9 @@ static void fifo_write(uint8_t rhport, uint8_t reg, uint8_t const * buffer, uint
|
||||
|
||||
max3421_spi_lock(rhport, in_isr);
|
||||
|
||||
tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 1);
|
||||
tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1);
|
||||
_hcd_data.hirq = hirq;
|
||||
tuh_max3421_spi_xfer_api(rhport, buffer, len, NULL, 0);
|
||||
tuh_max3421_spi_xfer_api(rhport, buffer, NULL, len);
|
||||
|
||||
max3421_spi_unlock(rhport, in_isr);
|
||||
|
||||
@@ -263,9 +268,9 @@ static void fifo_read(uint8_t rhport, uint8_t * buffer, uint16_t len, bool in_is
|
||||
|
||||
max3421_spi_lock(rhport, in_isr);
|
||||
|
||||
tuh_max3421_spi_xfer_api(rhport, ®, 1, &hirq, 0);
|
||||
tuh_max3421_spi_xfer_api(rhport, ®, &hirq, 1);
|
||||
_hcd_data.hirq = hirq;
|
||||
tuh_max3421_spi_xfer_api(rhport, NULL, 0, buffer, len);
|
||||
tuh_max3421_spi_xfer_api(rhport, NULL, buffer, len);
|
||||
|
||||
max3421_spi_unlock(rhport, in_isr);
|
||||
}
|
||||
@@ -276,7 +281,7 @@ static void reg_write(uint8_t rhport, uint8_t reg, uint8_t data, bool in_isr) {
|
||||
|
||||
max3421_spi_lock(rhport, in_isr);
|
||||
|
||||
tuh_max3421_spi_xfer_api(rhport, tx_buf, 2, rx_buf, 2);
|
||||
tuh_max3421_spi_xfer_api(rhport, tx_buf, rx_buf, 2);
|
||||
|
||||
max3421_spi_unlock(rhport, in_isr);
|
||||
|
||||
@@ -290,7 +295,7 @@ static uint8_t reg_read(uint8_t rhport, uint8_t reg, bool in_isr) {
|
||||
|
||||
max3421_spi_lock(rhport, in_isr);
|
||||
|
||||
bool ret = tuh_max3421_spi_xfer_api(rhport, tx_buf, 2, rx_buf, 2);
|
||||
bool ret = tuh_max3421_spi_xfer_api(rhport, tx_buf, rx_buf, 2);
|
||||
|
||||
max3421_spi_unlock(rhport, in_isr);
|
||||
|
||||
@@ -428,8 +433,8 @@ bool hcd_init(uint8_t rhport) {
|
||||
reg_write(rhport, PINCTL_ADDR, PINCTL_FDUPSPI, false);
|
||||
|
||||
// V1 is 0x01, V2 is 0x12, V3 is 0x13
|
||||
// uint8_t const revision = reg_read(rhport, REVISION_ADDR, false);
|
||||
// TU_LOG2_HEX(revision);
|
||||
// uint8_t const revision = reg_read(rhport, REVISION_ADDR, false);
|
||||
// TU_LOG2_HEX(revision);
|
||||
|
||||
// reset
|
||||
reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
|
||||
@@ -693,9 +698,7 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
|
||||
|
||||
// port reset anyway, this will help to stable bus signal for next connection
|
||||
reg_write(rhport, HCTL_ADDR, HCTL_BUSRST, in_isr);
|
||||
|
||||
hcd_event_device_remove(rhport, in_isr);
|
||||
|
||||
reg_write(rhport, HCTL_ADDR, 0, in_isr);
|
||||
break;
|
||||
|
||||
@@ -721,13 +724,12 @@ static void handle_connect_irq(uint8_t rhport, bool in_isr) {
|
||||
free_ep(daddr);
|
||||
|
||||
hcd_event_device_attach(rhport, in_isr);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl) {
|
||||
static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t result, uint8_t hrsl, bool in_isr) {
|
||||
uint8_t const ep_addr = tu_edpt_addr(ep->ep_num, ep->ep_dir);
|
||||
|
||||
// save data toggle
|
||||
@@ -738,20 +740,20 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re
|
||||
}
|
||||
|
||||
ep->xfer_pending = 0;
|
||||
hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, true);
|
||||
hcd_event_xfer_complete(ep->daddr, ep_addr, ep->xferred_len, result, in_isr);
|
||||
|
||||
// Find next pending endpoint
|
||||
max3421_ep_t *next_ep = find_next_pending_ep(ep);
|
||||
if (next_ep) {
|
||||
xact_inout(rhport, next_ep, true, true);
|
||||
xact_inout(rhport, next_ep, true, in_isr);
|
||||
}else {
|
||||
// no more pending
|
||||
atomic_flag_clear(&_hcd_data.busy);
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_xfer_done(uint8_t rhport) {
|
||||
uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, true);
|
||||
static void handle_xfer_done(uint8_t rhport, bool in_isr) {
|
||||
uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr);
|
||||
uint8_t const hresult = hrsl & HRSL_RESULT_MASK;
|
||||
|
||||
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
|
||||
@@ -774,17 +776,17 @@ static void handle_xfer_done(uint8_t rhport) {
|
||||
case HRSL_NAK:
|
||||
if (ep_num == 0) {
|
||||
// NAK on control, retry immediately
|
||||
hxfr_write(rhport, _hcd_data.hxfr, true);
|
||||
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
|
||||
}else {
|
||||
// NAK on non-control, find next pending to switch
|
||||
max3421_ep_t *next_ep = find_next_pending_ep(ep);
|
||||
|
||||
if (ep == next_ep) {
|
||||
// this endpoint is only one pending, retry immediately
|
||||
hxfr_write(rhport, _hcd_data.hxfr, true);
|
||||
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
|
||||
}else if (next_ep) {
|
||||
// switch to next pending TODO could have issue with double buffered if not clear previously out data
|
||||
xact_inout(rhport, next_ep, true, true);
|
||||
xact_inout(rhport, next_ep, true, in_isr);
|
||||
}else {
|
||||
TU_ASSERT(false,);
|
||||
}
|
||||
@@ -802,7 +804,7 @@ static void handle_xfer_done(uint8_t rhport) {
|
||||
}
|
||||
|
||||
if (xfer_result != XFER_RESULT_SUCCESS) {
|
||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl);
|
||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -814,10 +816,10 @@ static void handle_xfer_done(uint8_t rhport) {
|
||||
|
||||
// short packet or all bytes transferred
|
||||
if ( ep->xfer_complete ) {
|
||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl);
|
||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
|
||||
}else {
|
||||
// more to transfer
|
||||
hxfr_write(rhport, _hcd_data.hxfr, true);
|
||||
hxfr_write(rhport, _hcd_data.hxfr, in_isr);
|
||||
}
|
||||
} else {
|
||||
// SETUP or OUT transfer
|
||||
@@ -835,10 +837,10 @@ static void handle_xfer_done(uint8_t rhport) {
|
||||
ep->buf += xact_len;
|
||||
|
||||
if (xact_len < ep->packet_size || ep->xferred_len >= ep->total_len) {
|
||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl);
|
||||
xfer_complete_isr(rhport, ep, xfer_result, hrsl, in_isr);
|
||||
} else {
|
||||
// more to transfer
|
||||
xact_out(rhport, ep, false, true);
|
||||
xact_out(rhport, ep, false, in_isr);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -862,9 +864,9 @@ void print_hirq(uint8_t hirq) {
|
||||
#define print_hirq(hirq)
|
||||
#endif
|
||||
|
||||
// Interrupt Handler
|
||||
void hcd_int_handler(uint8_t rhport) {
|
||||
uint8_t hirq = reg_read(rhport, HIRQ_ADDR, true) & _hcd_data.hien;
|
||||
// Interrupt handler
|
||||
void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
||||
uint8_t hirq = reg_read(rhport, HIRQ_ADDR, in_isr) & _hcd_data.hien;
|
||||
if (!hirq) return;
|
||||
// print_hirq(hirq);
|
||||
|
||||
@@ -873,7 +875,7 @@ void hcd_int_handler(uint8_t rhport) {
|
||||
}
|
||||
|
||||
if (hirq & HIRQ_CONDET_IRQ) {
|
||||
handle_connect_irq(rhport, true);
|
||||
handle_connect_irq(rhport, in_isr);
|
||||
}
|
||||
|
||||
// queue more transfer in handle_xfer_done() can cause hirq to be set again while external IRQ may not catch and/or
|
||||
@@ -882,21 +884,21 @@ void hcd_int_handler(uint8_t rhport) {
|
||||
if ( hirq & HIRQ_RCVDAV_IRQ ) {
|
||||
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
|
||||
max3421_ep_t *ep = find_opened_ep(_hcd_data.peraddr, ep_num, 1);
|
||||
uint8_t xact_len;
|
||||
uint8_t xact_len = 0;
|
||||
|
||||
// RCVDAV_IRQ can trigger 2 times (dual buffered)
|
||||
while ( hirq & HIRQ_RCVDAV_IRQ ) {
|
||||
uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, true);
|
||||
uint8_t rcvbc = reg_read(rhport, RCVBC_ADDR, in_isr);
|
||||
xact_len = (uint8_t) tu_min16(rcvbc, ep->total_len - ep->xferred_len);
|
||||
if ( xact_len ) {
|
||||
fifo_read(rhport, ep->buf, xact_len, true);
|
||||
fifo_read(rhport, ep->buf, xact_len, in_isr);
|
||||
ep->buf += xact_len;
|
||||
ep->xferred_len += xact_len;
|
||||
}
|
||||
|
||||
// ack RCVDVAV IRQ
|
||||
hirq_write(rhport, HIRQ_RCVDAV_IRQ, true);
|
||||
hirq = reg_read(rhport, HIRQ_ADDR, true);
|
||||
hirq_write(rhport, HIRQ_RCVDAV_IRQ, in_isr);
|
||||
hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
|
||||
}
|
||||
|
||||
if ( xact_len < ep->packet_size || ep->xferred_len >= ep->total_len ) {
|
||||
@@ -905,17 +907,17 @@ void hcd_int_handler(uint8_t rhport) {
|
||||
}
|
||||
|
||||
if ( hirq & HIRQ_HXFRDN_IRQ ) {
|
||||
hirq_write(rhport, HIRQ_HXFRDN_IRQ, true);
|
||||
handle_xfer_done(rhport);
|
||||
hirq_write(rhport, HIRQ_HXFRDN_IRQ, in_isr);
|
||||
handle_xfer_done(rhport, in_isr);
|
||||
}
|
||||
|
||||
hirq = reg_read(rhport, HIRQ_ADDR, true);
|
||||
hirq = reg_read(rhport, HIRQ_ADDR, in_isr);
|
||||
}
|
||||
|
||||
// clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
|
||||
hirq &= ~HIRQ_SNDBAV_IRQ;
|
||||
if ( hirq ) {
|
||||
hirq_write(rhport, hirq, true);
|
||||
hirq_write(rhport, hirq, in_isr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -656,8 +656,8 @@ void process_period_xfer_isr(uint8_t rhport, uint32_t interval_ms)
|
||||
}
|
||||
|
||||
//------------- Host Controller Driver's Interrupt Handler -------------//
|
||||
void hcd_int_handler(uint8_t rhport)
|
||||
{
|
||||
void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
||||
(void) in_isr;
|
||||
ehci_registers_t* regs = ehci_data.regs;
|
||||
uint32_t const int_status = regs->status;
|
||||
|
||||
|
||||
@@ -847,8 +847,10 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
/*-------------------------------------------------------------------
|
||||
* ISR
|
||||
*-------------------------------------------------------------------*/
|
||||
void hcd_int_handler(uint8_t rhport)
|
||||
void hcd_int_handler(uint8_t rhport, bool in_isr)
|
||||
{
|
||||
(void) in_isr;
|
||||
|
||||
uint_fast8_t is, txis, rxis;
|
||||
|
||||
is = USB0->IS; /* read and clear interrupt status */
|
||||
|
||||
@@ -447,6 +447,10 @@ void hcd_port_reset(uint8_t rhport)
|
||||
_hcd.need_reset = false;
|
||||
}
|
||||
|
||||
void hcd_port_reset_end(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
tusb_speed_t hcd_port_speed_get(uint8_t rhport)
|
||||
{
|
||||
(void)rhport;
|
||||
@@ -583,8 +587,9 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
/*--------------------------------------------------------------------+
|
||||
* ISR
|
||||
*--------------------------------------------------------------------+*/
|
||||
void hcd_int_handler(uint8_t rhport)
|
||||
void hcd_int_handler(uint8_t rhport, bool in_isr)
|
||||
{
|
||||
(void) in_isr;
|
||||
uint32_t is = KHCI->ISTAT;
|
||||
uint32_t msk = KHCI->INTEN;
|
||||
|
||||
|
||||
@@ -667,8 +667,9 @@ static void done_queue_isr(uint8_t hostid)
|
||||
}
|
||||
}
|
||||
|
||||
void hcd_int_handler(uint8_t hostid)
|
||||
{
|
||||
void hcd_int_handler(uint8_t hostid, bool in_isr) {
|
||||
(void) in_isr;
|
||||
|
||||
uint32_t const int_en = OHCI_REG->interrupt_enable;
|
||||
uint32_t const int_status = OHCI_REG->interrupt_status & int_en;
|
||||
|
||||
|
||||
@@ -252,9 +252,9 @@ static void __tusb_irq_path_func(hcd_rp2040_irq)(void)
|
||||
}
|
||||
}
|
||||
|
||||
void __tusb_irq_path_func(hcd_int_handler)(uint8_t rhport)
|
||||
{
|
||||
void __tusb_irq_path_func(hcd_int_handler)(uint8_t rhport, bool in_isr) {
|
||||
(void) rhport;
|
||||
(void) in_isr;
|
||||
hcd_rp2040_irq();
|
||||
}
|
||||
|
||||
|
||||
@@ -771,8 +771,9 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
//--------------------------------------------------------------------+
|
||||
// ISR
|
||||
//--------------------------------------------------------------------+
|
||||
void hcd_int_handler(uint8_t rhport)
|
||||
{
|
||||
void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
||||
(void) in_isr;
|
||||
|
||||
rusb2_reg_t* rusb = RUSB2_REG(rhport);
|
||||
unsigned is0 = rusb->INTSTS0;
|
||||
unsigned is1 = rusb->INTSTS1;
|
||||
|
||||
@@ -51,8 +51,9 @@ bool hcd_init(uint8_t rhport) {
|
||||
}
|
||||
|
||||
// Interrupt Handler
|
||||
void hcd_int_handler(uint8_t rhport) {
|
||||
void hcd_int_handler(uint8_t rhport, bool in_isr) {
|
||||
(void) rhport;
|
||||
(void) in_isr;
|
||||
}
|
||||
|
||||
// Enable USB interrupt
|
||||
|
||||
@@ -17,3 +17,10 @@ TINYUSB_SRC_C += \
|
||||
src/class/usbtmc/usbtmc_device.c \
|
||||
src/class/video/video_device.c \
|
||||
src/class/vendor/vendor_device.c \
|
||||
src/host/usbh.c \
|
||||
src/host/hub.c \
|
||||
src/class/cdc/cdc_host.c \
|
||||
src/class/hid/hid_host.c \
|
||||
src/class/msc/msc_host.c \
|
||||
src/class/vendor/vendor_host.c \
|
||||
src/typec/usbc.c \
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
#endif
|
||||
#else
|
||||
#ifndef tuh_int_handler
|
||||
#define tuh_int_handler(_x)
|
||||
#define tuh_int_handler(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
#endif
|
||||
#else
|
||||
#ifndef tud_int_handler
|
||||
#define tud_int_handler(_x)
|
||||
#define tud_int_handler(...)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -424,11 +424,11 @@
|
||||
//------------- CLASS -------------//
|
||||
|
||||
#ifndef CFG_TUH_HUB
|
||||
#define CFG_TUH_HUB 0
|
||||
#define CFG_TUH_HUB 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_CDC
|
||||
#define CFG_TUH_CDC 0
|
||||
#define CFG_TUH_CDC 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_CDC_FTDI
|
||||
@@ -442,34 +442,38 @@
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_HID
|
||||
#define CFG_TUH_HID 0
|
||||
#define CFG_TUH_HID 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_MIDI
|
||||
#define CFG_TUH_MIDI 0
|
||||
#define CFG_TUH_MIDI 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_MSC
|
||||
#define CFG_TUH_MSC 0
|
||||
#define CFG_TUH_MSC 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_VENDOR
|
||||
#define CFG_TUH_VENDOR 0
|
||||
#define CFG_TUH_VENDOR 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUH_API_EDPT_XFER
|
||||
#define CFG_TUH_API_EDPT_XFER 0
|
||||
#define CFG_TUH_API_EDPT_XFER 0
|
||||
#endif
|
||||
|
||||
// Enable PIO-USB software host controller
|
||||
#ifndef CFG_TUH_RPI_PIO_USB
|
||||
#define CFG_TUH_RPI_PIO_USB 0
|
||||
#define CFG_TUH_RPI_PIO_USB 0
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_RPI_PIO_USB
|
||||
#define CFG_TUD_RPI_PIO_USB 0
|
||||
#define CFG_TUD_RPI_PIO_USB 0
|
||||
#endif
|
||||
|
||||
// MAX3421 Host controller option
|
||||
#ifndef CFG_TUH_MAX3421
|
||||
#define CFG_TUH_MAX3421 0
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// TypeC Options (Default)
|
||||
|
||||
Reference in New Issue
Block a user