diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 5058191f4..a96eb6276 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -173,6 +173,56 @@ bool hidh_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c tusb_desc_endpoint_t const * p_endpoint_desc = (tusb_desc_endpoint_t const *) p_desc; TU_ASSERT(TUSB_DESC_ENDPOINT == p_endpoint_desc->bDescriptorType, TUSB_ERROR_INVALID_PARA); + if ( HID_SUBCLASS_BOOT == p_interface_desc->bInterfaceSubClass ) + { + #if CFG_TUH_HID_KEYBOARD + if ( HID_PROTOCOL_KEYBOARD == p_interface_desc->bInterfaceProtocol) + { + TU_ASSERT( hidh_interface_open(rhport, dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &keyboardh_data[dev_addr-1]) ); + TU_LOG2_HEX(keyboardh_data[dev_addr-1].ep_in); + } else + #endif + + #if CFG_TUH_HID_MOUSE + if ( HID_PROTOCOL_MOUSE == p_interface_desc->bInterfaceProtocol) + { + TU_ASSERT ( hidh_interface_open(rhport, dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &mouseh_data[dev_addr-1]) ); + TU_LOG2_HEX(mouseh_data[dev_addr-1].ep_in); + } else + #endif + + { + // Not supported protocol + return false; + } + }else + { + // Not supported subclass + return false; + } + + *p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + sizeof(tusb_desc_endpoint_t); + + return true; +} + +bool hidh_set_config(uint8_t dev_addr, uint8_t itf_num) +{ +#if 0 + //------------- Get Report Descriptor TODO HID parser -------------// + if ( p_desc_hid->bNumDescriptors ) + { + STASK_INVOKE( + usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_INTERFACE), + TUSB_REQ_GET_DESCRIPTOR, (p_desc_hid->bReportType << 8), 0, + p_desc_hid->wReportLength, report_descriptor ), + error + ); + (void) error; // if error in getting report descriptor --> treating like there is none + } +#endif + +#if 0 // SET IDLE = 0 request // Device can stall if not support this request tusb_control_request_t const request = @@ -191,52 +241,23 @@ bool hidh_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c // stall is a valid response for SET_IDLE, therefore we could ignore result of this request tuh_control_xfer(dev_addr, &request, NULL, NULL); +#endif -#if 0 - //------------- Get Report Descriptor TODO HID parser -------------// - if ( p_desc_hid->bNumDescriptors ) + usbh_driver_set_config_complete(dev_addr, itf_num); + +#if CFG_TUH_HID_KEYBOARD + if ( keyboardh_data[dev_addr-1].itf_num == itf_num) { - STASK_INVOKE( - usbh_control_xfer_subtask( dev_addr, bm_request_type(TUSB_DIR_IN, TUSB_REQ_TYPE_STANDARD, TUSB_REQ_RCPT_INTERFACE), - TUSB_REQ_GET_DESCRIPTOR, (p_desc_hid->bReportType << 8), 0, - p_desc_hid->wReportLength, report_descriptor ), - error - ); - (void) error; // if error in getting report descriptor --> treating like there is none + tuh_hid_keyboard_mounted_cb(dev_addr); } #endif - if ( HID_SUBCLASS_BOOT == p_interface_desc->bInterfaceSubClass ) +#if CFG_TUH_HID_MOUSE + if ( mouseh_data[dev_addr-1].ep_in == itf_num ) { - #if CFG_TUH_HID_KEYBOARD - if ( HID_PROTOCOL_KEYBOARD == p_interface_desc->bInterfaceProtocol) - { - TU_ASSERT( hidh_interface_open(rhport, dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &keyboardh_data[dev_addr-1]) ); - TU_LOG2_HEX(keyboardh_data[dev_addr-1].ep_in); - tuh_hid_keyboard_mounted_cb(dev_addr); - } else - #endif - - #if CFG_TUH_HID_MOUSE - if ( HID_PROTOCOL_MOUSE == p_interface_desc->bInterfaceProtocol) - { - TU_ASSERT ( hidh_interface_open(rhport, dev_addr, p_interface_desc->bInterfaceNumber, p_endpoint_desc, &mouseh_data[dev_addr-1]) ); - TU_LOG2_HEX(mouseh_data[dev_addr-1].ep_in); - tuh_hid_mouse_mounted_cb(dev_addr); - } else - #endif - - { - // Not supported protocol - return false; - } - }else - { - // Not supported subclass - return false; + tuh_hid_mouse_mounted_cb(dev_addr); } - - *p_length = sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + sizeof(tusb_desc_endpoint_t); +#endif return true; } diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 324dad203..5c77398f8 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -197,6 +197,7 @@ void tuh_hid_generic_isr(uint8_t dev_addr, xfer_result_t event); //--------------------------------------------------------------------+ void hidh_init(void); bool hidh_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *p_interface_desc, uint16_t *p_length); +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 event, uint32_t xferred_bytes); void hidh_close(uint8_t dev_addr); diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 83423cfc7..02ca81e77 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -334,9 +334,9 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 // MSC Enumeration //--------------------------------------------------------------------+ -static bool open_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); -static bool open_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); -static bool open_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); +static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length) { @@ -367,6 +367,14 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it p_msc->itf_num = itf_desc->bInterfaceNumber; (*p_length) += sizeof(tusb_desc_interface_t) + 2*sizeof(tusb_desc_endpoint_t); + return true; +} + +bool msch_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + msch_interface_t* p_msc = get_itf(dev_addr); + TU_ASSERT(p_msc->itf_num == itf_num); + //------------- Get Max Lun -------------// TU_LOG2("MSC Get Max Lun\r\n"); tusb_control_request_t request = @@ -379,15 +387,15 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it }, .bRequest = MSC_REQ_GET_MAX_LUN, .wValue = 0, - .wIndex = p_msc->itf_num, + .wIndex = itf_num, .wLength = 1 }; - TU_ASSERT(tuh_control_xfer(dev_addr, &request, &p_msc->max_lun, open_get_maxlun_complete)); + TU_ASSERT(tuh_control_xfer(dev_addr, &request, &p_msc->max_lun, config_get_maxlun_complete)); return true; } -static bool open_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +static bool config_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { (void) request; @@ -399,17 +407,19 @@ static bool open_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t c // TODO multiple LUN support TU_LOG2("SCSI Test Unit Ready\r\n"); - tuh_msc_test_unit_ready(dev_addr, 0, open_test_unit_ready_complete); + tuh_msc_test_unit_ready(dev_addr, 0, config_test_unit_ready_complete); return true; } -static bool open_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) { if (csw->status == 0) { msch_interface_t* p_msc = get_itf(dev_addr); + usbh_driver_set_config_complete(dev_addr, p_msc->itf_num); + // Unit is ready, Enumeration is complete p_msc->mounted = true; tuh_msc_mounted_cb(dev_addr); @@ -418,16 +428,16 @@ static bool open_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw // Note: During enumeration, some device fails Test Unit Ready and require a few retries // with Request Sense to start working !! // TODO limit number of retries - TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, msch_buffer, open_request_sense_complete)); + TU_ASSERT(tuh_msc_request_sense(dev_addr, cbw->lun, msch_buffer, config_request_sense_complete)); } return true; } -static bool open_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +static bool config_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) { TU_ASSERT(csw->status == 0); - TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, open_test_unit_ready_complete)); + TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, config_test_unit_ready_complete)); return true; } diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 06b1067cc..5913350b8 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -125,6 +125,7 @@ void tuh_msc_unmounted_cb(uint8_t dev_addr); void msch_init(void); bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length); +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); diff --git a/src/host/usbh.c b/src/host/usbh.c index 7d1201aa4..3e321652b 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -67,6 +67,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_MSC, .init = msch_init, .open = msch_open, + .set_config = msch_set_config, .xfer_cb = msch_xfer_cb, .close = msch_close }, @@ -78,6 +79,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_HID, .init = hidh_init, .open = hidh_open_subtask, + .set_config = hidh_set_config, .xfer_cb = hidh_xfer_cb, .close = hidh_close }, @@ -308,6 +310,7 @@ bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const 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++) { @@ -525,6 +528,31 @@ static uint8_t get_new_address(void) return CFG_TUSB_HOST_DEVICE_MAX+1; } +void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) +{ + usbh_device_t* dev = &_usbh_devices[dev_addr]; + + for(itf_num++; itf_num < sizeof(dev->itf2drv); itf_num++) + { + // continue with next valid interface + uint8_t const drv_id = dev->itf2drv[itf_num]; + if (drv_id != 0xff) + { + usbh_class_driver_t const * driver = &usbh_class_drivers[drv_id]; + TU_LOG2("%s set config itf = %u\r\n", driver->name, itf_num); + driver->set_config(dev_addr, itf_num); + break; + } + } + + // all interface are configured + if (itf_num == sizeof(dev->itf2drv)) + { + // Invoke callback if available + if (tuh_mount_cb) tuh_mount_cb(dev_addr); + } +} + //--------------------------------------------------------------------+ // Enumeration Process // is a lengthy process with a seires of control transfer to configure @@ -783,6 +811,7 @@ static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_r .wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1), .wIndex = 0, .wLength = total_len + }; TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_config_desc_complete) ); @@ -795,6 +824,10 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); + // Parse configuration & set up drivers + // Driver open aren't allowed to make any usb transfer yet + parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf); + TU_LOG2("Set Configuration Descriptor\r\n"); tusb_control_request_t const new_request = { @@ -825,12 +858,10 @@ static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t co dev->configured = 1; dev->state = TUSB_DEVICE_STATE_CONFIGURED; - // Parse configuration & set up drivers - // TODO driver open still use usbh_control_xfer - parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf); - - // Invoke callback if available - if (tuh_mount_cb) tuh_mount_cb(dev_addr); + // Start the Set Configuration process for interfaces (itf = 0xff) + // 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() + usbh_driver_set_config_complete(dev_addr, 0xff); return true; } @@ -883,9 +914,6 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura TU_LOG2("%s open\r\n", driver->name); uint16_t itf_len = 0; - - // TODO class driver can perform control transfer when opening which is - // non-blocking --> need a way to coordinate composite device TU_ASSERT( driver->open(dev->rhport, dev_addr, desc_itf, &itf_len) ); TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); p_desc += itf_len; diff --git a/src/host/usbh.h b/src/host/usbh.h index fde1dd11c..19ab72f54 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -58,10 +58,11 @@ typedef struct { uint8_t class_code; - void (* const init) (void); - bool (* const open)(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen); - 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); + void (* const init )(void); + bool (* const open )(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen); + 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; typedef bool (*tuh_control_complete_cb_t)(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); @@ -105,6 +106,7 @@ TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr); //--------------------------------------------------------------------+ // CLASS-USBH & INTERNAL API +// TODO move to usbh_pvt.h //--------------------------------------------------------------------+ bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); @@ -116,6 +118,8 @@ bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr); bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data); // TODO remove later +void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num); + #ifdef __cplusplus } #endif diff --git a/src/host/usbh_hcd.h b/src/host/usbh_hcd.h index 20348eed1..79b547fb3 100644 --- a/src/host/usbh_hcd.h +++ b/src/host/usbh_hcd.h @@ -47,6 +47,8 @@ //--------------------------------------------------------------------+ // USBH-HCD common data structure //--------------------------------------------------------------------+ + +// TODO move to usbh.c typedef struct { //------------- port -------------// uint8_t rhport; @@ -95,7 +97,6 @@ typedef struct { // TODO merge ep2drv here, 4-bit should be sufficient }ep_status[CFG_TUH_EP_MAX][2]; - // Mutex for claiming endpoint, only needed when using with preempted RTOS #if CFG_TUSB_OS != OPT_OS_NONE osal_mutex_def_t mutexdef;