mirror of
https://github.com/hathach/tinyusb.git
synced 2025-03-29 10:20:57 +00:00
commit
aa71b8fd87
3
.gitmodules
vendored
3
.gitmodules
vendored
@ -4,6 +4,3 @@
|
||||
[submodule "hw/mcu/microchip/samd/asf4"]
|
||||
path = hw/mcu/microchip/samd/asf4
|
||||
url = https://github.com/adafruit/asf4.git
|
||||
[submodule "hw/mcu/microchip/samd/samd-peripherals"]
|
||||
path = hw/mcu/microchip/samd/samd-peripherals
|
||||
url = https://github.com/adafruit/samd-peripherals.git
|
||||
|
@ -19,7 +19,7 @@
|
||||
arm_target_device_name="nRF52840_xxAA"
|
||||
arm_target_interface_type="SWD"
|
||||
build_treat_warnings_as_errors="Yes"
|
||||
c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_PCA10056"
|
||||
c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_PCA10056;CFG_TUSB_MCU=OPT_MCU_NRF5X"
|
||||
c_user_include_directories="../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(nrfxDir)/..;$(nrfxDir);$(nrfxDir)/mdk;$(nrfxDir)/hal;$(nrfxDir)/drivers/include"
|
||||
debug_register_definition_file="ses_nrf5x/nrf52840_Registers.xml"
|
||||
debug_target_connection="J-Link"
|
||||
@ -118,8 +118,8 @@
|
||||
arm_target_device_name="ATSAMD51J19"
|
||||
arm_target_interface_type="SWD"
|
||||
build_treat_warnings_as_errors="Yes"
|
||||
c_preprocessor_definitions="__SAME51_FAMILY;__SAMD51J19A__;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_METRO_M4_EXPRESS;USE_SIMPLE_ASSERT"
|
||||
c_user_include_directories="../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(asf4Dir);$(asf4Dir)/include;$(asf4Dir)/hri;$(asf4Dir)/hal/include;$(asf4Dir)/hal/utils/include;$(asf4Dir)/hpl/port"
|
||||
c_preprocessor_definitions="__SAME51_FAMILY;__SAMD51J19A__;ARM_MATH_CM4;FLASH_PLACEMENT=1;USE_SIMPLE_ASSERT;BOARD_METRO_M4_EXPRESS;CIRCUITPY_GCLK_INIT_1ST=0xffff;CFG_TUSB_MCU=OPT_MCU_SAMD51"
|
||||
c_user_include_directories="../src;$(rootDir)/hw/cmsis/Include;$(rootDir)/hw;$(rootDir)/src;$(asf4Dir);$(asf4Dir)/include;$(asf4Dir)/config;$(asf4Dir)/hri;$(asf4Dir)/hal/include;$(asf4Dir)/hal/utils/include;$(asf4Dir)/hpl/port;$(asf4Dir)/hpl/gclk"
|
||||
debug_register_definition_file="ses_samd51/ATSAME51J19A_Registers.xml"
|
||||
debug_target_connection="J-Link"
|
||||
gcc_entry_point="Reset_Handler"
|
||||
@ -156,6 +156,23 @@
|
||||
<folder Name="gcc">
|
||||
<file file_name="../../../../hw/mcu/microchip/samd/asf4/samd51/gcc/system_samd51.c" />
|
||||
</folder>
|
||||
<folder Name="hpl">
|
||||
<folder Name="core">
|
||||
<file file_name="../../../../../../../adafruit/circuitpython/thach_cp/ports/atmel-samd/asf4/samd51/hpl/core/hpl_init.c" />
|
||||
</folder>
|
||||
<folder Name="osc32kctrl">
|
||||
<file file_name="../../../../hw/mcu/microchip/samd/asf4/samd51/hpl/osc32kctrl/hpl_osc32kctrl.c" />
|
||||
</folder>
|
||||
<folder Name="oscctrl">
|
||||
<file file_name="../../../../hw/mcu/microchip/samd/asf4/samd51/hpl/oscctrl/hpl_oscctrl.c" />
|
||||
</folder>
|
||||
<folder Name="mclk">
|
||||
<file file_name="../../../../hw/mcu/microchip/samd/asf4/samd51/hpl/mclk/hpl_mclk.c" />
|
||||
</folder>
|
||||
<folder Name="gclk">
|
||||
<file file_name="../../../../hw/mcu/microchip/samd/asf4/samd51/hpl/gclk/hpl_gclk.c" />
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
</folder>
|
||||
@ -163,15 +180,6 @@
|
||||
</folder>
|
||||
</folder>
|
||||
<configuration Name="Debug" build_treat_warnings_as_errors="Yes" />
|
||||
<folder Name="src">
|
||||
<file file_name="../src/main.c" />
|
||||
<folder Name="segger_rtt">
|
||||
<file file_name="../src/segger_rtt/SEGGER_RTT.c" />
|
||||
<file file_name="../src/segger_rtt/SEGGER_RTT.h" />
|
||||
<file file_name="../src/segger_rtt/SEGGER_RTT_Conf.h" />
|
||||
<file file_name="../src/segger_rtt/SEGGER_RTT_SES.c" />
|
||||
</folder>
|
||||
</folder>
|
||||
<folder Name="ses_samd51">
|
||||
<file file_name="ses_samd51/ATSAME51J19A_MemoryMap.xml" />
|
||||
<file file_name="ses_samd51/ATSAME51J19A_Registers.xml" />
|
||||
@ -181,5 +189,11 @@
|
||||
<file file_name="ses_samd51/SAME51_Startup.s" />
|
||||
<file file_name="ses_samd51/SAME51_Target.js" />
|
||||
</folder>
|
||||
<folder
|
||||
Name="src"
|
||||
exclude=""
|
||||
filter="*.c;*.h"
|
||||
path="../src"
|
||||
recurse="Yes" />
|
||||
</project>
|
||||
</solution>
|
||||
|
@ -36,9 +36,6 @@
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
@ -47,15 +44,39 @@
|
||||
#include "tusb.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL OBJECT & FUNCTION DECLARATION
|
||||
// MACRO CONSTANT TYPEDEF PROTYPES
|
||||
//--------------------------------------------------------------------+
|
||||
void print_greeting(void);
|
||||
void led_blinking_task(void);
|
||||
|
||||
/*------------- MAIN -------------*/
|
||||
int main(void)
|
||||
{
|
||||
board_init();
|
||||
print_greeting();
|
||||
|
||||
tusb_init();
|
||||
|
||||
while (1)
|
||||
{
|
||||
tusb_task();
|
||||
|
||||
led_blinking_task();
|
||||
|
||||
#if CFG_TUD_CDC
|
||||
extern void virtual_com_task(void);
|
||||
virtual_com_task();
|
||||
#endif
|
||||
|
||||
#if CFG_TUD_HID
|
||||
extern void usb_hid_task(void);
|
||||
usb_hid_task();
|
||||
#endif
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USB CDC
|
||||
//--------------------------------------------------------------------+
|
||||
@ -90,8 +111,6 @@ void tud_cdc_line_state_cb(uint8_t itf, bool dtr, bool rts)
|
||||
tud_cdc_write_str("tinyusb usb cdc\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define virtual_com_task()
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -151,32 +170,8 @@ void tud_hid_generic_set_report_cb(uint8_t report_id, hid_report_type_t report_t
|
||||
{
|
||||
// TODO not Implemented
|
||||
}
|
||||
|
||||
#else
|
||||
#define usb_hid_task()
|
||||
#endif
|
||||
|
||||
|
||||
/*------------- MAIN -------------*/
|
||||
int main(void)
|
||||
{
|
||||
board_init();
|
||||
print_greeting();
|
||||
|
||||
tusb_init();
|
||||
|
||||
while (1)
|
||||
{
|
||||
tusb_task();
|
||||
|
||||
led_blinking_task();
|
||||
virtual_com_task();
|
||||
usb_hid_task();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// tinyusb callbacks
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -48,7 +48,12 @@
|
||||
//--------------------------------------------------------------------
|
||||
// COMMON CONFIGURATION
|
||||
//--------------------------------------------------------------------
|
||||
#define CFG_TUSB_MCU OPT_MCU_NRF5X
|
||||
|
||||
// defined by compiler flags for flexibility
|
||||
#ifndef CFG_TUSB_MCU
|
||||
#error CFG_TUSB_MCU should be defined using compiler flags
|
||||
#endif
|
||||
|
||||
#define CFG_TUSB_RHPORT0_MODE OPT_MODE_DEVICE
|
||||
|
||||
#define CFG_TUSB_DEBUG 2
|
||||
@ -82,7 +87,7 @@
|
||||
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_CDC 1
|
||||
#define CFG_TUD_MSC 1
|
||||
#define CFG_TUD_MSC 0
|
||||
|
||||
#define CFG_TUD_HID 0
|
||||
#define CFG_TUD_HID_KEYBOARD 0
|
||||
|
@ -19,7 +19,7 @@
|
||||
arm_target_device_name="nRF52840_xxAA"
|
||||
arm_target_interface_type="SWD"
|
||||
build_treat_warnings_as_errors="Yes"
|
||||
c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_PCA10056"
|
||||
c_preprocessor_definitions="NRF52840_XXAA;__nRF_FAMILY;ARM_MATH_CM4;FLASH_PLACEMENT=1;BOARD_PCA10056;CFG_TUSB_MCU=OPT_MCU_NRF5X"
|
||||
c_user_include_directories="../src;$(tusbDir)/hw/cmsis/Include;$(tusbDir)/hw;$(tusbDir)/src;$(nrfxDir)/..;$(nrfxDir);$(nrfxDir)/mdk;$(nrfxDir)/hal;$(nrfxDir)/drivers/include;$(freertosDir)/Source/include;$(freertosDir)/Source/portable/GCC/ARM_CM4F"
|
||||
debug_register_definition_file="$(ProjectDir)/nrf52840_Registers.xml"
|
||||
debug_target_connection="J-Link"
|
||||
|
@ -37,7 +37,12 @@
|
||||
/**************************************************************************/
|
||||
|
||||
#include "bsp/board.h"
|
||||
|
||||
#include "sam.h"
|
||||
#include "hal/include/hal_gpio.h"
|
||||
#include "hal/include/hal_init.h"
|
||||
#include "peripheral_clk_config.h"
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO TYPEDEF CONSTANT ENUM DECLARATION
|
||||
@ -46,6 +51,8 @@
|
||||
|
||||
void board_init(void)
|
||||
{
|
||||
init_mcu();
|
||||
|
||||
gpio_set_pin_direction(BOARD_LED0, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(BOARD_LED0, 1-LED_STATE_ON);
|
||||
|
||||
@ -53,6 +60,24 @@ void board_init(void)
|
||||
// Tick init
|
||||
SysTick_Config(SystemCoreClock/1000);
|
||||
#endif
|
||||
|
||||
/* USB Clock init
|
||||
* The USB module requires a GCLK_USB of 48 MHz ~ 0.25% clock
|
||||
* for low speed and full speed operation. */
|
||||
hri_gclk_write_PCHCTRL_reg(GCLK, USB_GCLK_ID, CONF_GCLK_USB_SRC | GCLK_PCHCTRL_CHEN);
|
||||
hri_mclk_set_AHBMASK_USB_bit(MCLK);
|
||||
hri_mclk_set_APBBMASK_USB_bit(MCLK);
|
||||
|
||||
// USB Pin Init
|
||||
gpio_set_pin_direction(PIN_PA24, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(PIN_PA24, false);
|
||||
gpio_set_pin_pull_mode(PIN_PA24, GPIO_PULL_OFF);
|
||||
gpio_set_pin_direction(PIN_PA25, GPIO_DIRECTION_OUT);
|
||||
gpio_set_pin_level(PIN_PA25, false);
|
||||
gpio_set_pin_pull_mode(PIN_PA25, GPIO_PULL_OFF);
|
||||
|
||||
gpio_set_pin_function(PIN_PA24, PINMUX_PA24H_USB_DM);
|
||||
gpio_set_pin_function(PIN_PA25, PINMUX_PA25H_USB_DP);
|
||||
}
|
||||
|
||||
void board_led_control(uint32_t led_id, bool state)
|
||||
@ -76,4 +101,4 @@ uint32_t tusb_hal_millis(void)
|
||||
{
|
||||
return board_tick2ms(system_ticks);
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
@ -1 +0,0 @@
|
||||
Subproject commit f20fcf642b5654ee68d7d551ea7db39716ef83bf
|
@ -45,7 +45,6 @@
|
||||
// INCLUDE
|
||||
//--------------------------------------------------------------------+
|
||||
#include "cdc_device.h"
|
||||
#include "device/control.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -63,7 +62,7 @@ typedef struct
|
||||
|
||||
/*------------- From this point, data is not cleared by bus reset -------------*/
|
||||
char wanted_char;
|
||||
CFG_TUSB_MEM_ALIGN cdc_line_coding_t line_coding;
|
||||
cdc_line_coding_t line_coding;
|
||||
|
||||
// FIFO
|
||||
tu_fifo_t rx_ff;
|
||||
@ -199,23 +198,23 @@ void cdcd_init(void)
|
||||
|
||||
for(uint8_t i=0; i<CFG_TUD_CDC; i++)
|
||||
{
|
||||
cdcd_interface_t* ser = &_cdcd_itf[i];
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[i];
|
||||
|
||||
ser->wanted_char = -1;
|
||||
p_cdc->wanted_char = -1;
|
||||
|
||||
// default line coding is : stop bit = 1, parity = none, data bits = 8
|
||||
ser->line_coding.bit_rate = 115200;
|
||||
ser->line_coding.stop_bits = 0;
|
||||
ser->line_coding.parity = 0;
|
||||
ser->line_coding.data_bits = 8;
|
||||
p_cdc->line_coding.bit_rate = 115200;
|
||||
p_cdc->line_coding.stop_bits = 0;
|
||||
p_cdc->line_coding.parity = 0;
|
||||
p_cdc->line_coding.data_bits = 8;
|
||||
|
||||
// config fifo
|
||||
tu_fifo_config(&ser->rx_ff, ser->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, true);
|
||||
tu_fifo_config(&ser->tx_ff, ser->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, 1, false);
|
||||
tu_fifo_config(&p_cdc->rx_ff, p_cdc->rx_ff_buf, CFG_TUD_CDC_RX_BUFSIZE, 1, true);
|
||||
tu_fifo_config(&p_cdc->tx_ff, p_cdc->tx_ff_buf, CFG_TUD_CDC_TX_BUFSIZE, 1, false);
|
||||
|
||||
#if CFG_FIFO_MUTEX
|
||||
tu_fifo_config_mutex(&ser->rx_ff, osal_mutex_create(&ser->rx_ff_mutex));
|
||||
tu_fifo_config_mutex(&ser->tx_ff, osal_mutex_create(&ser->tx_ff_mutex));
|
||||
tu_fifo_config_mutex(&p_cdc->rx_ff, osal_mutex_create(&p_cdc->rx_ff_mutex));
|
||||
tu_fifo_config_mutex(&p_cdc->tx_ff, osal_mutex_create(&p_cdc->tx_ff_mutex));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@ -299,57 +298,64 @@ tusb_error_t cdcd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
void cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
// Invoked when class request DATA stage is finished.
|
||||
// return false to stall control endpoint (e.g Host send non-sense DATA)
|
||||
bool cdcd_control_request_complete(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
//------------- Class Specific Request -------------//
|
||||
if (p_request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) return;
|
||||
TU_VERIFY (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
// TODO Support multiple interfaces
|
||||
uint8_t const itf = 0;
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
|
||||
// Invoke callback
|
||||
if (CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) {
|
||||
if ( CDC_REQUEST_SET_LINE_CODING == request->bRequest )
|
||||
{
|
||||
if ( tud_cdc_line_coding_cb ) tud_cdc_line_coding_cb(itf, &p_cdc->line_coding);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
tusb_error_t cdcd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent)
|
||||
// Handle class control request
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool cdcd_control_request(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
//------------- Class Specific Request -------------//
|
||||
if (p_request->bmRequestType_bit.type != TUSB_REQ_TYPE_CLASS) return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
|
||||
TU_ASSERT(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
// TODO Support multiple interfaces
|
||||
uint8_t const itf = 0;
|
||||
cdcd_interface_t* p_cdc = &_cdcd_itf[itf];
|
||||
|
||||
if ((CDC_REQUEST_SET_LINE_CODING == p_request->bRequest) )
|
||||
switch ( request->bRequest )
|
||||
{
|
||||
uint16_t len = tu_min16(sizeof(cdc_line_coding_t), p_request->wLength);
|
||||
dcd_edpt_xfer(rhport, 0, (uint8_t*) &p_cdc->line_coding, len);
|
||||
}
|
||||
else if ( (CDC_REQUEST_GET_LINE_CODING == p_request->bRequest))
|
||||
{
|
||||
uint16_t len = tu_min16(sizeof(cdc_line_coding_t), p_request->wLength);
|
||||
dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, (uint8_t*) &p_cdc->line_coding, len);
|
||||
}
|
||||
else if (CDC_REQUEST_SET_CONTROL_LINE_STATE == p_request->bRequest )
|
||||
{
|
||||
// CDC PSTN v1.2 section 6.3.12
|
||||
// Bit 0: Indicates if DTE is present or not.
|
||||
// This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready)
|
||||
// Bit 1: Carrier control for half-duplex modems.
|
||||
// This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send)
|
||||
p_cdc->line_state = (uint8_t) p_request->wValue;
|
||||
case CDC_REQUEST_SET_LINE_CODING:
|
||||
usbd_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
|
||||
break;
|
||||
|
||||
// Invoke callback
|
||||
if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, BIT_TEST_(p_request->wValue, 0), BIT_TEST_(p_request->wValue, 1));
|
||||
case CDC_REQUEST_GET_LINE_CODING:
|
||||
usbd_control_xfer(rhport, request, &p_cdc->line_coding, sizeof(cdc_line_coding_t));
|
||||
break;
|
||||
|
||||
case CDC_REQUEST_SET_CONTROL_LINE_STATE:
|
||||
// CDC PSTN v1.2 section 6.3.12
|
||||
// Bit 0: Indicates if DTE is present or not.
|
||||
// This signal corresponds to V.24 signal 108/2 and RS-232 signal DTR (Data Terminal Ready)
|
||||
// Bit 1: Carrier control for half-duplex modems.
|
||||
// This signal corresponds to V.24 signal 105 and RS-232 signal RTS (Request to Send)
|
||||
p_cdc->line_state = (uint8_t) request->wValue;
|
||||
|
||||
// Invoke callback
|
||||
if ( tud_cdc_line_state_cb) tud_cdc_line_state_cb(itf, BIT_TEST_(request->wValue, 0), BIT_TEST_(request->wValue, 1));
|
||||
usbd_control_status(rhport, request);
|
||||
break;
|
||||
|
||||
default: return false; // stall unsupported request
|
||||
}
|
||||
else
|
||||
{
|
||||
return TUSB_ERROR_FAILED; // stall unsupported request
|
||||
}
|
||||
return TUSB_ERROR_NONE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
tusb_error_t cdcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
|
@ -114,8 +114,8 @@ ATTR_WEAK void tud_cdc_line_coding_cb(uint8_t itf, cdc_line_coding_t const* p_li
|
||||
|
||||
void cdcd_init (void);
|
||||
tusb_error_t cdcd_open (uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
tusb_error_t cdcd_control_request (uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent);
|
||||
void cdcd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool cdcd_control_request (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool cdcd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
tusb_error_t cdcd_xfer_cb (uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void cdcd_reset (uint8_t rhport);
|
||||
|
||||
|
@ -89,9 +89,9 @@ tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf,
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t cusd_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
bool cusd_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
return TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT;
|
||||
return false;
|
||||
}
|
||||
|
||||
tusb_error_t cusd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
|
@ -64,8 +64,8 @@
|
||||
|
||||
void cusd_init(void);
|
||||
tusb_error_t cusd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
tusb_error_t cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
void cusd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool cusd_control_request_st(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool cusd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
tusb_error_t cusd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void cusd_reset(uint8_t rhport);
|
||||
#endif
|
||||
|
@ -46,7 +46,6 @@
|
||||
//--------------------------------------------------------------------+
|
||||
#include "common/tusb_common.h"
|
||||
#include "hid_device.h"
|
||||
#include "device/control.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -403,110 +402,112 @@ tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, u
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent)
|
||||
// Handle class control request
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex );
|
||||
TU_ASSERT(p_hid, TUSB_ERROR_FAILED);
|
||||
TU_ASSERT(p_hid);
|
||||
|
||||
//------------- STD Request -------------//
|
||||
if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
|
||||
{
|
||||
//------------- STD Request -------------//
|
||||
uint8_t const desc_type = tu_u16_high(p_request->wValue);
|
||||
uint8_t const desc_index = tu_u16_low (p_request->wValue);
|
||||
(void) desc_index;
|
||||
|
||||
if (p_request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT)
|
||||
{
|
||||
// TODO: Handle zero length packet.
|
||||
uint16_t remaining_bytes = p_hid->desc_len - bytes_already_sent;
|
||||
if (remaining_bytes > 64) {
|
||||
remaining_bytes = 64;
|
||||
}
|
||||
memcpy(_shared_control_buffer, p_hid->desc_report + bytes_already_sent, remaining_bytes);
|
||||
|
||||
dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, remaining_bytes);
|
||||
usbd_control_xfer(rhport, p_request, p_hid->desc_report, p_hid->desc_len);
|
||||
}else
|
||||
{
|
||||
return TUSB_ERROR_FAILED;
|
||||
return false; // stall unsupported request
|
||||
}
|
||||
}
|
||||
//------------- Class Specific Request -------------//
|
||||
else if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
|
||||
{
|
||||
if( HID_REQ_CONTROL_GET_REPORT == p_request->bRequest )
|
||||
//------------- Class Specific Request -------------//
|
||||
switch( p_request->bRequest )
|
||||
{
|
||||
// wValue = Report Type | Report ID
|
||||
uint8_t const report_type = tu_u16_high(p_request->wValue);
|
||||
uint8_t const report_id = tu_u16_low(p_request->wValue);
|
||||
case HID_REQ_CONTROL_GET_REPORT:
|
||||
{
|
||||
// wValue = Report Type | Report ID
|
||||
uint8_t const report_type = tu_u16_high(p_request->wValue);
|
||||
uint8_t const report_id = tu_u16_low(p_request->wValue);
|
||||
|
||||
uint16_t xferlen;
|
||||
if ( p_hid->get_report_cb )
|
||||
{
|
||||
xferlen = p_hid->get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength);
|
||||
}else
|
||||
{
|
||||
// For boot Interface only: re-use report_buf -> report has no change
|
||||
xferlen = p_request->wLength;
|
||||
uint16_t xferlen;
|
||||
if ( p_hid->get_report_cb )
|
||||
{
|
||||
xferlen = p_hid->get_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength);
|
||||
}else
|
||||
{
|
||||
// For boot Interface only: re-use report_buf -> report has no change
|
||||
xferlen = p_request->wLength;
|
||||
}
|
||||
|
||||
TU_ASSERT( xferlen > 0 );
|
||||
usbd_control_xfer(rhport, p_request, p_hid->report_buf, xferlen);
|
||||
}
|
||||
break;
|
||||
|
||||
TU_ASSERT( xferlen > 0 );
|
||||
dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, xferlen);
|
||||
}
|
||||
else if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest )
|
||||
{
|
||||
dcd_edpt_xfer(rhport, 0, _shared_control_buffer, p_request->wLength);
|
||||
}
|
||||
else if (HID_REQ_CONTROL_SET_IDLE == p_request->bRequest)
|
||||
{
|
||||
// TODO idle rate of report
|
||||
p_hid->idle_rate = tu_u16_high(p_request->wValue);
|
||||
}
|
||||
else if (HID_REQ_CONTROL_GET_IDLE == p_request->bRequest)
|
||||
{
|
||||
// TODO idle rate of report
|
||||
_shared_control_buffer[0] = p_hid->idle_rate;
|
||||
dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1);
|
||||
}
|
||||
else if (HID_REQ_CONTROL_GET_PROTOCOL == p_request->bRequest )
|
||||
{
|
||||
_shared_control_buffer[0] = 1-p_hid->boot_protocol; // 0 is Boot, 1 is Report protocol
|
||||
dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1);
|
||||
}
|
||||
else if (HID_REQ_CONTROL_SET_PROTOCOL == p_request->bRequest )
|
||||
{
|
||||
p_hid->boot_protocol = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol
|
||||
}else
|
||||
{
|
||||
return TUSB_ERROR_FAILED;
|
||||
case HID_REQ_CONTROL_SET_REPORT:
|
||||
usbd_control_xfer(rhport, p_request, p_hid->report_buf, p_request->wLength);
|
||||
break;
|
||||
|
||||
case HID_REQ_CONTROL_SET_IDLE:
|
||||
// TODO idle rate of report
|
||||
p_hid->idle_rate = tu_u16_high(p_request->wValue);
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
case HID_REQ_CONTROL_GET_IDLE:
|
||||
// TODO idle rate of report
|
||||
usbd_control_xfer(rhport, p_request, &p_hid->idle_rate, 1);
|
||||
break;
|
||||
|
||||
case HID_REQ_CONTROL_GET_PROTOCOL:
|
||||
{
|
||||
uint8_t protocol = 1-p_hid->boot_protocol; // 0 is Boot, 1 is Report protocol
|
||||
usbd_control_xfer(rhport, p_request, &protocol, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
case HID_REQ_CONTROL_SET_PROTOCOL:
|
||||
p_hid->boot_protocol = 1 - p_request->wValue; // 0 is Boot, 1 is Report protocol
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
default: return false; // stall unsupported request
|
||||
}
|
||||
}else
|
||||
{
|
||||
return TUSB_ERROR_FAILED;
|
||||
return false; // stall unsupported request
|
||||
}
|
||||
return TUSB_ERROR_NONE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void hidd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
// Invoked when class request DATA stage is finished.
|
||||
// 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)
|
||||
{
|
||||
hidd_interface_t* p_hid = get_interface_by_itfnum( (uint8_t) p_request->wIndex );
|
||||
if (p_hid == NULL) {
|
||||
return;
|
||||
}
|
||||
TU_ASSERT(p_hid);
|
||||
|
||||
if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
|
||||
if (p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS &&
|
||||
p_request->bRequest == HID_REQ_CONTROL_SET_REPORT)
|
||||
{
|
||||
if ( HID_REQ_CONTROL_SET_REPORT == p_request->bRequest )
|
||||
{
|
||||
// wValue = Report Type | Report ID
|
||||
uint8_t const report_type = tu_u16_high(p_request->wValue);
|
||||
uint8_t const report_id = tu_u16_low(p_request->wValue);
|
||||
// wValue = Report Type | Report ID
|
||||
uint8_t const report_type = tu_u16_high(p_request->wValue);
|
||||
uint8_t const report_id = tu_u16_low(p_request->wValue);
|
||||
|
||||
if ( p_hid->set_report_cb )
|
||||
{
|
||||
p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, _shared_control_buffer, p_request->wLength);
|
||||
}
|
||||
if ( p_hid->set_report_cb )
|
||||
{
|
||||
p_hid->set_report_cb(report_id, (hid_report_type_t) report_type, p_hid->report_buf, p_request->wLength);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
|
@ -378,8 +378,8 @@ ATTR_WEAK void tud_hid_mouse_set_report_cb(uint8_t report_id, hid_report_type_t
|
||||
|
||||
void hidd_init(void);
|
||||
tusb_error_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
tusb_error_t hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent);
|
||||
void hidd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool hidd_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool hidd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
tusb_error_t hidd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void hidd_reset(uint8_t rhport);
|
||||
|
||||
@ -390,3 +390,4 @@ void hidd_reset(uint8_t rhport);
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_HID_DEVICE_H_ */
|
||||
|
||||
|
@ -47,7 +47,6 @@
|
||||
|
||||
#include "common/tusb_common.h"
|
||||
#include "msc_device.h"
|
||||
#include "device/control.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -60,7 +59,31 @@ enum
|
||||
MSC_STAGE_STATUS
|
||||
};
|
||||
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN mscd_interface_t _mscd_itf;
|
||||
typedef struct {
|
||||
CFG_TUSB_MEM_ALIGN msc_cbw_t cbw;
|
||||
|
||||
//#if defined (__ICCARM__) && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13UXX)
|
||||
// uint8_t padding1[64-sizeof(msc_cbw_t)]; // IAR cannot align struct's member
|
||||
//#endif
|
||||
|
||||
CFG_TUSB_MEM_ALIGN msc_csw_t csw;
|
||||
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
// Bulk Only Transfer (BOT) Protocol
|
||||
uint8_t stage;
|
||||
uint32_t total_len;
|
||||
uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage
|
||||
|
||||
// Sense Response Data
|
||||
uint8_t sense_key;
|
||||
uint8_t add_sense_code;
|
||||
uint8_t add_sense_qualifier;
|
||||
}mscd_interface_t;
|
||||
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static mscd_interface_t _mscd_itf;
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN static uint8_t _mscd_buf[CFG_TUD_MSC_BUFSIZE];
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
@ -147,29 +170,39 @@ tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_desc_itf,
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
tusb_error_t mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent)
|
||||
// Handle class control request
|
||||
// return false to stall control endpoint (e.g unsupported request)
|
||||
bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
TU_ASSERT(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS, TUSB_ERROR_DCD_CONTROL_REQUEST_NOT_SUPPORT);
|
||||
TU_ASSERT(p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS);
|
||||
|
||||
if(MSC_REQ_RESET == p_request->bRequest)
|
||||
switch ( p_request->bRequest )
|
||||
{
|
||||
// TODO: Actually reset.
|
||||
case MSC_REQ_RESET:
|
||||
// TODO: Actually reset interface.
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
case MSC_REQ_GET_MAX_LUN:
|
||||
{
|
||||
// returned MAX LUN is minus 1 by specs
|
||||
uint8_t maxlun = CFG_TUD_MSC_MAXLUN-1;
|
||||
usbd_control_xfer(rhport, p_request, &maxlun, 1);
|
||||
}
|
||||
break;
|
||||
|
||||
default: return false; // stall unsupported request
|
||||
}
|
||||
else if (MSC_REQ_GET_MAX_LUN == p_request->bRequest)
|
||||
{
|
||||
// returned MAX LUN is minus 1 by specs
|
||||
_shared_control_buffer[0] = CFG_TUD_MSC_MAXLUN-1;
|
||||
dcd_edpt_xfer(rhport, TUSB_DIR_IN_MASK, _shared_control_buffer, 1);
|
||||
}else
|
||||
{
|
||||
return TUSB_ERROR_FAILED; // stall unsupported request
|
||||
}
|
||||
return TUSB_ERROR_NONE;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
// Invoked when class request DATA stage is finished.
|
||||
// return false to stall control endpoint (e.g Host send non-sense DATA)
|
||||
bool mscd_control_request_complete(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
return;
|
||||
// nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
// For backwards compatibility we support static block counts.
|
||||
@ -296,7 +329,7 @@ int32_t proc_builtin_scsi(msc_cbw_t const * p_cbw, uint8_t* buffer, uint32_t buf
|
||||
return ret;
|
||||
}
|
||||
|
||||
tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, uint8_t event, uint32_t xferred_bytes)
|
||||
tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
mscd_interface_t* p_msc = &_mscd_itf;
|
||||
msc_cbw_t const * p_cbw = &p_msc->cbw;
|
||||
|
@ -81,32 +81,6 @@ TU_VERIFY_STATIC(CFG_TUD_MSC_BUFSIZE < UINT16_MAX, "Size is not correct");
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
CFG_TUSB_MEM_ALIGN msc_cbw_t cbw;
|
||||
|
||||
//#if defined (__ICCARM__) && (CFG_TUSB_MCU == OPT_MCU_LPC11UXX || CFG_TUSB_MCU == OPT_MCU_LPC13UXX)
|
||||
// uint8_t padding1[64-sizeof(msc_cbw_t)]; // IAR cannot align struct's member
|
||||
//#endif
|
||||
|
||||
CFG_TUSB_MEM_ALIGN msc_csw_t csw;
|
||||
|
||||
uint8_t itf_num;
|
||||
uint8_t ep_in;
|
||||
uint8_t ep_out;
|
||||
|
||||
// Bulk Only Transfer (BOT) Protocol
|
||||
uint8_t stage;
|
||||
uint32_t total_len;
|
||||
uint32_t xferred_len; // numbered of bytes transferred so far in the Data Stage
|
||||
|
||||
// Sense Response Data
|
||||
uint8_t sense_key;
|
||||
uint8_t add_sense_code;
|
||||
uint8_t add_sense_qualifier;
|
||||
}mscd_interface_t;
|
||||
|
||||
extern mscd_interface_t _mscd_itf;
|
||||
|
||||
/** \addtogroup ClassDriver_MSC
|
||||
* @{
|
||||
* \defgroup MSC_Device Device
|
||||
@ -198,8 +172,8 @@ ATTR_WEAK bool tud_lun_capacity_cb(uint8_t lun, uint32_t* last_valid_sector, uin
|
||||
|
||||
void mscd_init(void);
|
||||
tusb_error_t mscd_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
tusb_error_t mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent);
|
||||
void mscd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool mscd_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
bool mscd_control_request_complete (uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
tusb_error_t mscd_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void mscd_reset(uint8_t rhport);
|
||||
|
||||
|
@ -203,12 +203,14 @@ typedef enum
|
||||
TUSB_EVENT_XFER_STALLED,
|
||||
}tusb_event_t;
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
DESC_OFFSET_LEN = 0,
|
||||
DESC_OFFSET_TYPE = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
enum
|
||||
{
|
||||
INTERFACE_INVALID_NUMBER = 0xff
|
||||
};
|
||||
|
||||
|
@ -1,264 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbd.c
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2013, hathach (tinyusb.org)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
This file is part of the tinyusb stack.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
#include "tusb.h"
|
||||
#include "control.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
control_t control_state;
|
||||
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _shared_control_buffer[64];
|
||||
|
||||
void controld_reset(uint8_t rhport) {
|
||||
control_state.current_stage = CONTROL_STAGE_SETUP;
|
||||
}
|
||||
|
||||
void controld_init(void) {
|
||||
}
|
||||
|
||||
// Helper to send STATUS (zero length) packet
|
||||
// Note dir is value of direction bit in setup packet (i.e DATA stage direction)
|
||||
static inline bool dcd_control_status(uint8_t rhport, uint8_t dir)
|
||||
{
|
||||
uint8_t ep_addr = 0;
|
||||
// Invert the direction.
|
||||
if (dir == TUSB_DIR_OUT) {
|
||||
ep_addr |= TUSB_DIR_IN_MASK;
|
||||
}
|
||||
// status direction is reversed to one in the setup packet
|
||||
return dcd_edpt_xfer(rhport, ep_addr, NULL, 0);
|
||||
}
|
||||
|
||||
static inline void dcd_control_stall(uint8_t rhport)
|
||||
{
|
||||
dcd_edpt_stall(rhport, 0 | TUSB_DIR_IN_MASK);
|
||||
}
|
||||
|
||||
|
||||
// return len of descriptor and change pointer to descriptor's buffer
|
||||
static uint16_t get_descriptor(uint8_t rhport, tusb_control_request_t const * const p_request, uint8_t const ** pp_buffer)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
|
||||
uint8_t const desc_index = tu_u16_low( p_request->wValue );
|
||||
|
||||
uint8_t const * desc_data = NULL ;
|
||||
uint16_t len = 0;
|
||||
|
||||
switch(desc_type)
|
||||
{
|
||||
case TUSB_DESC_DEVICE:
|
||||
desc_data = (uint8_t const *) usbd_desc_set->device;
|
||||
len = sizeof(tusb_desc_device_t);
|
||||
break;
|
||||
|
||||
case TUSB_DESC_CONFIGURATION:
|
||||
desc_data = (uint8_t const *) usbd_desc_set->config;
|
||||
len = ((tusb_desc_configuration_t const*) desc_data)->wTotalLength;
|
||||
break;
|
||||
|
||||
case TUSB_DESC_STRING:
|
||||
// String Descriptor always uses the desc set from user
|
||||
if ( desc_index < tud_desc_set.string_count )
|
||||
{
|
||||
desc_data = tud_desc_set.string_arr[desc_index];
|
||||
TU_VERIFY( desc_data != NULL, 0 );
|
||||
|
||||
len = desc_data[0]; // first byte of descriptor is its size
|
||||
}else
|
||||
{
|
||||
// out of range
|
||||
/* The 0xee string is indeed a Microsoft USB extension.
|
||||
* It can be used to tell Windows what driver it should use for the device !!!
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_DESC_DEVICE_QUALIFIER:
|
||||
// TODO If not highspeed capable stall this request otherwise
|
||||
// return the descriptor that could work in highspeed
|
||||
return 0;
|
||||
break;
|
||||
|
||||
default: return 0;
|
||||
}
|
||||
|
||||
TU_ASSERT( desc_data != NULL, 0);
|
||||
|
||||
// up to Host's length
|
||||
len = tu_min16(p_request->wLength, len );
|
||||
(*pp_buffer) = desc_data;
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
tusb_error_t controld_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes) {
|
||||
if (control_state.current_stage == CONTROL_STAGE_STATUS && xferred_bytes == 0) {
|
||||
control_state.current_stage = CONTROL_STAGE_SETUP;
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
tusb_error_t error = TUSB_ERROR_NONE;
|
||||
control_state.total_transferred += xferred_bytes;
|
||||
tusb_control_request_t const *p_request = &control_state.current_request;
|
||||
|
||||
if (p_request->wLength == control_state.total_transferred || xferred_bytes < 64) {
|
||||
control_state.current_stage = CONTROL_STAGE_STATUS;
|
||||
dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
|
||||
|
||||
// Do the user callback after queueing the STATUS packet because the callback could be slow.
|
||||
if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient )
|
||||
{
|
||||
tud_control_interface_control_complete_cb(rhport, tu_u16_low(p_request->wIndex), p_request);
|
||||
}
|
||||
} else {
|
||||
if (TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient) {
|
||||
error = tud_control_interface_control_cb(rhport, tu_u16_low(p_request->wIndex), p_request, control_state.total_transferred);
|
||||
} else {
|
||||
error = controld_process_control_request(rhport, p_request, control_state.total_transferred);
|
||||
}
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// This tracks the state of a control request.
|
||||
tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * p_request) {
|
||||
tusb_error_t error = TUSB_ERROR_NONE;
|
||||
memcpy(&control_state.current_request, p_request, sizeof(tusb_control_request_t));
|
||||
if (p_request->wLength == 0) {
|
||||
control_state.current_stage = CONTROL_STAGE_STATUS;
|
||||
} else {
|
||||
control_state.current_stage = CONTROL_STAGE_DATA;
|
||||
control_state.total_transferred = 0;
|
||||
}
|
||||
|
||||
if ( TUSB_REQ_RCPT_INTERFACE == p_request->bmRequestType_bit.recipient )
|
||||
{
|
||||
error = tud_control_interface_control_cb(rhport, tu_u16_low(p_request->wIndex), p_request, 0);
|
||||
} else {
|
||||
error = controld_process_control_request(rhport, p_request, 0);
|
||||
}
|
||||
|
||||
if (error != TUSB_ERROR_NONE) {
|
||||
dcd_control_stall(rhport); // Stall errored requests
|
||||
} else if (control_state.current_stage == CONTROL_STAGE_STATUS) {
|
||||
dcd_control_status(rhport, p_request->bmRequestType_bit.direction);
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
// This handles the actual request and its response.
|
||||
tusb_error_t controld_process_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent)
|
||||
{
|
||||
tusb_error_t error = TUSB_ERROR_NONE;
|
||||
uint8_t ep_addr = 0;
|
||||
if (p_request->bmRequestType_bit.direction == TUSB_DIR_IN) {
|
||||
ep_addr |= TUSB_DIR_IN_MASK;
|
||||
}
|
||||
|
||||
//------------- Standard Request e.g in enumeration -------------//
|
||||
if( TUSB_REQ_RCPT_DEVICE == p_request->bmRequestType_bit.recipient &&
|
||||
TUSB_REQ_TYPE_STANDARD == p_request->bmRequestType_bit.type ) {
|
||||
switch (p_request->bRequest) {
|
||||
case TUSB_REQ_GET_DESCRIPTOR: {
|
||||
uint8_t const * buffer = NULL;
|
||||
uint16_t const len = get_descriptor(rhport, p_request, &buffer);
|
||||
|
||||
if (len) {
|
||||
uint16_t remaining_bytes = len - bytes_already_sent;
|
||||
if (remaining_bytes > 64) {
|
||||
remaining_bytes = 64;
|
||||
}
|
||||
memcpy(_shared_control_buffer, buffer + bytes_already_sent, remaining_bytes);
|
||||
dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, remaining_bytes);
|
||||
} else {
|
||||
return TUSB_ERROR_FAILED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case TUSB_REQ_GET_CONFIGURATION:
|
||||
memcpy(_shared_control_buffer, &control_state.config, 1);
|
||||
dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, 1);
|
||||
break;
|
||||
case TUSB_REQ_SET_ADDRESS:
|
||||
dcd_set_address(rhport, (uint8_t) p_request->wValue);
|
||||
break;
|
||||
case TUSB_REQ_SET_CONFIGURATION:
|
||||
control_state.config = p_request->wValue;
|
||||
tud_control_set_config_cb (rhport, control_state.config);
|
||||
break;
|
||||
default:
|
||||
return TUSB_ERROR_FAILED;
|
||||
}
|
||||
} else if (p_request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_ENDPOINT &&
|
||||
p_request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
|
||||
//------------- Endpoint Request -------------//
|
||||
switch (p_request->bRequest) {
|
||||
case TUSB_REQ_GET_STATUS: {
|
||||
uint16_t status = dcd_edpt_stalled(rhport, tu_u16_low(p_request->wIndex)) ? 0x0001 : 0x0000;
|
||||
memcpy(_shared_control_buffer, &status, 2);
|
||||
|
||||
dcd_edpt_xfer(rhport, ep_addr, _shared_control_buffer, 2);
|
||||
break;
|
||||
}
|
||||
case TUSB_REQ_CLEAR_FEATURE:
|
||||
// only endpoint feature is halted/stalled
|
||||
dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
|
||||
break;
|
||||
case TUSB_REQ_SET_FEATURE:
|
||||
// only endpoint feature is halted/stalled
|
||||
dcd_edpt_stall(rhport, tu_u16_low(p_request->wIndex));
|
||||
break;
|
||||
default:
|
||||
return TUSB_ERROR_FAILED;
|
||||
}
|
||||
} else {
|
||||
//------------- Unsupported Request -------------//
|
||||
return TUSB_ERROR_FAILED;
|
||||
}
|
||||
return error;
|
||||
}
|
||||
|
||||
#endif
|
@ -1,98 +0,0 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbd.h
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2013, hathach (tinyusb.org)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
This file is part of the tinyusb stack.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
/** \ingroup group_usbd
|
||||
* @{ */
|
||||
|
||||
#ifndef _TUSB_CONTROL_H_
|
||||
#define _TUSB_CONTROL_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "tusb.h"
|
||||
|
||||
typedef enum {
|
||||
CONTROL_STAGE_SETUP, // Waiting for a setup token.
|
||||
CONTROL_STAGE_DATA, // In the process of sending or receiving data.
|
||||
CONTROL_STAGE_STATUS // In the process of transmitting the STATUS ZLP.
|
||||
} control_stage_t;
|
||||
|
||||
typedef struct {
|
||||
control_stage_t current_stage;
|
||||
tusb_control_request_t current_request;
|
||||
uint16_t total_transferred;
|
||||
uint8_t config;
|
||||
} control_t;
|
||||
|
||||
extern uint8_t _shared_control_buffer[64];
|
||||
|
||||
tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * const p_request);
|
||||
|
||||
// Callback when the configuration of the device is changed.
|
||||
tusb_error_t tud_control_set_config_cb(uint8_t rhport, uint8_t config_number);
|
||||
|
||||
// Called when the DATA stage of a control transaction is complete.
|
||||
void tud_control_interface_control_complete_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request);
|
||||
|
||||
tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request, uint16_t bytes_already_sent);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void controld_init(void);
|
||||
tusb_error_t controld_open(uint8_t rhport, tusb_desc_interface_t const * p_interface_desc, uint16_t *p_length);
|
||||
|
||||
// This tracks the state of a control request.
|
||||
tusb_error_t controld_process_setup_request(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
|
||||
// This handles the actual request and its response.
|
||||
tusb_error_t controld_process_control_request(uint8_t rhport, tusb_control_request_t const * p_request, uint16_t bytes_already_sent);
|
||||
|
||||
tusb_error_t controld_xfer_cb(uint8_t rhport, uint8_t edpt_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void controld_reset(uint8_t rhport);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _TUSB_CONTROL_H_ */
|
||||
|
||||
/** @} */
|
@ -124,6 +124,10 @@ void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Endpoint API
|
||||
* Note:
|
||||
* - Address of control endpoint OUT is 0x00, In is 0x80
|
||||
* - When stalling control endpoint both control OUT and IN must be stalled
|
||||
* (according to USB spec, stalled control is only recovered with setup token)
|
||||
*------------------------------------------------------------------*/
|
||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc);
|
||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes);
|
||||
|
@ -44,7 +44,6 @@
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
#include "control.h"
|
||||
#include "tusb.h"
|
||||
#include "usbd.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
@ -68,16 +67,13 @@
|
||||
typedef struct {
|
||||
uint8_t config_num;
|
||||
|
||||
// map interface number to driver (0xff is invalid)
|
||||
uint8_t itf2drv[16];
|
||||
uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
|
||||
uint8_t ep2drv[2][8]; // map endpoint to driver ( 0xff is invalid )
|
||||
|
||||
// map endpoint to driver ( 0xff is invalid )
|
||||
uint8_t ep2drv[2][8];
|
||||
}usbd_device_t;
|
||||
|
||||
static usbd_device_t _usbd_dev;
|
||||
|
||||
|
||||
// Auto descriptor is enabled, descriptor set point to auto generated one
|
||||
#if CFG_TUD_DESC_AUTO
|
||||
extern tud_desc_set_t const _usbd_auto_desc_set;
|
||||
@ -94,9 +90,8 @@ typedef struct {
|
||||
|
||||
void (* init ) (void);
|
||||
tusb_error_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t* p_length);
|
||||
// Control request is called one or more times for a request and can queue multiple data packets.
|
||||
tusb_error_t (* control_request ) (uint8_t rhport, tusb_control_request_t const *, uint16_t bytes_already_sent);
|
||||
void (* control_request_complete ) (uint8_t rhport, tusb_control_request_t const *);
|
||||
bool (* control_request ) (uint8_t rhport, tusb_control_request_t const * request);
|
||||
bool (* control_request_complete ) (uint8_t rhport, tusb_control_request_t const * request);
|
||||
tusb_error_t (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, tusb_event_t, uint32_t);
|
||||
void (* sof ) (uint8_t rhport);
|
||||
void (* reset ) (uint8_t);
|
||||
@ -104,16 +99,6 @@ typedef struct {
|
||||
|
||||
static usbd_class_driver_t const usbd_class_drivers[] =
|
||||
{
|
||||
{
|
||||
.class_code = TUSB_CLASS_UNSPECIFIED,
|
||||
.init = controld_init,
|
||||
.open = NULL,
|
||||
.control_request = NULL,
|
||||
.control_request_complete = NULL,
|
||||
.xfer_cb = controld_xfer_cb,
|
||||
.sof = NULL,
|
||||
.reset = controld_reset
|
||||
},
|
||||
#if CFG_TUD_CDC
|
||||
{
|
||||
.class_code = TUSB_CLASS_CDC,
|
||||
@ -181,9 +166,16 @@ OSAL_QUEUE_DEF(_usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
|
||||
static osal_queue_t _usbd_q;
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// INTERNAL FUNCTION
|
||||
// Prototypes
|
||||
//--------------------------------------------------------------------+
|
||||
static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
|
||||
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
static bool process_set_config(uint8_t rhport, uint8_t config_number);
|
||||
static void const* get_descriptor(tusb_control_request_t const * p_request, uint16_t* desc_len);
|
||||
|
||||
void usbd_control_reset (uint8_t rhport);
|
||||
tusb_error_t usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes);
|
||||
void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) );
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// APPLICATION API
|
||||
@ -194,7 +186,7 @@ bool tud_mounted(void)
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// IMPLEMENTATION
|
||||
// USBD Task
|
||||
//--------------------------------------------------------------------+
|
||||
tusb_error_t usbd_init (void)
|
||||
{
|
||||
@ -223,9 +215,8 @@ static void usbd_reset(uint8_t rhport)
|
||||
tu_varclr(&_usbd_dev);
|
||||
memset(_usbd_dev.itf2drv, 0xff, sizeof(_usbd_dev.itf2drv)); // invalid mapping
|
||||
memset(_usbd_dev.ep2drv , 0xff, sizeof(_usbd_dev.ep2drv )); // invalid mapping
|
||||
// Always map the 0th endpoint to the control driver.
|
||||
_usbd_dev.ep2drv[TUSB_DIR_IN][0] = 0;
|
||||
_usbd_dev.ep2drv[TUSB_DIR_OUT][0] = 0;
|
||||
|
||||
usbd_control_reset(rhport);
|
||||
|
||||
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
|
||||
{
|
||||
@ -233,30 +224,41 @@ static void usbd_reset(uint8_t rhport)
|
||||
}
|
||||
}
|
||||
|
||||
// Main device task implementation
|
||||
static void usbd_task_body(void)
|
||||
{
|
||||
dcd_event_t event;
|
||||
|
||||
// Loop until there is no more events in the queue
|
||||
while (1)
|
||||
{
|
||||
dcd_event_t event;
|
||||
|
||||
if ( !osal_queue_receive(_usbd_q, &event) ) return;
|
||||
|
||||
switch ( event.event_id )
|
||||
{
|
||||
case DCD_EVENT_SETUP_RECEIVED:
|
||||
// Setup tokens are unique to the Control endpoint so we delegate to it directly.
|
||||
controld_process_setup_request(event.rhport, &event.setup_received);
|
||||
// Process control request, if failed control endpoint is stalled
|
||||
if ( !process_control_request(event.rhport, &event.setup_received) )
|
||||
{
|
||||
usbd_control_stall(event.rhport);
|
||||
}
|
||||
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;
|
||||
uint8_t const drv_id = _usbd_dev.ep2drv[edpt_dir(ep_addr)][edpt_number(ep_addr)];
|
||||
|
||||
if ( drv_id < USBD_CLASS_DRIVER_COUNT )
|
||||
if ( 0 == 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[edpt_dir(ep_addr)][edpt_number(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);
|
||||
}
|
||||
}
|
||||
@ -316,66 +318,142 @@ void usbd_task( void* param)
|
||||
#endif
|
||||
}
|
||||
|
||||
void tud_control_interface_control_complete_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request) {
|
||||
if (_usbd_dev.itf2drv[ interface ] < USBD_CLASS_DRIVER_COUNT)
|
||||
{
|
||||
const usbd_class_driver_t *driver = &usbd_class_drivers[_usbd_dev.itf2drv[interface]];
|
||||
if (driver->control_request_complete != NULL) {
|
||||
driver->control_request_complete(rhport, p_request);
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------+
|
||||
// Control Request Parser & Handling
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
tusb_error_t tud_control_interface_control_cb(uint8_t rhport, uint8_t interface, tusb_control_request_t const * const p_request, uint16_t bytes_already_sent) {
|
||||
if (_usbd_dev.itf2drv[ interface ] < USBD_CLASS_DRIVER_COUNT)
|
||||
// This handles the actual request and its response.
|
||||
// return false will cause its caller to stall control endpoint
|
||||
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
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 )
|
||||
{
|
||||
//------------- Standard Device Requests e.g in enumeration -------------//
|
||||
void* data_buf = NULL;
|
||||
uint16_t data_len = 0;
|
||||
|
||||
switch ( p_request->bRequest )
|
||||
{
|
||||
return usbd_class_drivers[_usbd_dev.itf2drv[interface]].control_request(rhport, p_request, bytes_already_sent);
|
||||
case TUSB_REQ_SET_ADDRESS:
|
||||
dcd_set_address(rhport, (uint8_t) p_request->wValue);
|
||||
break;
|
||||
|
||||
case TUSB_REQ_GET_CONFIGURATION:
|
||||
data_buf = &_usbd_dev.config_num;
|
||||
data_len = 1;
|
||||
break;
|
||||
|
||||
case TUSB_REQ_SET_CONFIGURATION:
|
||||
{
|
||||
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, config) );
|
||||
}
|
||||
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: return false;
|
||||
}
|
||||
return TUSB_ERROR_FAILED;
|
||||
|
||||
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_GET_STATUS:
|
||||
{
|
||||
uint16_t status = dcd_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:
|
||||
// only endpoint feature is halted/stalled
|
||||
dcd_edpt_clear_stall(rhport, tu_u16_low(p_request->wIndex));
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
case TUSB_REQ_SET_FEATURE:
|
||||
// only endpoint feature is halted/stalled
|
||||
dcd_edpt_stall(rhport, tu_u16_low(p_request->wIndex));
|
||||
usbd_control_status(rhport, p_request);
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//------------- Unsupported Request -------------//
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Process Set Configure Request
|
||||
// TODO Host (windows) can get HID report descriptor before set configured
|
||||
// may need to open interface before set configured
|
||||
tusb_error_t tud_control_set_config_cb(uint8_t rhport, uint8_t config_number)
|
||||
// This function parse configuration descriptor & open drivers accordingly
|
||||
static bool process_set_config(uint8_t rhport, uint8_t config_number)
|
||||
{
|
||||
dcd_set_config(rhport, config_number);
|
||||
|
||||
_usbd_dev.config_num = config_number;
|
||||
|
||||
//------------- parse configuration & open drivers -------------//
|
||||
uint8_t const * desc_cfg = (uint8_t const *) usbd_desc_set->config;
|
||||
TU_ASSERT(desc_cfg != NULL, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
|
||||
TU_ASSERT(desc_cfg != NULL);
|
||||
|
||||
uint8_t const * p_desc = desc_cfg + sizeof(tusb_desc_configuration_t);
|
||||
uint16_t const cfg_len = ((tusb_desc_configuration_t*)desc_cfg)->wTotalLength;
|
||||
|
||||
while( p_desc < desc_cfg + cfg_len )
|
||||
{
|
||||
// Each interface always starts with Interface or Association descriptor
|
||||
if ( TUSB_DESC_INTERFACE_ASSOCIATION == descriptor_type(p_desc) )
|
||||
{
|
||||
p_desc = descriptor_next(p_desc); // ignore Interface Association
|
||||
}else
|
||||
{
|
||||
TU_ASSERT( TUSB_DESC_INTERFACE == descriptor_type(p_desc), TUSB_ERROR_NOT_SUPPORTED_YET );
|
||||
TU_ASSERT( TUSB_DESC_INTERFACE == descriptor_type(p_desc) );
|
||||
|
||||
tusb_desc_interface_t* p_desc_itf = (tusb_desc_interface_t*) p_desc;
|
||||
uint8_t const class_code = p_desc_itf->bInterfaceClass;
|
||||
tusb_desc_interface_t* desc_itf = (tusb_desc_interface_t*) p_desc;
|
||||
|
||||
// Check if class is supported
|
||||
uint8_t drv_id;
|
||||
for (drv_id = 0; drv_id < USBD_CLASS_DRIVER_COUNT; drv_id++)
|
||||
{
|
||||
if ( usbd_class_drivers[drv_id].class_code == class_code ) break;
|
||||
if ( usbd_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
|
||||
}
|
||||
TU_ASSERT( drv_id < USBD_CLASS_DRIVER_COUNT, TUSB_ERROR_NOT_SUPPORTED_YET );
|
||||
TU_ASSERT( drv_id < USBD_CLASS_DRIVER_COUNT ); // unsupported class
|
||||
|
||||
// Interface number must not be used
|
||||
TU_ASSERT( 0xff == _usbd_dev.itf2drv[p_desc_itf->bInterfaceNumber], TUSB_ERROR_FAILED);
|
||||
_usbd_dev.itf2drv[p_desc_itf->bInterfaceNumber] = drv_id;
|
||||
// Interface number must not be used already TODO alternate interface
|
||||
TU_ASSERT( 0xff == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber] );
|
||||
_usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id;
|
||||
|
||||
uint16_t len=0;
|
||||
TU_ASSERT_ERR( usbd_class_drivers[drv_id].open( rhport, p_desc_itf, &len ) );
|
||||
TU_ASSERT( len >= sizeof(tusb_desc_interface_t), TUSB_ERROR_FAILED );
|
||||
TU_ASSERT_ERR( usbd_class_drivers[drv_id].open( rhport, desc_itf, &len ), false );
|
||||
TU_ASSERT( len >= sizeof(tusb_desc_interface_t) );
|
||||
|
||||
mark_interface_endpoint(p_desc, len, drv_id);
|
||||
|
||||
@ -408,8 +486,62 @@ static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, ui
|
||||
}
|
||||
}
|
||||
|
||||
// return descriptor's buffer and update desc_len
|
||||
static void const* get_descriptor(tusb_control_request_t const * p_request, uint16_t* desc_len)
|
||||
{
|
||||
tusb_desc_type_t const desc_type = (tusb_desc_type_t) tu_u16_high(p_request->wValue);
|
||||
uint8_t const desc_index = tu_u16_low( p_request->wValue );
|
||||
|
||||
uint8_t const * desc_data = NULL;
|
||||
uint16_t len = 0;
|
||||
|
||||
*desc_len = 0;
|
||||
|
||||
switch(desc_type)
|
||||
{
|
||||
case TUSB_DESC_DEVICE:
|
||||
desc_data = (uint8_t const *) usbd_desc_set->device;
|
||||
len = sizeof(tusb_desc_device_t);
|
||||
break;
|
||||
|
||||
case TUSB_DESC_CONFIGURATION:
|
||||
desc_data = (uint8_t const *) usbd_desc_set->config;
|
||||
len = ((tusb_desc_configuration_t const*) desc_data)->wTotalLength;
|
||||
break;
|
||||
|
||||
case TUSB_DESC_STRING:
|
||||
// String Descriptor always uses the desc set from user
|
||||
if ( desc_index < tud_desc_set.string_count )
|
||||
{
|
||||
desc_data = tud_desc_set.string_arr[desc_index];
|
||||
TU_VERIFY( desc_data != NULL, NULL );
|
||||
|
||||
len = desc_data[0]; // first byte of descriptor is its size
|
||||
}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 !!!
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_DESC_DEVICE_QUALIFIER:
|
||||
// TODO If not highspeed capable stall this request otherwise
|
||||
// return the descriptor that could work in highspeed
|
||||
return NULL;
|
||||
break;
|
||||
|
||||
default: return NULL;
|
||||
}
|
||||
|
||||
*desc_len = len;
|
||||
return desc_data;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBD-DCD Callback API
|
||||
// DCD Event Handler
|
||||
//--------------------------------------------------------------------+
|
||||
void dcd_event_handler(dcd_event_t const * event, bool in_isr)
|
||||
{
|
||||
@ -434,6 +566,9 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
|
||||
break;
|
||||
|
||||
case DCD_EVENT_XFER_COMPLETE:
|
||||
// skip zero-length control status complete event, should dcd notifies us.
|
||||
if ( 0 == 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 == DCD_XFER_SUCCESS,);
|
||||
break;
|
||||
@ -442,8 +577,6 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr)
|
||||
}
|
||||
}
|
||||
|
||||
void dcd_event_handler(dcd_event_t const * event, bool in_isr);
|
||||
|
||||
// helper to send bus signal event
|
||||
void dcd_event_bus_signal (uint8_t rhport, dcd_eventid_t eid, bool in_isr)
|
||||
{
|
||||
|
170
src/device/usbd_control.c
Normal file
170
src/device/usbd_control.c
Normal file
@ -0,0 +1,170 @@
|
||||
/**************************************************************************/
|
||||
/*!
|
||||
@file usbd_control.c
|
||||
@author hathach (tinyusb.org)
|
||||
|
||||
@section LICENSE
|
||||
|
||||
Software License Agreement (BSD License)
|
||||
|
||||
Copyright (c) 2013, hathach (tinyusb.org)
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
3. Neither the name of the copyright holders nor the
|
||||
names of its contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY
|
||||
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE FOR ANY
|
||||
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
This file is part of the tinyusb stack.
|
||||
*/
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tusb_option.h"
|
||||
|
||||
#if TUSB_OPT_DEVICE_ENABLED
|
||||
|
||||
#define _TINY_USB_SOURCE_FILE_
|
||||
|
||||
#include "tusb.h"
|
||||
#include "device/usbd_pvt.h"
|
||||
|
||||
enum
|
||||
{
|
||||
EDPT_CTRL_OUT = 0x00,
|
||||
EDPT_CTRL_IN = 0x80
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
tusb_control_request_t request;
|
||||
|
||||
void* buffer;
|
||||
uint16_t total_len;
|
||||
uint16_t total_transferred;
|
||||
|
||||
bool (*complete_cb) (uint8_t, tusb_control_request_t const *);
|
||||
} usbd_control_xfer_t;
|
||||
|
||||
static usbd_control_xfer_t _control_state;
|
||||
|
||||
CFG_TUSB_ATTR_USBRAM CFG_TUSB_MEM_ALIGN uint8_t _usbd_ctrl_buf[CFG_TUD_ENDOINT0_SIZE];
|
||||
|
||||
void usbd_control_reset (uint8_t rhport)
|
||||
{
|
||||
tu_varclr(&_control_state);
|
||||
}
|
||||
|
||||
void usbd_control_stall(uint8_t rhport)
|
||||
{
|
||||
dcd_edpt_stall(rhport, 0);
|
||||
}
|
||||
|
||||
bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request)
|
||||
{
|
||||
// status direction is reversed to one in the setup packet
|
||||
return dcd_edpt_xfer(rhport, request->bmRequestType_bit.direction ? EDPT_CTRL_OUT : EDPT_CTRL_IN, NULL, 0);
|
||||
}
|
||||
|
||||
|
||||
// Each transaction is up to endpoint0's max packet size
|
||||
static bool start_control_data_xact(uint8_t rhport)
|
||||
{
|
||||
uint16_t const xact_len = tu_min16(_control_state.total_len - _control_state.total_transferred, CFG_TUD_ENDOINT0_SIZE);
|
||||
|
||||
uint8_t ep_addr = EDPT_CTRL_OUT;
|
||||
|
||||
if ( _control_state.request.bmRequestType_bit.direction == TUSB_DIR_IN )
|
||||
{
|
||||
ep_addr = EDPT_CTRL_IN;
|
||||
memcpy(_usbd_ctrl_buf, _control_state.buffer, xact_len);
|
||||
}
|
||||
|
||||
return dcd_edpt_xfer(rhport, ep_addr, _usbd_ctrl_buf, xact_len);
|
||||
}
|
||||
|
||||
// TODO may find a better way
|
||||
void usbd_control_set_complete_callback( bool (*fp) (uint8_t, tusb_control_request_t const * ) )
|
||||
{
|
||||
_control_state.complete_cb = fp;
|
||||
}
|
||||
|
||||
bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len)
|
||||
{
|
||||
_control_state.request = (*request);
|
||||
_control_state.buffer = buffer;
|
||||
_control_state.total_len = tu_min16(len, request->wLength);
|
||||
_control_state.total_transferred = 0;
|
||||
|
||||
if ( buffer != NULL && len )
|
||||
{
|
||||
// Data stage
|
||||
TU_ASSERT( start_control_data_xact(rhport) );
|
||||
}else
|
||||
{
|
||||
// Status stage
|
||||
TU_ASSERT( usbd_control_status(rhport, request) );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// callback when a transaction complete on DATA stage of control endpoint
|
||||
tusb_error_t usbd_control_xfer_cb (uint8_t rhport, uint8_t ep_addr, tusb_event_t event, uint32_t xferred_bytes)
|
||||
{
|
||||
if ( _control_state.request.bmRequestType_bit.direction == TUSB_DIR_OUT )
|
||||
{
|
||||
memcpy(_control_state.buffer, _usbd_ctrl_buf, xferred_bytes);
|
||||
}
|
||||
|
||||
_control_state.total_transferred += xferred_bytes;
|
||||
_control_state.buffer += xferred_bytes;
|
||||
|
||||
if ( _control_state.total_len == _control_state.total_transferred || xferred_bytes < CFG_TUD_ENDOINT0_SIZE )
|
||||
{
|
||||
// DATA stage is complete
|
||||
bool is_ok = true;
|
||||
|
||||
// invoke complete callback if set
|
||||
// callback can still stall control in status phase e.g out data does not make sense
|
||||
if ( _control_state.complete_cb )
|
||||
{
|
||||
is_ok = _control_state.complete_cb(rhport, &_control_state.request);
|
||||
}
|
||||
|
||||
if ( is_ok )
|
||||
{
|
||||
// Send status
|
||||
TU_ASSERT( usbd_control_status(rhport, &_control_state.request), TUSB_ERROR_FAILED );
|
||||
}else
|
||||
{
|
||||
// stall due to callback
|
||||
usbd_control_stall(rhport);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// More data to transfer
|
||||
TU_ASSERT(start_control_data_xact(rhport), TUSB_ERROR_FAILED);
|
||||
}
|
||||
|
||||
return TUSB_ERROR_NONE;
|
||||
}
|
||||
|
||||
#endif
|
@ -54,15 +54,24 @@ extern tud_desc_set_t const* usbd_desc_set;
|
||||
tusb_error_t usbd_init (void);
|
||||
void usbd_task (void* param);
|
||||
|
||||
|
||||
// Carry out Data and Status stage of control transfer
|
||||
// - If len = 0, it is equivalent to sending status only
|
||||
// - If len > wLength : it will be truncated
|
||||
bool usbd_control_xfer(uint8_t rhport, tusb_control_request_t const * request, void* buffer, uint16_t len);
|
||||
|
||||
// Send STATUS (zero length) packet
|
||||
bool usbd_control_status(uint8_t rhport, tusb_control_request_t const * request);
|
||||
|
||||
// Stall control endpoint until new setup packet arrived
|
||||
void usbd_control_stall(uint8_t rhport);
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Endpoint helper
|
||||
/* Helper
|
||||
*------------------------------------------------------------------*/
|
||||
// helper to parse an pair of In and Out endpoint descriptors. They must be consecutive
|
||||
tusb_error_t usbd_open_edpt_pair(uint8_t rhport, tusb_desc_endpoint_t const* p_desc_ep, uint8_t xfer_type, uint8_t* ep_out, uint8_t* ep_in);
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Other Helpers
|
||||
*------------------------------------------------------------------*/
|
||||
void usbd_defer_func( osal_task_func_t func, void* param, bool in_isr );
|
||||
|
||||
|
||||
|
@ -44,13 +44,6 @@
|
||||
|
||||
#include "tusb_hal.h"
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* MACRO TYPEDEF CONSTANT ENUM
|
||||
*------------------------------------------------------------------*/
|
||||
#define USB_NVIC_PRIO 7
|
||||
|
||||
void tusb_hal_nrf_power_event(uint32_t event);
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* TUSB HAL
|
||||
*------------------------------------------------------------------*/
|
||||
|
@ -64,9 +64,7 @@ enum
|
||||
USBD_INTENCLR_ENDISOIN_Msk | USBD_INTEN_ENDISOOUT_Msk
|
||||
};
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* VARIABLE DECLARATION
|
||||
*------------------------------------------------------------------*/
|
||||
// Transfer descriptor
|
||||
typedef struct
|
||||
{
|
||||
uint8_t* buffer;
|
||||
@ -78,35 +76,119 @@ typedef struct
|
||||
// indicate packet is already ACK
|
||||
volatile bool data_received;
|
||||
|
||||
} nom_xfer_t;
|
||||
} xfer_td_t;
|
||||
|
||||
/*static*/ struct
|
||||
// Data for managing dcd
|
||||
static struct
|
||||
{
|
||||
// All 8 endpoints including control IN & OUT (offset 1)
|
||||
nom_xfer_t xfer[8][2];
|
||||
xfer_td_t xfer[8][2];
|
||||
|
||||
// Only one DMA can run at a time
|
||||
volatile bool dma_running;
|
||||
}_dcd;
|
||||
|
||||
void bus_reset(void)
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Control / Bulk / Interrupt (CBI) Transfer
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
// helper to start DMA
|
||||
static void edpt_dma_start(volatile uint32_t* reg_startep)
|
||||
{
|
||||
for(int i=0; i<8; i++)
|
||||
// Only one dma can be active
|
||||
if ( _dcd.dma_running )
|
||||
{
|
||||
NRF_USBD->TASKS_STARTEPIN[i] = 0;
|
||||
NRF_USBD->TASKS_STARTEPOUT[i] = 0;
|
||||
if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)
|
||||
{
|
||||
// If called within ISR, use usbd task to defer later
|
||||
usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise simply block wait
|
||||
while ( _dcd.dma_running ) { }
|
||||
}
|
||||
}
|
||||
|
||||
NRF_USBD->TASKS_STARTISOIN = 0;
|
||||
NRF_USBD->TASKS_STARTISOOUT = 0;
|
||||
_dcd.dma_running = true;
|
||||
|
||||
tu_varclr(&_dcd);
|
||||
_dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE;
|
||||
_dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE;
|
||||
(*reg_startep) = 1;
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Controller API
|
||||
*------------------------------------------------------------------*/
|
||||
// DMA is complete
|
||||
static void edpt_dma_end(void)
|
||||
{
|
||||
TU_ASSERT(_dcd.dma_running, );
|
||||
_dcd.dma_running = false;
|
||||
}
|
||||
|
||||
// helper getting td
|
||||
static inline xfer_td_t* get_td(uint8_t epnum, uint8_t dir)
|
||||
{
|
||||
return &_dcd.xfer[epnum][dir];
|
||||
}
|
||||
|
||||
/*------------- CBI OUT Transfer -------------*/
|
||||
|
||||
// Prepare for a CBI transaction OUT, call at the start
|
||||
// Allow ACK incoming data
|
||||
static void xact_out_prepare(uint8_t epnum)
|
||||
{
|
||||
if ( epnum == 0 )
|
||||
{
|
||||
NRF_USBD->TASKS_EP0RCVOUT = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Write zero value to SIZE register will allow hw to ACK (accept data)
|
||||
// If it is not already done by DMA
|
||||
NRF_USBD->SIZE.EPOUT[epnum] = 0;
|
||||
}
|
||||
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
|
||||
// Start DMA to move data from Endpoint -> RAM
|
||||
static void xact_out_dma(uint8_t epnum)
|
||||
{
|
||||
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
|
||||
uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum];
|
||||
|
||||
// Trigger DMA move data from Endpoint -> SRAM
|
||||
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
|
||||
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
|
||||
|
||||
edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
|
||||
|
||||
xfer->buffer += xact_len;
|
||||
xfer->actual_len += xact_len;
|
||||
}
|
||||
|
||||
/*------------- CBI IN Transfer -------------*/
|
||||
|
||||
// Prepare for a CBI transaction IN, call at the start
|
||||
// it start DMA to transfer data from RAM -> Endpoint
|
||||
static void xact_in_prepare(uint8_t epnum)
|
||||
{
|
||||
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
||||
|
||||
// Each transaction is up to Max Packet Size
|
||||
uint8_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
|
||||
|
||||
NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
|
||||
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
|
||||
|
||||
xfer->buffer += xact_len;
|
||||
|
||||
edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Tinyusb DCD API
|
||||
//--------------------------------------------------------------------+
|
||||
bool dcd_init (uint8_t rhport)
|
||||
{
|
||||
(void) rhport;
|
||||
@ -135,101 +217,6 @@ void dcd_set_config (uint8_t rhport, uint8_t config_num)
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Control
|
||||
*------------------------------------------------------------------*/
|
||||
static void edpt_dma_start(volatile uint32_t* reg_startep)
|
||||
{
|
||||
// Only one dma can be active
|
||||
if ( _dcd.dma_running )
|
||||
{
|
||||
if (SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)
|
||||
{
|
||||
// If called within ISR, use usbd task to defer later
|
||||
usbd_defer_func( (osal_task_func_t) edpt_dma_start, (void*) reg_startep, true );
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Otherwise simply block wait
|
||||
while ( _dcd.dma_running ) { }
|
||||
}
|
||||
}
|
||||
|
||||
_dcd.dma_running = true;
|
||||
|
||||
(*reg_startep) = 1;
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
|
||||
static void edpt_dma_end(void)
|
||||
{
|
||||
TU_ASSERT(_dcd.dma_running, );
|
||||
|
||||
_dcd.dma_running = false;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
*------------------------------------------------------------------*/
|
||||
|
||||
static inline nom_xfer_t* get_td(uint8_t epnum, uint8_t dir)
|
||||
{
|
||||
return &_dcd.xfer[epnum][dir];
|
||||
}
|
||||
|
||||
/*------------- Bulk/Int OUT transfer -------------*/
|
||||
|
||||
/**
|
||||
* Prepare Bulk/Int out transaction, Endpoint start to accept/ACK Data
|
||||
* @param epnum
|
||||
*/
|
||||
static void xact_out_prepare(uint8_t epnum)
|
||||
{
|
||||
// Write zero value to SIZE register will allow hw to ACK (accept data)
|
||||
// If it is not already done by DMA
|
||||
NRF_USBD->SIZE.EPOUT[epnum] = 0;
|
||||
__ISB(); __DSB();
|
||||
}
|
||||
|
||||
static void xact_out_dma(uint8_t epnum)
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
|
||||
uint8_t const xact_len = NRF_USBD->SIZE.EPOUT[epnum];
|
||||
|
||||
// Trigger DMA move data from Endpoint -> SRAM
|
||||
NRF_USBD->EPOUT[epnum].PTR = (uint32_t) xfer->buffer;
|
||||
NRF_USBD->EPOUT[epnum].MAXCNT = xact_len;
|
||||
|
||||
edpt_dma_start(&NRF_USBD->TASKS_STARTEPOUT[epnum]);
|
||||
|
||||
xfer->buffer += xact_len;
|
||||
xfer->actual_len += xact_len;
|
||||
}
|
||||
|
||||
|
||||
/*------------- Bulk/Int IN transfer -------------*/
|
||||
|
||||
/**
|
||||
* Prepare Bulk/Int in transaction, use DMA to transfer data from Memory -> Endpoint
|
||||
* @param epnum
|
||||
*/
|
||||
static void xact_in_prepare(uint8_t epnum)
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
||||
|
||||
// Each transaction is up to Max Packet Size
|
||||
uint8_t const xact_len = tu_min16(xfer->total_len - xfer->actual_len, xfer->mps);
|
||||
|
||||
NRF_USBD->EPIN[epnum].PTR = (uint32_t) xfer->buffer;
|
||||
NRF_USBD->EPIN[epnum].MAXCNT = xact_len;
|
||||
|
||||
xfer->buffer += xact_len;
|
||||
|
||||
edpt_dma_start(&NRF_USBD->TASKS_STARTEPIN[epnum]);
|
||||
}
|
||||
|
||||
bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
|
||||
{
|
||||
(void) rhport;
|
||||
@ -253,16 +240,6 @@ bool dcd_edpt_open (uint8_t rhport, tusb_desc_endpoint_t const * desc_edpt)
|
||||
return true;
|
||||
}
|
||||
|
||||
void control_status_token(uint8_t addr) {
|
||||
NRF_USBD->EPIN[0].PTR = 0;
|
||||
NRF_USBD->EPIN[0].MAXCNT = 0;
|
||||
// Status Phase also require Easy DMA has to be free as well !!!!
|
||||
NRF_USBD->TASKS_EP0STATUS = 1;
|
||||
|
||||
// The nRF doesn't interrupt on status transmit so we queue up a success response.
|
||||
dcd_event_xfer_complete(0, addr, 0, DCD_XFER_SUCCESS, false);
|
||||
}
|
||||
|
||||
bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||
{
|
||||
(void) rhport;
|
||||
@ -270,27 +247,36 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
|
||||
uint8_t const epnum = edpt_number(ep_addr);
|
||||
uint8_t const dir = edpt_dir(ep_addr);
|
||||
|
||||
nom_xfer_t* xfer = get_td(epnum, dir);
|
||||
xfer_td_t* xfer = get_td(epnum, dir);
|
||||
|
||||
xfer->buffer = buffer;
|
||||
xfer->total_len = total_bytes;
|
||||
xfer->actual_len = 0;
|
||||
|
||||
// How does the control endpoint handle a ZLP in the data phase?
|
||||
if (epnum == 0 && total_bytes == 0) {
|
||||
control_status_token(ep_addr);
|
||||
} else if ( dir == TUSB_DIR_OUT )
|
||||
// Control endpoint with zero-length packet --> status stage
|
||||
if ( epnum == 0 && total_bytes == 0 )
|
||||
{
|
||||
// Status Phase also require Easy DMA has to be free as well !!!!
|
||||
edpt_dma_start(&NRF_USBD->TASKS_EP0STATUS);
|
||||
edpt_dma_end();
|
||||
|
||||
// The nRF doesn't interrupt on status transmit so we queue up a success response.
|
||||
dcd_event_xfer_complete(0, ep_addr, 0, DCD_XFER_SUCCESS, false);
|
||||
}
|
||||
else if ( dir == TUSB_DIR_OUT )
|
||||
{
|
||||
if ( xfer->data_received )
|
||||
{
|
||||
// nrf52840 auto ACK OUT packet after DMA is done
|
||||
// Data already received previously --> trigger DMA to copy to SRAM
|
||||
xact_out_dma(epnum);
|
||||
}else
|
||||
}
|
||||
else
|
||||
{
|
||||
xact_out_prepare(epnum);
|
||||
}
|
||||
}else
|
||||
}
|
||||
else
|
||||
{
|
||||
xact_in_prepare(epnum);
|
||||
}
|
||||
@ -313,7 +299,7 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
if ( ep_addr == 0)
|
||||
if ( edpt_number(ep_addr) == 0 )
|
||||
{
|
||||
NRF_USBD->TASKS_EP0STALL = 1;
|
||||
}else
|
||||
@ -328,7 +314,7 @@ void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr)
|
||||
{
|
||||
(void) rhport;
|
||||
|
||||
if ( ep_addr )
|
||||
if ( edpt_number(ep_addr) )
|
||||
{
|
||||
NRF_USBD->EPSTALL = (USBD_EPSTALL_STALL_UnStall << USBD_EPSTALL_STALL_Pos) | ep_addr;
|
||||
__ISB(); __DSB();
|
||||
@ -340,19 +326,35 @@ bool dcd_edpt_busy (uint8_t rhport, uint8_t ep_addr)
|
||||
(void) rhport;
|
||||
|
||||
// USBD shouldn't check control endpoint state
|
||||
if ( 0 == ep_addr ) return false;
|
||||
if ( 0 == edpt_number(ep_addr) ) return false;
|
||||
|
||||
uint8_t const epnum = edpt_number(ep_addr);
|
||||
uint8_t const dir = edpt_dir(ep_addr);
|
||||
|
||||
nom_xfer_t* xfer = get_td(epnum, dir);
|
||||
xfer_td_t* xfer = get_td(epnum, dir);
|
||||
|
||||
return xfer->actual_len < xfer->total_len;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/*
|
||||
/* Interrupt Handler
|
||||
*------------------------------------------------------------------*/
|
||||
void bus_reset(void)
|
||||
{
|
||||
for(int i=0; i<8; i++)
|
||||
{
|
||||
NRF_USBD->TASKS_STARTEPIN[i] = 0;
|
||||
NRF_USBD->TASKS_STARTEPOUT[i] = 0;
|
||||
}
|
||||
|
||||
NRF_USBD->TASKS_STARTISOIN = 0;
|
||||
NRF_USBD->TASKS_STARTISOOUT = 0;
|
||||
|
||||
tu_varclr(&_dcd);
|
||||
_dcd.xfer[0][TUSB_DIR_IN].mps = MAX_PACKET_SIZE;
|
||||
_dcd.xfer[0][TUSB_DIR_OUT].mps = MAX_PACKET_SIZE;
|
||||
}
|
||||
|
||||
void USBD_IRQHandler(void)
|
||||
{
|
||||
uint32_t const inten = NRF_USBD->INTEN;
|
||||
@ -388,19 +390,52 @@ void USBD_IRQHandler(void)
|
||||
// Setup tokens are specific to the Control endpoint.
|
||||
if ( int_status & USBD_INTEN_EP0SETUP_Msk )
|
||||
{
|
||||
uint8_t setup[8] = {
|
||||
uint8_t const setup[8] = {
|
||||
NRF_USBD->BMREQUESTTYPE , NRF_USBD->BREQUEST, NRF_USBD->WVALUEL , NRF_USBD->WVALUEH,
|
||||
NRF_USBD->WINDEXL , NRF_USBD->WINDEXH , NRF_USBD->WLENGTHL, NRF_USBD->WLENGTHH
|
||||
};
|
||||
if (setup[1] != TUSB_REQ_SET_ADDRESS) {
|
||||
|
||||
// nrf5x hw auto handle set address, there is no need to inform usb stack
|
||||
tusb_control_request_t const * request = (tusb_control_request_t const *) setup;
|
||||
|
||||
if ( !(TUSB_REQ_RCPT_DEVICE == request->bmRequestType_bit.recipient &&
|
||||
TUSB_REQ_TYPE_STANDARD == request->bmRequestType_bit.type &&
|
||||
TUSB_REQ_SET_ADDRESS == request->bRequest) )
|
||||
{
|
||||
dcd_event_setup_received(0, setup, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*------------- Bulk/Interrupt Transfer -------------*/
|
||||
//--------------------------------------------------------------------+
|
||||
/* Control/Bulk/Interrupt (CBI) Transfer
|
||||
*
|
||||
* Data flow is:
|
||||
* (bus) (dma)
|
||||
* Host <-------> Endpoint <-------> RAM
|
||||
*
|
||||
* For CBI OUT:
|
||||
* - Host -> Endpoint
|
||||
* EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPOUT[i]
|
||||
* to start DMA. This step can occur automatically (without sw),
|
||||
* which means data may or may not ready (data_received flag).
|
||||
* - Endpoint -> RAM
|
||||
* ENDEPOUT[i] interrupted, transaction complete, sw prepare next transaction
|
||||
*
|
||||
* For CBI IN:
|
||||
* - RAM -> Endpoint
|
||||
* ENDEPIN[i] interrupted indicate DMA is complete. HW will start
|
||||
* to move daat to host
|
||||
* - Endpoint -> Host
|
||||
* EPDATA (or EP0DATADONE) interrupted, check EPDATASTATUS.EPIN[i].
|
||||
* Transaction is complete, sw prepare next transaction
|
||||
*
|
||||
* Note: in both Control In and Out of Data stage from Host <-> Endpoint
|
||||
* EP0DATADONE will be set as interrupt source
|
||||
*/
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
/* Bulk/Int OUT: data from DMA -> SRAM
|
||||
* Note: Since nrf controller auto ACK next packet without SW awareness
|
||||
/* CBI OUT: Endpoint -> SRAM (aka transaction complete)
|
||||
* Note: Since nRF controller auto ACK next packet without SW awareness
|
||||
* We must handle this stage before Host -> Endpoint just in case
|
||||
* 2 event happens at once
|
||||
*/
|
||||
@ -408,10 +443,10 @@ void USBD_IRQHandler(void)
|
||||
{
|
||||
if ( BIT_TEST_(int_status, USBD_INTEN_ENDEPOUT0_Pos+epnum))
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
|
||||
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
uint8_t const xact_len = NRF_USBD->EPOUT[epnum].AMOUNT;
|
||||
|
||||
// Data in endpoint has been consumed
|
||||
xfer->data_received = false;
|
||||
|
||||
// Transfer complete if transaction len < Max Packet Size or total len is transferred
|
||||
@ -428,21 +463,27 @@ void USBD_IRQHandler(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Ended event for Bulk/Int : nothing to do
|
||||
// Ended event for CBI IN : nothing to do
|
||||
}
|
||||
|
||||
if ( int_status & USBD_INTEN_EPDATA_Msk || int_status & USBD_INTEN_EP0DATADONE_Msk)
|
||||
// Endpoint <-> Host
|
||||
if ( int_status & (USBD_INTEN_EPDATA_Msk | USBD_INTEN_EP0DATADONE_Msk) )
|
||||
{
|
||||
uint32_t data_status = NRF_USBD->EPDATASTATUS;
|
||||
|
||||
nrf_usbd_epdatastatus_clear(data_status);
|
||||
|
||||
// Bulk/Int In: data from Endpoint -> Host
|
||||
// EP0DATADONE is set with either Control Out on IN Data
|
||||
// Since EPDATASTATUS cannot be used to determine whether it is control OUT or IN.
|
||||
// We will use BMREQUESTTYPE in setup packet to determine the direction
|
||||
bool const is_control_in = (int_status & USBD_INTEN_EP0DATADONE_Msk) && (NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK);
|
||||
bool const is_control_out = (int_status & USBD_INTEN_EP0DATADONE_Msk) && !(NRF_USBD->BMREQUESTTYPE & TUSB_DIR_IN_MASK);
|
||||
|
||||
// CBI In: Endpoint -> Host (transaction complete)
|
||||
for(uint8_t epnum=0; epnum<8; epnum++)
|
||||
{
|
||||
if ( BIT_TEST_(data_status, epnum ) || (epnum == 0 && BIT_TEST_(int_status, USBD_INTEN_EP0DATADONE_Pos)))
|
||||
if ( BIT_TEST_(data_status, epnum ) || ( epnum == 0 && is_control_in) )
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
||||
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_IN);
|
||||
|
||||
xfer->actual_len += NRF_USBD->EPIN[epnum].MAXCNT;
|
||||
|
||||
@ -458,12 +499,12 @@ void USBD_IRQHandler(void)
|
||||
}
|
||||
}
|
||||
|
||||
// Bulk/Int OUT: data from Host -> Endpoint
|
||||
// CBI OUT: Host -> Endpoint
|
||||
for(uint8_t epnum=0; epnum<8; epnum++)
|
||||
{
|
||||
if ( BIT_TEST_(data_status, 16+epnum ) )
|
||||
if ( BIT_TEST_(data_status, 16+epnum ) || ( epnum == 0 && is_control_out) )
|
||||
{
|
||||
nom_xfer_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
xfer_td_t* xfer = get_td(epnum, TUSB_DIR_OUT);
|
||||
|
||||
if (xfer->actual_len < xfer->total_len)
|
||||
{
|
||||
|
@ -148,10 +148,8 @@
|
||||
#define CFG_TUD_ENDOINT0_SIZE 64
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_ENUM_BUFFER_SIZE
|
||||
#ifndef CFG_TUD_CTRL_BUFSIZE
|
||||
#define CFG_TUD_CTRL_BUFSIZE 256
|
||||
#else
|
||||
#define CFG_TUD_CTRL_BUFSIZE CFG_TUD_ENUM_BUFFER_SIZE
|
||||
#endif
|
||||
|
||||
#ifndef CFG_TUD_DESC_AUTO
|
||||
|
Loading…
x
Reference in New Issue
Block a user