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.
|
|
|
|
*/
|
|
|
|
/**************************************************************************/
|
|
|
|
|
2018-11-07 23:04:34 -08:00
|
|
|
// This top level class manages the bus state and delegates events to class-specific drivers.
|
|
|
|
|
2014-03-12 14:01:38 +07:00
|
|
|
#include "tusb_option.h"
|
|
|
|
|
2018-07-23 15:25:45 +07:00
|
|
|
#if TUSB_OPT_DEVICE_ENABLED
|
2014-03-12 14:01:38 +07:00
|
|
|
|
|
|
|
#define _TINY_USB_SOURCE_FILE_
|
|
|
|
|
2018-11-07 23:04:34 -08:00
|
|
|
#include "control.h"
|
2014-03-12 14:01:38 +07:00
|
|
|
#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-06-23 13:19:36 +07:00
|
|
|
#ifndef CFG_TUD_TASK_QUEUE_SZ
|
|
|
|
#define CFG_TUD_TASK_QUEUE_SZ 16
|
|
|
|
#endif
|
2018-05-17 19:19:55 +07:00
|
|
|
|
2018-06-23 13:19:36 +07:00
|
|
|
#ifndef CFG_TUD_TASK_STACK_SZ
|
|
|
|
#define CFG_TUD_TASK_STACK_SZ 150
|
2018-05-17 19:19:55 +07:00
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifndef CFG_TUD_TASK_PRIO
|
|
|
|
#define CFG_TUD_TASK_PRIO 0
|
|
|
|
#endif
|
|
|
|
|
2018-07-13 15:08:38 +07:00
|
|
|
|
2018-04-16 13:46:28 +07:00
|
|
|
//--------------------------------------------------------------------+
|
2018-07-13 15:08:38 +07:00
|
|
|
// Device Data
|
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
typedef struct {
|
|
|
|
uint8_t config_num;
|
2018-07-13 16:52:22 +07:00
|
|
|
|
|
|
|
// map interface number to driver (0xff is invalid)
|
2018-07-13 17:48:26 +07:00
|
|
|
uint8_t itf2drv[16];
|
|
|
|
|
|
|
|
// map endpoint to driver ( 0xff is invalid )
|
|
|
|
uint8_t ep2drv[2][8];
|
2018-07-13 15:08:38 +07:00
|
|
|
}usbd_device_t;
|
|
|
|
|
|
|
|
static usbd_device_t _usbd_dev;
|
|
|
|
|
2018-08-01 00:50:04 +07:00
|
|
|
|
|
|
|
// 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;
|
|
|
|
tud_desc_set_t const* usbd_desc_set = &_usbd_auto_desc_set;
|
|
|
|
#else
|
|
|
|
tud_desc_set_t const* usbd_desc_set = &tud_desc_set;
|
|
|
|
#endif
|
|
|
|
|
2018-07-13 15:08:38 +07:00
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
// Class Driver
|
2018-04-16 13:46:28 +07:00
|
|
|
//--------------------------------------------------------------------+
|
2018-03-23 14:57:17 +07:00
|
|
|
typedef struct {
|
2018-05-14 13:02:01 +07:00
|
|
|
uint8_t class_code;
|
|
|
|
|
2018-06-16 12:30:10 +07:00
|
|
|
void (* init ) (void);
|
|
|
|
tusb_error_t (* open ) (uint8_t rhport, tusb_desc_interface_t const * desc_intf, uint16_t* p_length);
|
2018-11-07 23:04:34 -08:00
|
|
|
// 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);
|
2018-11-08 13:45:30 -08:00
|
|
|
void (* control_request_complete ) (uint8_t rhport, tusb_control_request_t const *);
|
2018-06-16 12:30:10 +07:00
|
|
|
tusb_error_t (* xfer_cb ) (uint8_t rhport, uint8_t ep_addr, tusb_event_t, uint32_t);
|
|
|
|
void (* sof ) (uint8_t rhport);
|
2018-07-13 16:09:26 +07:00
|
|
|
void (* reset ) (uint8_t);
|
2018-03-23 14:57:17 +07:00
|
|
|
} usbd_class_driver_t;
|
|
|
|
|
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
|
|
|
{
|
2018-11-07 23:04:34 -08:00
|
|
|
{
|
|
|
|
.class_code = TUSB_CLASS_UNSPECIFIED,
|
|
|
|
.init = controld_init,
|
|
|
|
.open = NULL,
|
|
|
|
.control_request = NULL,
|
2018-11-08 13:45:30 -08:00
|
|
|
.control_request_complete = NULL,
|
2018-11-07 23:04:34 -08:00
|
|
|
.xfer_cb = controld_xfer_cb,
|
|
|
|
.sof = NULL,
|
|
|
|
.reset = controld_reset
|
|
|
|
},
|
2018-05-14 13:02:01 +07:00
|
|
|
#if CFG_TUD_CDC
|
2014-03-12 14:01:38 +07:00
|
|
|
{
|
2018-11-07 23:04:34 -08:00
|
|
|
.class_code = TUSB_CLASS_CDC,
|
|
|
|
.init = cdcd_init,
|
|
|
|
.open = cdcd_open,
|
|
|
|
.control_request = cdcd_control_request,
|
2018-11-08 13:45:30 -08:00
|
|
|
.control_request_complete = cdcd_control_request_complete,
|
2018-11-07 23:04:34 -08:00
|
|
|
.xfer_cb = cdcd_xfer_cb,
|
|
|
|
.sof = NULL,
|
|
|
|
.reset = cdcd_reset
|
2014-03-12 14:01:38 +07:00
|
|
|
},
|
2014-03-14 17:18:05 +07:00
|
|
|
#endif
|
2014-03-12 14:01:38 +07:00
|
|
|
|
2018-05-14 13:02:01 +07:00
|
|
|
#if CFG_TUD_MSC
|
2014-03-12 14:01:38 +07:00
|
|
|
{
|
2018-11-07 23:04:34 -08:00
|
|
|
.class_code = TUSB_CLASS_MSC,
|
|
|
|
.init = mscd_init,
|
|
|
|
.open = mscd_open,
|
|
|
|
.control_request = mscd_control_request,
|
2018-11-08 13:45:30 -08:00
|
|
|
.control_request_complete = mscd_control_request_complete,
|
2018-11-07 23:04:34 -08:00
|
|
|
.xfer_cb = mscd_xfer_cb,
|
|
|
|
.sof = NULL,
|
|
|
|
.reset = mscd_reset
|
2018-06-16 12:30:10 +07:00
|
|
|
},
|
|
|
|
#endif
|
|
|
|
|
2018-07-13 17:48:26 +07:00
|
|
|
|
2018-07-28 12:38:45 +07:00
|
|
|
#if CFG_TUD_HID
|
2018-07-13 17:48:26 +07:00
|
|
|
{
|
2018-11-07 23:04:34 -08:00
|
|
|
.class_code = TUSB_CLASS_HID,
|
|
|
|
.init = hidd_init,
|
|
|
|
.open = hidd_open,
|
|
|
|
.control_request = hidd_control_request,
|
2018-11-08 13:45:30 -08:00
|
|
|
.control_request_complete = hidd_control_request_complete,
|
2018-11-07 23:04:34 -08:00
|
|
|
.xfer_cb = hidd_xfer_cb,
|
|
|
|
.sof = NULL,
|
|
|
|
.reset = hidd_reset
|
2018-07-13 17:48:26 +07:00
|
|
|
},
|
|
|
|
#endif
|
|
|
|
|
2018-06-16 12:30:10 +07:00
|
|
|
#if CFG_TUD_CUSTOM_CLASS
|
|
|
|
{
|
2018-11-07 23:04:34 -08:00
|
|
|
.class_code = TUSB_CLASS_VENDOR_SPECIFIC,
|
|
|
|
.init = cusd_init,
|
|
|
|
.open = cusd_open,
|
|
|
|
.control_request = cusd_control_request,
|
2018-11-08 13:45:30 -08:00
|
|
|
.control_request_complete = cusd_control_request_complete,
|
2018-11-07 23:04:34 -08:00
|
|
|
.xfer_cb = cusd_xfer_cb,
|
|
|
|
.sof = NULL,
|
|
|
|
.reset = cusd_reset
|
2014-03-12 14:01:38 +07:00
|
|
|
},
|
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-04-16 13:46:28 +07:00
|
|
|
|
2014-03-12 14:01:38 +07:00
|
|
|
//--------------------------------------------------------------------+
|
2018-05-17 19:19:55 +07:00
|
|
|
// DCD Event
|
2014-03-12 14:01:38 +07:00
|
|
|
//--------------------------------------------------------------------+
|
2018-06-23 13:19:36 +07:00
|
|
|
OSAL_TASK_DEF(_usbd_task_def, "usbd", usbd_task, CFG_TUD_TASK_PRIO, CFG_TUD_TASK_STACK_SZ);
|
2018-05-17 20:04:52 +07:00
|
|
|
|
2018-05-17 19:19:55 +07:00
|
|
|
/*------------- event queue -------------*/
|
2018-10-23 15:08:31 +07:00
|
|
|
OSAL_QUEUE_DEF(_usbd_qdef, CFG_TUD_TASK_QUEUE_SZ, dcd_event_t);
|
2018-05-17 19:19:55 +07:00
|
|
|
static osal_queue_t _usbd_q;
|
2018-02-28 14:21:31 +07:00
|
|
|
|
2018-05-17 19:19:55 +07:00
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
// INTERNAL FUNCTION
|
|
|
|
//--------------------------------------------------------------------+
|
2018-07-13 17:48:26 +07:00
|
|
|
static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
|
2014-03-12 14:01:38 +07:00
|
|
|
|
2018-05-17 19:19:55 +07:00
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
// APPLICATION API
|
|
|
|
//--------------------------------------------------------------------+
|
2018-07-12 22:25:06 +07:00
|
|
|
bool tud_mounted(void)
|
2018-05-17 19:19:55 +07:00
|
|
|
{
|
2018-07-13 15:08:38 +07:00
|
|
|
return _usbd_dev.config_num > 0;
|
2018-05-17 19:19:55 +07:00
|
|
|
}
|
|
|
|
|
2014-03-31 13:12:51 +07:00
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
// IMPLEMENTATION
|
|
|
|
//--------------------------------------------------------------------+
|
2018-03-30 16:24:55 +07:00
|
|
|
static tusb_error_t usbd_main_st(void);
|
2014-03-31 13:12:51 +07:00
|
|
|
|
|
|
|
tusb_error_t usbd_init (void)
|
|
|
|
{
|
2018-04-14 14:08:48 +07:00
|
|
|
#if (CFG_TUSB_RHPORT0_MODE & OPT_MODE_DEVICE)
|
2018-03-28 13:47:58 +07:00
|
|
|
dcd_init(0);
|
2018-03-02 22:46:36 +07:00
|
|
|
#endif
|
|
|
|
|
2018-04-14 14:08:48 +07:00
|
|
|
#if (CFG_TUSB_RHPORT1_MODE & OPT_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-05-17 19:19:55 +07:00
|
|
|
_usbd_q = osal_queue_create(&_usbd_qdef);
|
2018-08-13 18:10:23 +07:00
|
|
|
TU_VERIFY(_usbd_q, TUSB_ERROR_OSAL_QUEUE_FAILED);
|
2014-03-31 13:12:51 +07:00
|
|
|
|
2018-05-17 20:04:52 +07:00
|
|
|
osal_task_create(&_usbd_task_def);
|
2018-02-28 14:21:31 +07:00
|
|
|
|
2014-03-31 13:12:51 +07:00
|
|
|
//------------- class init -------------//
|
2018-07-13 16:52:22 +07:00
|
|
|
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++) usbd_class_drivers[i].init();
|
2014-03-31 13:12:51 +07:00
|
|
|
|
|
|
|
return TUSB_ERROR_NONE;
|
|
|
|
}
|
|
|
|
|
2018-11-02 17:29:49 +07:00
|
|
|
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
|
2018-11-07 23:04:34 -08:00
|
|
|
// 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;
|
2018-11-02 17:29:49 +07:00
|
|
|
|
|
|
|
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
|
|
|
|
{
|
|
|
|
if ( usbd_class_drivers[i].reset ) usbd_class_drivers[i].reset( rhport );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-31 13:12:51 +07:00
|
|
|
// 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-08-30 15:21:15 +07:00
|
|
|
|
|
|
|
// Within tinyusb stack, all task's code must be placed in subtask to be able to support multiple RTOS
|
|
|
|
// including none.
|
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-30 16:24:55 +07:00
|
|
|
usbd_main_st();
|
2018-03-01 12:14:44 +07:00
|
|
|
OSAL_TASK_END
|
2014-03-31 13:12:51 +07:00
|
|
|
}
|
|
|
|
|
2018-03-30 16:24:55 +07:00
|
|
|
static tusb_error_t usbd_main_st(void)
|
2014-03-31 13:12:51 +07:00
|
|
|
{
|
2018-10-24 23:55:10 -07:00
|
|
|
dcd_event_t event;
|
|
|
|
tusb_error_t err = TUSB_ERROR_NONE;
|
2018-08-28 15:56:43 +07:00
|
|
|
// Loop until there is no more events in the queue
|
2018-10-24 23:55:10 -07:00
|
|
|
while (_usbd_q->count > 0)
|
2018-08-28 15:56:43 +07:00
|
|
|
{
|
2018-10-23 15:08:31 +07:00
|
|
|
tu_memclr(&event, sizeof(dcd_event_t));
|
2014-03-31 13:12:51 +07:00
|
|
|
|
2018-10-24 23:55:10 -07:00
|
|
|
err = osal_queue_receive(_usbd_q, &event);
|
|
|
|
if (err != TUSB_ERROR_NONE) {
|
|
|
|
break;
|
|
|
|
}
|
2018-07-13 18:01:16 +07:00
|
|
|
|
2018-10-23 15:12:30 +07:00
|
|
|
if ( DCD_EVENT_SETUP_RECEIVED == event.event_id )
|
2018-03-06 16:50:50 +07:00
|
|
|
{
|
2018-11-07 23:04:34 -08:00
|
|
|
// Setup tokens are unique to the Control endpointso we delegate to it directly.
|
|
|
|
controld_process_setup_request(event.rhport, &event.setup_received);
|
2018-03-06 16:50:50 +07:00
|
|
|
}
|
2018-10-23 15:12:30 +07:00
|
|
|
else if (DCD_EVENT_XFER_COMPLETE == event.event_id)
|
2018-03-08 14:38:06 +07:00
|
|
|
{
|
2018-08-28 15:56:43 +07:00
|
|
|
// Invoke the class callback associated with the endpoint address
|
2018-10-23 13:09:54 +07:00
|
|
|
uint8_t const ep_addr = event.xfer_complete.ep_addr;
|
2018-08-28 15:56:43 +07:00
|
|
|
uint8_t const drv_id = _usbd_dev.ep2drv[ edpt_dir(ep_addr) ][ edpt_number(ep_addr) ];
|
|
|
|
|
|
|
|
if (drv_id < USBD_CLASS_DRIVER_COUNT)
|
2018-03-08 14:38:06 +07:00
|
|
|
{
|
2018-10-24 23:55:10 -07:00
|
|
|
usbd_class_drivers[drv_id].xfer_cb( event.rhport, ep_addr, event.xfer_complete.result, event.xfer_complete.len);
|
2018-03-08 14:38:06 +07:00
|
|
|
}
|
|
|
|
}
|
2018-11-02 17:29:49 +07:00
|
|
|
else if (DCD_EVENT_BUS_RESET == event.event_id)
|
|
|
|
{
|
|
|
|
usbd_reset(event.rhport);
|
|
|
|
osal_queue_reset(_usbd_q);
|
|
|
|
}
|
|
|
|
else if (DCD_EVENT_UNPLUGGED == event.event_id)
|
|
|
|
{
|
|
|
|
usbd_reset(event.rhport);
|
|
|
|
osal_queue_reset(_usbd_q);
|
|
|
|
|
|
|
|
tud_umount_cb(); // invoke callback
|
|
|
|
}
|
2018-10-23 15:12:30 +07:00
|
|
|
else if (DCD_EVENT_SOF == event.event_id)
|
2018-08-28 15:56:43 +07:00
|
|
|
{
|
|
|
|
for (uint8_t i = 0; i < USBD_CLASS_DRIVER_COUNT; i++)
|
|
|
|
{
|
|
|
|
if ( usbd_class_drivers[i].sof )
|
|
|
|
{
|
|
|
|
usbd_class_drivers[i].sof( event.rhport );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if ( USBD_EVT_FUNC_CALL == event.event_id )
|
|
|
|
{
|
|
|
|
if ( event.func_call.func ) event.func_call.func(event.func_call.param);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-10-24 12:37:43 +07:00
|
|
|
TU_BREAKPOINT();
|
2018-08-28 15:56:43 +07:00
|
|
|
}
|
2014-03-31 13:12:51 +07:00
|
|
|
}
|
|
|
|
|
2018-10-24 23:55:10 -07:00
|
|
|
return err;
|
2014-03-31 13:12:51 +07:00
|
|
|
}
|
|
|
|
|
2018-11-08 13:45:30 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-11-07 23:04:34 -08:00
|
|
|
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)
|
2018-07-25 21:21:33 +07:00
|
|
|
{
|
2018-11-07 23:04:34 -08:00
|
|
|
return usbd_class_drivers[_usbd_dev.itf2drv[interface]].control_request(rhport, p_request, bytes_already_sent);
|
2018-07-25 21:21:33 +07:00
|
|
|
}
|
2018-11-07 23:04:34 -08:00
|
|
|
return TUSB_ERROR_FAILED;
|
2014-03-12 14:01:38 +07:00
|
|
|
}
|
|
|
|
|
2018-07-13 17:48:26 +07:00
|
|
|
// Process Set Configure Request
|
2014-03-12 14:01:38 +07:00
|
|
|
// 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-11-07 23:04:34 -08:00
|
|
|
tusb_error_t tud_control_set_config_cb(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-07-12 22:25:06 +07:00
|
|
|
_usbd_dev.config_num = config_number;
|
2014-03-12 14:01:38 +07:00
|
|
|
|
|
|
|
//------------- parse configuration & open drivers -------------//
|
2018-08-01 00:50:04 +07:00
|
|
|
uint8_t const * desc_cfg = (uint8_t const *) usbd_desc_set->config;
|
2018-07-01 15:11:58 +07:00
|
|
|
TU_ASSERT(desc_cfg != NULL, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
|
|
|
|
uint8_t const * p_desc = desc_cfg + sizeof(tusb_desc_configuration_t);
|
|
|
|
uint16_t const cfg_len = ((tusb_desc_configuration_t*)desc_cfg)->wTotalLength;
|
2014-03-23 15:39:55 +07:00
|
|
|
|
2018-07-01 15:11:58 +07:00
|
|
|
while( p_desc < desc_cfg + cfg_len )
|
2014-03-12 14:01:38 +07:00
|
|
|
{
|
2018-07-13 17:48:26 +07:00
|
|
|
if ( TUSB_DESC_INTERFACE_ASSOCIATION == descriptor_type(p_desc) )
|
2014-03-12 14:01:38 +07:00
|
|
|
{
|
2018-07-13 17:48:26 +07:00
|
|
|
p_desc = descriptor_next(p_desc); // ignore Interface Association
|
2014-03-12 14:01:38 +07:00
|
|
|
}else
|
|
|
|
{
|
2018-07-13 17:48:26 +07:00
|
|
|
TU_ASSERT( TUSB_DESC_INTERFACE == descriptor_type(p_desc), TUSB_ERROR_NOT_SUPPORTED_YET );
|
2014-03-12 14:01:38 +07:00
|
|
|
|
2018-05-14 13:02:01 +07:00
|
|
|
tusb_desc_interface_t* p_desc_itf = (tusb_desc_interface_t*) p_desc;
|
|
|
|
uint8_t const class_code = p_desc_itf->bInterfaceClass;
|
2014-03-12 14:01:38 +07:00
|
|
|
|
2018-05-14 13:02:01 +07:00
|
|
|
// Check if class is supported
|
2018-07-13 17:48:26 +07:00
|
|
|
uint8_t drv_id;
|
|
|
|
for (drv_id = 0; drv_id < USBD_CLASS_DRIVER_COUNT; drv_id++)
|
2018-05-14 13:02:01 +07:00
|
|
|
{
|
2018-07-13 17:48:26 +07:00
|
|
|
if ( usbd_class_drivers[drv_id].class_code == class_code ) break;
|
2018-05-14 13:02:01 +07:00
|
|
|
}
|
2018-07-13 17:48:26 +07:00
|
|
|
TU_ASSERT( drv_id < USBD_CLASS_DRIVER_COUNT, TUSB_ERROR_NOT_SUPPORTED_YET );
|
2014-03-12 14:01:38 +07:00
|
|
|
|
2018-07-13 16:52:22 +07:00
|
|
|
// Interface number must not be used
|
|
|
|
TU_ASSERT( 0xff == _usbd_dev.itf2drv[p_desc_itf->bInterfaceNumber], TUSB_ERROR_FAILED);
|
2018-07-13 17:48:26 +07:00
|
|
|
_usbd_dev.itf2drv[p_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 );
|
2014-03-12 14:01:38 +07:00
|
|
|
|
2018-07-13 17:48:26 +07:00
|
|
|
mark_interface_endpoint(p_desc, len, drv_id);
|
2014-03-12 14:01:38 +07:00
|
|
|
|
2018-07-13 17:48:26 +07:00
|
|
|
p_desc += len; // next interface
|
2014-03-12 14:01:38 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-07 16:39:33 +07:00
|
|
|
// invoke callback
|
2018-07-13 14:26:40 +07:00
|
|
|
tud_mount_cb();
|
2018-03-07 16:39:33 +07:00
|
|
|
|
2014-03-12 14:01:38 +07:00
|
|
|
return TUSB_ERROR_NONE;
|
|
|
|
}
|
|
|
|
|
2018-07-13 17:48:26 +07:00
|
|
|
// Helper marking endpoint of interface belongs to class driver
|
|
|
|
static void mark_interface_endpoint(uint8_t const* p_desc, uint16_t desc_len, uint8_t driver_id)
|
|
|
|
{
|
|
|
|
uint16_t len = 0;
|
|
|
|
|
|
|
|
while( len < desc_len )
|
|
|
|
{
|
|
|
|
if ( TUSB_DESC_ENDPOINT == descriptor_type(p_desc) )
|
|
|
|
{
|
|
|
|
uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
|
|
|
|
|
|
|
|
_usbd_dev.ep2drv[ edpt_dir(ep_addr) ][ edpt_number(ep_addr) ] = driver_id;
|
|
|
|
}
|
|
|
|
|
|
|
|
len += descriptor_len(p_desc);
|
|
|
|
p_desc = descriptor_next(p_desc);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-03-12 14:01:38 +07:00
|
|
|
//--------------------------------------------------------------------+
|
|
|
|
// USBD-DCD Callback API
|
|
|
|
//--------------------------------------------------------------------+
|
2018-10-23 15:08:31 +07:00
|
|
|
void dcd_event_handler(dcd_event_t const * event, bool in_isr)
|
|
|
|
{
|
|
|
|
switch (event->event_id)
|
|
|
|
{
|
2018-10-23 15:12:30 +07:00
|
|
|
case DCD_EVENT_BUS_RESET:
|
|
|
|
case DCD_EVENT_UNPLUGGED:
|
2018-11-02 17:29:49 +07:00
|
|
|
case DCD_EVENT_SOF:
|
|
|
|
osal_queue_send(_usbd_q, event, in_isr);
|
2018-10-23 15:08:31 +07:00
|
|
|
break;
|
|
|
|
|
2018-10-23 15:12:30 +07:00
|
|
|
case DCD_EVENT_SUSPENDED:
|
2018-10-23 15:08:31 +07:00
|
|
|
// TODO support suspended
|
|
|
|
break;
|
|
|
|
|
2018-10-23 15:12:30 +07:00
|
|
|
case DCD_EVENT_RESUME:
|
2018-10-23 15:08:31 +07:00
|
|
|
// TODO support resume
|
|
|
|
break;
|
|
|
|
|
2018-10-23 16:07:48 +07:00
|
|
|
case DCD_EVENT_SETUP_RECEIVED:
|
|
|
|
osal_queue_send(_usbd_q, event, in_isr);
|
|
|
|
break;
|
2018-10-23 15:08:31 +07:00
|
|
|
|
2018-10-24 00:44:26 +07:00
|
|
|
case DCD_EVENT_XFER_COMPLETE:
|
2018-11-07 23:04:34 -08:00
|
|
|
osal_queue_send(_usbd_q, event, in_isr);
|
2018-10-24 00:44:26 +07:00
|
|
|
TU_ASSERT(event->xfer_complete.result == DCD_XFER_SUCCESS,);
|
|
|
|
break;
|
|
|
|
|
2018-10-23 16:07:48 +07:00
|
|
|
default: break;
|
2018-10-23 15:08:31 +07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-24 23:55:10 -07:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
dcd_event_t event = { .rhport = 0, .event_id = eid, };
|
|
|
|
dcd_event_handler(&event, in_isr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// helper to send setup received
|
|
|
|
void dcd_event_setup_received(uint8_t rhport, uint8_t const * setup, bool in_isr)
|
|
|
|
{
|
|
|
|
dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_SETUP_RECEIVED };
|
|
|
|
memcpy(&event.setup_received, setup, 8);
|
|
|
|
|
|
|
|
dcd_event_handler(&event, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
// helper to send transfer complete event
|
|
|
|
void dcd_event_xfer_complete (uint8_t rhport, uint8_t ep_addr, uint32_t xferred_bytes, uint8_t result, bool in_isr)
|
|
|
|
{
|
|
|
|
dcd_event_t event = { .rhport = 0, .event_id = DCD_EVENT_XFER_COMPLETE };
|
|
|
|
|
|
|
|
event.xfer_complete.ep_addr = ep_addr;
|
|
|
|
event.xfer_complete.len = xferred_bytes;
|
|
|
|
event.xfer_complete.result = result;
|
|
|
|
|
|
|
|
dcd_event_handler(&event, in_isr);
|
|
|
|
}
|
|
|
|
|
2014-03-12 14:01:38 +07:00
|
|
|
//--------------------------------------------------------------------+
|
2018-06-22 12:53:13 +07:00
|
|
|
// Helper
|
2014-03-12 14:01:38 +07:00
|
|
|
//--------------------------------------------------------------------+
|
2018-10-24 23:55:10 -07:00
|
|
|
|
2018-06-16 12:30:10 +07:00
|
|
|
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)
|
|
|
|
{
|
|
|
|
for(int i=0; i<2; i++)
|
|
|
|
{
|
|
|
|
TU_ASSERT(TUSB_DESC_ENDPOINT == p_desc_ep->bDescriptorType &&
|
|
|
|
xfer_type == p_desc_ep->bmAttributes.xfer, TUSB_ERROR_DESCRIPTOR_CORRUPTED);
|
|
|
|
|
|
|
|
TU_ASSERT( dcd_edpt_open(rhport, p_desc_ep), TUSB_ERROR_DCD_OPEN_PIPE_FAILED );
|
|
|
|
|
2018-06-18 14:31:15 +07:00
|
|
|
if ( edpt_dir(p_desc_ep->bEndpointAddress) == TUSB_DIR_IN )
|
2018-06-16 12:30:10 +07:00
|
|
|
{
|
|
|
|
(*ep_in) = p_desc_ep->bEndpointAddress;
|
|
|
|
}else
|
|
|
|
{
|
|
|
|
(*ep_out) = p_desc_ep->bEndpointAddress;
|
|
|
|
}
|
2014-03-12 14:01:38 +07:00
|
|
|
|
2018-06-16 12:30:10 +07:00
|
|
|
p_desc_ep = (tusb_desc_endpoint_t const *) descriptor_next( (uint8_t const*) p_desc_ep );
|
|
|
|
}
|
|
|
|
|
|
|
|
return TUSB_ERROR_NONE;
|
|
|
|
}
|
2018-06-22 12:53:13 +07:00
|
|
|
|
2018-10-23 16:07:48 +07:00
|
|
|
void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr )
|
2018-06-22 12:53:13 +07:00
|
|
|
{
|
2018-10-23 15:08:31 +07:00
|
|
|
dcd_event_t event =
|
2018-06-22 12:53:13 +07:00
|
|
|
{
|
2018-07-13 14:26:40 +07:00
|
|
|
.rhport = 0,
|
|
|
|
.event_id = USBD_EVT_FUNC_CALL,
|
2018-06-22 12:53:13 +07:00
|
|
|
};
|
|
|
|
|
|
|
|
event.func_call.func = func;
|
|
|
|
event.func_call.param = param;
|
|
|
|
|
2018-10-23 16:07:48 +07:00
|
|
|
osal_queue_send(_usbd_q, &event, in_isr);
|
2018-06-22 12:53:13 +07:00
|
|
|
}
|
|
|
|
|
2014-03-12 14:01:38 +07:00
|
|
|
#endif
|