mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-17 05:32:55 +08:00
Merge pull request #1035 from hathach/improve-host-stack
Improve host stack
This commit is contained in:
commit
58477b71f2
@ -61,6 +61,8 @@ void hid_app_task(void)
|
||||
// Invoked when device with hid interface is mounted
|
||||
// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
|
||||
// can be used to parse common/simple enough descriptor.
|
||||
// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
|
||||
// therefore report_desc = NULL, desc_len = 0
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
|
||||
{
|
||||
printf("HID device address = %d, instance = %d is mounted\r\n", dev_addr, instance);
|
||||
|
@ -149,7 +149,7 @@ void cdch_init(void)
|
||||
tu_memclr(cdch_data, sizeof(cdch_data_t)*CFG_TUSB_HOST_DEVICE_MAX);
|
||||
}
|
||||
|
||||
uint16_t cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
|
||||
bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
|
||||
{
|
||||
(void) max_len;
|
||||
|
||||
@ -157,7 +157,7 @@ uint16_t cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
|
||||
// Protocol 0xFF can be RNDIS device for windows XP
|
||||
TU_VERIFY( TUSB_CLASS_CDC == itf_desc->bInterfaceClass &&
|
||||
CDC_COMM_SUBCLASS_ABSTRACT_CONTROL_MODEL == itf_desc->bInterfaceSubClass &&
|
||||
0xFF != itf_desc->bInterfaceProtocol, 0);
|
||||
0xFF != itf_desc->bInterfaceProtocol);
|
||||
|
||||
cdch_data_t * p_cdc = get_itf(dev_addr);
|
||||
|
||||
@ -186,7 +186,7 @@ uint16_t cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
|
||||
// notification endpoint
|
||||
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
|
||||
|
||||
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep), 0 );
|
||||
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
|
||||
p_cdc->ep_notif = desc_ep->bEndpointAddress;
|
||||
|
||||
drv_len += tu_desc_len(p_desc);
|
||||
@ -205,9 +205,9 @@ uint16_t cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer, 0);
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType && TUSB_XFER_BULK == desc_ep->bmAttributes.xfer);
|
||||
|
||||
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep), 0);
|
||||
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, desc_ep));
|
||||
|
||||
if ( tu_edpt_dir(desc_ep->bEndpointAddress) == TUSB_DIR_IN )
|
||||
{
|
||||
@ -222,7 +222,7 @@ uint16_t cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
|
||||
}
|
||||
}
|
||||
|
||||
return drv_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num)
|
||||
|
@ -121,11 +121,11 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void cdch_init (void);
|
||||
uint16_t cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
|
||||
bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void cdch_close (uint8_t dev_addr);
|
||||
void cdch_init (void);
|
||||
bool cdch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
|
||||
bool cdch_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool cdch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void cdch_close (uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -247,19 +247,24 @@ static bool config_set_protocol (uint8_t dev_addr, tusb_control_requ
|
||||
static bool config_get_report_desc (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||
static bool config_get_report_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result);
|
||||
|
||||
uint16_t hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
|
||||
static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len);
|
||||
|
||||
bool hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
|
||||
{
|
||||
(void) max_len;
|
||||
|
||||
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
|
||||
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass);
|
||||
|
||||
// len = interface + hid + n*endpoints
|
||||
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
|
||||
TU_ASSERT(max_len >= drv_len);
|
||||
|
||||
uint16_t drv_len = sizeof(tusb_desc_interface_t);
|
||||
uint8_t const *p_desc = (uint8_t const *) desc_itf;
|
||||
|
||||
//------------- HID descriptor -------------//
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
tusb_hid_descriptor_hid_t const *desc_hid = (tusb_hid_descriptor_hid_t const *) p_desc;
|
||||
TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType, 0);
|
||||
TU_ASSERT(HID_DESC_TYPE_HID == desc_hid->bDescriptorType);
|
||||
|
||||
// not enough interface, try to increase CFG_TUH_HID
|
||||
// TODO multiple devices
|
||||
@ -267,13 +272,12 @@ uint16_t hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
|
||||
TU_ASSERT(hid_dev->inst_count < CFG_TUH_HID, 0);
|
||||
|
||||
//------------- Endpoint Descriptor -------------//
|
||||
drv_len += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
tusb_desc_endpoint_t const * desc_ep = (tusb_desc_endpoint_t const *) p_desc;
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType, 0);
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == desc_ep->bDescriptorType);
|
||||
|
||||
// TODO also open endpoint OUT
|
||||
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep), 0 );
|
||||
TU_ASSERT( usbh_edpt_open(rhport, dev_addr, desc_ep) );
|
||||
|
||||
hidh_interface_t* hid_itf = get_instance(dev_addr, hid_dev->inst_count);
|
||||
hid_dev->inst_count++;
|
||||
@ -290,9 +294,7 @@ uint16_t hidh_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
|
||||
hid_itf->protocol_mode = HID_PROTOCOL_BOOT;
|
||||
if ( HID_SUBCLASS_BOOT == desc_itf->bInterfaceSubClass ) hid_itf->itf_protocol = desc_itf->bInterfaceProtocol;
|
||||
|
||||
drv_len += desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
|
||||
|
||||
return drv_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num)
|
||||
@ -367,26 +369,34 @@ static bool config_get_report_desc(uint8_t dev_addr, tusb_control_request_t cons
|
||||
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
|
||||
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
|
||||
|
||||
// Get Report Descriptor
|
||||
// Get Report Descriptor if possible
|
||||
// using usbh enumeration buffer since report descriptor can be very long
|
||||
TU_ASSERT( hid_itf->report_desc_len <= CFG_TUH_ENUMERATION_BUFSIZE );
|
||||
|
||||
TU_LOG2("HID Get Report Descriptor\r\n");
|
||||
tusb_control_request_t const new_request =
|
||||
if( hid_itf->report_desc_len > CFG_TUH_ENUMERATION_BUFSIZE )
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_STANDARD,
|
||||
.direction = TUSB_DIR_IN
|
||||
},
|
||||
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
|
||||
.wValue = tu_u16(hid_itf->report_desc_type, 0),
|
||||
.wIndex = itf_num,
|
||||
.wLength = hid_itf->report_desc_len
|
||||
};
|
||||
TU_LOG2("HID Skip Report Descriptor since it is too large %u bytes\r\n", hid_itf->report_desc_len);
|
||||
|
||||
// Driver is mounted without report descriptor
|
||||
config_driver_mount_complete(dev_addr, instance, NULL, 0);
|
||||
}else
|
||||
{
|
||||
TU_LOG2("HID Get Report Descriptor\r\n");
|
||||
tusb_control_request_t const new_request =
|
||||
{
|
||||
.bmRequestType_bit =
|
||||
{
|
||||
.recipient = TUSB_REQ_RCPT_INTERFACE,
|
||||
.type = TUSB_REQ_TYPE_STANDARD,
|
||||
.direction = TUSB_DIR_IN
|
||||
},
|
||||
.bRequest = TUSB_REQ_GET_DESCRIPTOR,
|
||||
.wValue = tu_u16(hid_itf->report_desc_type, 0),
|
||||
.wIndex = itf_num,
|
||||
.wLength = hid_itf->report_desc_len
|
||||
};
|
||||
|
||||
TU_ASSERT(tuh_control_xfer(dev_addr, &new_request, usbh_get_enum_buf(), config_get_report_desc_complete));
|
||||
}
|
||||
|
||||
TU_ASSERT(tuh_control_xfer(dev_addr, &new_request, usbh_get_enum_buf(), config_get_report_desc_complete));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -394,13 +404,21 @@ static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_reque
|
||||
{
|
||||
TU_ASSERT(XFER_RESULT_SUCCESS == result);
|
||||
|
||||
uint8_t const itf_num = (uint8_t) request->wIndex;
|
||||
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
|
||||
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
|
||||
uint8_t const itf_num = (uint8_t) request->wIndex;
|
||||
uint8_t const instance = get_instance_id_by_itfnum(dev_addr, itf_num);
|
||||
|
||||
uint8_t const* desc_report = usbh_get_enum_buf();
|
||||
uint16_t const desc_len = request->wLength;
|
||||
|
||||
config_driver_mount_complete(dev_addr, instance, desc_report, desc_len);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void config_driver_mount_complete(uint8_t dev_addr, uint8_t instance, uint8_t const* desc_report, uint16_t desc_len)
|
||||
{
|
||||
hidh_interface_t* hid_itf = get_instance(dev_addr, instance);
|
||||
|
||||
// enumeration is complete
|
||||
tuh_hid_mount_cb(dev_addr, instance, desc_report, desc_len);
|
||||
|
||||
@ -408,9 +426,7 @@ static bool config_get_report_desc_complete(uint8_t dev_addr, tusb_control_reque
|
||||
hidh_get_report(dev_addr, hid_itf);
|
||||
|
||||
// notify usbh that driver enumeration is complete
|
||||
usbh_driver_set_config_complete(dev_addr, itf_num);
|
||||
|
||||
return true;
|
||||
usbh_driver_set_config_complete(dev_addr, hid_itf->itf_num);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
|
@ -97,6 +97,8 @@ uint8_t tuh_hid_parse_report_descriptor(tuh_hid_report_info_t* reports_info_arr,
|
||||
// Invoked when device with hid interface is mounted
|
||||
// Report descriptor is also available for use. tuh_hid_parse_report_descriptor()
|
||||
// can be used to parse common/simple enough descriptor.
|
||||
// Note: if report descriptor length > CFG_TUH_ENUMERATION_BUFSIZE, it will be skipped
|
||||
// therefore report_desc = NULL, desc_len = 0
|
||||
void tuh_hid_mount_cb(uint8_t dev_addr, uint8_t instance, uint8_t const* report_desc, uint16_t desc_len);
|
||||
|
||||
// Invoked when device with hid interface is un-mounted
|
||||
@ -119,11 +121,11 @@ TU_ATTR_WEAK void tuh_hid_set_protocol_complete_cb(uint8_t dev_addr, uint8_t ins
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void hidh_init (void);
|
||||
uint16_t hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
|
||||
bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
void hidh_close (uint8_t dev_addr);
|
||||
void hidh_init (void);
|
||||
bool hidh_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
|
||||
bool hidh_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool hidh_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
void hidh_close (uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -360,22 +360,22 @@ static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* c
|
||||
static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
|
||||
static bool config_read_capacity_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw);
|
||||
|
||||
uint16_t msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
|
||||
bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
|
||||
{
|
||||
TU_VERIFY (MSC_SUBCLASS_SCSI == desc_itf->bInterfaceSubClass &&
|
||||
MSC_PROTOCOL_BOT == desc_itf->bInterfaceProtocol);
|
||||
|
||||
// msc driver length is fixed
|
||||
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + desc_itf->bNumEndpoints*sizeof(tusb_desc_endpoint_t);
|
||||
TU_ASSERT(drv_len <= max_len, 0);
|
||||
TU_ASSERT(drv_len <= max_len);
|
||||
|
||||
msch_interface_t* p_msc = get_itf(dev_addr);
|
||||
tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(desc_itf);
|
||||
|
||||
for(uint32_t i=0; i<2; i++)
|
||||
{
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer, 0);
|
||||
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc), 0);
|
||||
TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType && TUSB_XFER_BULK == ep_desc->bmAttributes.xfer);
|
||||
TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc));
|
||||
|
||||
if ( tu_edpt_dir(ep_desc->bEndpointAddress) == TUSB_DIR_IN )
|
||||
{
|
||||
@ -390,7 +390,7 @@ uint16_t msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
|
||||
|
||||
p_msc->itf_num = desc_itf->bInterfaceNumber;
|
||||
|
||||
return drv_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool msch_set_config(uint8_t dev_addr, uint8_t itf_num)
|
||||
|
@ -106,11 +106,11 @@ TU_ATTR_WEAK void tuh_msc_umount_cb(uint8_t dev_addr);
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
void msch_init (void);
|
||||
uint16_t msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
|
||||
bool msch_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void msch_close (uint8_t dev_addr);
|
||||
void msch_init (void);
|
||||
bool msch_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *desc_itf, uint16_t max_len);
|
||||
bool msch_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
void msch_close (uint8_t dev_addr);
|
||||
bool msch_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -73,6 +73,23 @@
|
||||
#include "tusb_error.h" // TODO remove
|
||||
#include "tusb_timeout.h" // TODO remove
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Helper used by Host and Device Stack
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Check if endpoint descriptor is valid per USB specs
|
||||
bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed);
|
||||
|
||||
// Bind all endpoint of a interface descriptor to class driver
|
||||
void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* p_desc, uint16_t desc_len, uint8_t driver_id);
|
||||
|
||||
// Calculate total length of n interfaces (depending on IAD)
|
||||
uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len);
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Inline Functions
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
//------------- Mem -------------//
|
||||
#define tu_memclr(buffer, size) memset((buffer), 0, (size))
|
||||
#define tu_varclr(_var) tu_memclr(_var, sizeof(*(_var)))
|
||||
|
@ -274,7 +274,6 @@ static osal_mutex_t _usbd_mutex;
|
||||
//--------------------------------------------------------------------+
|
||||
// Prototypes
|
||||
//--------------------------------------------------------------------+
|
||||
static void mark_interface_endpoint(uint8_t ep2drv[][2], 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 cfg_num);
|
||||
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
|
||||
@ -857,12 +856,12 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
|
||||
|
||||
while( p_desc < desc_end )
|
||||
{
|
||||
tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL;
|
||||
tusb_desc_interface_assoc_t const * desc_iad = NULL;
|
||||
|
||||
// Class will always starts with Interface Association (if any) and then Interface descriptor
|
||||
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
|
||||
{
|
||||
desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc;
|
||||
desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
|
||||
p_desc = tu_desc_next(p_desc); // next to Interface
|
||||
}
|
||||
|
||||
@ -871,6 +870,13 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
|
||||
tusb_desc_interface_t const * desc_itf = (tusb_desc_interface_t const*) p_desc;
|
||||
uint16_t const remaining_len = desc_end-p_desc;
|
||||
|
||||
// Interface number must not be used already
|
||||
TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber]);
|
||||
|
||||
// TODO usbd can calculate the total length used for driver --> driver open() does not need to calculate it
|
||||
// uint16_t const drv_len = tu_desc_get_interface_total_len(desc_itf, desc_iad ? desc_iad->bInterfaceCount : 1, desc_end-p_desc);
|
||||
|
||||
// Find driver for this interface
|
||||
uint8_t drv_id;
|
||||
for (drv_id = 0; drv_id < TOTAL_DRIVER_COUNT; drv_id++)
|
||||
{
|
||||
@ -882,30 +888,30 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
|
||||
// Open successfully, check if length is correct
|
||||
TU_ASSERT( sizeof(tusb_desc_interface_t) <= drv_len && drv_len <= remaining_len);
|
||||
|
||||
// Interface number must not be used already
|
||||
TU_ASSERT(DRVID_INVALID == _usbd_dev.itf2drv[desc_itf->bInterfaceNumber]);
|
||||
|
||||
TU_LOG2(" %s opened\r\n", driver->name);
|
||||
|
||||
// bind interface to found driver
|
||||
_usbd_dev.itf2drv[desc_itf->bInterfaceNumber] = drv_id;
|
||||
|
||||
// If IAD exist, assign all interfaces to the same driver
|
||||
if (desc_itf_assoc)
|
||||
// If using IAD, bind all interfaces to the same driver
|
||||
if (desc_iad)
|
||||
{
|
||||
// IAD's first interface number and class should match with opened interface
|
||||
TU_ASSERT(desc_itf_assoc->bFirstInterface == desc_itf->bInterfaceNumber &&
|
||||
desc_itf_assoc->bFunctionClass == desc_itf->bInterfaceClass);
|
||||
TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
|
||||
desc_iad->bFunctionClass == desc_itf->bInterfaceClass);
|
||||
|
||||
for(uint8_t i=1; i<desc_itf_assoc->bInterfaceCount; i++)
|
||||
for(uint8_t i=1; i<desc_iad->bInterfaceCount; i++)
|
||||
{
|
||||
_usbd_dev.itf2drv[desc_itf->bInterfaceNumber+i] = drv_id;
|
||||
}
|
||||
}
|
||||
|
||||
mark_interface_endpoint(_usbd_dev.ep2drv, p_desc, drv_len, drv_id); // TODO refactor
|
||||
// bind all endpoints to found driver
|
||||
tu_edpt_bind_driver(_usbd_dev.ep2drv, desc_itf, drv_len, drv_id);
|
||||
|
||||
p_desc += drv_len; // next interface
|
||||
|
||||
break;
|
||||
break; // exit driver find loop
|
||||
}
|
||||
}
|
||||
|
||||
@ -919,25 +925,6 @@ static bool process_set_config(uint8_t rhport, uint8_t cfg_num)
|
||||
return true;
|
||||
}
|
||||
|
||||
// Helper marking endpoint of interface belongs to class driver
|
||||
static void mark_interface_endpoint(uint8_t ep2drv[][2], 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 == tu_desc_type(p_desc) )
|
||||
{
|
||||
uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
|
||||
|
||||
ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id;
|
||||
}
|
||||
|
||||
len = (uint16_t)(len + tu_desc_len(p_desc));
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
}
|
||||
|
||||
// return descriptor's buffer and update desc_len
|
||||
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request)
|
||||
{
|
||||
@ -1177,41 +1164,8 @@ void usbd_defer_func(osal_task_func_t func, void* param, bool in_isr)
|
||||
|
||||
bool usbd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * desc_ep)
|
||||
{
|
||||
uint16_t const max_packet_size = tu_le16toh(desc_ep->wMaxPacketSize.size);
|
||||
|
||||
TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size);
|
||||
TU_ASSERT(tu_edpt_number(desc_ep->bEndpointAddress) < CFG_TUD_ENDPPOINT_MAX);
|
||||
|
||||
switch (desc_ep->bmAttributes.xfer)
|
||||
{
|
||||
case TUSB_XFER_ISOCHRONOUS:
|
||||
{
|
||||
uint16_t const spec_size = (_usbd_dev.speed == TUSB_SPEED_HIGH ? 1024 : 1023);
|
||||
TU_ASSERT(max_packet_size <= spec_size);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_XFER_BULK:
|
||||
if (_usbd_dev.speed == TUSB_SPEED_HIGH)
|
||||
{
|
||||
// Bulk highspeed must be EXACTLY 512
|
||||
TU_ASSERT(max_packet_size == 512);
|
||||
}else
|
||||
{
|
||||
// TODO Bulk fullspeed can only be 8, 16, 32, 64
|
||||
TU_ASSERT(max_packet_size <= 64);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_XFER_INTERRUPT:
|
||||
{
|
||||
uint16_t const spec_size = (_usbd_dev.speed == TUSB_SPEED_HIGH ? 1024 : 64);
|
||||
TU_ASSERT(max_packet_size <= spec_size);
|
||||
}
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) _usbd_dev.speed));
|
||||
|
||||
return dcd_edpt_open(rhport, desc_ep);
|
||||
}
|
||||
|
@ -147,16 +147,17 @@ void hub_init(void)
|
||||
tu_memclr(hub_data, CFG_TUSB_HOST_DEVICE_MAX*sizeof(hub_interface_t));
|
||||
}
|
||||
|
||||
uint16_t hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
|
||||
bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len)
|
||||
{
|
||||
// hub driver does not support multiple TT yet
|
||||
TU_VERIFY(TUSB_CLASS_HUB == itf_desc->bInterfaceClass &&
|
||||
0 == itf_desc->bInterfaceSubClass &&
|
||||
1 <= itf_desc->bInterfaceProtocol, 0);
|
||||
0 == itf_desc->bInterfaceSubClass);
|
||||
|
||||
// hub driver does not support multiple TT yet
|
||||
TU_VERIFY(itf_desc->bInterfaceProtocol <= 1);
|
||||
|
||||
// msc driver length is fixed
|
||||
uint16_t const drv_len = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t);
|
||||
TU_ASSERT(drv_len <= max_len, 0);
|
||||
TU_ASSERT(drv_len <= max_len);
|
||||
|
||||
//------------- Interrupt Status endpoint -------------//
|
||||
tusb_desc_endpoint_t const *desc_ep = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc);
|
||||
@ -169,7 +170,7 @@ uint16_t hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const
|
||||
hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber;
|
||||
hub_data[dev_addr-1].ep_in = desc_ep->bEndpointAddress;
|
||||
|
||||
return drv_len;
|
||||
return true;
|
||||
}
|
||||
|
||||
void hub_close(uint8_t dev_addr)
|
||||
|
@ -181,11 +181,11 @@ bool hub_status_pipe_queue(uint8_t dev_addr);
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Class Driver API
|
||||
//--------------------------------------------------------------------+
|
||||
void hub_init (void);
|
||||
uint16_t hub_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
|
||||
bool hub_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool hub_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void hub_close (uint8_t dev_addr);
|
||||
void hub_init (void);
|
||||
bool hub_open (uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t max_len);
|
||||
bool hub_set_config (uint8_t dev_addr, uint8_t itf_num);
|
||||
bool hub_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
|
||||
void hub_close (uint8_t dev_addr);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
393
src/host/usbh.c
393
src/host/usbh.c
@ -28,19 +28,30 @@
|
||||
|
||||
#if TUSB_OPT_HOST_ENABLED
|
||||
|
||||
#ifndef CFG_TUH_TASK_QUEUE_SZ
|
||||
#define CFG_TUH_TASK_QUEUE_SZ 16
|
||||
#endif
|
||||
|
||||
#include "tusb.h"
|
||||
#include "host/usbh.h"
|
||||
#include "host/usbh_classdriver.h"
|
||||
#include "hub.h"
|
||||
#include "usbh_hcd.h"
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// USBH Configuration
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
#ifndef CFG_TUH_TASK_QUEUE_SZ
|
||||
#define CFG_TUH_TASK_QUEUE_SZ 16
|
||||
#endif
|
||||
|
||||
// Debug level of USBD
|
||||
#define USBH_DBG_LVL 2
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// MACRO CONSTANT TYPEDEF
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// Invalid driver ID in itf2drv[] ep2drv[][] mapping
|
||||
enum { DRVID_INVALID = 0xFFu };
|
||||
|
||||
#if CFG_TUSB_DEBUG >= 2
|
||||
#define DRIVER_NAME(_name) .name = _name,
|
||||
#else
|
||||
@ -52,7 +63,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
||||
#if CFG_TUH_CDC
|
||||
{
|
||||
DRIVER_NAME("CDC")
|
||||
.class_code = TUSB_CLASS_CDC,
|
||||
.init = cdch_init,
|
||||
.open = cdch_open,
|
||||
.set_config = cdch_set_config,
|
||||
@ -64,7 +74,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
||||
#if CFG_TUH_MSC
|
||||
{
|
||||
DRIVER_NAME("MSC")
|
||||
.class_code = TUSB_CLASS_MSC,
|
||||
.init = msch_init,
|
||||
.open = msch_open,
|
||||
.set_config = msch_set_config,
|
||||
@ -76,7 +85,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
||||
#if CFG_TUH_HID
|
||||
{
|
||||
DRIVER_NAME("HID")
|
||||
.class_code = TUSB_CLASS_HID,
|
||||
.init = hidh_init,
|
||||
.open = hidh_open,
|
||||
.set_config = hidh_set_config,
|
||||
@ -88,7 +96,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
||||
#if CFG_TUH_HUB
|
||||
{
|
||||
DRIVER_NAME("HUB")
|
||||
.class_code = TUSB_CLASS_HUB,
|
||||
.init = hub_init,
|
||||
.open = hub_open,
|
||||
.set_config = hub_set_config,
|
||||
@ -100,7 +107,6 @@ static usbh_class_driver_t const usbh_class_drivers[] =
|
||||
#if CFG_TUH_VENDOR
|
||||
{
|
||||
DRIVER_NAME("VENDOR")
|
||||
.class_code = TUSB_CLASS_VENDOR_SPECIFIC,
|
||||
.init = cush_init,
|
||||
.open = cush_open_subtask,
|
||||
.xfer_cb = cush_isr,
|
||||
@ -135,6 +141,7 @@ CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN static uint8_t _usbh_ctrl_buf[CFG_TUH_EN
|
||||
//------------- Helper Function Prototypes -------------//
|
||||
static bool enum_new_device(hcd_event_t* event);
|
||||
static void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port);
|
||||
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size);
|
||||
|
||||
// from usbh_control.c
|
||||
extern bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
@ -195,8 +202,8 @@ bool tuh_init(uint8_t rhport)
|
||||
TU_ASSERT(dev->mutex);
|
||||
#endif
|
||||
|
||||
memset(dev->itf2drv, 0xff, sizeof(dev->itf2drv)); // invalid mapping
|
||||
memset(dev->ep2drv , 0xff, sizeof(dev->ep2drv )); // invalid mapping
|
||||
memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
|
||||
memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
|
||||
}
|
||||
|
||||
// Class drivers init
|
||||
@ -314,151 +321,6 @@ uint8_t* usbh_get_enum_buf(void)
|
||||
return _usbh_ctrl_buf;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
// pre-check to help reducing mutex lock
|
||||
TU_VERIFY((dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0));
|
||||
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
#endif
|
||||
|
||||
// can only claim the endpoint if it is not busy and not claimed yet.
|
||||
bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0);
|
||||
if (ret)
|
||||
{
|
||||
dev->ep_status[epnum][dir].claimed = 1;
|
||||
}
|
||||
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
osal_mutex_unlock(dev->mutex);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
#endif
|
||||
|
||||
// can only release the endpoint if it is claimed and not busy
|
||||
bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 1);
|
||||
if (ret)
|
||||
{
|
||||
dev->ep_status[epnum][dir].claimed = 0;
|
||||
}
|
||||
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
osal_mutex_unlock(dev->mutex);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
|
||||
|
||||
// Attempt to transfer on a busy endpoint, sound like an race condition !
|
||||
TU_ASSERT(dev->ep_status[epnum][dir].busy == 0);
|
||||
|
||||
// Set busy first since the actual transfer can be complete before hcd_edpt_xfer()
|
||||
// could return and USBH task can preempt and clear the busy
|
||||
dev->ep_status[epnum][dir].busy = true;
|
||||
|
||||
if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
|
||||
{
|
||||
TU_LOG2("OK\r\n");
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
// HCD error, mark endpoint as ready to allow next transfer
|
||||
dev->ep_status[epnum][dir].busy = false;
|
||||
dev->ep_status[epnum][dir].claimed = 0;
|
||||
TU_LOG2("failed\r\n");
|
||||
TU_BREAKPOINT();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
|
||||
{
|
||||
TU_LOG2("Open EP Control with Size = %u\r\n", max_packet_size);
|
||||
|
||||
tusb_desc_endpoint_t ep0_desc =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||
.bEndpointAddress = 0,
|
||||
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
|
||||
.wMaxPacketSize = { .size = max_packet_size },
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
return hcd_edpt_open(_usbh_devices[dev_addr].rhport, dev_addr, &ep0_desc);
|
||||
}
|
||||
|
||||
bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
|
||||
{
|
||||
TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, desc_ep->wMaxPacketSize.size);
|
||||
|
||||
bool ret = hcd_edpt_open(rhport, dev_addr, desc_ep);
|
||||
|
||||
if (ret)
|
||||
{
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
// new endpoints belongs to latest interface (last valid value)
|
||||
// TODO FIXME not true with ISO
|
||||
uint8_t drvid = 0xff;
|
||||
for(uint8_t i=0; i < sizeof(dev->itf2drv); i++)
|
||||
{
|
||||
if ( dev->itf2drv[i] == 0xff ) break;
|
||||
drvid = dev->itf2drv[i];
|
||||
}
|
||||
TU_ASSERT(drvid < USBH_CLASS_DRIVER_COUNT);
|
||||
|
||||
uint8_t const ep_addr = desc_ep->bEndpointAddress;
|
||||
dev->ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = drvid;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
return dev->ep_status[epnum][dir].busy;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// HCD Event Handler
|
||||
//--------------------------------------------------------------------+
|
||||
@ -473,7 +335,6 @@ void hcd_event_handler(hcd_event_t const* event, bool in_isr)
|
||||
}
|
||||
}
|
||||
|
||||
// interrupt caused by a TD (with IOC=1) in pipe of class class_code
|
||||
void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr)
|
||||
{
|
||||
hcd_event_t event =
|
||||
@ -546,8 +407,8 @@ void process_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_port
|
||||
usbh_class_drivers[drv_id].close(dev_addr);
|
||||
}
|
||||
|
||||
memset(dev->itf2drv, 0xff, sizeof(dev->itf2drv)); // invalid mapping
|
||||
memset(dev->ep2drv , 0xff, sizeof(dev->ep2drv )); // invalid mapping
|
||||
memset(dev->itf2drv, DRVID_INVALID, sizeof(dev->itf2drv)); // invalid mapping
|
||||
memset(dev->ep2drv , DRVID_INVALID, sizeof(dev->ep2drv )); // invalid mapping
|
||||
|
||||
hcd_device_close(rhport, dev_addr);
|
||||
|
||||
@ -576,7 +437,7 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num)
|
||||
{
|
||||
// continue with next valid interface
|
||||
uint8_t const drv_id = dev->itf2drv[itf_num];
|
||||
if (drv_id != 0xff)
|
||||
if (drv_id != DRVID_INVALID)
|
||||
{
|
||||
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
||||
TU_LOG2("%s set config: itf = %u\r\n", driver->name, itf_num);
|
||||
@ -841,7 +702,7 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c
|
||||
dev0->state = TUSB_DEVICE_STATE_UNPLUG;
|
||||
|
||||
// open control pipe for new address
|
||||
TU_ASSERT ( usbh_edpt_control_open(new_addr, new_dev->ep0_packet_size) );
|
||||
TU_ASSERT( usbh_edpt_control_open(new_addr, new_dev->ep0_packet_size) );
|
||||
|
||||
// Get full device descriptor
|
||||
TU_LOG2("Get Device Descriptor\r\n");
|
||||
@ -972,11 +833,11 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co
|
||||
dev->configured = 1;
|
||||
dev->state = TUSB_DEVICE_STATE_CONFIGURED;
|
||||
|
||||
// Start the Set Configuration process for interfaces (itf = 0xff)
|
||||
// Start the Set Configuration process for interfaces (itf = DRVID_INVALID)
|
||||
// Since driver can perform control transfer within its set_config, this is done asynchronously.
|
||||
// The process continue with next interface when class driver complete its sequence with usbh_driver_set_config_complete()
|
||||
// TODO use separated API instead of usig 0xff
|
||||
usbh_driver_set_config_complete(dev_addr, 0xff);
|
||||
// TODO use separated API instead of using DRVID_INVALID
|
||||
usbh_driver_set_config_complete(dev_addr, DRVID_INVALID);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -992,58 +853,206 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura
|
||||
while( p_desc < desc_end )
|
||||
{
|
||||
// TODO Do we need to use IAD
|
||||
// tusb_desc_interface_assoc_t const * desc_itf_assoc = NULL;
|
||||
tusb_desc_interface_assoc_t const * desc_iad = NULL;
|
||||
|
||||
// Class will always starts with Interface Association (if any) and then Interface descriptor
|
||||
if ( TUSB_DESC_INTERFACE_ASSOCIATION == tu_desc_type(p_desc) )
|
||||
{
|
||||
// desc_itf_assoc = (tusb_desc_interface_assoc_t const *) p_desc;
|
||||
desc_iad = (tusb_desc_interface_assoc_t const *) p_desc;
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
|
||||
TU_ASSERT( TUSB_DESC_INTERFACE == tu_desc_type(p_desc) );
|
||||
|
||||
tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc;
|
||||
uint16_t const remaining_len = desc_end-p_desc;
|
||||
|
||||
// Check if class is supported TODO drop class_code
|
||||
uint8_t drv_id;
|
||||
for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
||||
{
|
||||
if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break;
|
||||
}
|
||||
// Interface number must not be used already
|
||||
TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == DRVID_INVALID );
|
||||
|
||||
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
|
||||
uint16_t const drv_len = tu_desc_get_interface_total_len(desc_itf, desc_iad ? desc_iad->bInterfaceCount : 1, desc_end-p_desc);
|
||||
TU_ASSERT(drv_len);
|
||||
|
||||
if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
|
||||
{
|
||||
// skip unsupported class
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
// TODO Attach hub to Hub is not currently supported
|
||||
// skip this interface
|
||||
TU_LOG(USBH_DBG_LVL, "Only 1 level of HUB is supported\r\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
||||
|
||||
// Interface number must not be used already TODO alternate interface
|
||||
TU_ASSERT( dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff );
|
||||
dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
|
||||
|
||||
if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && dev->hub_addr != 0)
|
||||
// Find driver for this interface
|
||||
uint8_t drv_id;
|
||||
for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++)
|
||||
{
|
||||
// TODO Attach hub to Hub is not currently supported
|
||||
// skip this interface
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id];
|
||||
|
||||
if ( driver->open(dev->rhport, dev_addr, desc_itf, drv_len) )
|
||||
{
|
||||
// open successfully
|
||||
TU_LOG2("%s opened\r\n", driver->name);
|
||||
|
||||
// bind interface to found driver
|
||||
dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id;
|
||||
|
||||
// If using IAD, bind all interfaces to the same driver
|
||||
if (desc_iad)
|
||||
{
|
||||
// IAD's first interface number and class should match with opened interface
|
||||
TU_ASSERT(desc_iad->bFirstInterface == desc_itf->bInterfaceNumber &&
|
||||
desc_iad->bFunctionClass == desc_itf->bInterfaceClass);
|
||||
|
||||
for(uint8_t i=1; i<desc_iad->bInterfaceCount; i++)
|
||||
{
|
||||
dev->itf2drv[desc_itf->bInterfaceNumber+i] = drv_id;
|
||||
}
|
||||
}
|
||||
|
||||
// bind all endpoints to found driver
|
||||
tu_edpt_bind_driver(dev->ep2drv, desc_itf, drv_len, drv_id);
|
||||
|
||||
break; // exit driver find loop
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
TU_LOG2("%s open\r\n", driver->name);
|
||||
|
||||
uint16_t const itf_len = driver->open(dev->rhport, dev_addr, desc_itf, remaining_len);
|
||||
TU_ASSERT( sizeof(tusb_desc_interface_t) <= itf_len && itf_len <= remaining_len);
|
||||
p_desc += itf_len;
|
||||
if( drv_id >= USBH_CLASS_DRIVER_COUNT )
|
||||
{
|
||||
TU_LOG(USBH_DBG_LVL, "Interface %u: class = %u subclass = %u protocol = %u is not supported\r\n",
|
||||
desc_itf->bInterfaceNumber, desc_itf->bInterfaceClass, desc_itf->bInterfaceSubClass, desc_itf->bInterfaceProtocol);
|
||||
}
|
||||
}
|
||||
|
||||
// next Interface or IAD descriptor
|
||||
p_desc += drv_len;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Endpoint API
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
// pre-check to help reducing mutex lock
|
||||
TU_VERIFY((dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0));
|
||||
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
#endif
|
||||
|
||||
// can only claim the endpoint if it is not busy and not claimed yet.
|
||||
bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 0);
|
||||
if (ret)
|
||||
{
|
||||
dev->ep_status[epnum][dir].claimed = 1;
|
||||
}
|
||||
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
osal_mutex_unlock(dev->mutex);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
osal_mutex_lock(dev->mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
#endif
|
||||
|
||||
// can only release the endpoint if it is claimed and not busy
|
||||
bool const ret = (dev->ep_status[epnum][dir].busy == 0) && (dev->ep_status[epnum][dir].claimed == 1);
|
||||
if (ret)
|
||||
{
|
||||
dev->ep_status[epnum][dir].claimed = 0;
|
||||
}
|
||||
|
||||
#if CFG_TUSB_OS != OPT_OS_NONE
|
||||
osal_mutex_unlock(dev->mutex);
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// TODO has some duplication code with device, refactor later
|
||||
bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
TU_LOG2(" Queue EP %02X with %u bytes ... ", ep_addr, total_bytes);
|
||||
|
||||
// Attempt to transfer on a busy endpoint, sound like an race condition !
|
||||
TU_ASSERT(dev->ep_status[epnum][dir].busy == 0);
|
||||
|
||||
// Set busy first since the actual transfer can be complete before hcd_edpt_xfer()
|
||||
// could return and USBH task can preempt and clear the busy
|
||||
dev->ep_status[epnum][dir].busy = true;
|
||||
|
||||
if ( hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes) )
|
||||
{
|
||||
TU_LOG2("OK\r\n");
|
||||
return true;
|
||||
}else
|
||||
{
|
||||
// HCD error, mark endpoint as ready to allow next transfer
|
||||
dev->ep_status[epnum][dir].busy = false;
|
||||
dev->ep_status[epnum][dir].claimed = 0;
|
||||
TU_LOG2("failed\r\n");
|
||||
TU_BREAKPOINT();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool usbh_edpt_control_open(uint8_t dev_addr, uint8_t max_packet_size)
|
||||
{
|
||||
TU_LOG2("Open EP Control with Size = %u\r\n", max_packet_size);
|
||||
|
||||
tusb_desc_endpoint_t ep0_desc =
|
||||
{
|
||||
.bLength = sizeof(tusb_desc_endpoint_t),
|
||||
.bDescriptorType = TUSB_DESC_ENDPOINT,
|
||||
.bEndpointAddress = 0,
|
||||
.bmAttributes = { .xfer = TUSB_XFER_CONTROL },
|
||||
.wMaxPacketSize = { .size = max_packet_size },
|
||||
.bInterval = 0
|
||||
};
|
||||
|
||||
return hcd_edpt_open(_usbh_devices[dev_addr].rhport, dev_addr, &ep0_desc);
|
||||
}
|
||||
|
||||
bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * desc_ep)
|
||||
{
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
TU_ASSERT(tu_edpt_validate(desc_ep, (tusb_speed_t) dev->speed));
|
||||
|
||||
return hcd_edpt_open(rhport, dev_addr, desc_ep);
|
||||
}
|
||||
|
||||
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr)
|
||||
{
|
||||
uint8_t const epnum = tu_edpt_number(ep_addr);
|
||||
uint8_t const dir = tu_edpt_dir(ep_addr);
|
||||
|
||||
usbh_device_t* dev = &_usbh_devices[dev_addr];
|
||||
|
||||
return dev->ep_status[epnum][dir].busy;
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
@ -43,13 +43,11 @@ typedef struct {
|
||||
char const* name;
|
||||
#endif
|
||||
|
||||
uint8_t class_code;
|
||||
|
||||
void (* const init )(void);
|
||||
uint16_t (* const open )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
|
||||
bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
|
||||
bool (* const xfer_cb )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
void (* const close )(uint8_t dev_addr);
|
||||
void (* const init )(void);
|
||||
bool (* const open )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t max_len);
|
||||
bool (* const set_config )(uint8_t dev_addr, uint8_t itf_num);
|
||||
bool (* const xfer_cb )(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
|
||||
void (* const close )(uint8_t dev_addr);
|
||||
} usbh_class_driver_t;
|
||||
|
||||
// Call by class driver to tell USBH that it has complete the enumeration
|
||||
@ -73,6 +71,8 @@ bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_
|
||||
// If caller does not make any transfer, it must release endpoint for others.
|
||||
bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
bool usbh_edpt_release(uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
// Check if endpoint transferring is complete
|
||||
bool usbh_edpt_busy(uint8_t dev_addr, uint8_t ep_addr);
|
||||
|
||||
|
@ -73,9 +73,9 @@ typedef struct {
|
||||
uint8_t suspended : 1;
|
||||
};
|
||||
|
||||
volatile uint8_t state; // device state, value from enum tusbh_device_state_t
|
||||
volatile uint8_t state; // device state, value from enum tusbh_device_state_t
|
||||
|
||||
uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
|
||||
uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid)
|
||||
uint8_t ep2drv[CFG_TUH_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid )
|
||||
|
||||
struct TU_ATTR_PACKED
|
||||
|
92
src/tusb.c
92
src/tusb.c
@ -63,6 +63,98 @@ bool tusb_inited(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------+
|
||||
// Internal Helper for both Host and Device stack
|
||||
//--------------------------------------------------------------------+
|
||||
|
||||
bool tu_edpt_validate(tusb_desc_endpoint_t const * desc_ep, tusb_speed_t speed)
|
||||
{
|
||||
uint16_t const max_packet_size = tu_le16toh(desc_ep->wMaxPacketSize.size);
|
||||
TU_LOG2(" Open EP %02X with Size = %u\r\n", desc_ep->bEndpointAddress, max_packet_size);
|
||||
|
||||
switch (desc_ep->bmAttributes.xfer)
|
||||
{
|
||||
case TUSB_XFER_ISOCHRONOUS:
|
||||
{
|
||||
uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 1023);
|
||||
TU_ASSERT(max_packet_size <= spec_size);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_XFER_BULK:
|
||||
if (speed == TUSB_SPEED_HIGH)
|
||||
{
|
||||
// Bulk highspeed must be EXACTLY 512
|
||||
TU_ASSERT(max_packet_size == 512);
|
||||
}else
|
||||
{
|
||||
// TODO Bulk fullspeed can only be 8, 16, 32, 64
|
||||
TU_ASSERT(max_packet_size <= 64);
|
||||
}
|
||||
break;
|
||||
|
||||
case TUSB_XFER_INTERRUPT:
|
||||
{
|
||||
uint16_t const spec_size = (speed == TUSB_SPEED_HIGH ? 1024 : 64);
|
||||
TU_ASSERT(max_packet_size <= spec_size);
|
||||
}
|
||||
break;
|
||||
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void tu_edpt_bind_driver(uint8_t ep2drv[][2], tusb_desc_interface_t const* desc_itf, uint16_t desc_len, uint8_t driver_id)
|
||||
{
|
||||
uint8_t const* p_desc = (uint8_t const*) desc_itf;
|
||||
uint16_t len = 0;
|
||||
|
||||
while( len < desc_len )
|
||||
{
|
||||
if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
|
||||
{
|
||||
uint8_t const ep_addr = ((tusb_desc_endpoint_t const*) p_desc)->bEndpointAddress;
|
||||
|
||||
ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)] = driver_id;
|
||||
}
|
||||
|
||||
len = (uint16_t)(len + tu_desc_len(p_desc));
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
}
|
||||
|
||||
uint16_t tu_desc_get_interface_total_len(tusb_desc_interface_t const* desc_itf, uint8_t itf_count, uint16_t max_len)
|
||||
{
|
||||
uint8_t const* p_desc = (uint8_t const*) desc_itf;
|
||||
uint16_t len = 0;
|
||||
|
||||
while (itf_count--)
|
||||
{
|
||||
// Next on interface desc
|
||||
len += tu_desc_len(desc_itf);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
|
||||
while (len < max_len)
|
||||
{
|
||||
// return on IAD regardless of itf count
|
||||
if ( tu_desc_type(p_desc) == TUSB_DESC_INTERFACE_ASSOCIATION ) return len;
|
||||
|
||||
if ( (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE) &&
|
||||
((tusb_desc_interface_t const*) p_desc)->bAlternateSetting == 0 )
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
len += tu_desc_len(p_desc);
|
||||
p_desc = tu_desc_next(p_desc);
|
||||
}
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
/*------------------------------------------------------------------*/
|
||||
/* Debug
|
||||
*------------------------------------------------------------------*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user