mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-14 04:18:56 +00:00
Merge pull request #51 from hathach/develop
Add suspend, resume and remote wakeup support
This commit is contained in:
commit
0848c462b3
@ -47,15 +47,15 @@ Currently the following OS are supported with tinyusb out of the box with a simp
|
||||
The stack supports the following MCUs
|
||||
|
||||
- **Nordic:** nRF52840
|
||||
- **NXP:** LPC11Uxx, LPC13xx, LPC175x_6x, LPC177x_8x, LPC40xx, LPC43xx
|
||||
- **MicroChip:** SAMD21, SAMD51 (device only)
|
||||
- **NXP:** LPC11Uxx, LPC13xx, LPC175x_6x, LPC177x_8x, LPC18xx, LPC40xx, LPC43xx
|
||||
- **MicroChip:** SAMD21, SAMD51
|
||||
- **ST:** STM32F4
|
||||
|
||||
[Here is the list of supported Boards](docs/boards.md)
|
||||
|
||||
## Compiler & IDE
|
||||
|
||||
The stack is developed with GCC compiler, and should be compilable with others. However, it requires C99 to build with. Folder `examples` provide Makefile and Segger Embedded Studio build support.
|
||||
The stack is developed with GCC compiler, and should be compilable with others. Folder `examples` provide Makefile and Segger Embedded Studio build support.
|
||||
|
||||
## Getting Started
|
||||
|
||||
|
@ -76,6 +76,9 @@ If your peripheral automatically changes address during enumeration (like the nr
|
||||
##### dcd_set_config
|
||||
Called when the device received SET_CONFIG request, you can leave this empty if your peripheral does not require any specific action.
|
||||
|
||||
##### dcd_remote_wakeup
|
||||
Called to remote wake up host when suspended (e.g hid keyboard)
|
||||
|
||||
#### Special events
|
||||
You must let TinyUSB know when certain events occur so that it can continue its work. There are a few methods you can call to queue events for TinyUSB to process.
|
||||
|
||||
|
@ -67,6 +67,11 @@
|
||||
<file file_name="../../../../../hw/mcu/microchip/samd/asf4/samd21/hpl/sysctrl/hpl_sysctrl.c" />
|
||||
</folder>
|
||||
</folder>
|
||||
<folder Name="hal">
|
||||
<folder Name="src">
|
||||
<file file_name="../../../../../hw/mcu/microchip/samd/asf4/samd21/hal/src/hal_atomic.c" />
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
|
@ -71,6 +71,11 @@
|
||||
<file file_name="../../../../../hw/mcu/microchip/samd/asf4/samd51/hpl/gclk/hpl_gclk.c" />
|
||||
</folder>
|
||||
</folder>
|
||||
<folder Name="hal">
|
||||
<folder Name="src">
|
||||
<file file_name="../../../../../hw/mcu/microchip/samd/asf4/samd51/hal/src/hal_atomic.c" />
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
|
@ -34,6 +34,14 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF PROTYPES
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/* Blink pattern
|
||||
* - 250 ms : device not mounted
|
||||
* - 1000 ms : device mounted
|
||||
* - 2500 ms : device is suspended
|
||||
*/
|
||||
static uint32_t blink_interval_ms = 250;
|
||||
|
||||
void led_blinking_task(void);
|
||||
|
||||
extern void virtual_com_task(void);
|
||||
@ -127,8 +135,16 @@ void usb_hid_task(void)
|
||||
if ( board_millis() < start_ms + interval_ms) return; // not enough time
|
||||
start_ms += interval_ms;
|
||||
|
||||
uint32_t const btn = board_buttons();
|
||||
uint32_t const btn = board_button_read();
|
||||
|
||||
if ( tud_suspended() && btn )
|
||||
{
|
||||
// Wake up host if we are in suspend mode
|
||||
// and REMOTE_WAKEUP feature is enabled by host
|
||||
tud_remote_wakeup();
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*------------- Keyboard -------------*/
|
||||
if ( tud_hid_keyboard_ready() )
|
||||
{
|
||||
@ -148,8 +164,9 @@ void usb_hid_task(void)
|
||||
tud_hid_keyboard_keycode(0, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if 0
|
||||
/*------------- Mouse -------------*/
|
||||
if ( tud_hid_mouse_ready() )
|
||||
{
|
||||
@ -160,33 +177,60 @@ void usb_hid_task(void)
|
||||
if ( btn & 0x04 ) tud_hid_mouse_move( 0 , -DELTA); // up
|
||||
if ( btn & 0x08 ) tud_hid_mouse_move( 0 , DELTA); // down
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint16_t tud_hid_generic_get_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen)
|
||||
{
|
||||
// TODO not Implemented
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
(void) buffer;
|
||||
(void) reqlen;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize)
|
||||
{
|
||||
// TODO not Implemented
|
||||
(void) report_id;
|
||||
(void) report_type;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// tinyusb callbacks
|
||||
// Device callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invoked when device is mounted
|
||||
void tud_mount_cb(void)
|
||||
{
|
||||
|
||||
blink_interval_ms = 1000;
|
||||
}
|
||||
|
||||
// Invoked when device is unmounted
|
||||
void tud_umount_cb(void)
|
||||
{
|
||||
blink_interval_ms = 250;
|
||||
}
|
||||
|
||||
// Invoked when usb bus is suspended
|
||||
// remote_wakeup_en : if host allow us to perform remote wakeup
|
||||
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
||||
void tud_suspend_cb(bool remote_wakeup_en)
|
||||
{
|
||||
(void) remote_wakeup_en;
|
||||
blink_interval_ms = 2500;
|
||||
}
|
||||
|
||||
// Invoked when usb bus is resumed
|
||||
void tud_resume_cb(void)
|
||||
{
|
||||
blink_interval_ms = 1000;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -194,14 +238,12 @@ void tud_umount_cb(void)
|
||||
//--------------------------------------------------------------------+
|
||||
void led_blinking_task(void)
|
||||
{
|
||||
const uint32_t interval_ms = 1000;
|
||||
static uint32_t start_ms = 0;
|
||||
|
||||
static bool led_state = false;
|
||||
|
||||
// Blink every 1000 ms
|
||||
if ( board_millis() < start_ms + interval_ms) return; // not enough time
|
||||
start_ms += interval_ms;
|
||||
if ( board_millis() < start_ms + blink_interval_ms) return; // not enough time
|
||||
start_ms += blink_interval_ms;
|
||||
|
||||
board_led_control(led_state);
|
||||
led_state = 1 - led_state; // toggle
|
||||
|
@ -158,7 +158,7 @@ void usb_hid_task(void* params)
|
||||
if ( board_millis() < start_ms + interval_ms) return; // not enough time
|
||||
start_ms += interval_ms;
|
||||
|
||||
uint32_t const btn = board_buttons();
|
||||
uint32_t const btn = board_button_read();
|
||||
|
||||
/*------------- Keyboard -------------*/
|
||||
if ( tud_hid_keyboard_ready() )
|
||||
|
@ -46,6 +46,7 @@
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Board Porting API
|
||||
// For simplicity, only one LED and one Button are used
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Initialize on-board peripherals : led, button, uart and USB
|
||||
@ -54,9 +55,9 @@ void board_init(void);
|
||||
// Turn LED on or off
|
||||
void board_led_control(bool state);
|
||||
|
||||
// Get the current state of buttons on the board
|
||||
// \return Bitmask where a '1' means active (pressed), a '0' means inactive.
|
||||
uint32_t board_buttons(void);
|
||||
// Get the current state of button
|
||||
// a '1' means active (pressed), a '0' means inactive.
|
||||
uint32_t board_button_read(void);
|
||||
|
||||
// Get characters from UART
|
||||
int board_uart_read(uint8_t* buf, int len);
|
||||
@ -65,28 +66,20 @@ int board_uart_read(uint8_t* buf, int len);
|
||||
int board_uart_write(void const * buf, int len);
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
|
||||
// Get current milliseconds, must be implemented in board.c when no OS is used
|
||||
uint32_t board_millis(void);
|
||||
|
||||
// Get current milliseconds, must be implemented when no RTOS is used
|
||||
uint32_t board_millis(void);
|
||||
#elif CFG_TUSB_OS == OPT_OS_FREERTOS
|
||||
|
||||
static inline uint32_t board_millis(void)
|
||||
{
|
||||
return ( ( ((uint64_t) xTaskGetTickCount()) * 1000) / configTICK_RATE_HZ );
|
||||
}
|
||||
|
||||
static inline uint32_t board_millis(void)
|
||||
{
|
||||
return ( ( ((uint64_t) xTaskGetTickCount()) * 1000) / configTICK_RATE_HZ );
|
||||
}
|
||||
#elif CFG_TUSB_OS == OPT_OS_MYNEWT
|
||||
|
||||
static inline uint32_t board_millis(void)
|
||||
{
|
||||
return os_time_ticks_to_ms32( os_time_get() );
|
||||
}
|
||||
|
||||
static inline uint32_t board_millis(void)
|
||||
{
|
||||
return os_time_ticks_to_ms32( os_time_get() );
|
||||
}
|
||||
#elif
|
||||
|
||||
#error "Need to implement board_millis() for this OS"
|
||||
|
||||
#error "Need to implement board_millis() for this OS"
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -127,7 +127,7 @@ static bool button_read(uint8_t id)
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t board_buttons(void)
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
|
@ -269,7 +269,7 @@ static bool button_read(uint8_t id)
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t board_buttons(void)
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
|
@ -121,7 +121,7 @@ void board_led_control(bool state)
|
||||
//--------------------------------------------------------------------+
|
||||
// Buttons
|
||||
//--------------------------------------------------------------------+
|
||||
uint32_t board_buttons(void)
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
// for(uint8_t i=0; i<BOARD_BUTTON_COUNT; i++) GPIOGetPinValue(buttons[i].port, buttons[i].pin);
|
||||
// return GPIOGetPinValue(buttons[0].port, buttons[0].pin) ? 0 : 1; // button is active low
|
||||
|
@ -144,7 +144,7 @@ static bool button_read(uint8_t id)
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t board_buttons(void)
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
|
@ -180,7 +180,7 @@ static bool button_read(uint8_t id)
|
||||
}
|
||||
#endif
|
||||
|
||||
uint32_t board_buttons(void)
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
|
@ -193,7 +193,7 @@ static bool button_read(uint8_t id)
|
||||
}
|
||||
*/
|
||||
|
||||
uint32_t board_buttons(void)
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
uint32_t result = 0;
|
||||
|
||||
|
@ -19,7 +19,8 @@ SRC_C += \
|
||||
hw/mcu/microchip/samd/asf4/samd21/gcc/system_samd21.c \
|
||||
hw/mcu/microchip/samd/asf4/samd21/hpl/gclk/hpl_gclk.c \
|
||||
hw/mcu/microchip/samd/asf4/samd21/hpl/pm/hpl_pm.c \
|
||||
hw/mcu/microchip/samd/asf4/samd21/hpl/sysctrl/hpl_sysctrl.c
|
||||
hw/mcu/microchip/samd/asf4/samd21/hpl/sysctrl/hpl_sysctrl.c \
|
||||
hw/mcu/microchip/samd/asf4/samd21/hal/src/hal_atomic.c
|
||||
|
||||
INC += \
|
||||
-I$(TOP)/hw/mcu/microchip/samd/asf4/samd21/ \
|
||||
|
@ -39,6 +39,7 @@
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
#define LED_PIN 17
|
||||
#define BUTTON_PIN 14 // pin D2
|
||||
|
||||
/* Referenced GCLKs, should be initialized firstly */
|
||||
#define _GCLK_INIT_1ST (1 << 0 | 1 << 1)
|
||||
@ -63,6 +64,10 @@ void board_init(void)
|
||||
gpio_set_pin_direction(LED_PIN, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(LED_PIN, 0);
|
||||
|
||||
// Button init
|
||||
gpio_set_pin_direction(BUTTON_PIN, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(BUTTON_PIN, GPIO_PULL_UP);
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
// 1ms tick timer (samd SystemCoreClock may not correct)
|
||||
SysTick_Config(CONF_CPU_FREQUENCY / 1000);
|
||||
@ -101,10 +106,12 @@ void board_led_control(bool state)
|
||||
gpio_set_pin_level(LED_PIN, state);
|
||||
}
|
||||
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
// button is active low
|
||||
return gpio_get_pin_level(BUTTON_PIN) ? 0 : 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TUSB HAL MILLISECOND
|
||||
*------------------------------------------------------------------*/
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
volatile uint32_t system_ticks = 0;
|
||||
|
||||
@ -118,5 +125,4 @@ uint32_t board_millis(void)
|
||||
return system_ticks;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -21,7 +21,8 @@ SRC_C += \
|
||||
hw/mcu/microchip/samd/asf4/samd51/hpl/gclk/hpl_gclk.c \
|
||||
hw/mcu/microchip/samd/asf4/samd51/hpl/mclk/hpl_mclk.c \
|
||||
hw/mcu/microchip/samd/asf4/samd51/hpl/osc32kctrl/hpl_osc32kctrl.c \
|
||||
hw/mcu/microchip/samd/asf4/samd51/hpl/oscctrl/hpl_oscctrl.c
|
||||
hw/mcu/microchip/samd/asf4/samd51/hpl/oscctrl/hpl_oscctrl.c \
|
||||
hw/mcu/microchip/samd/asf4/samd51/hal/src/hal_atomic.c
|
||||
|
||||
INC += \
|
||||
-I$(TOP)/hw/mcu/microchip/samd/asf4/samd51/ \
|
||||
|
@ -35,7 +35,8 @@
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
#define LED_PIN 16
|
||||
#define LED_PIN 16
|
||||
#define BUTTON_PIN (32 + 17) // pin D2
|
||||
|
||||
/* Referenced GCLKs, should be initialized firstly */
|
||||
#define _GCLK_INIT_1ST 0xFFFFFFFF
|
||||
@ -61,6 +62,10 @@ void board_init(void)
|
||||
gpio_set_pin_direction(LED_PIN, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(LED_PIN, 0);
|
||||
|
||||
// Button init
|
||||
gpio_set_pin_direction(BUTTON_PIN, GPIO_DIRECTION_IN);
|
||||
gpio_set_pin_pull_mode(BUTTON_PIN, GPIO_PULL_UP);
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
// 1ms tick timer (samd SystemCoreClock may not correct)
|
||||
SysTick_Config(CONF_CPU_FREQUENCY / 1000);
|
||||
@ -90,6 +95,11 @@ void board_led_control(bool state)
|
||||
gpio_set_pin_level(LED_PIN, state);
|
||||
}
|
||||
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
// button is active low
|
||||
return gpio_get_pin_level(BUTTON_PIN) ? 0 : 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TUSB HAL MILLISECOND
|
||||
|
@ -42,10 +42,7 @@
|
||||
#define LED_PIN 13
|
||||
#define LED_STATE_ON 0
|
||||
|
||||
uint8_t _button_pins[] = { 11, 12, 24, 25 };
|
||||
|
||||
#define BOARD_BUTTON_COUNT sizeof(_button_pins)
|
||||
|
||||
#define BUTTON_PIN 11
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TUSB HAL MILLISECOND
|
||||
@ -79,12 +76,12 @@ void board_init(void)
|
||||
NRF_CLOCK->LFCLKSRC = (uint32_t)((CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos) & CLOCK_LFCLKSRC_SRC_Msk);
|
||||
NRF_CLOCK->TASKS_LFCLKSTART = 1UL;
|
||||
|
||||
// LEDs
|
||||
// LED
|
||||
nrf_gpio_cfg_output(LED_PIN);
|
||||
board_led_control(false);
|
||||
|
||||
// Button
|
||||
for(uint8_t i=0; i<BOARD_BUTTON_COUNT; i++) nrf_gpio_cfg_input(_button_pins[i], NRF_GPIO_PIN_PULLUP);
|
||||
nrf_gpio_cfg_input(BUTTON_PIN, NRF_GPIO_PIN_PULLUP);
|
||||
|
||||
#if CFG_TUSB_OS == OPT_OS_NONE
|
||||
// 1ms tick timer
|
||||
@ -134,17 +131,10 @@ void board_led_control(bool state)
|
||||
nrf_gpio_pin_write(LED_PIN, state ? LED_STATE_ON : (1-LED_STATE_ON));
|
||||
}
|
||||
|
||||
uint32_t board_buttons(void)
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
uint32_t ret = 0;
|
||||
|
||||
for(uint8_t i=0; i<BOARD_BUTTON_COUNT; i++)
|
||||
{
|
||||
// button is active LOW
|
||||
ret |= ( nrf_gpio_pin_read(_button_pins[i]) ? 0 : (1 << i));
|
||||
}
|
||||
|
||||
return ret;
|
||||
// button is active LOW
|
||||
return (nrf_gpio_pin_read(BUTTON_PIN) ? 0 : 1);
|
||||
}
|
||||
|
||||
int board_uart_read(uint8_t* buf, int len)
|
||||
|
@ -97,6 +97,12 @@ void board_led_control(bool state)
|
||||
HAL_GPIO_WritePin(GPIOE, GPIO_PIN_9, state);
|
||||
}
|
||||
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
// TODO implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TUSB HAL MILLISECOND
|
||||
*------------------------------------------------------------------*/
|
||||
|
@ -91,6 +91,12 @@ void board_led_control(bool state)
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t board_button_read(void)
|
||||
{
|
||||
// TODO implement
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TUSB HAL MILLISECOND
|
||||
|
@ -99,7 +99,7 @@ static void _prep_out_transaction (uint8_t itf)
|
||||
bool tud_cdc_n_connected(uint8_t itf)
|
||||
{
|
||||
// DTR (bit 0) active is considered as connected
|
||||
return TU_BIT_TEST(_cdcd_itf[itf].line_state, 0);
|
||||
return tud_ready() && TU_BIT_TEST(_cdcd_itf[itf].line_state, 0);
|
||||
}
|
||||
|
||||
uint8_t tud_cdc_n_get_line_state (uint8_t itf)
|
||||
|
@ -38,7 +38,6 @@
|
||||
#define CFG_TUD_CDC_EPSIZE 64
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
@ -97,7 +96,6 @@ ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_li
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL USBD-CLASS DRIVER API
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
void cdcd_init (void);
|
||||
bool cdcd_open (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
|
@ -107,7 +107,7 @@ static inline hidd_interface_t* get_interface_by_itfnum(uint8_t itf_num)
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_hid_generic_ready(void)
|
||||
{
|
||||
return (_hidd_itf[ITF_IDX_GENERIC].ep_in != 0) && !dcd_edpt_busy(TUD_OPT_RHPORT, _hidd_itf[ITF_IDX_GENERIC].ep_in);
|
||||
return tud_ready() && (_hidd_itf[ITF_IDX_GENERIC].ep_in != 0) && !dcd_edpt_busy(TUD_OPT_RHPORT, _hidd_itf[ITF_IDX_GENERIC].ep_in);
|
||||
}
|
||||
|
||||
bool tud_hid_generic_report(uint8_t report_id, void const* report, uint8_t len)
|
||||
@ -265,6 +265,7 @@ void hidd_init(void)
|
||||
|
||||
void hidd_reset(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
tu_memclr(_hidd_itf, sizeof(_hidd_itf));
|
||||
|
||||
#if CFG_TUD_HID_KEYBOARD
|
||||
@ -447,6 +448,7 @@ bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_reque
|
||||
// return false to stall control endpoint (e.g Host send non-sense DATA)
|
||||
bool hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
(void) rhport;
|
||||
hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex );
|
||||
TU_ASSERT(p_hid);
|
||||
|
||||
@ -469,6 +471,11 @@ bool hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const
|
||||
bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
// nothing to do
|
||||
(void) rhport;
|
||||
(void) ep_addr;
|
||||
(void) event;
|
||||
(void) xferred_bytes;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -102,11 +102,6 @@ static inline uint16_t rdwr10_get_blockcount(uint8_t const command[])
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_msc_ready(void)
|
||||
{
|
||||
return ( _mscd_itf.ep_in != 0 ) && ( _mscd_itf.ep_out != 0 ) ;
|
||||
}
|
||||
|
||||
bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier)
|
||||
{
|
||||
(void) lun;
|
||||
|
@ -68,9 +68,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
|
||||
* \defgroup MSC_Device Device
|
||||
* @{ */
|
||||
|
||||
|
||||
// Check if MSC interface is ready to use
|
||||
bool tud_msc_ready(void);
|
||||
bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -103,6 +103,13 @@ typedef enum
|
||||
TUSB_REQ_SYNCH_FRAME ///< 12
|
||||
}tusb_request_code_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_FEATURE_EDPT_HALT = 0,
|
||||
TUSB_REQ_FEATURE_REMOTE_WAKEUP = 1,
|
||||
TUSB_REQ_FEATURE_TEST_MODE = 2
|
||||
}tusb_request_feature_selector_t;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
TUSB_REQ_TYPE_STANDARD = 0,
|
||||
@ -159,8 +166,7 @@ typedef enum
|
||||
|
||||
enum {
|
||||
TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP = TU_BIT(5),
|
||||
TUSB_DESC_CONFIG_ATT_SELF_POWER = TU_BIT(6),
|
||||
TUSB_DESC_CONFIG_ATT_BUS_POWER = TU_BIT(7)
|
||||
TUSB_DESC_CONFIG_ATT_SELF_POWERED = TU_BIT(6),
|
||||
};
|
||||
|
||||
#define TUSB_DESC_CONFIG_POWER_MA(x) ((x)/2)
|
||||
|
@ -42,13 +42,14 @@ typedef enum
|
||||
DCD_EVENT_BUS_RESET = 1,
|
||||
DCD_EVENT_UNPLUGGED,
|
||||
DCD_EVENT_SOF,
|
||||
DCD_EVENT_SUSPENDED,
|
||||
DCD_EVENT_SUSPEND,
|
||||
DCD_EVENT_RESUME,
|
||||
|
||||
DCD_EVENT_SETUP_RECEIVED,
|
||||
DCD_EVENT_XFER_COMPLETE,
|
||||
|
||||
USBD_EVT_FUNC_CALL
|
||||
// Not an DCD event, just a convenient way to defer ISR function
|
||||
USBD_EVENT_FUNC_CALL
|
||||
} dcd_eventid_t;
|
||||
|
||||
typedef struct ATTR_ALIGNED(4)
|
||||
@ -67,7 +68,7 @@ typedef struct ATTR_ALIGNED(4)
|
||||
uint32_t len;
|
||||
}xfer_complete;
|
||||
|
||||
// USBD_EVT_FUNC_CALL
|
||||
// USBD_EVENT_FUNC_CALL
|
||||
struct {
|
||||
void (*func) (void*);
|
||||
void* param;
|
||||
@ -80,7 +81,9 @@ TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Device API
|
||||
*------------------------------------------------------------------*/
|
||||
bool dcd_init (uint8_t rhport);
|
||||
|
||||
// Initialize controller to device mode
|
||||
void dcd_init (uint8_t rhport);
|
||||
|
||||
// Enable device interrupt
|
||||
void dcd_int_enable (uint8_t rhport);
|
||||
@ -91,9 +94,12 @@ void dcd_int_disable(uint8_t rhport);
|
||||
// Receive Set Address request, mcu port must also include status IN response
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr);
|
||||
|
||||
// Receive Set Config request
|
||||
// Receive Set Configure request
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num);
|
||||
|
||||
// Wake up host
|
||||
void dcd_remote_wakeup(uint8_t rhport);
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Endpoint API
|
||||
* - open : Configure endpoint's registers
|
||||
|
@ -40,13 +40,22 @@
|
||||
// Device Data
|
||||
//--------------------------------------------------------------------+
|
||||
typedef struct {
|
||||
uint8_t config_num;
|
||||
struct ATTR_PACKED
|
||||
{
|
||||
volatile uint8_t connected : 1;
|
||||
volatile uint8_t configured : 1;
|
||||
volatile uint8_t suspended : 1;
|
||||
|
||||
uint8_t remote_wakeup_en : 1; // enable/disable by host
|
||||
uint8_t remote_wakeup_support : 1; // configuration descriptor's attribute
|
||||
uint8_t self_powered : 1; // configuration descriptor's attribute
|
||||
};
|
||||
|
||||
// uint8_t ep_busy_mask[2]; // bit mask for busy endpoint
|
||||
uint8_t ep_stall_mask[2]; // bit mask for stalled endpoint
|
||||
|
||||
uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
|
||||
uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid )
|
||||
|
||||
uint8_t ep_busy_mask[2]; // bit mask for busy endpoint
|
||||
uint8_t ep_stall_mask[2]; // bit mask for stalled endpoint
|
||||
}usbd_device_t;
|
||||
|
||||
static usbd_device_t _usbd_dev = { 0 };
|
||||
@ -166,11 +175,24 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event,
|
||||
void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) );
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
// Application API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_mounted(void)
|
||||
{
|
||||
return _usbd_dev.config_num > 0;
|
||||
return _usbd_dev.configured;
|
||||
}
|
||||
|
||||
bool tud_suspended(void)
|
||||
{
|
||||
return _usbd_dev.suspended;
|
||||
}
|
||||
|
||||
bool tud_remote_wakeup(void)
|
||||
{
|
||||
// only wake up host if this feature is supported and enabled and we are suspended
|
||||
TU_VERIFY (_usbd_dev.suspended && _usbd_dev.remote_wakeup_support && _usbd_dev.remote_wakeup_en );
|
||||
dcd_remote_wakeup(TUD_OPT_RHPORT);
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -178,6 +200,8 @@ bool tud_mounted(void)
|
||||
//--------------------------------------------------------------------+
|
||||
bool usbd_init (void)
|
||||
{
|
||||
tu_varclr(&_usbd_dev);
|
||||
|
||||
// Init device queue & task
|
||||
_usbd_q = osal_queue_create(&_usbd_qdef);
|
||||
TU_ASSERT(_usbd_q != NULL);
|
||||
@ -186,7 +210,7 @@ bool usbd_init (void)
|
||||
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++) usbd_class_drivers[i].init();
|
||||
|
||||
// Init device controller driver
|
||||
TU_ASSERT(dcd_init(TUD_OPT_RHPORT));
|
||||
dcd_init(TUD_OPT_RHPORT);
|
||||
dcd_int_enable(TUD_OPT_RHPORT);
|
||||
|
||||
return true;
|
||||
@ -195,6 +219,7 @@ bool usbd_init (void)
|
||||
static void usbd_reset(uint8_t rhport)
|
||||
{
|
||||
tu_varclr(&_usbd_dev);
|
||||
|
||||
memset(_usbd_dev.itf2drv, 0xff, sizeof(_usbd_dev.itf2drv)); // invalid mapping
|
||||
memset(_usbd_dev.ep2drv , 0xff, sizeof(_usbd_dev.ep2drv )); // invalid mapping
|
||||
|
||||
@ -239,7 +264,22 @@ void tud_task (void)
|
||||
|
||||
switch ( event.event_id )
|
||||
{
|
||||
case DCD_EVENT_BUS_RESET:
|
||||
usbd_reset(event.rhport);
|
||||
break;
|
||||
|
||||
case DCD_EVENT_UNPLUGGED:
|
||||
usbd_reset(event.rhport);
|
||||
|
||||
// invoke callback
|
||||
if (tud_umount_cb) tud_umount_cb();
|
||||
break;
|
||||
|
||||
case DCD_EVENT_SETUP_RECEIVED:
|
||||
// Mark as connected after receiving 1st setup packet.
|
||||
// But it is easier to set it every time instead of wasting time to check then set
|
||||
_usbd_dev.connected = 1;
|
||||
|
||||
// Process control request
|
||||
if ( !process_control_request(event.rhport, &event.setup_received) )
|
||||
{
|
||||
@ -250,38 +290,33 @@ void tud_task (void)
|
||||
break;
|
||||
|
||||
case DCD_EVENT_XFER_COMPLETE:
|
||||
{
|
||||
// Invoke the class callback associated with the endpoint address
|
||||
uint8_t const ep_addr = event.xfer_complete.ep_addr;
|
||||
|
||||
if ( 0 == tu_edpt_number(ep_addr) )
|
||||
// Only handle xfer callback in ready state
|
||||
// if (_usbd_dev.connected && !_usbd_dev.suspended)
|
||||
{
|
||||
// control transfer DATA stage callback
|
||||
usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t const drv_id = _usbd_dev.ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)];
|
||||
TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,);
|
||||
// Invoke the class callback associated with the endpoint address
|
||||
uint8_t const ep_addr = event.xfer_complete.ep_addr;
|
||||
|
||||
usbd_class_drivers[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
|
||||
if ( 0 == tu_edpt_number(ep_addr) )
|
||||
{
|
||||
// control transfer DATA stage callback
|
||||
usbd_control_xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint8_t const drv_id = _usbd_dev.ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)];
|
||||
TU_ASSERT(drv_id < USBD_CLASS_DRIVER_COUNT,);
|
||||
|
||||
usbd_class_drivers[drv_id].xfer_cb(event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DCD_EVENT_BUS_RESET:
|
||||
usbd_reset(event.rhport);
|
||||
// TODO remove since if task is too slow, we could clear the event of the new attached
|
||||
osal_queue_reset(_usbd_q);
|
||||
case DCD_EVENT_SUSPEND:
|
||||
if (tud_suspend_cb) tud_suspend_cb(_usbd_dev.remote_wakeup_en);
|
||||
break;
|
||||
|
||||
case DCD_EVENT_UNPLUGGED:
|
||||
usbd_reset(event.rhport);
|
||||
// TODO remove since if task is too slow, we could clear the event of the new attached
|
||||
osal_queue_reset(_usbd_q);
|
||||
|
||||
// invoke callback
|
||||
if (tud_umount_cb) tud_umount_cb();
|
||||
case DCD_EVENT_RESUME:
|
||||
if (tud_resume_cb) tud_resume_cb();
|
||||
break;
|
||||
|
||||
case DCD_EVENT_SOF:
|
||||
@ -294,7 +329,7 @@ void tud_task (void)
|
||||
}
|
||||
break;
|
||||
|
||||
case USBD_EVT_FUNC_CALL:
|
||||
case USBD_EVENT_FUNC_CALL:
|
||||
if ( event.func_call.func ) event.func_call.func(event.func_call.param);
|
||||
break;
|
||||
|
||||
@ -315,98 +350,140 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
{
|
||||
usbd_control_set_complete_callback(NULL);
|
||||
|
||||
if ( TUSB_REQ_RCPT_DEVICE == p_request->bmRequestType_bit.recipient &&
|
||||
TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type )
|
||||
switch ( p_request->bmRequestType_bit.recipient )
|
||||
{
|
||||
//------------- Standard Device Requests e.g in enumeration -------------//
|
||||
void* data_buf = NULL;
|
||||
uint16_t data_len = 0;
|
||||
|
||||
switch ( p_request->bRequest )
|
||||
{
|
||||
case TUSB_REQ_SET_ADDRESS:
|
||||
// DCD must include zero-length status response since depending on mcu,
|
||||
// status could be sent either before or after changing device address
|
||||
dcd_set_address(rhport, (uint8_t) p_request->wValue);
|
||||
return true; // skip the rest
|
||||
break;
|
||||
|
||||
case TUSB_REQ_GET_CONFIGURATION:
|
||||
data_buf = &_usbd_dev.config_num;
|
||||
data_len = 1;
|
||||
break;
|
||||
|
||||
case TUSB_REQ_SET_CONFIGURATION:
|
||||
//------------- Device Requests e.g in enumeration -------------//
|
||||
case TUSB_REQ_RCPT_DEVICE:
|
||||
if ( TUSB_REQ_TYPE_STANDARD != p_request->bmRequestType_bit.type )
|
||||
{
|
||||
uint8_t const config = (uint8_t) p_request->wValue;
|
||||
|
||||
dcd_set_config(rhport, config);
|
||||
_usbd_dev.config_num = config;
|
||||
|
||||
TU_ASSERT( TUSB_ERROR_NONE == process_set_config(rhport) );
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_REQ_GET_DESCRIPTOR:
|
||||
data_buf = (void*) get_descriptor(p_request, &data_len);
|
||||
if ( data_buf == NULL || data_len == 0 ) return false;
|
||||
break;
|
||||
|
||||
default:
|
||||
// Non standard request is not supported
|
||||
TU_BREAKPOINT();
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
switch ( p_request->bRequest )
|
||||
{
|
||||
case TUSB_REQ_SET_ADDRESS:
|
||||
// Depending on mcu, status phase could be sent either before or after changing device address
|
||||
// Therefore DCD must include zero-length status response
|
||||
dcd_set_address(rhport, (uint8_t) p_request->wValue);
|
||||
return true; // skip status
|
||||
break;
|
||||
|
||||
case TUSB_REQ_GET_CONFIGURATION:
|
||||
{
|
||||
uint8_t cfgnum = _usbd_dev.configured ? 1 : 0;
|
||||
usbd_control_xfer(rhport, p_request, &cfgnum, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_REQ_SET_CONFIGURATION:
|
||||
{
|
||||
uint8_t const cfg_num = (uint8_t) p_request->wValue;
|
||||
|
||||
dcd_set_config(rhport, cfg_num);
|
||||
_usbd_dev.configured = cfg_num ? 1 : 0;
|
||||
|
||||
TU_ASSERT( process_set_config(rhport) );
|
||||
usbd_control_status(rhport, p_request);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_REQ_GET_DESCRIPTOR:
|
||||
{
|
||||
uint16_t len = 0;
|
||||
void* buf = (void*) get_descriptor(p_request, &len);
|
||||
if ( buf == NULL || len == 0 ) return false;
|
||||
|
||||
usbd_control_xfer(rhport, p_request, buf, len);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_REQ_SET_FEATURE:
|
||||
// Only support remote wakeup for device feature
|
||||
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
|
||||
|
||||
// Host may enable remote wake up before suspending especially HID device
|
||||
_usbd_dev.remote_wakeup_en = true;
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
case TUSB_REQ_CLEAR_FEATURE:
|
||||
// Only support remote wakeup for device feature
|
||||
TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
|
||||
|
||||
// Host may disable remote wake up after resuming
|
||||
_usbd_dev.remote_wakeup_en = false;
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
case TUSB_REQ_GET_STATUS:
|
||||
{
|
||||
// Device status bit mask
|
||||
// - Bit 0: Self Powered
|
||||
// - Bit 1: Remote Wakeup enabled
|
||||
uint16_t status = (_usbd_dev.self_powered ? 1 : 0) | (_usbd_dev.remote_wakeup_en ? 2 : 0);
|
||||
usbd_control_xfer(rhport, p_request, &status, 2);
|
||||
}
|
||||
break;
|
||||
|
||||
// Unknown/Unsupported request
|
||||
default: TU_BREAKPOINT(); return false;
|
||||
}
|
||||
break;
|
||||
|
||||
usbd_control_xfer(rhport, p_request, data_buf, data_len);
|
||||
}
|
||||
else if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient )
|
||||
{
|
||||
//------------- Class/Interface Specific Request -------------//
|
||||
uint8_t const itf = tu_u16_low(p_request->wIndex);
|
||||
uint8_t const drvid = _usbd_dev.itf2drv[ itf ];
|
||||
|
||||
TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT);
|
||||
|
||||
usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_request_complete );
|
||||
|
||||
// control endpoint will be stalled if driver return false
|
||||
return usbd_class_drivers[drvid].control_request(rhport, p_request);
|
||||
}
|
||||
else if ( p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT &&
|
||||
p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD )
|
||||
{
|
||||
//------------- Endpoint Request -------------//
|
||||
switch ( p_request->bRequest )
|
||||
case TUSB_REQ_RCPT_INTERFACE:
|
||||
{
|
||||
case TUSB_REQ_GET_STATUS:
|
||||
{
|
||||
uint16_t status = usbd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000;
|
||||
usbd_control_xfer(rhport, p_request, &status, 2);
|
||||
}
|
||||
break;
|
||||
uint8_t const itf = tu_u16_low(p_request->wIndex);
|
||||
uint8_t const drvid = _usbd_dev.itf2drv[itf];
|
||||
|
||||
case TUSB_REQ_CLEAR_FEATURE:
|
||||
// only endpoint feature is halted/stalled
|
||||
dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
TU_VERIFY(drvid < USBD_CLASS_DRIVER_COUNT);
|
||||
|
||||
case TUSB_REQ_SET_FEATURE:
|
||||
// only endpoint feature is halted/stalled
|
||||
usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex));
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
usbd_control_set_complete_callback(usbd_class_drivers[drvid].control_request_complete );
|
||||
|
||||
default:
|
||||
TU_BREAKPOINT();
|
||||
return false;
|
||||
// stall control endpoint if driver return false
|
||||
return usbd_class_drivers[drvid].control_request(rhport, p_request);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//------------- Unsupported Request -------------//
|
||||
TU_BREAKPOINT();
|
||||
return false;
|
||||
break;
|
||||
|
||||
//------------- Endpoint Request -------------//
|
||||
case TUSB_REQ_RCPT_ENDPOINT:
|
||||
// Non standard request is not supported
|
||||
TU_VERIFY( TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type );
|
||||
|
||||
switch ( p_request->bRequest )
|
||||
{
|
||||
case TUSB_REQ_GET_STATUS:
|
||||
{
|
||||
uint16_t status = usbd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000;
|
||||
usbd_control_xfer(rhport, p_request, &status, 2);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_REQ_CLEAR_FEATURE:
|
||||
if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
|
||||
{
|
||||
dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
|
||||
}
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
case TUSB_REQ_SET_FEATURE:
|
||||
if ( TUSB_REQ_FEATURE_EDPT_HALT == p_request->wValue )
|
||||
{
|
||||
usbd_edpt_stall(rhport, tu_u16_low(p_request->wIndex));
|
||||
}
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
// Unknown/Unsupported request
|
||||
default: TU_BREAKPOINT(); return false;
|
||||
}
|
||||
break;
|
||||
|
||||
// Unknown recipient
|
||||
default: TU_BREAKPOINT(); return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -416,13 +493,18 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
|
||||
// This function parse configuration descriptor & open drivers accordingly
|
||||
static bool process_set_config(uint8_t rhport)
|
||||
{
|
||||
uint8_t const * desc_cfg = (uint8_t const *) usbd_desc_set->config;
|
||||
TU_ASSERT(desc_cfg != NULL);
|
||||
tusb_desc_configuration_t const * desc_cfg = (tusb_desc_configuration_t const *) usbd_desc_set->config;
|
||||
TU_ASSERT(desc_cfg != NULL && desc_cfg->bDescriptorType == TUSB_DESC_CONFIGURATION);
|
||||
|
||||
uint8_t const * p_desc = desc_cfg + sizeof(tusb_desc_configuration_t);
|
||||
uint16_t const cfg_len = ((tusb_desc_configuration_t*)desc_cfg)->wTotalLength;
|
||||
// Parse configuration descriptor
|
||||
_usbd_dev.remote_wakeup_support = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP) ? 1 : 0;
|
||||
_usbd_dev.self_powered = (desc_cfg->bmAttributes & TUSB_DESC_CONFIG_ATT_SELF_POWERED) ? 1 : 0;
|
||||
|
||||
while( p_desc < desc_cfg + cfg_len )
|
||||
// Parse interface descriptor
|
||||
uint8_t const * p_desc = ((uint8_t const*) desc_cfg) + sizeof(tusb_desc_configuration_t);
|
||||
uint8_t const * desc_end = ((uint8_t const*) desc_cfg) + desc_cfg->wTotalLength;
|
||||
|
||||
while( p_desc < desc_end )
|
||||
{
|
||||
// Each interface always starts with Interface or Association descriptor
|
||||
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
|
||||
@ -459,7 +541,7 @@ static bool process_set_config(uint8_t rhport)
|
||||
// invoke callback
|
||||
if (tud_mount_cb) tud_mount_cb();
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper marking endpoint of interface belongs to class driver
|
||||
@ -515,9 +597,8 @@ static void const* get_descriptor(tusb_control_request_t const * p_request, uint
|
||||
}else
|
||||
{
|
||||
// out of range
|
||||
/* The 0xEE index string is a Microsoft USB extension.
|
||||
* It can be used to tell Windows what driver it should use for the device !!!
|
||||
*/
|
||||
// The 0xEE index string is a Microsoft USB extension.
|
||||
// It can be used to tell Windows what driver it should use for the device !!!
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
@ -543,7 +624,13 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
|
||||
switch (event->event_id)
|
||||
{
|
||||
case DCD_EVENT_BUS_RESET:
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
break;
|
||||
|
||||
case DCD_EVENT_UNPLUGGED:
|
||||
_usbd_dev.connected = 0;
|
||||
_usbd_dev.configured = 0;
|
||||
_usbd_dev.suspended = 0;
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
break;
|
||||
|
||||
@ -551,12 +638,23 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
|
||||
// nothing to do now
|
||||
break;
|
||||
|
||||
case DCD_EVENT_SUSPENDED:
|
||||
// TODO support suspended
|
||||
case DCD_EVENT_SUSPEND:
|
||||
// NOTE: When plugging/unplugging device, the D+/D- state are unstable and can accidentally meet the
|
||||
// SUSPEND condition ( Idle for 3ms ). Some MCUs such as samd don't distinguish suspend vs disconnect as well.
|
||||
// We will skip handling SUSPEND/RESUME event if not currently connected
|
||||
if ( _usbd_dev.connected )
|
||||
{
|
||||
_usbd_dev.suspended = 1;
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
}
|
||||
break;
|
||||
|
||||
case DCD_EVENT_RESUME:
|
||||
// TODO support resume
|
||||
if ( _usbd_dev.connected )
|
||||
{
|
||||
_usbd_dev.suspended = 0;
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
}
|
||||
break;
|
||||
|
||||
case DCD_EVENT_SETUP_RECEIVED:
|
||||
@ -565,14 +663,14 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
|
||||
|
||||
case DCD_EVENT_XFER_COMPLETE:
|
||||
// skip zero-length control status complete event, should dcd notifies us.
|
||||
if ( 0 == tu_edpt_number(event->xfer_complete.ep_addr) && event->xfer_complete.len == 0) break;
|
||||
if ( (0 == tu_edpt_number(event->xfer_complete.ep_addr)) && (event->xfer_complete.len == 0) ) break;
|
||||
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
TU_ASSERT(event->xfer_complete.result == XFER_RESULT_SUCCESS,);
|
||||
break;
|
||||
|
||||
// Not an DCD event, just a convenient way to defer ISR function should we need
|
||||
case USBD_EVT_FUNC_CALL:
|
||||
// Not an DCD event, just a convenient way to defer ISR function should we need to
|
||||
case USBD_EVENT_FUNC_CALL:
|
||||
osal_queue_send(_usbd_q, event, in_isr);
|
||||
break;
|
||||
|
||||
@ -642,7 +740,7 @@ void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr)
|
||||
dcd_event_t event =
|
||||
{
|
||||
.rhport = 0,
|
||||
.event_id = USBD_EVT_FUNC_CALL,
|
||||
.event_id = USBD_EVENT_FUNC_CALL,
|
||||
};
|
||||
|
||||
event.func_call.func = func;
|
||||
|
@ -34,16 +34,9 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include <common/tusb_common.h>
|
||||
#include "common/tusb_common.h"
|
||||
#include "device/dcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/// \brief Descriptor pointer collector to all the needed.
|
||||
typedef struct {
|
||||
void const * device; ///< pointer to device descriptor \ref tusb_desc_device_t
|
||||
@ -60,27 +53,47 @@ typedef struct {
|
||||
|
||||
}tud_desc_set_t;
|
||||
|
||||
|
||||
// Must be defined by application
|
||||
extern tud_desc_set_t tud_desc_set;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
// Application API
|
||||
//--------------------------------------------------------------------+
|
||||
bool tud_mounted(void);
|
||||
|
||||
// Task function should be called in main/rtos loop
|
||||
void tud_task (void);
|
||||
|
||||
// Check if device is connected and configured
|
||||
bool tud_mounted(void);
|
||||
|
||||
// Check if device is suspended
|
||||
bool tud_suspended(void);
|
||||
|
||||
// Check if device is ready to transfer
|
||||
static inline bool tud_ready(void)
|
||||
{
|
||||
return tud_mounted() && !tud_suspended();
|
||||
}
|
||||
|
||||
// Remote wake up host, only if suspended and enabled by host
|
||||
bool tud_remote_wakeup(void);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION CALLBACK (WEAK is optional)
|
||||
// Application Callbacks (WEAK is optional)
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Callback invoked when device is mounted (configured)
|
||||
// Invoked when device is mounted (configured)
|
||||
ATTR_WEAK void tud_mount_cb(void);
|
||||
|
||||
// Callback invoked when device is unmounted (bus reset/unplugged)
|
||||
// Invoked when device is unmounted
|
||||
ATTR_WEAK void tud_umount_cb(void);
|
||||
|
||||
//void tud_device_suspended_cb(void);
|
||||
// Invoked when usb bus is suspended
|
||||
// Within 7ms, device must draw an average of current less than 2.5 mA from bus
|
||||
ATTR_WEAK void tud_suspend_cb(bool remote_wakeup_en);
|
||||
|
||||
// Invoked when usb bus is resumed
|
||||
ATTR_WEAK void tud_resume_cb(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -254,7 +254,7 @@ tusb_desc_device_t const _desc_auto_device =
|
||||
.iProduct = 0x02,
|
||||
.iSerialNumber = 0x03,
|
||||
|
||||
.bNumConfigurations = 0x01 // TODO multiple configurations
|
||||
.bNumConfigurations = 0x01
|
||||
};
|
||||
|
||||
|
||||
@ -342,7 +342,7 @@ desc_auto_cfg_t const _desc_auto_config_struct =
|
||||
|
||||
.bConfigurationValue = 1,
|
||||
.iConfiguration = 0x00,
|
||||
.bmAttributes = TUSB_DESC_CONFIG_ATT_BUS_POWER,
|
||||
.bmAttributes = TU_BIT(7) | TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP,
|
||||
.bMaxPower = TUSB_DESC_CONFIG_POWER_MA(100)
|
||||
},
|
||||
|
||||
|
@ -114,6 +114,7 @@ bool usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t result
|
||||
|
||||
if ( _control_state.request.bmRequestType_bit.direction == TUSB_DIR_OUT )
|
||||
{
|
||||
TU_VERIFY(_control_state.buffer);
|
||||
memcpy(_control_state.buffer, _usbd_ctrl_buf, xferred_bytes);
|
||||
}
|
||||
|
||||
|
@ -61,7 +61,6 @@ typedef void (*osal_task_func_t)( void * );
|
||||
* osal_queue_t osal_queue_create(osal_queue_def_t* qdef)
|
||||
* osal_queue_receive (osal_queue_t const queue_hdl, void *p_data, uint32_t msec, uint32_t *p_error)
|
||||
* bool osal_queue_send(osal_queue_t const queue_hdl, void const * data, bool in_isr)
|
||||
* osal_queue_reset()
|
||||
*
|
||||
* Semaphore
|
||||
* osal_semaphore_def_t, osal_semaphore_t
|
||||
|
@ -125,11 +125,6 @@ static inline bool osal_queue_send(osal_queue_t const queue_hdl, void const * da
|
||||
return in_isr ? xQueueSendToBackFromISR(queue_hdl, data, NULL) : xQueueSendToBack(queue_hdl, data, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
}
|
||||
|
||||
static inline void osal_queue_reset(osal_queue_t const queue_hdl)
|
||||
{
|
||||
xQueueReset(queue_hdl);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -161,11 +161,6 @@ static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, b
|
||||
return true;
|
||||
}
|
||||
|
||||
static inline void osal_queue_reset(osal_queue_t const queue_hdl)
|
||||
{
|
||||
// TODO implement later
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -190,13 +190,6 @@ static inline bool osal_queue_send(osal_queue_t const qhdl, void const * data, b
|
||||
return success;
|
||||
}
|
||||
|
||||
static inline void osal_queue_reset(osal_queue_t const qhdl)
|
||||
{
|
||||
// tusb_hal_int_disable_all();
|
||||
tu_fifo_clear(&qhdl->ff);
|
||||
// tusb_hal_int_enable_all();
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -38,26 +38,27 @@ static ATTR_ALIGNED(4) UsbDeviceDescBank sram_registers[8][2];
|
||||
static ATTR_ALIGNED(4) uint8_t _setup_packet[8];
|
||||
|
||||
// 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;
|
||||
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;
|
||||
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;
|
||||
|
||||
// Prepare for setup packet
|
||||
dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
|
||||
// Prepare for setup packet
|
||||
dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Controller API
|
||||
*------------------------------------------------------------------*/
|
||||
bool dcd_init (uint8_t rhport)
|
||||
void dcd_init (uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
@ -79,9 +80,8 @@ bool dcd_init (uint8_t rhport)
|
||||
USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY;
|
||||
while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {}
|
||||
|
||||
USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending
|
||||
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
@ -105,6 +105,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
|
||||
while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
|
||||
|
||||
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
|
||||
|
||||
// Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
|
||||
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND;
|
||||
}
|
||||
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
@ -112,6 +116,14 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
(void) rhport;
|
||||
(void) config_num;
|
||||
// Nothing to do
|
||||
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USB->DEVICE.CTRLB.bit.UPRSM = 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
@ -292,23 +304,48 @@ void maybe_transfer_complete(void) {
|
||||
}
|
||||
}
|
||||
|
||||
void USB_Handler(void) {
|
||||
uint32_t int_status = USB->DEVICE.INTFLAG.reg;
|
||||
void USB_Handler(void)
|
||||
{
|
||||
uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg;
|
||||
USB->DEVICE.INTFLAG.reg = int_status; // clear interrupt
|
||||
|
||||
/*------------- 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);
|
||||
}
|
||||
|
||||
// SAMD doesn't distinguish between Suspend and Disconnect state.
|
||||
// Both condition will cause SUSPEND interrupt triggered.
|
||||
// To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only
|
||||
// enabled when we received SET_ADDRESS request and cleared on Bus Reset
|
||||
if ( int_status & USB_DEVICE_INTFLAG_SUSPEND )
|
||||
{
|
||||
// Enable wakeup interrupt
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending
|
||||
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP;
|
||||
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
||||
}
|
||||
|
||||
// Wakeup interrupt is only enabled when we got suspended.
|
||||
// Wakeup interrupt will disable itself
|
||||
if ( int_status & USB_DEVICE_INTFLAG_WAKEUP )
|
||||
{
|
||||
// disable wakeup interrupt itself
|
||||
USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP;
|
||||
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
||||
}
|
||||
|
||||
if ( int_status & USB_DEVICE_INTFLAG_EORST )
|
||||
{
|
||||
// Disable both suspend and wakeup interrupt
|
||||
USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND;
|
||||
|
||||
bus_reset();
|
||||
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
|
||||
}
|
||||
|
||||
// Setup packet received.
|
||||
maybe_handle_setup_packet();
|
||||
|
||||
|
@ -38,26 +38,27 @@ static UsbDeviceDescBank sram_registers[8][2];
|
||||
static ATTR_ALIGNED(4) uint8_t _setup_packet[8];
|
||||
|
||||
// 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;
|
||||
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;
|
||||
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;
|
||||
|
||||
// Prepare for setup packet
|
||||
dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
|
||||
// Prepare for setup packet
|
||||
dcd_edpt_xfer(0, 0, _setup_packet, sizeof(_setup_packet));
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Controller API
|
||||
*------------------------------------------------------------------*/
|
||||
bool dcd_init (uint8_t rhport)
|
||||
void dcd_init (uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
@ -78,9 +79,9 @@ bool dcd_init (uint8_t rhport)
|
||||
USB->DEVICE.CTRLB.reg = USB_DEVICE_CTRLB_SPDCONF_FS;
|
||||
USB->DEVICE.CTRLA.reg = USB_CTRLA_MODE_DEVICE | USB_CTRLA_ENABLE | USB_CTRLA_RUNSTDBY;
|
||||
while (USB->DEVICE.SYNCBUSY.bit.ENABLE == 1) {}
|
||||
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST;
|
||||
|
||||
return true;
|
||||
USB->DEVICE.INTFLAG.reg |= USB->DEVICE.INTFLAG.reg; // clear pending
|
||||
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SOF | USB_DEVICE_INTENSET_EORST;
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
@ -110,6 +111,10 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
|
||||
while (USB->DEVICE.DeviceEndpoint[0].EPSTATUS.bit.BK1RDY == 1) {}
|
||||
|
||||
USB->DEVICE.DADD.reg = USB_DEVICE_DADD_DADD(dev_addr) | USB_DEVICE_DADD_ADDEN;
|
||||
|
||||
// Enable SUSPEND interrupt since the bus signal D+/D- are stable now.
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_SUSPEND; // clear pending
|
||||
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTENSET_SUSPEND;
|
||||
}
|
||||
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
@ -119,6 +124,13 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
USB->DEVICE.CTRLB.bit.UPRSM = 1;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* DCD Endpoint port
|
||||
*------------------------------------------------------------------*/
|
||||
@ -267,12 +279,42 @@ 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;
|
||||
uint32_t int_status = USB->DEVICE.INTFLAG.reg & USB->DEVICE.INTENSET.reg;
|
||||
|
||||
/*------------- Interrupt Processing -------------*/
|
||||
// SAMD doesn't distinguish between Suspend and Disconnect state.
|
||||
// Both condition will cause SUSPEND interrupt triggered.
|
||||
// To prevent being triggered when D+/D- are not stable, SUSPEND interrupt is only
|
||||
// enabled when we received SET_ADDRESS request and cleared on Bus Reset
|
||||
if ( int_status & USB_DEVICE_INTFLAG_SUSPEND )
|
||||
{
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SUSPEND;
|
||||
|
||||
// Enable wakeup interrupt
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP; // clear pending
|
||||
USB->DEVICE.INTENSET.reg = USB_DEVICE_INTFLAG_WAKEUP;
|
||||
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
||||
}
|
||||
|
||||
// Wakeup interrupt is only enabled when we got suspended.
|
||||
// Wakeup interrupt will disable itself
|
||||
if ( int_status & USB_DEVICE_INTFLAG_WAKEUP )
|
||||
{
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_WAKEUP;
|
||||
|
||||
// disable wakeup interrupt itself
|
||||
USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP;
|
||||
dcd_event_bus_signal(0, DCD_EVENT_RESUME, true);
|
||||
}
|
||||
|
||||
if ( int_status & USB_DEVICE_INTFLAG_EORST )
|
||||
{
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTENCLR_EORST;
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_EORST;
|
||||
|
||||
// Disable both suspend and wakeup interrupt
|
||||
USB->DEVICE.INTENCLR.reg = USB_DEVICE_INTFLAG_WAKEUP | USB_DEVICE_INTFLAG_SUSPEND;
|
||||
|
||||
bus_reset();
|
||||
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
|
||||
}
|
||||
@ -280,6 +322,7 @@ void USB_0_Handler(void) {
|
||||
// Setup packet received.
|
||||
maybe_handle_setup_packet();
|
||||
}
|
||||
|
||||
/* USB_SOF_HSOF */
|
||||
void USB_1_Handler(void) {
|
||||
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
|
||||
|
@ -177,10 +177,9 @@ static void xact_in_prepare(uint8_t epnum)
|
||||
//--------------------------------------------------------------------+
|
||||
// Controller API
|
||||
//--------------------------------------------------------------------+
|
||||
bool dcd_init (uint8_t rhport)
|
||||
void dcd_init (uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
@ -200,13 +199,36 @@ void dcd_set_address (uint8_t rhport, uint8_t dev_addr)
|
||||
(void) rhport;
|
||||
(void) dev_addr;
|
||||
// Set Address is automatically update by hw controller, nothing to do
|
||||
|
||||
// Enable usbevent for suspend and resume detection
|
||||
// Since the bus signal D+/D- are stable now.
|
||||
|
||||
// Clear current pending first
|
||||
NRF_USBD->EVENTCAUSE |= NRF_USBD->EVENTCAUSE;
|
||||
NRF_USBD->EVENTS_USBEVENT = 0;
|
||||
|
||||
NRF_USBD->INTENSET = USBD_INTEN_USBEVENT_Msk;
|
||||
}
|
||||
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) config_num;
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
// Bring controller out of low power mode
|
||||
NRF_USBD->LOWPOWER = 0;
|
||||
|
||||
// Initiate RESUME signal
|
||||
NRF_USBD->DPDMVALUE = USBD_DPDMVALUE_STATE_Resume;
|
||||
NRF_USBD->TASKS_DPDMDRIVE = 1;
|
||||
|
||||
// TODO There is no USBEVENT Resume interrupt
|
||||
// We may manually raise DCD_EVENT_RESUME event here
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -358,19 +380,44 @@ void USBD_IRQHandler(void)
|
||||
}
|
||||
}
|
||||
|
||||
/*------------- Interrupt Processing -------------*/
|
||||
if ( int_status & USBD_INTEN_USBRESET_Msk )
|
||||
{
|
||||
bus_reset();
|
||||
dcd_event_bus_signal(0, DCD_EVENT_BUS_RESET, true);
|
||||
}
|
||||
|
||||
if ( int_status & USBD_INTEN_SOF_Msk )
|
||||
{
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
|
||||
}
|
||||
|
||||
if ( int_status & USBD_INTEN_USBEVENT_Msk )
|
||||
{
|
||||
uint32_t const evt_cause = NRF_USBD->EVENTCAUSE & (USBD_EVENTCAUSE_SUSPEND_Msk | USBD_EVENTCAUSE_RESUME_Msk);
|
||||
NRF_USBD->EVENTCAUSE = evt_cause; // clear interrupt
|
||||
|
||||
if ( evt_cause & USBD_EVENTCAUSE_SUSPEND_Msk )
|
||||
{
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
||||
|
||||
// Put controller into low power mode
|
||||
NRF_USBD->LOWPOWER = 1;
|
||||
|
||||
// Leave HFXO disable to application, since it may be used by other
|
||||
}
|
||||
|
||||
if ( evt_cause & USBD_EVENTCAUSE_RESUME_Msk )
|
||||
{
|
||||
dcd_event_bus_signal(0, DCD_EVENT_RESUME , true);
|
||||
}
|
||||
}
|
||||
|
||||
if ( int_status & EDPT_END_ALL_MASK )
|
||||
{
|
||||
// DMA complete move data from SRAM -> Endpoint
|
||||
edpt_dma_end();
|
||||
}
|
||||
|
||||
|
||||
// Setup tokens are specific to the Control endpoint.
|
||||
if ( int_status & USBD_INTEN_EP0SETUP_Msk )
|
||||
{
|
||||
@ -502,12 +549,6 @@ void USBD_IRQHandler(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SOF interrupt
|
||||
if ( int_status & USBD_INTEN_SOF_Msk )
|
||||
{
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -212,8 +212,8 @@ void tusb_hal_nrf_power_event (uint32_t event)
|
||||
|
||||
nrf_usbd_isosplit_set(USBD_ISOSPLIT_SPLIT_HalfIN);
|
||||
|
||||
// Enable interrupt. SOF is used as CDC auto flush
|
||||
NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_USBEVENT_Msk | USBD_INTEN_EPDATA_Msk |
|
||||
// Enable interrupt
|
||||
NRF_USBD->INTENSET = USBD_INTEN_USBRESET_Msk | USBD_INTEN_EPDATA_Msk |
|
||||
USBD_INTEN_EP0SETUP_Msk | USBD_INTEN_EP0DATADONE_Msk | USBD_INTEN_ENDEPIN0_Msk | USBD_INTEN_ENDEPOUT0_Msk;
|
||||
|
||||
// Enable interrupt, priorities should be set by application
|
||||
|
@ -126,6 +126,21 @@ static inline uint8_t ep_addr2id(uint8_t endpoint_addr)
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROLLER API
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_init(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
LPC_USB->EPLISTSTART = (uint32_t) _dcd.ep;
|
||||
LPC_USB->DATABUFSTART = SRAM_REGION;
|
||||
|
||||
LPC_USB->INTSTAT = LPC_USB->INTSTAT; // clear all pending interrupt
|
||||
LPC_USB->INTEN = INT_DEVICE_STATUS_MASK;
|
||||
LPC_USB->DEVCMDSTAT |= CMDSTAT_DEVICE_ENABLE_MASK | CMDSTAT_DEVICE_CONNECT_MASK |
|
||||
CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
|
||||
|
||||
NVIC_ClearPendingIRQ(USB0_IRQn);
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
@ -138,12 +153,6 @@ void dcd_int_disable(uint8_t rhport)
|
||||
NVIC_DisableIRQ(USB0_IRQn);
|
||||
}
|
||||
|
||||
void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) config_num;
|
||||
}
|
||||
|
||||
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
{
|
||||
// Response with status first before changing device address
|
||||
@ -153,21 +162,15 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
LPC_USB->DEVCMDSTAT |= dev_addr;
|
||||
}
|
||||
|
||||
bool dcd_init(uint8_t rhport)
|
||||
void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
{
|
||||
(void) rhport;
|
||||
(void) config_num;
|
||||
}
|
||||
|
||||
LPC_USB->EPLISTSTART = (uint32_t) _dcd.ep;
|
||||
LPC_USB->DATABUFSTART = SRAM_REGION;
|
||||
|
||||
LPC_USB->INTSTAT = LPC_USB->INTSTAT; // clear all pending interrupt
|
||||
LPC_USB->INTEN = INT_DEVICE_STATUS_MASK;
|
||||
LPC_USB->DEVCMDSTAT |= CMDSTAT_DEVICE_ENABLE_MASK | CMDSTAT_DEVICE_CONNECT_MASK |
|
||||
CMDSTAT_RESET_CHANGE_MASK | CMDSTAT_CONNECT_CHANGE_MASK | CMDSTAT_SUSPEND_CHANGE_MASK;
|
||||
|
||||
NVIC_EnableIRQ(USB0_IRQn);
|
||||
|
||||
return true;
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -339,7 +342,7 @@ void USB_IRQHandler(void)
|
||||
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
|
||||
if (dev_cmd_stat & CMDSTAT_DEVICE_ADDR_MASK)
|
||||
{
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPENDED, true);
|
||||
dcd_event_bus_signal(0, DCD_EVENT_SUSPEND, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ static void bus_reset(void)
|
||||
tu_memclr(&_dcd, sizeof(dcd_data_t));
|
||||
}
|
||||
|
||||
bool dcd_init(uint8_t rhport)
|
||||
void dcd_init(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
@ -185,9 +185,6 @@ bool dcd_init(uint8_t rhport)
|
||||
|
||||
// USB IRQ priority should be set by application previously
|
||||
NVIC_ClearPendingIRQ(USB_IRQn);
|
||||
NVIC_EnableIRQ(USB_IRQn);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
@ -217,6 +214,11 @@ void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
sie_write(SIE_CMDCODE_CONFIGURE_DEVICE, 1, 1);
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// CONTROL HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
@ -481,7 +483,7 @@ static void bus_event_isr(uint8_t rhport)
|
||||
{
|
||||
if (dev_status & SIE_DEV_STATUS_SUSPEND_MASK)
|
||||
{
|
||||
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPENDED, true);
|
||||
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -121,7 +121,7 @@ static void bus_reset(uint8_t rhport)
|
||||
p_dcd->qhd[0].int_on_setup = 1; // OUT only
|
||||
}
|
||||
|
||||
bool dcd_init(uint8_t rhport)
|
||||
void dcd_init(uint8_t rhport)
|
||||
{
|
||||
LPC_USBHS_T* const lpc_usb = LPC_USB[rhport];
|
||||
dcd_data_t* p_dcd = dcd_data_ptr[rhport];
|
||||
@ -134,8 +134,6 @@ bool dcd_init(uint8_t rhport)
|
||||
|
||||
lpc_usb->USBCMD_D &= ~0x00FF0000; // Interrupt Threshold Interval = 0
|
||||
lpc_usb->USBCMD_D |= TU_BIT(0); // connect
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_int_enable(uint8_t rhport)
|
||||
@ -163,6 +161,11 @@ void dcd_set_config(uint8_t rhport, uint8_t config_num)
|
||||
// nothing to do
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HELPER
|
||||
//--------------------------------------------------------------------+
|
||||
@ -303,7 +306,7 @@ void hal_dcd_isr(uint8_t rhport)
|
||||
// Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration.
|
||||
if ((lpc_usb->DEVICEADDR >> 25) & 0x0f)
|
||||
{
|
||||
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPENDED, true);
|
||||
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -35,10 +35,8 @@
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
|
||||
bool dcd_init (uint8_t rhport)
|
||||
void dcd_init (uint8_t rhport)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
// Enable device interrupt
|
||||
@ -57,6 +55,14 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
|
||||
void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
{}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc)
|
||||
{
|
||||
return false;
|
||||
|
@ -128,7 +128,7 @@ static void end_of_reset(void) {
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Controller API
|
||||
*------------------------------------------------------------------*/
|
||||
bool dcd_init (uint8_t rhport)
|
||||
void dcd_init (uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
@ -161,8 +161,6 @@ bool dcd_init (uint8_t rhport)
|
||||
|
||||
// Enable pullup, enable peripheral.
|
||||
USB_OTG_FS->GCCFG |= USB_OTG_GCCFG_VBUSBSEN | USB_OTG_GCCFG_PWRDWN;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void dcd_int_enable (uint8_t rhport)
|
||||
@ -196,6 +194,11 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void dcd_remote_wakeup(uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* DCD Endpoint port
|
||||
*------------------------------------------------------------------*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user