2014-03-12 14:01:38 +07:00
/**************************************************************************/
/*!
@ 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 MODE_DEVICE_SUPPORTED
# define _TINY_USB_SOURCE_FILE_
//--------------------------------------------------------------------+
// INCLUDE
//--------------------------------------------------------------------+
# include "tusb.h"
2018-03-11 12:31:24 +07:00
# include "usbd.h"
2018-03-22 14:15:16 +07:00
# include "device/usbd_pvt.h"
2014-03-12 14:01:38 +07:00
2018-03-23 14:57:17 +07:00
typedef struct {
void ( * init ) ( void ) ;
tusb_error_t ( * open ) ( uint8_t rhport , tusb_desc_interface_t const * desc_intf , uint16_t * p_length ) ;
tusb_error_t ( * control_request_st ) ( uint8_t rhport , tusb_control_request_t const * ) ;
tusb_error_t ( * xfer_cb ) ( uint8_t rhport , uint8_t ep_addr , tusb_event_t , uint32_t ) ;
// void (* routine)(void);
void ( * sof ) ( uint8_t rhport ) ;
void ( * close ) ( uint8_t ) ;
} usbd_class_driver_t ;
enum {
USBD_INTERFACE_NUM_MAX = 16 // USB specs specify up to 16 endpoints per device
} ;
typedef struct {
volatile uint8_t state ;
uint8_t config_num ;
uint8_t interface2class [ USBD_INTERFACE_NUM_MAX ] ; // determine interface number belongs to which class
} usbd_device_info_t ;
2014-03-12 14:01:38 +07:00
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
usbd_device_info_t usbd_devices [ CONTROLLER_DEVICE_NUMBER ] ;
2018-03-23 14:15:35 +07:00
TUSB_CFG_ATTR_USBRAM ATTR_USB_MIN_ALIGNMENT uint8_t usbd_enum_buffer [ TUSB_CFG_DEVICE_ENUM_BUFFER_SIZE ] ;
2014-03-12 14:01:38 +07:00
2014-03-14 17:18:05 +07:00
static usbd_class_driver_t const usbd_class_drivers [ ] =
2014-03-12 14:01:38 +07:00
{
2014-03-14 17:18:05 +07:00
# if DEVICE_CLASS_HID
2014-03-12 14:01:38 +07:00
[ TUSB_CLASS_HID ] =
{
. init = hidd_init ,
. open = hidd_open ,
2018-03-22 16:28:40 +07:00
. control_request_st = hidd_control_request_st ,
2014-03-12 14:01:38 +07:00
. xfer_cb = hidd_xfer_cb ,
2018-03-08 14:38:06 +07:00
// .routine = NULL,
. sof = NULL ,
2014-03-12 14:01:38 +07:00
. close = hidd_close
} ,
2014-03-14 17:18:05 +07:00
# endif
2014-03-12 14:01:38 +07:00
2014-03-14 17:18:05 +07:00
# if TUSB_CFG_DEVICE_MSC
2014-03-12 14:01:38 +07:00
[ TUSB_CLASS_MSC ] =
{
. init = mscd_init ,
. open = mscd_open ,
2018-03-22 16:28:40 +07:00
. control_request_st = mscd_control_request_st ,
2014-03-12 14:01:38 +07:00
. xfer_cb = mscd_xfer_cb ,
2018-03-08 14:38:06 +07:00
// .routine = NULL,
. sof = NULL ,
2014-03-12 14:01:38 +07:00
. close = mscd_close
} ,
2014-03-14 17:18:05 +07:00
# endif
2014-03-12 14:01:38 +07:00
2014-03-14 17:18:05 +07:00
# if TUSB_CFG_DEVICE_CDC
2014-03-12 14:01:38 +07:00
[ TUSB_CLASS_CDC ] =
{
. init = cdcd_init ,
. open = cdcd_open ,
2018-03-22 16:28:40 +07:00
. control_request_st = cdcd_control_request_st ,
2014-03-12 14:01:38 +07:00
. xfer_cb = cdcd_xfer_cb ,
2018-03-08 14:38:06 +07:00
// .routine = NULL,
. sof = cdcd_sof ,
2014-03-12 14:01:38 +07:00
. close = cdcd_close
} ,
2014-03-14 17:18:05 +07:00
# endif
2014-03-12 14:01:38 +07:00
} ;
2014-03-18 16:58:24 +07:00
enum { USBD_CLASS_DRIVER_COUNT = sizeof ( usbd_class_drivers ) / sizeof ( usbd_class_driver_t ) } ;
2014-03-14 17:18:05 +07:00
2018-03-14 22:01:16 +07:00
2018-03-23 12:32:40 +07:00
//tusb_desc_device_qualifier_t _device_qual =
2018-03-14 22:01:16 +07:00
//{
2018-03-23 12:32:40 +07:00
// .bLength = sizeof(tusb_desc_device_qualifier_t),
2018-03-14 22:01:16 +07:00
// .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER,
// .bcdUSB = 0x0200,
// .bDeviceClass =
//};
2014-03-12 14:01:38 +07:00
//--------------------------------------------------------------------+
// INTERNAL OBJECT & FUNCTION DECLARATION
//--------------------------------------------------------------------+
2018-03-23 12:17:47 +07:00
static tusb_error_t proc_set_config_req ( uint8_t rhport , uint8_t config_number ) ;
static uint16_t get_descriptor ( uint8_t rhport , tusb_control_request_t const * const p_request , uint8_t const * * pp_buffer ) ;
2014-03-12 14:01:38 +07:00
//--------------------------------------------------------------------+
// APPLICATION INTERFACE
//--------------------------------------------------------------------+
2018-03-23 12:17:47 +07:00
bool tud_n_mounted ( uint8_t rhport )
2014-03-12 14:01:38 +07:00
{
2018-03-23 12:17:47 +07:00
return usbd_devices [ rhport ] . state = = TUSB_DEVICE_STATE_CONFIGURED ;
2014-03-12 14:01:38 +07:00
}
//--------------------------------------------------------------------+
// IMPLEMENTATION
//--------------------------------------------------------------------+
//------------- OSAL Task -------------//
2014-04-24 23:40:28 +07:00
enum { USBD_TASK_QUEUE_DEPTH = 16 } ;
2014-03-12 14:01:38 +07:00
2015-05-01 18:45:22 +07:00
typedef enum
{
2014-03-12 14:01:38 +07:00
USBD_EVENTID_SETUP_RECEIVED = 1 ,
2018-03-08 14:38:06 +07:00
USBD_EVENTID_XFER_DONE ,
USBD_EVENTID_SOF
2014-03-12 14:01:38 +07:00
} usbd_eventid_t ;
typedef struct ATTR_ALIGNED ( 4 )
{
2018-03-23 12:17:47 +07:00
uint8_t rhport ;
2014-03-12 14:01:38 +07:00
uint8_t event_id ;
uint8_t sub_event_id ;
uint8_t reserved ;
union {
2018-03-08 14:38:06 +07:00
tusb_control_request_t setup_received ;
2014-03-12 14:01:38 +07:00
struct { // USBD_EVENTID_XFER_DONE
2018-03-17 02:17:40 +07:00
uint8_t ep_addr ;
2014-03-12 14:01:38 +07:00
uint32_t xferred_byte ;
} xfer_done ;
} ;
2014-03-14 17:18:05 +07:00
} usbd_task_event_t ;
2014-03-12 14:01:38 +07:00
2018-03-28 14:16:14 +07:00
VERIFY_STATIC ( sizeof ( usbd_task_event_t ) < = 12 , " size is not correct " ) ;
2014-03-12 14:01:38 +07:00
2018-02-28 14:21:31 +07:00
# ifndef TUC_DEVICE_STACKSIZE
# define TUC_DEVICE_STACKSIZE 150
# endif
# ifndef TUSB_CFG_OS_TASK_PRIO
# define TUSB_CFG_OS_TASK_PRIO 0
# endif
2014-03-12 14:01:38 +07:00
2018-02-28 16:45:54 +07:00
static osal_queue_t usbd_queue_hdl ;
2018-03-01 11:17:11 +07:00
/*static*/ osal_semaphore_t usbd_control_xfer_sem_hdl ; // TODO may need to change to static with wrapper function
2014-03-12 14:01:38 +07:00
2014-03-31 13:12:51 +07:00
//--------------------------------------------------------------------+
// IMPLEMENTATION
//--------------------------------------------------------------------+
2018-03-23 12:17:47 +07:00
static tusb_error_t proc_control_request_st ( uint8_t rhport , tusb_control_request_t const * const p_request ) ;
2018-03-22 16:28:40 +07:00
static tusb_error_t usbd_main_stk ( void ) ;
2014-03-31 13:12:51 +07:00
tusb_error_t usbd_init ( void )
{
2018-03-02 22:46:36 +07:00
# if (TUSB_CFG_CONTROLLER_0_MODE & TUSB_MODE_DEVICE)
2018-03-28 13:47:58 +07:00
dcd_init ( 0 ) ;
2018-03-02 22:46:36 +07:00
# endif
# if (TUSB_CFG_CONTROLLER_1_MODE & TUSB_MODE_DEVICE)
2018-03-28 13:47:58 +07:00
dcd_init ( 1 ) ;
2018-03-02 22:46:36 +07:00
# endif
2014-03-31 13:12:51 +07:00
//------------- Task init -------------//
2018-02-28 16:45:54 +07:00
usbd_queue_hdl = osal_queue_create ( USBD_TASK_QUEUE_DEPTH , sizeof ( usbd_task_event_t ) ) ;
2018-03-06 17:22:40 +07:00
VERIFY ( usbd_queue_hdl , TUSB_ERROR_OSAL_QUEUE_FAILED ) ;
2014-03-31 13:12:51 +07:00
2018-03-01 11:17:11 +07:00
usbd_control_xfer_sem_hdl = osal_semaphore_create ( 1 , 0 ) ;
2018-03-06 17:22:40 +07:00
VERIFY ( usbd_queue_hdl , TUSB_ERROR_OSAL_SEMAPHORE_FAILED ) ;
2014-03-31 13:12:51 +07:00
2018-03-01 11:28:26 +07:00
osal_task_create ( usbd_task , " usbd " , TUC_DEVICE_STACKSIZE , NULL , TUSB_CFG_OS_TASK_PRIO ) ;
2018-02-28 14:21:31 +07:00
2014-03-31 13:12:51 +07:00
//------------- Descriptor Check -------------//
2018-03-28 14:49:00 +07:00
TU_ASSERT ( tusbd_descriptor_pointers . p_device ! = NULL & & tusbd_descriptor_pointers . p_configuration ! = NULL , TUSB_ERROR_DESCRIPTOR_CORRUPTED ) ;
2014-03-31 13:12:51 +07:00
//------------- class init -------------//
for ( uint8_t class_code = TUSB_CLASS_AUDIO ; class_code < USBD_CLASS_DRIVER_COUNT ; class_code + + )
{
if ( usbd_class_drivers [ class_code ] . init )
{
usbd_class_drivers [ class_code ] . init ( ) ;
}
}
return TUSB_ERROR_NONE ;
}
// To enable the TASK_ASSERT style (quick return on false condition) in a real RTOS, a task must act as a wrapper
// and is used mainly to call subtasks. Within a subtask return statement can be called freely, the task with
// forever loop cannot have any return at all.
2018-02-28 14:21:31 +07:00
void usbd_task ( void * param )
2014-03-31 13:12:51 +07:00
{
2018-02-28 14:21:31 +07:00
( void ) param ;
2014-03-31 13:12:51 +07:00
2018-03-01 12:14:44 +07:00
OSAL_TASK_BEGIN
2018-03-22 16:28:40 +07:00
usbd_main_stk ( ) ;
2018-03-01 12:14:44 +07:00
OSAL_TASK_END
2014-03-31 13:12:51 +07:00
}
2018-03-22 16:28:40 +07:00
static tusb_error_t usbd_main_stk ( void )
2014-03-31 13:12:51 +07:00
{
2014-04-09 22:29:38 +07:00
static usbd_task_event_t event ;
2014-03-31 13:12:51 +07:00
OSAL_SUBTASK_BEGIN
tusb_error_t error ;
error = TUSB_ERROR_NONE ;
2014-04-24 23:40:28 +07:00
memclr_ ( & event , sizeof ( usbd_task_event_t ) ) ;
2018-03-08 14:38:06 +07:00
# if 1
2014-03-31 13:12:51 +07:00
osal_queue_receive ( usbd_queue_hdl , & event , OSAL_TIMEOUT_WAIT_FOREVER , & error ) ;
2018-03-22 16:25:24 +07:00
STASK_ASSERT_STATUS ( error ) ;
2018-03-08 14:38:06 +07:00
# else
enum { ROUTINE_INTERVAL_MS = 10 } ;
osal_queue_receive ( usbd_queue_hdl , & event , ROUTINE_INTERVAL_MS , & error ) ;
if ( error ! = TUSB_ERROR_NONE )
{
// time out, run class routine then
if ( error = = TUSB_ERROR_OSAL_TIMEOUT )
{
for ( uint8_t class_code = TUSB_CLASS_AUDIO ; class_code < USBD_CLASS_DRIVER_COUNT ; class_code + + )
{
if ( usbd_class_drivers [ class_code ] . routine ) usbd_class_drivers [ class_code ] . routine ( ) ;
}
}
2018-03-22 16:25:24 +07:00
STASK_RETURN ( error ) ;
2018-03-08 14:38:06 +07:00
}
# endif
2014-03-31 13:12:51 +07:00
if ( USBD_EVENTID_SETUP_RECEIVED = = event . event_id )
{
2018-03-23 12:17:47 +07:00
STASK_INVOKE ( proc_control_request_st ( event . rhport , & event . setup_received ) , error ) ;
2014-04-24 23:40:28 +07:00
} else if ( USBD_EVENTID_XFER_DONE = = event . event_id )
2014-03-31 13:12:51 +07:00
{
2018-03-22 17:43:13 +07:00
// Call class handling function. Those doest not own the endpoint should check and return
2018-03-06 16:50:50 +07:00
for ( uint8_t class_code = TUSB_CLASS_AUDIO ; class_code < USBD_CLASS_DRIVER_COUNT ; class_code + + )
{
2018-03-07 15:30:32 +07:00
if ( usbd_class_drivers [ class_code ] . xfer_cb )
{
2018-03-23 12:17:47 +07:00
usbd_class_drivers [ class_code ] . xfer_cb ( event . rhport , event . xfer_done . ep_addr , ( tusb_event_t ) event . sub_event_id , event . xfer_done . xferred_byte ) ;
2018-03-07 15:30:32 +07:00
}
2018-03-06 16:50:50 +07:00
}
2018-03-08 14:38:06 +07:00
} else if ( USBD_EVENTID_SOF = = event . event_id )
{
for ( uint8_t class_code = TUSB_CLASS_AUDIO ; class_code < USBD_CLASS_DRIVER_COUNT ; class_code + + )
{
if ( usbd_class_drivers [ class_code ] . sof )
{
2018-03-23 12:17:47 +07:00
usbd_class_drivers [ class_code ] . sof ( event . rhport ) ;
2018-03-08 14:38:06 +07:00
}
}
}
else
2014-04-24 23:40:28 +07:00
{
2018-03-22 16:25:24 +07:00
STASK_ASSERT ( false ) ;
2014-03-31 13:12:51 +07:00
}
OSAL_SUBTASK_END
}
//--------------------------------------------------------------------+
// CONTROL REQUEST
//--------------------------------------------------------------------+
2018-03-23 12:17:47 +07:00
tusb_error_t usbd_control_xfer_st ( uint8_t rhport , tusb_dir_t dir , uint8_t * buffer , uint16_t length )
2018-03-14 22:01:16 +07:00
{
OSAL_SUBTASK_BEGIN
tusb_error_t error ;
// Data
if ( length )
{
2018-03-28 13:47:58 +07:00
dcd_control_xfer ( rhport , dir , buffer , length ) ;
2018-03-14 22:01:16 +07:00
osal_semaphore_wait ( usbd_control_xfer_sem_hdl , 100 , & error ) ;
2018-03-22 16:25:24 +07:00
STASK_ASSERT_STATUS ( error ) ;
2018-03-14 22:01:16 +07:00
}
// Status opposite direction with Zero Length
2018-03-22 14:15:16 +07:00
// No need to wait for status to complete therefore
2018-03-28 13:47:58 +07:00
// status phase must not call dcd_control_complete/dcd_xfer_complete
2018-03-28 13:54:28 +07:00
dcd_control_status ( rhport , dir ) ;
2018-03-14 22:01:16 +07:00
OSAL_SUBTASK_END
}
2018-03-23 12:17:47 +07:00
static tusb_error_t proc_control_request_st ( uint8_t rhport , tusb_control_request_t const * const p_request )
2014-03-12 14:01:38 +07:00
{
OSAL_SUBTASK_BEGIN
2014-03-14 17:18:05 +07:00
tusb_error_t error ;
error = TUSB_ERROR_NONE ;
2014-03-12 14:01:38 +07:00
2018-03-22 14:15:16 +07:00
//------------- Standard Request e.g in enumeration -------------//
2018-03-21 15:32:35 +07:00
if ( TUSB_REQ_RCPT_DEVICE = = p_request - > bmRequestType_bit . recipient & &
TUSB_REQ_TYPE_STANDARD = = p_request - > bmRequestType_bit . type )
2014-03-12 14:01:38 +07:00
{
2018-03-21 15:32:35 +07:00
if ( TUSB_REQ_GET_DESCRIPTOR = = p_request - > bRequest )
2014-03-12 14:01:38 +07:00
{
2018-03-22 14:15:16 +07:00
uint8_t const * buffer = NULL ;
2018-03-23 12:17:47 +07:00
uint16_t const len = get_descriptor ( rhport , p_request , & buffer ) ;
2014-03-12 14:01:38 +07:00
2018-03-22 14:15:16 +07:00
if ( len )
2014-03-12 14:01:38 +07:00
{
2018-03-23 12:17:47 +07:00
STASK_INVOKE ( usbd_control_xfer_st ( rhport , p_request - > bmRequestType_bit . direction , ( uint8_t * ) buffer , len ) , error ) ;
2018-03-22 14:15:16 +07:00
} else
{
2018-03-28 13:54:28 +07:00
dcd_control_stall ( rhport ) ; // stall unsupported descriptor
2014-03-12 14:01:38 +07:00
}
}
2018-03-23 14:57:17 +07:00
else if ( TUSB_REQ_GET_CONFIGURATION = = p_request - > bRequest )
{
memcpy ( usbd_enum_buffer , & usbd_devices [ rhport ] . config_num , 1 ) ;
STASK_INVOKE ( usbd_control_xfer_st ( rhport , p_request - > bmRequestType_bit . direction , ( uint8_t * ) usbd_enum_buffer , 1 ) , error ) ;
}
2018-03-21 15:32:35 +07:00
else if ( TUSB_REQ_SET_ADDRESS = = p_request - > bRequest )
2014-03-12 14:01:38 +07:00
{
2018-03-28 13:47:58 +07:00
dcd_set_address ( rhport , ( uint8_t ) p_request - > wValue ) ;
2018-03-23 12:17:47 +07:00
usbd_devices [ rhport ] . state = TUSB_DEVICE_STATE_ADDRESSED ;
2018-03-14 22:01:16 +07:00
2018-03-22 14:15:16 +07:00
# ifndef NRF52840_XXAA // nrf52 auto handle set address, we must not return status
2018-03-28 13:54:28 +07:00
dcd_control_status ( rhport , p_request - > bmRequestType_bit . direction ) ;
2018-03-21 15:32:35 +07:00
# endif
2014-03-12 14:01:38 +07:00
}
2018-03-21 15:32:35 +07:00
else if ( TUSB_REQ_SET_CONFIGURATION = = p_request - > bRequest )
2014-03-12 14:01:38 +07:00
{
2018-03-23 12:17:47 +07:00
proc_set_config_req ( rhport , ( uint8_t ) p_request - > wValue ) ;
2018-03-28 13:54:28 +07:00
dcd_control_status ( rhport , p_request - > bmRequestType_bit . direction ) ;
2018-03-22 14:15:16 +07:00
}
else
2014-03-12 14:01:38 +07:00
{
2018-03-28 13:54:28 +07:00
dcd_control_stall ( rhport ) ; // Stall unsupported request
2014-03-12 14:01:38 +07:00
}
}
2018-03-22 14:15:16 +07:00
2014-03-12 14:01:38 +07:00
//------------- Class/Interface Specific Request -------------//
2018-03-11 21:05:27 +07:00
else if ( TUSB_REQ_RCPT_INTERFACE = = p_request - > bmRequestType_bit . recipient )
2014-03-12 14:01:38 +07:00
{
2014-04-09 22:29:38 +07:00
static uint8_t class_code ;
2014-03-12 14:01:38 +07:00
2018-03-23 12:17:47 +07:00
class_code = usbd_devices [ rhport ] . interface2class [ u16_low_u8 ( p_request - > wIndex ) ] ;
2014-03-12 14:01:38 +07:00
2014-03-14 17:18:05 +07:00
// TODO [Custom] TUSB_CLASS_DIAGNOSTIC, vendor etc ...
if ( ( class_code > 0 ) & & ( class_code < USBD_CLASS_DRIVER_COUNT ) & &
2018-03-22 16:28:40 +07:00
usbd_class_drivers [ class_code ] . control_request_st )
2014-03-12 14:01:38 +07:00
{
2018-03-23 12:17:47 +07:00
STASK_INVOKE ( usbd_class_drivers [ class_code ] . control_request_st ( rhport , p_request ) , error ) ;
2014-03-12 14:01:38 +07:00
} else
{
2018-03-28 13:54:28 +07:00
dcd_control_stall ( rhport ) ; // Stall unsupported request
2014-03-12 14:01:38 +07:00
}
}
//------------- Endpoint Request -------------//
2018-03-11 21:05:27 +07:00
else if ( TUSB_REQ_RCPT_ENDPOINT = = p_request - > bmRequestType_bit . recipient & &
2018-03-22 14:15:16 +07:00
TUSB_REQ_TYPE_STANDARD = = p_request - > bmRequestType_bit . type )
2014-03-12 14:01:38 +07:00
{
2018-03-22 14:15:16 +07:00
if ( TUSB_REQ_CLEAR_FEATURE = = p_request - > bRequest )
{
2018-03-28 13:47:58 +07:00
dcd_edpt_clear_stall ( rhport , u16_low_u8 ( p_request - > wIndex ) ) ;
2018-03-28 13:54:28 +07:00
dcd_control_status ( rhport , p_request - > bmRequestType_bit . direction ) ;
2018-03-22 14:15:16 +07:00
} else
{
2018-03-28 13:54:28 +07:00
dcd_control_stall ( rhport ) ; // Stall unsupported request
2018-03-22 14:15:16 +07:00
}
2014-03-12 14:01:38 +07:00
}
2018-03-22 14:15:16 +07:00
//------------- Unsupported Request -------------//
else
2014-03-12 14:01:38 +07:00
{
2018-03-28 13:54:28 +07:00
dcd_control_stall ( rhport ) ; // Stall unsupported request
2014-03-12 14:01:38 +07:00
}
OSAL_SUBTASK_END
}
// TODO Host (windows) can get HID report descriptor before set configured
2014-03-23 15:39:55 +07:00
// may need to open interface before set configured
2018-03-23 12:17:47 +07:00
static tusb_error_t proc_set_config_req ( uint8_t rhport , uint8_t config_number )
2014-03-12 14:01:38 +07:00
{
2018-03-28 13:47:58 +07:00
dcd_set_config ( rhport , config_number ) ;
2018-03-23 14:57:17 +07:00
2018-03-23 12:17:47 +07:00
usbd_devices [ rhport ] . state = TUSB_DEVICE_STATE_CONFIGURED ;
2018-03-23 14:57:17 +07:00
usbd_devices [ rhport ] . config_num = config_number ;
2014-03-12 14:01:38 +07:00
//------------- parse configuration & open drivers -------------//
2014-03-23 15:39:55 +07:00
uint8_t const * p_desc_config = tusbd_descriptor_pointers . p_configuration ;
2018-03-23 12:32:40 +07:00
uint8_t const * p_desc = p_desc_config + sizeof ( tusb_desc_configuration_t ) ;
2014-03-12 14:01:38 +07:00
2018-03-23 12:32:40 +07:00
uint16_t const config_total_length = ( ( tusb_desc_configuration_t * ) p_desc_config ) - > wTotalLength ;
2014-03-23 15:39:55 +07:00
while ( p_desc < p_desc_config + config_total_length )
2014-03-12 14:01:38 +07:00
{
2018-03-11 21:16:51 +07:00
if ( TUSB_DESC_INTERFACE_ASSOCIATION = = p_desc [ DESCRIPTOR_OFFSET_TYPE ] )
2014-03-12 14:01:38 +07:00
{
2014-03-18 18:38:15 +07:00
p_desc + = p_desc [ DESCRIPTOR_OFFSET_LENGTH ] ; // ignore Interface Association
2014-03-12 14:01:38 +07:00
} else
{
2018-03-28 14:49:00 +07:00
TU_ASSERT ( TUSB_DESC_INTERFACE = = p_desc [ DESCRIPTOR_OFFSET_TYPE ] , TUSB_ERROR_NOT_SUPPORTED_YET ) ;
2014-03-12 14:01:38 +07:00
uint8_t class_index ;
2018-03-23 12:32:40 +07:00
tusb_desc_interface_t * p_desc_interface = ( tusb_desc_interface_t * ) p_desc ;
2014-03-12 14:01:38 +07:00
class_index = p_desc_interface - > bInterfaceClass ;
2018-03-28 14:49:00 +07:00
TU_ASSERT ( class_index ! = 0 & & class_index < USBD_CLASS_DRIVER_COUNT & & usbd_class_drivers [ class_index ] . open ! = NULL , TUSB_ERROR_NOT_SUPPORTED_YET ) ;
TU_ASSERT ( 0 = = usbd_devices [ rhport ] . interface2class [ p_desc_interface - > bInterfaceNumber ] , TUSB_ERROR_FAILED ) ; // duplicate interface number TODO alternate setting
2014-03-12 14:01:38 +07:00
2018-03-23 12:17:47 +07:00
usbd_devices [ rhport ] . interface2class [ p_desc_interface - > bInterfaceNumber ] = class_index ;
2014-03-12 14:01:38 +07:00
uint16_t length = 0 ;
2018-03-23 12:17:47 +07:00
ASSERT_STATUS ( usbd_class_drivers [ class_index ] . open ( rhport , p_desc_interface , & length ) ) ;
2014-03-12 14:01:38 +07:00
2018-03-28 14:49:00 +07:00
TU_ASSERT ( length > = sizeof ( tusb_desc_interface_t ) , TUSB_ERROR_FAILED ) ;
2014-03-12 14:01:38 +07:00
p_desc + = length ;
}
}
2018-03-07 16:39:33 +07:00
// invoke callback
2018-03-23 12:17:47 +07:00
tud_mount_cb ( rhport ) ;
2018-03-07 16:39:33 +07:00
2014-03-12 14:01:38 +07:00
return TUSB_ERROR_NONE ;
}
2018-03-23 12:17:47 +07:00
static uint16_t get_descriptor ( uint8_t rhport , tusb_control_request_t const * const p_request , uint8_t const * * pp_buffer )
2014-03-12 14:01:38 +07:00
{
2018-03-12 22:37:12 +07:00
tusb_desc_type_t const desc_type = ( tusb_desc_type_t ) u16_high_u8 ( p_request - > wValue ) ;
2014-03-12 14:01:38 +07:00
uint8_t const desc_index = u16_low_u8 ( p_request - > wValue ) ;
2018-03-22 14:15:16 +07:00
uint8_t const * desc_data = NULL ;
uint16_t len = 0 ;
2014-03-12 14:01:38 +07:00
2014-03-23 15:39:55 +07:00
switch ( desc_type )
2014-03-12 14:01:38 +07:00
{
2018-03-11 21:16:51 +07:00
case TUSB_DESC_DEVICE :
2018-03-22 14:15:16 +07:00
desc_data = tusbd_descriptor_pointers . p_device ;
2018-03-23 12:32:40 +07:00
len = sizeof ( tusb_desc_device_t ) ;
2014-03-23 15:39:55 +07:00
break ;
2018-03-11 21:16:51 +07:00
case TUSB_DESC_CONFIGURATION :
2018-03-22 14:15:16 +07:00
desc_data = tusbd_descriptor_pointers . p_configuration ;
2018-03-23 12:32:40 +07:00
len = ( ( tusb_desc_configuration_t * ) tusbd_descriptor_pointers . p_configuration ) - > wTotalLength ;
2014-03-23 15:39:55 +07:00
break ;
2018-03-11 21:16:51 +07:00
case TUSB_DESC_STRING :
2018-03-22 14:15:16 +07:00
// windows sometimes ask for string at index 238 !!!
if ( ! ( desc_index < 100 ) ) return 0 ;
2014-03-23 15:39:55 +07:00
2018-03-22 14:15:16 +07:00
desc_data = tusbd_descriptor_pointers . p_string_arr [ desc_index ] ;
VERIFY ( desc_data ! = NULL , 0 ) ;
2014-03-23 15:39:55 +07:00
2018-03-22 14:15:16 +07:00
len = desc_data [ 0 ] ; // first byte of descriptor is its size
2014-03-23 15:39:55 +07:00
break ;
2018-03-14 22:01:16 +07:00
case TUSB_DESC_DEVICE_QUALIFIER :
// TODO If not highspeed capable stall this request otherwise
// return the descriptor that could work in highspeed
2018-03-22 14:15:16 +07:00
return 0 ;
2018-03-14 22:01:16 +07:00
break ;
2018-03-22 14:15:16 +07:00
default : return 0 ;
2014-03-12 14:01:38 +07:00
}
2018-03-22 14:15:16 +07:00
// up to Host's length
len = min16_of ( p_request - > wLength , len ) ;
2018-03-23 14:57:17 +07:00
TU_ASSERT ( len < = TUSB_CFG_DEVICE_ENUM_BUFFER_SIZE , 0 ) ;
2014-03-23 15:39:55 +07:00
2018-03-22 14:15:16 +07:00
memcpy ( usbd_enum_buffer , desc_data , len ) ;
2014-03-23 15:39:55 +07:00
( * pp_buffer ) = usbd_enum_buffer ;
2014-03-12 14:01:38 +07:00
2018-03-22 14:15:16 +07:00
return len ;
2014-03-12 14:01:38 +07:00
}
//--------------------------------------------------------------------+
// USBD-CLASS API
//--------------------------------------------------------------------+
//--------------------------------------------------------------------+
// USBD-DCD Callback API
//--------------------------------------------------------------------+
2018-03-28 13:47:58 +07:00
void dcd_bus_event ( uint8_t rhport , usbd_bus_event_type_t bus_event )
2014-03-12 14:01:38 +07:00
{
switch ( bus_event )
{
case USBD_BUS_EVENT_RESET :
2018-03-23 12:17:47 +07:00
memclr_ ( & usbd_devices [ rhport ] , sizeof ( usbd_device_info_t ) ) ;
2014-04-24 23:40:28 +07:00
osal_queue_flush ( usbd_queue_hdl ) ;
2014-04-04 12:22:33 +07:00
osal_semaphore_reset ( usbd_control_xfer_sem_hdl ) ;
2014-03-14 17:32:01 +07:00
for ( uint8_t class_code = TUSB_CLASS_AUDIO ; class_code < USBD_CLASS_DRIVER_COUNT ; class_code + + )
2014-03-12 14:01:38 +07:00
{
2018-03-23 12:17:47 +07:00
if ( usbd_class_drivers [ class_code ] . close ) usbd_class_drivers [ class_code ] . close ( rhport ) ;
2014-03-12 14:01:38 +07:00
}
break ;
2018-03-08 14:38:06 +07:00
case USBD_BUS_EVENT_SOF :
{
usbd_task_event_t task_event =
{
2018-03-23 12:17:47 +07:00
. rhport = rhport ,
2018-03-08 14:38:06 +07:00
. event_id = USBD_EVENTID_SOF ,
} ;
osal_queue_send ( usbd_queue_hdl , & task_event ) ;
}
break ;
2018-03-23 14:57:17 +07:00
case USBD_BUS_EVENT_UNPLUGGED :
// invoke callback
tud_umount_cb ( rhport ) ;
break ;
2018-03-03 16:24:43 +07:00
2014-03-12 14:01:38 +07:00
case USBD_BUS_EVENT_SUSPENDED :
2018-03-23 12:17:47 +07:00
usbd_devices [ rhport ] . state = TUSB_DEVICE_STATE_SUSPENDED ;
2014-03-12 14:01:38 +07:00
break ;
default : break ;
}
}
2018-03-28 13:47:58 +07:00
void dcd_setup_received ( uint8_t rhport , uint8_t const * p_request )
2014-03-12 14:01:38 +07:00
{
usbd_task_event_t task_event =
{
2018-03-23 12:17:47 +07:00
. rhport = rhport ,
2014-03-12 14:01:38 +07:00
. event_id = USBD_EVENTID_SETUP_RECEIVED ,
} ;
2018-03-03 14:45:29 +07:00
memcpy ( & task_event . setup_received , p_request , sizeof ( tusb_control_request_t ) ) ;
2018-03-01 12:20:35 +07:00
osal_queue_send ( usbd_queue_hdl , & task_event ) ;
2014-03-12 14:01:38 +07:00
}
2018-03-28 13:47:58 +07:00
void dcd_xfer_complete ( uint8_t rhport , uint8_t ep_addr , uint32_t xferred_bytes , bool succeeded )
2014-03-12 14:01:38 +07:00
{
2018-03-17 02:17:40 +07:00
if ( ep_addr = = 0 )
2014-03-12 14:01:38 +07:00
{
2018-03-23 12:17:47 +07:00
( void ) rhport ;
2018-03-21 16:08:42 +07:00
( void ) xferred_bytes ;
( void ) succeeded ;
2018-03-06 16:50:50 +07:00
// Control Transfer
2018-03-01 11:42:13 +07:00
osal_semaphore_post ( usbd_control_xfer_sem_hdl ) ;
2014-03-12 14:01:38 +07:00
} else
{
usbd_task_event_t task_event =
{
2018-03-23 12:17:47 +07:00
. rhport = rhport ,
2014-03-12 14:01:38 +07:00
. event_id = USBD_EVENTID_XFER_DONE ,
2018-03-11 13:59:37 +07:00
. sub_event_id = succeeded ? TUSB_EVENT_XFER_COMPLETE : TUSB_EVENT_XFER_ERROR
2014-03-12 14:01:38 +07:00
} ;
2018-03-21 16:08:42 +07:00
task_event . xfer_done . ep_addr = ep_addr ;
2014-03-12 14:01:38 +07:00
task_event . xfer_done . xferred_byte = xferred_bytes ;
2018-03-01 12:20:35 +07:00
osal_queue_send ( usbd_queue_hdl , & task_event ) ;
2014-03-12 14:01:38 +07:00
}
}
//--------------------------------------------------------------------+
// HELPER
//--------------------------------------------------------------------+
# endif