mirror of
https://github.com/hathach/tinyusb.git
synced 2025-02-15 21:40:18 +00:00
able to send setup packet
This commit is contained in:
parent
b413439416
commit
274578ff46
@ -46,10 +46,10 @@
|
||||
#define UART_TX_PIN 25
|
||||
|
||||
// SPI for USB host shield
|
||||
#define SPI_SCK_PIN 14
|
||||
#define SPI_MOSI_PIN 13
|
||||
#define SPI_MISO_PIN 15
|
||||
#define SPI_CS_PIN 27
|
||||
#define MAX3421E_SCK_PIN 14
|
||||
#define MAX3421E_MOSI_PIN 13
|
||||
#define MAX3421E_MISO_PIN 15
|
||||
#define MAX3421E_CS_PIN 27
|
||||
#define MAX3241E_INTR_PIN 26
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -96,22 +96,38 @@ TU_ATTR_UNUSED static void power_event_handler(nrfx_power_usb_evt_t event) {
|
||||
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E
|
||||
static nrfx_spim_t _spi = NRFX_SPIM_INSTANCE(0);
|
||||
|
||||
void max2342e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
||||
void max3421e_int_handler(nrfx_gpiote_pin_t pin, nrf_gpiote_polarity_t action) {
|
||||
if ( !(pin == MAX3241E_INTR_PIN && action == NRF_GPIOTE_POLARITY_HITOLO) ) return;
|
||||
|
||||
tuh_int_handler(1);
|
||||
}
|
||||
|
||||
static inline void max3421e_cs_assert(bool active) {
|
||||
nrf_gpio_pin_write(MAX3421E_CS_PIN, active ? 0 : 1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// API: SPI transfer with MAX3421E, must be implemented by application
|
||||
bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len) {
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len,
|
||||
uint8_t * rx_buf, size_t rx_len, bool keep_cs) {
|
||||
(void) rhport;
|
||||
|
||||
max3421e_cs_assert(true);
|
||||
|
||||
nrfx_spim_xfer_desc_t xfer = {
|
||||
.p_tx_buffer = tx_buf,
|
||||
.tx_length = tx_len,
|
||||
.p_rx_buffer = rx_buf,
|
||||
.rx_length = rx_len,
|
||||
};
|
||||
return nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS;
|
||||
|
||||
bool ret = (nrfx_spim_xfer(&_spi, &xfer, 0) == NRFX_SUCCESS);
|
||||
|
||||
if ( !keep_cs ) max3421e_cs_assert(false);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
@ -203,12 +219,16 @@ void board_init(void) {
|
||||
#endif
|
||||
|
||||
#if CFG_TUH_ENABLED && defined(CFG_TUH_MAX3421E) && CFG_TUH_MAX3421E
|
||||
// manually manage CS
|
||||
nrf_gpio_cfg_output(MAX3421E_CS_PIN);
|
||||
max3421e_cs_assert(false);
|
||||
|
||||
// USB host using max3421e usb controller via SPI
|
||||
nrfx_spim_config_t cfg = {
|
||||
.sck_pin = SPI_SCK_PIN,
|
||||
.mosi_pin = SPI_MOSI_PIN,
|
||||
.miso_pin = SPI_MISO_PIN,
|
||||
.ss_pin = SPI_CS_PIN,
|
||||
.sck_pin = MAX3421E_SCK_PIN,
|
||||
.mosi_pin = MAX3421E_MOSI_PIN,
|
||||
.miso_pin = MAX3421E_MISO_PIN,
|
||||
.ss_pin = NRFX_SPIM_PIN_NOT_USED,
|
||||
.ss_active_high = false,
|
||||
.irq_priority = 3,
|
||||
.orc = 0xFF,
|
||||
@ -226,7 +246,7 @@ void board_init(void) {
|
||||
nrfx_gpiote_in_config_t in_config = NRFX_GPIOTE_CONFIG_IN_SENSE_HITOLO(true);
|
||||
in_config.pull = NRF_GPIO_PIN_PULLUP;
|
||||
|
||||
nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max2342e_int_handler);
|
||||
nrfx_gpiote_in_init(MAX3241E_INTR_PIN, &in_config, max3421e_int_handler);
|
||||
nrfx_gpiote_in_event_enable(MAX3241E_INTR_PIN, true);
|
||||
#endif
|
||||
|
||||
|
@ -177,7 +177,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t *
|
||||
bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]);
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]);
|
||||
|
||||
// clear stall, data toggle is also reset to DATA0
|
||||
bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
@ -552,8 +552,7 @@ static void _control_blocking_complete_cb(tuh_xfer_t* xfer)
|
||||
}
|
||||
|
||||
// TODO timeout_ms is not supported yet
|
||||
bool tuh_control_xfer (tuh_xfer_t* xfer)
|
||||
{
|
||||
bool tuh_control_xfer (tuh_xfer_t* xfer) {
|
||||
// EP0 with setup packet
|
||||
TU_VERIFY(xfer->ep_addr == 0 && xfer->setup);
|
||||
|
||||
@ -565,8 +564,7 @@ bool tuh_control_xfer (tuh_xfer_t* xfer)
|
||||
(void) osal_mutex_lock(_usbh_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
|
||||
bool const is_idle = (_ctrl_xfer.stage == CONTROL_STAGE_IDLE);
|
||||
if (is_idle)
|
||||
{
|
||||
if (is_idle) {
|
||||
_ctrl_xfer.stage = CONTROL_STAGE_SETUP;
|
||||
_ctrl_xfer.daddr = daddr;
|
||||
_ctrl_xfer.actual_len = 0;
|
||||
@ -588,11 +586,9 @@ bool tuh_control_xfer (tuh_xfer_t* xfer)
|
||||
TU_LOG_PTR(CFG_TUH_LOG_LEVEL, xfer->setup);
|
||||
TU_LOG_USBH("\r\n");
|
||||
|
||||
if (xfer->complete_cb)
|
||||
{
|
||||
if (xfer->complete_cb) {
|
||||
TU_ASSERT( hcd_setup_send(rhport, daddr, (uint8_t const*) &_ctrl_xfer.request) );
|
||||
}else
|
||||
{
|
||||
}else {
|
||||
// blocking if complete callback is not provided
|
||||
// change callback to internal blocking, and result as user argument
|
||||
volatile xfer_result_t result = XFER_RESULT_INVALID;
|
||||
@ -656,15 +652,13 @@ static void _xfer_complete(uint8_t daddr, xfer_result_t result)
|
||||
}
|
||||
}
|
||||
|
||||
static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
|
||||
{
|
||||
static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
|
||||
(void) ep_addr;
|
||||
|
||||
const uint8_t rhport = usbh_get_rhport(dev_addr);
|
||||
tusb_control_request_t const * request = &_ctrl_xfer.request;
|
||||
|
||||
if (XFER_RESULT_SUCCESS != result)
|
||||
{
|
||||
if (XFER_RESULT_SUCCESS != result) {
|
||||
TU_LOG1("[%u:%u] Control %s, xferred_bytes = %lu\r\n", rhport, dev_addr, result == XFER_RESULT_STALLED ? "STALLED" : "FAILED", xferred_bytes);
|
||||
#if CFG_TUSB_DEBUG == 1
|
||||
TU_LOG1_PTR(request);
|
||||
@ -673,13 +667,10 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
|
||||
|
||||
// terminate transfer if any stage failed
|
||||
_xfer_complete(dev_addr, result);
|
||||
}else
|
||||
{
|
||||
switch(_ctrl_xfer.stage)
|
||||
{
|
||||
}else {
|
||||
switch(_ctrl_xfer.stage) {
|
||||
case CONTROL_STAGE_SETUP:
|
||||
if (request->wLength)
|
||||
{
|
||||
if (request->wLength) {
|
||||
// DATA stage: initial data toggle is always 1
|
||||
_set_control_xfer_stage(CONTROL_STAGE_DATA);
|
||||
TU_ASSERT( hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength) );
|
||||
@ -688,8 +679,7 @@ static bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result
|
||||
TU_ATTR_FALLTHROUGH;
|
||||
|
||||
case CONTROL_STAGE_DATA:
|
||||
if (request->wLength)
|
||||
{
|
||||
if (request->wLength) {
|
||||
TU_LOG_USBH("[%u:%u] Control data:\r\n", rhport, dev_addr);
|
||||
TU_LOG_MEM(CFG_TUH_LOG_LEVEL, _ctrl_xfer.buffer, xferred_bytes, 2);
|
||||
}
|
||||
@ -1538,9 +1528,7 @@ static bool enum_new_device(hcd_event_t* event)
|
||||
xfer.result = XFER_RESULT_SUCCESS;
|
||||
xfer.user_data = ENUM_ADDR0_DEVICE_DESC;
|
||||
|
||||
|
||||
process_enumeration(&xfer);
|
||||
|
||||
}
|
||||
#if CFG_TUH_HUB
|
||||
else
|
||||
|
@ -136,30 +136,64 @@ enum {
|
||||
HRSL_JSTATUS = 1u << 7,
|
||||
};
|
||||
|
||||
enum {
|
||||
HRSL_SUCCESS = 0,
|
||||
HRSL_BUSY,
|
||||
HRSL_BAD_REQ,
|
||||
HRSL_UNDEF,
|
||||
HRSL_NAK,
|
||||
HRSL_STALL,
|
||||
HRSL_TOG_ERR,
|
||||
HRSL_WRONG_PID,
|
||||
HRSL_BAD_BYTECOUNT,
|
||||
HRSL_PID_ERR,
|
||||
HRSL_PKT_ERR,
|
||||
HRSL_CRC_ERR,
|
||||
HRSL_K_ERR,
|
||||
HRSL_J_ERR,
|
||||
HRSL_TIMEOUT,
|
||||
HRSL_BABBLE,
|
||||
};
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
typedef struct {
|
||||
// cached register
|
||||
uint8_t mode;
|
||||
uint8_t peraddr;
|
||||
uint8_t hxfr;
|
||||
|
||||
volatile uint16_t frame_count;
|
||||
|
||||
struct {
|
||||
uint16_t packet_size;
|
||||
uint16_t total_len;
|
||||
uint8_t xfer_type;
|
||||
}ep[8][2];
|
||||
} max2341e_data_t;
|
||||
|
||||
static max2341e_data_t _hcd_data;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
// API: SPI transfer with MAX3421E, must be implemented by application
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// API: SPI transfer with MAX3421E, must be implemented by application
|
||||
bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len, uint8_t * rx_buf, size_t rx_len);
|
||||
bool tuh_max3421e_spi_xfer_api(uint8_t rhport, uint8_t const * tx_buf, size_t tx_len,
|
||||
uint8_t * rx_buf, size_t rx_len, bool keep_cs);
|
||||
//void tuh_max3421e_int_enable(uint8_t rhport, bool enabled);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
//
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// return HIRQ register since we are in full-duplex mode
|
||||
static uint8_t reg_write(uint8_t reg, uint8_t data) {
|
||||
uint8_t tx_buf[2] = {reg | CMDBYTE_WRITE, data};
|
||||
uint8_t rx_buf[2] = {0, 0};
|
||||
tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2);
|
||||
tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2, false);
|
||||
TU_LOG2("HIRQ: %02X\r\n", rx_buf[0]);
|
||||
return rx_buf[0];
|
||||
}
|
||||
@ -167,7 +201,7 @@ static uint8_t reg_write(uint8_t reg, uint8_t data) {
|
||||
static uint8_t reg_read(uint8_t reg) {
|
||||
uint8_t tx_buf[2] = {reg, 0};
|
||||
uint8_t rx_buf[2] = {0, 0};
|
||||
return tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2) ? rx_buf[1] : 0;
|
||||
return tuh_max3421e_spi_xfer_api(0, tx_buf, 2, rx_buf, 2, false) ? rx_buf[1] : 0;
|
||||
}
|
||||
|
||||
static inline uint8_t mode_write(uint8_t data) {
|
||||
@ -175,6 +209,24 @@ static inline uint8_t mode_write(uint8_t data) {
|
||||
return reg_write(MODE_ADDR, data);
|
||||
}
|
||||
|
||||
static inline uint8_t peraddr_write(uint8_t data) {
|
||||
if ( _hcd_data.peraddr == data ) return 0; // no need to change address
|
||||
|
||||
_hcd_data.peraddr = data;
|
||||
return reg_write(PERADDR_ADDR, data);
|
||||
}
|
||||
|
||||
static inline uint8_t hxfr_write(uint8_t data) {
|
||||
_hcd_data.hxfr = data;
|
||||
return reg_write(HXFR_ADDR, data);
|
||||
}
|
||||
|
||||
static void fifo_write(uint8_t reg, uint8_t const * buffer, uint16_t len) {
|
||||
uint8_t tx_buf[1] = {reg | CMDBYTE_WRITE};
|
||||
tuh_max3421e_spi_xfer_api(0, tx_buf, 1, NULL, 0, true);
|
||||
tuh_max3421e_spi_xfer_api(0, buffer, len, NULL, 0, false);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
@ -252,7 +304,7 @@ bool hcd_init(uint8_t rhport) {
|
||||
mode_write(MODE_DPPULLDN | MODE_DMPULLDN | MODE_HOST);
|
||||
|
||||
// Enable Connection IRQ
|
||||
reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ);
|
||||
reg_write(HIEN_ADDR, HIRQ_CONDET_IRQ | HIRQ_FRAME_IRQ | HIRQ_HXFRDN_IRQ);
|
||||
|
||||
#if 0
|
||||
// Note: if device is already connected, CONDET IRQ may not be triggered.
|
||||
@ -271,33 +323,6 @@ bool hcd_init(uint8_t rhport) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Interrupt Handler
|
||||
void hcd_int_handler(uint8_t rhport) {
|
||||
(void) rhport;
|
||||
|
||||
uint8_t hirq = reg_read(HIRQ_ADDR);
|
||||
TU_LOG3_HEX(hirq);
|
||||
|
||||
if (hirq & HIRQ_CONDET_IRQ) {
|
||||
tusb_speed_t speed = handle_connect_irq(rhport);
|
||||
|
||||
if (speed == TUSB_SPEED_INVALID) {
|
||||
hcd_event_device_remove(rhport, true);
|
||||
}else {
|
||||
hcd_event_device_attach(rhport, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (hirq & HIRQ_FRAME_IRQ) {
|
||||
_hcd_data.frame_count++;
|
||||
}
|
||||
|
||||
// clear all interrupt
|
||||
if ( hirq ) {
|
||||
reg_write(HIRQ_ADDR, hirq);
|
||||
}
|
||||
}
|
||||
|
||||
// Enable USB interrupt
|
||||
void hcd_int_enable (uint8_t rhport) {
|
||||
(void) rhport;
|
||||
@ -359,7 +384,12 @@ bool hcd_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const
|
||||
(void) dev_addr;
|
||||
(void) ep_desc;
|
||||
|
||||
return false;
|
||||
uint8_t ep_num = tu_edpt_number(ep_desc->bEndpointAddress);
|
||||
uint8_t ep_dir = tu_edpt_dir(ep_desc->bEndpointAddress);
|
||||
|
||||
_hcd_data.ep[ep_num][ep_dir].packet_size = tu_edpt_packet_size(ep_desc);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Submit a transfer, when complete hcd_event_xfer_complete() must be invoked
|
||||
@ -384,12 +414,18 @@ bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
}
|
||||
|
||||
// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet[8]) {
|
||||
bool hcd_setup_send(uint8_t rhport, uint8_t daddr, uint8_t const setup_packet[8]) {
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
(void) daddr;
|
||||
(void) setup_packet;
|
||||
|
||||
return false;
|
||||
_hcd_data.ep[0][0].total_len = 8;
|
||||
|
||||
peraddr_write(daddr);
|
||||
fifo_write(SUDFIFO_ADDR, setup_packet, 8);
|
||||
hxfr_write(HXFR_SETUP);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// clear stall, data toggle is also reset to DATA0
|
||||
@ -401,4 +437,67 @@ bool hcd_edpt_clear_stall(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Interrupt Handler
|
||||
void hcd_int_handler(uint8_t rhport) {
|
||||
uint8_t hirq = reg_read(HIRQ_ADDR);
|
||||
TU_LOG3_HEX(hirq);
|
||||
|
||||
if (hirq & HIRQ_CONDET_IRQ) {
|
||||
tusb_speed_t speed = handle_connect_irq(rhport);
|
||||
|
||||
if (speed == TUSB_SPEED_INVALID) {
|
||||
hcd_event_device_remove(rhport, true);
|
||||
}else {
|
||||
hcd_event_device_attach(rhport, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (hirq & HIRQ_FRAME_IRQ) {
|
||||
_hcd_data.frame_count++;
|
||||
}
|
||||
|
||||
if (hirq & HIRQ_HXFRDN_IRQ) {
|
||||
uint8_t const hrsl = reg_read(HRSL_ADDR);
|
||||
uint8_t const result = hrsl & HRSL_RESULT_MASK;
|
||||
uint8_t xfer_result;
|
||||
|
||||
TU_LOG3("HRSL: %02X\r\n", hrsl);
|
||||
switch(result) {
|
||||
case HRSL_SUCCESS:
|
||||
xfer_result = XFER_RESULT_SUCCESS;
|
||||
break;
|
||||
|
||||
case HRSL_STALL:
|
||||
xfer_result = XFER_RESULT_STALLED;
|
||||
break;
|
||||
|
||||
default:
|
||||
xfer_result = XFER_RESULT_FAILED;
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t ep_dir = 0;
|
||||
uint8_t ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
|
||||
uint8_t const xfer_type = _hcd_data.hxfr & 0xf0;
|
||||
|
||||
if ( xfer_type & HXFR_SETUP ) {
|
||||
// SETUP transfer
|
||||
ep_dir = 0;
|
||||
}else if ( !(xfer_type & HXFR_OUT_NIN) ) {
|
||||
// IN transfer
|
||||
ep_dir = 1;
|
||||
}
|
||||
|
||||
uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir);
|
||||
uint16_t xferred_len = _hcd_data.ep[ep_num][ep_dir].total_len;
|
||||
|
||||
hcd_event_xfer_complete(_hcd_data.peraddr, ep_addr, xferred_len, xfer_result, true);
|
||||
}
|
||||
|
||||
// clear all interrupt
|
||||
if ( hirq ) {
|
||||
reg_write(HIRQ_ADDR, hirq);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user