From 4d57b4ea336d0ba89b97b388aa02f15c2d947a2a Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 13:57:07 +0700 Subject: [PATCH 01/25] clean up --- src/device/usbd.h | 2 -- src/host/usbh.c | 12 ++++-------- src/host/usbh.h | 9 +++++---- src/tusb.c | 2 +- tools/build_esp32s.py | 16 ++++++++++------ 5 files changed, 20 insertions(+), 21 deletions(-) diff --git a/src/device/usbd.h b/src/device/usbd.h index 5338be157..bbdd1be99 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -41,8 +41,6 @@ //--------------------------------------------------------------------+ // Init device stack -// Note: when using with RTOS, this should be called after scheduler/kernel is started. -// Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API. bool tud_init (void); // Task function should be called in main/rtos loop diff --git a/src/host/usbh.c b/src/host/usbh.c index 58550c93b..b6df6bad8 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -116,7 +116,7 @@ enum { USBH_CLASS_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; CFG_TUSB_MEM_SECTION usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1]; // Event queue -// role device/host is used by OS NONE for mutex (disable usb isr) only +// role device/host is used by OS NONE for mutex (disable usb isr) OSAL_QUEUE_DEF(OPT_MODE_HOST, _usbh_qdef, CFG_TUH_TASK_QUEUE_SZ, hcd_event_t); static osal_queue_t _usbh_q; @@ -137,7 +137,6 @@ tusb_device_state_t tuh_device_get_state (uint8_t const dev_addr) return (tusb_device_state_t) _usbh_devices[dev_addr].state; } - static inline void osal_task_delay(uint32_t msec) { (void) msec; @@ -149,7 +148,7 @@ static inline void osal_task_delay(uint32_t msec) //--------------------------------------------------------------------+ // CLASS-USBD API (don't require to verify parameters) //--------------------------------------------------------------------+ -bool usbh_init(void) +bool tuh_init(void) { tu_memclr(_usbh_devices, sizeof(usbh_device_t)*(CFG_TUSB_HOST_DEVICE_MAX+1)); @@ -385,13 +384,10 @@ bool enum_task(hcd_event_t* event) #endif }; - // for OSAL_NONE local variable won't retain value after blocking service sem_wait/queue_recv - static uint8_t configure_selected = 1; // TODO move - usbh_device_t* dev0 = &_usbh_devices[0]; tusb_control_request_t request; - dev0->rhport = event->rhport; // TODO refractor integrate to device_pool + dev0->rhport = event->rhport; // TODO refractor integrate to device_pool dev0->hub_addr = event->attach.hub_addr; dev0->hub_port = event->attach.hub_port; dev0->state = TUSB_DEVICE_STATE_UNPLUG; @@ -552,7 +548,7 @@ bool enum_task(hcd_event_t* event) new_dev->product_id = ((tusb_desc_device_t*) _usbh_ctrl_buf)->idProduct; new_dev->configure_count = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bNumConfigurations; - configure_selected = get_configure_number_for_device((tusb_desc_device_t*) _usbh_ctrl_buf); + uint8_t const configure_selected = get_configure_number_for_device((tusb_desc_device_t*) _usbh_ctrl_buf); TU_ASSERT(configure_selected <= new_dev->configure_count); // TODO notify application when invalid configuration //------------- Get 9 bytes of configuration descriptor -------------// diff --git a/src/host/usbh.h b/src/host/usbh.h index 27193d378..1930dc20b 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -70,6 +70,11 @@ typedef struct { //--------------------------------------------------------------------+ // APPLICATION API //--------------------------------------------------------------------+ + +// Init host stack +bool tuh_init(void); + +// Task function should be called in main/rtos loop void tuh_task(void); // Interrupt handler, name alias to HCD @@ -97,11 +102,7 @@ TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr); // CLASS-USBH & INTERNAL API //--------------------------------------------------------------------+ -// Note: when using with RTOS, this should be called after scheduler/kernel is started. -// Otherwise it could cause kernel issue since USB IRQ handler does use RTOS queue API. -bool usbh_init(void); bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data); - bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); #ifdef __cplusplus diff --git a/src/tusb.c b/src/tusb.c index 1bc134dba..ae1bc47e3 100644 --- a/src/tusb.c +++ b/src/tusb.c @@ -43,7 +43,7 @@ bool tusb_init(void) if (_initialized) return true; #if TUSB_OPT_HOST_ENABLED - TU_ASSERT( usbh_init() ); // init host stack + TU_ASSERT( tuh_init() ); // init host stack #endif #if TUSB_OPT_DEVICE_ENABLED diff --git a/tools/build_esp32s.py b/tools/build_esp32s.py index 9600b6145..44364806b 100644 --- a/tools/build_esp32s.py +++ b/tools/build_esp32s.py @@ -4,6 +4,10 @@ import sys import subprocess import time +SUCCEEDED = "\033[32msucceeded\033[0m" +FAILED = "\033[31mfailed\033[0m" +SKIPPED = "\033[33mskipped\033[0m" + success_count = 0 fail_count = 0 skip_count = 0 @@ -11,7 +15,7 @@ exit_status = 0 total_time = time.monotonic() -build_format = '| {:23} | {:30} | {:9} | {:7} | {:6} | {:6} |' +build_format = '| {:23} | {:30} | {:18} | {:7} | {:6} | {:6} |' build_separator = '-' * 100 # 1st Argument is Example, build all examples if not existed @@ -58,7 +62,7 @@ def skip_example(example, board): return 0 print(build_separator) -print(build_format.format('Example', 'Board', 'Result', 'Time', 'Flash', 'SRAM')) +print(build_format.format('Example', 'Board', '\033[39mResult\033[0m', 'Time', 'Flash', 'SRAM')) print(build_separator) for example in all_examples: @@ -70,19 +74,19 @@ for example in all_examples: # Check if board is skipped if skip_example(example, board): - success = "\033[33mskipped\033[0m " + success = SKIPPED skip_count += 1 print(build_format.format(example, board, success, '-', flash_size, sram_size)) else: build_result = build_example(example, board) if build_result.returncode == 0: - success = "\033[32msucceeded\033[0m" + success = SUCCEEDED success_count += 1 (flash_size, sram_size) = build_size(example, board) else: exit_status = build_result.returncode - success = "\033[31mfailed\033[0m " + success = FAILED fail_count += 1 build_duration = time.monotonic() - start_time @@ -95,7 +99,7 @@ for example in all_examples: total_time = time.monotonic() - total_time print(build_separator) -print("Build Sumamary: {} \033[32msucceeded\033[0m, {} \033[31mfailed\033[0m, {} \033[33mskipped\033[0m and took {:.2f}s".format(success_count, fail_count, skip_count, total_time)) +print("Build Summary: {} {}, {} {}, {} {} and took {:.2f}s".format(success_count, SUCCEEDED, fail_count, FAILED, skip_count, SKIPPED, total_time)) print(build_separator) sys.exit(exit_status) From f7cf8cdf27a016093df65c0de7167685e407d014 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 14:28:58 +0700 Subject: [PATCH 02/25] defer xfer_isr to xfer_cb --- src/class/cdc/cdc_host.c | 2 +- src/class/cdc/cdc_host.h | 2 +- src/class/hid/hid_host.c | 2 +- src/class/hid/hid_host.h | 2 +- src/class/msc/msc_host.c | 2 +- src/class/msc/msc_host.h | 2 +- src/host/hcd.h | 8 ++-- src/host/hub.c | 2 +- src/host/hub.h | 2 +- src/host/usbh.c | 88 ++++++++++++++++++++++++++-------------- src/host/usbh.h | 2 +- 11 files changed, 70 insertions(+), 44 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index e62f47b72..23e342134 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -209,7 +209,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it return true; } -void cdch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +void cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { (void) ep_addr; tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 306420ce4..0e2820fef 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -113,7 +113,7 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i //--------------------------------------------------------------------+ void cdch_init(void); bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length); -void cdch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void 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 diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 378278cc3..e17bfc9e5 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -232,7 +232,7 @@ bool hidh_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c return true; } -void hidh_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +void hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { (void) xferred_bytes; // TODO may need to use this para later diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 2e7f52674..54542de55 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -197,7 +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); -void hidh_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void 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); #ifdef __cplusplus diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 539e98376..b129d538f 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -383,7 +383,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it return true; } -void msch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +void msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { msch_interface_t* p_msc = &msch_data[dev_addr-1]; if ( ep_addr == p_msc->ep_in ) diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 959294adf..3eb45e6fc 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -193,7 +193,7 @@ typedef struct 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); -void msch_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void 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); #ifdef __cplusplus diff --git a/src/host/hcd.h b/src/host/hcd.h index 24cc62501..da530421d 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -51,17 +51,17 @@ typedef struct { uint8_t rhport; uint8_t event_id; + uint8_t dev_addr; union { - struct - { + struct { uint8_t hub_addr; uint8_t hub_port; } attach, remove; - struct - { + // XFER_COMPLETE + struct { uint8_t ep_addr; uint8_t result; uint32_t len; diff --git a/src/host/hub.c b/src/host/hub.c index eb85dfa42..4fb28b72f 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -199,7 +199,7 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf // is the response of interrupt endpoint polling #include "usbh_hcd.h" // FIXME remove -void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +void hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports (void) ep_addr; diff --git a/src/host/hub.h b/src/host/hub.h index 621356315..8f307190b 100644 --- a/src/host/hub.h +++ b/src/host/hub.h @@ -182,7 +182,7 @@ bool hub_status_pipe_queue(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 *p_length); -void hub_isr(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +void 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 diff --git a/src/host/usbh.c b/src/host/usbh.c index b6df6bad8..73a4fc9f3 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -56,7 +56,7 @@ static host_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_CDC, .init = cdch_init, .open = cdch_open, - .isr = cdch_isr, + .xfer_cb = cdch_xfer_cb, .close = cdch_close }, #endif @@ -67,7 +67,7 @@ static host_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_MSC, .init = msch_init, .open = msch_open, - .isr = msch_isr, + .xfer_cb = msch_xfer_cb, .close = msch_close }, #endif @@ -78,7 +78,7 @@ static host_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_HID, .init = hidh_init, .open = hidh_open_subtask, - .isr = hidh_isr, + .xfer_cb = hidh_xfer_cb, .close = hidh_close }, #endif @@ -89,7 +89,7 @@ static host_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_HUB, .init = hub_init, .open = hub_open, - .isr = hub_isr, + .xfer_cb = hub_xfer_cb, .close = hub_close }, #endif @@ -100,7 +100,7 @@ static host_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_VENDOR_SPECIFIC, .init = cush_init, .open = cush_open_subtask, - .isr = cush_isr, + .xfer_cb = cush_isr, .close = cush_close } #endif @@ -263,33 +263,46 @@ bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const } //--------------------------------------------------------------------+ -// USBH-HCD ISR/Callback API +// HCD Event Handler //--------------------------------------------------------------------+ + +void hcd_event_handler(hcd_event_t const* event, bool in_isr) +{ + switch (event->event_id) + { + default: + osal_queue_send(_usbh_q, event, in_isr); + break; + } +} + // 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, xfer_result_t event, uint32_t xferred_bytes) +void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint8_t result, uint32_t xferred_bytes) { usbh_device_t* dev = &_usbh_devices[ dev_addr ]; if (0 == tu_edpt_number(ep_addr)) { - dev->control.pipe_status = event; + dev->control.pipe_status = result; // usbh_devices[ pipe_hdl.dev_addr ].control.xferred_bytes = xferred_bytes; not yet neccessary osal_semaphore_post( dev->control.sem_hdl, true ); } else { - uint8_t drv_id = dev->ep2drv[tu_edpt_number(ep_addr)][tu_edpt_dir(ep_addr)]; - TU_ASSERT(drv_id < USBH_CLASS_DRIVER_COUNT, ); + hcd_event_t event = + { + .rhport = 0, + .event_id = HCD_EVENT_XFER_COMPLETE, + .dev_addr = dev_addr, + .xfer_complete = + { + .ep_addr = ep_addr, + .result = result, + .len = xferred_bytes + } + }; - if (usbh_class_drivers[drv_id].isr) - { - //TU_LOG2("%s isr\r\n", usbh_class_drivers[drv_id].name); - usbh_class_drivers[drv_id].isr(dev_addr, ep_addr, event, xferred_bytes); - } - else - { - TU_BREAKPOINT(); // something wrong, no one claims the isr's source - } + hcd_event_handler(&event, true); } } @@ -307,16 +320,6 @@ void hcd_event_device_attach(uint8_t rhport) hcd_event_handler(&event, true); } -void hcd_event_handler(hcd_event_t const* event, bool in_isr) -{ - switch (event->event_id) - { - default: - osal_queue_send(_usbh_q, event, in_isr); - break; - } -} - void hcd_event_device_remove(uint8_t hostid) { hcd_event_t event = @@ -419,7 +422,7 @@ bool enum_task(hcd_event_t* event) return true; // restart task } } - #if CFG_TUH_HUB +#if CFG_TUH_HUB //------------- connected/disconnected via hub -------------// else { @@ -462,7 +465,7 @@ bool enum_task(hcd_event_t* event) hub_port_clear_feature_subtask(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); } } - #endif +#endif // CFG_TUH_HUB TU_ASSERT_ERR( usbh_pipe_control_open(0, 8) ); @@ -684,6 +687,29 @@ void tuh_task(void) enum_task(&event); break; + case HCD_EVENT_XFER_COMPLETE: + { + usbh_device_t* dev = &_usbh_devices[event.dev_addr]; + uint8_t const ep_addr = event.xfer_complete.ep_addr; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + TU_LOG2("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); + + if ( 0 == epnum ) + { + // TODO control transfer + }else + { + uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; + TU_ASSERT(drv_id < USBH_CLASS_DRIVER_COUNT, ); + + TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name); + usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len); + } + } + break; + default: break; } } diff --git a/src/host/usbh.h b/src/host/usbh.h index 1930dc20b..56a5ce72f 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -60,7 +60,7 @@ typedef struct { void (* const init) (void); bool (* const open)(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen); - void (* const isr) (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t len); + void (* const xfer_cb) (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t len); void (* const close) (uint8_t); } host_class_driver_t; //--------------------------------------------------------------------+ From 9531e47d10915b652c2c5cff9ef2956889639f93 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 14:59:07 +0700 Subject: [PATCH 03/25] update example to test with mouse --- examples/host/cdc_msc_hid/src/main.c | 97 +++++++++++++++++++++++----- src/class/hid/hid_host.c | 5 +- 2 files changed, 85 insertions(+), 17 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/main.c b/examples/host/cdc_msc_hid/src/main.c index 4200cc5e0..bbaac8644 100644 --- a/examples/host/cdc_msc_hid/src/main.c +++ b/examples/host/cdc_msc_hid/src/main.c @@ -111,6 +111,7 @@ void cdc_task(void) //--------------------------------------------------------------------+ #if CFG_TUH_HID_KEYBOARD +CFG_TUSB_MEM_SECTION static hid_keyboard_report_t usb_keyboard_report; uint8_t const keycode2ascii[128][2] = { HID_KEYCODE_TO_ASCII }; // look up new key in previous keys @@ -153,21 +154,6 @@ static inline void process_kbd_report(hid_keyboard_report_t const *p_new_report) prev_report = *p_new_report; } -CFG_TUSB_MEM_SECTION static hid_keyboard_report_t usb_keyboard_report; - -void hid_task(void) -{ - uint8_t const addr = 1; - if ( tuh_hid_keyboard_is_mounted(addr) ) - { - if ( !tuh_hid_keyboard_is_busy(addr) ) - { - process_kbd_report(&usb_keyboard_report); - tuh_hid_keyboard_get_report(addr, &usb_keyboard_report); - } - } -} - void tuh_hid_keyboard_mounted_cb(uint8_t dev_addr) { // application set-up @@ -192,6 +178,58 @@ void tuh_hid_keyboard_isr(uint8_t dev_addr, xfer_result_t event) #endif #if CFG_TUH_HID_MOUSE + +CFG_TUSB_MEM_SECTION static hid_mouse_report_t usb_mouse_report; + +void cursor_movement(int8_t x, int8_t y, int8_t wheel) +{ + //------------- X -------------// + if ( x < 0) + { + printf(ANSI_CURSOR_BACKWARD(%d), (-x)); // move left + }else if ( x > 0) + { + printf(ANSI_CURSOR_FORWARD(%d), x); // move right + }else { } + + //------------- Y -------------// + if ( y < 0) + { + printf(ANSI_CURSOR_UP(%d), (-y)); // move up + }else if ( y > 0) + { + printf(ANSI_CURSOR_DOWN(%d), y); // move down + }else { } + + //------------- wheel -------------// + if (wheel < 0) + { + printf(ANSI_SCROLL_UP(%d), (-wheel)); // scroll up + }else if (wheel > 0) + { + printf(ANSI_SCROLL_DOWN(%d), wheel); // scroll down + }else { } +} + +static inline void process_mouse_report(hid_mouse_report_t const * p_report) +{ + static hid_mouse_report_t prev_report = { 0 }; + + //------------- button state -------------// + uint8_t button_changed_mask = p_report->buttons ^ prev_report.buttons; + if ( button_changed_mask & p_report->buttons) + { + printf(" %c%c%c ", + p_report->buttons & MOUSE_BUTTON_LEFT ? 'L' : '-', + p_report->buttons & MOUSE_BUTTON_MIDDLE ? 'M' : '-', + p_report->buttons & MOUSE_BUTTON_RIGHT ? 'R' : '-'); + } + + //------------- cursor movement -------------// + cursor_movement(p_report->x, p_report->y, p_report->wheel); +} + + void tuh_hid_mouse_mounted_cb(uint8_t dev_addr) { // application set-up @@ -212,6 +250,35 @@ void tuh_hid_mouse_isr(uint8_t dev_addr, xfer_result_t event) } #endif + + +void hid_task(void) +{ + uint8_t const addr = 1; + +#if CFG_TUH_HID_KEYBOARD + if ( tuh_hid_keyboard_is_mounted(addr) ) + { + if ( !tuh_hid_keyboard_is_busy(addr) ) + { + process_kbd_report(&usb_keyboard_report); + tuh_hid_keyboard_get_report(addr, &usb_mouse_report); + } + } +#endif + +#if CFG_TUH_HID_MOUSE + if ( tuh_hid_mouse_is_mounted(addr) ) + { + if ( !tuh_hid_mouse_is_busy(addr) ) + { + process_mouse_report(&usb_mouse_report); + tuh_hid_mouse_get_report(addr, &usb_mouse_report); + } + } +#endif +} + //--------------------------------------------------------------------+ // tinyusb callbacks //--------------------------------------------------------------------+ diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index e17bfc9e5..d9ed1f651 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -173,7 +173,8 @@ 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); - //------------- SET IDLE (0) request -------------// + // SET IDLE = 0 request + // Device can stall if not support this request tusb_control_request_t request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, .bRequest = HID_REQ_CONTROL_SET_IDLE, @@ -181,7 +182,7 @@ bool hidh_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c .wIndex = p_interface_desc->bInterfaceNumber, .wLength = 0 }; - TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) ); + usbh_control_xfer( dev_addr, &request, NULL ); // TODO stall is valid #if 0 //------------- Get Report Descriptor TODO HID parser -------------// From d87f2a96914ef381045d80f35299a84a5118c57f Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 15:05:25 +0700 Subject: [PATCH 04/25] remove usbh control mutex --- src/host/usbh.c | 7 ------- src/host/usbh_hcd.h | 3 --- 2 files changed, 10 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 73a4fc9f3..4c35e7d65 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -164,9 +164,6 @@ bool tuh_init(void) dev->control.sem_hdl = osal_semaphore_create(&dev->control.sem_def); TU_ASSERT(dev->control.sem_hdl != NULL); - dev->control.mutex_hdl = osal_mutex_create(&dev->control.mutex_def); - TU_ASSERT(dev->control.mutex_hdl != NULL); - memset(dev->itf2drv, 0xff, sizeof(dev->itf2drv)); // invalid mapping memset(dev->ep2drv , 0xff, sizeof(dev->ep2drv )); // invalid mapping } @@ -190,8 +187,6 @@ bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8 usbh_device_t* dev = &_usbh_devices[dev_addr]; const uint8_t rhport = dev->rhport; - TU_ASSERT(osal_mutex_lock(dev->control.mutex_hdl, OSAL_TIMEOUT_NORMAL)); - dev->control.request = *request; dev->control.pipe_status = 0; @@ -210,8 +205,6 @@ bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8 hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0); TU_VERIFY(osal_semaphore_wait(dev->control.sem_hdl, OSAL_TIMEOUT_NORMAL)); - osal_mutex_unlock(dev->control.mutex_hdl); - if ( XFER_RESULT_STALLED == dev->control.pipe_status ) return false; if ( XFER_RESULT_FAILED == dev->control.pipe_status ) return false; diff --git a/src/host/usbh_hcd.h b/src/host/usbh_hcd.h index 01be82851..019b9f037 100644 --- a/src/host/usbh_hcd.h +++ b/src/host/usbh_hcd.h @@ -69,9 +69,6 @@ typedef struct { osal_semaphore_def_t sem_def; osal_semaphore_t sem_hdl; // used to synchronize with HCD when control xfer complete - - osal_mutex_def_t mutex_def; - osal_mutex_t mutex_hdl; // used to exclusively occupy control pipe } control; uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) From bc09b6065fc2b90783a56ff66b84933353566b08 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 15:16:45 +0700 Subject: [PATCH 05/25] refactor extract parse_configuration_descriptor() --- src/host/usbh.c | 113 ++++++++++++++++++++++++++---------------------- 1 file changed, 61 insertions(+), 52 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 4c35e7d65..67b6efbd1 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -366,6 +366,64 @@ static void usbh_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_ //--------------------------------------------------------------------+ // ENUMERATION TASK //--------------------------------------------------------------------+ +static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) +{ + usbh_device_t* dev = &_usbh_devices[dev_addr]; + uint8_t const* p_desc = (uint8_t const*) desc_cfg; + p_desc = tu_desc_next(p_desc); + + TU_LOG2_MEM(desc_cfg, desc_cfg->wTotalLength, 0); + + // parse each interfaces + while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength ) + { + // skip until we see interface descriptor + if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) + { + p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length + }else + { + tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; + + // Check if class is supported + 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; + } + + if( drv_id >= USBH_CLASS_DRIVER_COUNT ) + { + // skip unsupported class + p_desc = tu_desc_next(p_desc); + } + else + { + // 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) + { + // TODO Attach hub to Hub is not currently supported + // skip this interface + p_desc = tu_desc_next(p_desc); + } + else + { + uint16_t itf_len = 0; + + TU_LOG2("%s open\r\n", usbh_class_drivers[drv_id].name); + TU_ASSERT( usbh_class_drivers[drv_id].open(dev->rhport, dev_addr, desc_itf, &itf_len) ); + TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); + p_desc += itf_len; + } + } + } + } + + return true; +} bool enum_task(hcd_event_t* event) { @@ -585,59 +643,10 @@ bool enum_task(hcd_event_t* event) //------------- TODO Get String Descriptors -------------// - //------------- parse configuration & install drivers -------------// - uint8_t const* p_desc = _usbh_ctrl_buf + sizeof(tusb_desc_configuration_t); - - // TU_LOG2_MEM(_usbh_ctrl_buf, ((tusb_desc_configuration_t*)_usbh_ctrl_buf)->wTotalLength, 0); - - // parse each interfaces - while( p_desc < _usbh_ctrl_buf + ((tusb_desc_configuration_t*)_usbh_ctrl_buf)->wTotalLength ) - { - // skip until we see interface descriptor - if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) - { - p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length - }else - { - tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; - - // Check if class is supported - 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; - } - - if( drv_id >= USBH_CLASS_DRIVER_COUNT ) - { - // skip unsupported class - p_desc = tu_desc_next(p_desc); - } - else - { - // Interface number must not be used already TODO alternate interface - TU_ASSERT( new_dev->itf2drv[desc_itf->bInterfaceNumber] == 0xff ); - new_dev->itf2drv[desc_itf->bInterfaceNumber] = drv_id; - - if (desc_itf->bInterfaceClass == TUSB_CLASS_HUB && new_dev->hub_addr != 0) - { - // TODO Attach hub to Hub is not currently supported - // skip this interface - p_desc = tu_desc_next(p_desc); - } - else - { - uint16_t itf_len = 0; - - TU_LOG2("%s open\r\n", usbh_class_drivers[drv_id].name); - TU_ASSERT( usbh_class_drivers[drv_id].open(new_dev->rhport, new_addr, desc_itf, &itf_len) ); - TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); - p_desc += itf_len; - } - } - } - } + // Parse configuration & set up drivers + parse_configuration_descriptor(new_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf); + // Invoke callback if available if (tuh_mount_cb) tuh_mount_cb(new_addr); return true; From 90c8c14652ec81b34c9f2fa6ce69fa25d74a5bbf Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 15:19:01 +0700 Subject: [PATCH 06/25] clean up --- src/host/usbh.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 67b6efbd1..da163f9e4 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -211,7 +211,7 @@ bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8 return true; } -tusb_error_t usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) +bool usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) { osal_semaphore_reset( _usbh_devices[dev_addr].control.sem_hdl ); //osal_mutex_reset( usbh_devices[dev_addr].control.mutex_hdl ); @@ -226,9 +226,7 @@ tusb_error_t usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) .bInterval = 0 }; - hcd_edpt_open(_usbh_devices[dev_addr].rhport, dev_addr, &ep0_desc); - - return TUSB_ERROR_NONE; + 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 * ep_desc) @@ -518,7 +516,7 @@ bool enum_task(hcd_event_t* event) } #endif // CFG_TUH_HUB - TU_ASSERT_ERR( usbh_pipe_control_open(0, 8) ); + TU_ASSERT( usbh_pipe_control_open(0, 8) ); //------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------// TU_LOG2("Get 8 byte of Device Descriptor\r\n"); @@ -584,7 +582,7 @@ bool enum_task(hcd_event_t* event) dev0->state = TUSB_DEVICE_STATE_UNPLUG; // open control pipe for new address - TU_ASSERT_ERR ( usbh_pipe_control_open(new_addr, ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0 ) ); + TU_ASSERT ( usbh_pipe_control_open(new_addr, ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0 ) ); //------------- Get full device descriptor -------------// TU_LOG2("Get Device Descriptor \r\n"); From b8b95e84944b4c07cc9c9f4a7e4d53e6256b42f0 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 15:45:03 +0700 Subject: [PATCH 07/25] add in_isr to all hcd event functions --- src/device/dcd.h | 2 +- src/host/ehci/ehci.c | 8 ++++---- src/host/hcd.h | 30 ++++++++++++++++-------------- src/host/hub.c | 2 +- src/host/ohci/ohci.c | 6 +++--- src/host/usbh.c | 14 +++++++------- 6 files changed, 32 insertions(+), 30 deletions(-) diff --git a/src/device/dcd.h b/src/device/dcd.h index 776f782b8..a5c485f9e 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -140,7 +140,7 @@ void dcd_edpt_stall (uint8_t rhport, uint8_t ep_addr); void dcd_edpt_clear_stall (uint8_t rhport, uint8_t ep_addr); //--------------------------------------------------------------------+ -// Event API (Implemented by device stack) +// Event API (implemented by stack) //--------------------------------------------------------------------+ // Called by DCD to notify device stack diff --git a/src/host/ehci/ehci.c b/src/host/ehci/ehci.c index 295da4566..c2d5ebf7b 100644 --- a/src/host/ehci/ehci.c +++ b/src/host/ehci/ehci.c @@ -489,10 +489,10 @@ static void port_connect_status_change_isr(uint8_t hostid) if (ehci_data.regs->portsc_bm.current_connect_status) { hcd_port_reset(hostid); - hcd_event_device_attach(hostid); + hcd_event_device_attach(hostid, true); }else // device unplugged { - hcd_event_device_remove(hostid); + hcd_event_device_remove(hostid, true); } } @@ -512,7 +512,7 @@ static void qhd_xfer_complete_isr(ehci_qhd_t * p_qhd) { // end of request // call USBH callback - hcd_event_xfer_complete(p_qhd->dev_addr, tu_edpt_addr(p_qhd->ep_number, p_qhd->pid == EHCI_PID_IN ? 1 : 0), XFER_RESULT_SUCCESS, p_qhd->total_xferred_bytes); + hcd_event_xfer_complete(p_qhd->dev_addr, tu_edpt_addr(p_qhd->ep_number, p_qhd->pid == EHCI_PID_IN ? 1 : 0), p_qhd->total_xferred_bytes, XFER_RESULT_SUCCESS, true); p_qhd->total_xferred_bytes = 0; } } @@ -599,7 +599,7 @@ static void qhd_xfer_error_isr(ehci_qhd_t * p_qhd) } // call USBH callback - hcd_event_xfer_complete(p_qhd->dev_addr, tu_edpt_addr(p_qhd->ep_number, p_qhd->pid == EHCI_PID_IN ? 1 : 0), error_event, p_qhd->total_xferred_bytes); + hcd_event_xfer_complete(p_qhd->dev_addr, tu_edpt_addr(p_qhd->ep_number, p_qhd->pid == EHCI_PID_IN ? 1 : 0), p_qhd->total_xferred_bytes, error_event, true); p_qhd->total_xferred_bytes = 0; } diff --git a/src/host/hcd.h b/src/host/hcd.h index da530421d..eebf2c801 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -109,20 +109,6 @@ tusb_speed_t hcd_port_speed_get(uint8_t hostid); // HCD closes all opened endpoints belong to this device void hcd_device_close(uint8_t rhport, uint8_t dev_addr); -//--------------------------------------------------------------------+ -// Event function -//--------------------------------------------------------------------+ -void hcd_event_handler(hcd_event_t const* event, bool in_isr); - -// Helper to send device attach event -void hcd_event_device_attach(uint8_t rhport); - -// Helper to send device removal event -void hcd_event_device_remove(uint8_t rhport); - -// Helper to send USB transfer event -void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); - //--------------------------------------------------------------------+ // Endpoints API //--------------------------------------------------------------------+ @@ -145,6 +131,22 @@ bool hcd_pipe_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t buffer[], uint16_t // tusb_error_t hcd_pipe_cancel(); +//--------------------------------------------------------------------+ +// Event API (implemented by stack) +//--------------------------------------------------------------------+ + +// Called by HCD to notify stack +extern void hcd_event_handler(hcd_event_t const* event, bool in_isr); + +// Helper to send device attach event +extern void hcd_event_device_attach(uint8_t rhport, bool in_isr); + +// Helper to send device removal event +extern void hcd_event_device_remove(uint8_t rhport, bool in_isr); + +// Helper to send USB transfer event +extern void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr); + #ifdef __cplusplus } #endif diff --git a/src/host/hub.c b/src/host/hub.c index 4fb28b72f..f88056c92 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -223,7 +223,7 @@ void hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_ event.attach.hub_port = port; hcd_event_handler(&event, true); - break; // handle one port at a time, next port if any will be handled in the next cycle + break; // TODO handle one port at a time, next port if any will be handled in the next cycle } } // NOTE: next status transfer is queued by usbh.c after handling this request diff --git a/src/host/ohci/ohci.c b/src/host/ohci/ohci.c index 114f52e7d..87da374d5 100644 --- a/src/host/ohci/ohci.c +++ b/src/host/ohci/ohci.c @@ -599,7 +599,7 @@ static void done_queue_isr(uint8_t hostid) hcd_event_xfer_complete(p_ed->dev_addr, tu_edpt_addr(p_ed->ep_number, p_ed->pid == OHCI_PID_IN), - event, xferred_bytes); + xferred_bytes, event, true); } td_head = (ohci_td_item_t*) td_head->next; @@ -632,10 +632,10 @@ void hcd_int_handler(uint8_t hostid) { // TODO reset port immediately, without this controller will got 2-3 (debouncing connection status change) OHCI_REG->rhport_status[0] = OHCI_RHPORT_PORT_RESET_STATUS_MASK; - hcd_event_device_attach(0); + hcd_event_device_attach(hostid, true); }else { - hcd_event_device_remove(0); + hcd_event_device_remove(hostid, true); } } diff --git a/src/host/usbh.c b/src/host/usbh.c index da163f9e4..6304b6b48 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -268,7 +268,7 @@ 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, uint8_t result, uint32_t xferred_bytes) +void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred_bytes, xfer_result_t result, bool in_isr) { usbh_device_t* dev = &_usbh_devices[ dev_addr ]; @@ -276,7 +276,7 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint8_t result, { dev->control.pipe_status = result; // usbh_devices[ pipe_hdl.dev_addr ].control.xferred_bytes = xferred_bytes; not yet neccessary - osal_semaphore_post( dev->control.sem_hdl, true ); + osal_semaphore_post( dev->control.sem_hdl, true ); // FIXME post within ISR } else { @@ -293,11 +293,11 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint8_t result, } }; - hcd_event_handler(&event, true); + hcd_event_handler(&event, in_isr); } } -void hcd_event_device_attach(uint8_t rhport) +void hcd_event_device_attach(uint8_t rhport, bool in_isr) { hcd_event_t event = { @@ -308,10 +308,10 @@ void hcd_event_device_attach(uint8_t rhport) event.attach.hub_addr = 0; event.attach.hub_port = 0; - hcd_event_handler(&event, true); + hcd_event_handler(&event, in_isr); } -void hcd_event_device_remove(uint8_t hostid) +void hcd_event_device_remove(uint8_t hostid, bool in_isr) { hcd_event_t event = { @@ -322,7 +322,7 @@ void hcd_event_device_remove(uint8_t hostid) event.attach.hub_addr = 0; event.attach.hub_port = 0; - hcd_event_handler(&event, true); + hcd_event_handler(&event, in_isr); } From 7ffb6acc1625022d8a79c1d408b11240707136ca Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 17:16:46 +0700 Subject: [PATCH 08/25] more clean up --- src/host/usbh.c | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 6304b6b48..2e1fed5e3 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -426,14 +426,8 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura bool enum_task(hcd_event_t* event) { enum { -#if 1 - // FIXME ohci LPC1769 xpresso + debugging to have 1st control xfer to work, some kind of timing or ohci driver issue !!! POWER_STABLE_DELAY = 100, - RESET_DELAY = 500 -#else - POWER_STABLE_DELAY = 500, - RESET_DELAY = 200, // USB specs say only 50ms but many devices require much longer -#endif + RESET_DELAY = 500, // 200 USB specs say only 50ms but many devices require much longer }; usbh_device_t* dev0 = &_usbh_devices[0]; @@ -534,14 +528,13 @@ bool enum_task(hcd_event_t* event) if (dev0->hub_addr == 0) { + TU_ASSERT(is_ok); + // connected directly to roothub - TU_ASSERT(is_ok); // TODO some slow device is observed to fail the very fist controller xfer, can try more times hcd_port_reset( dev0->rhport ); // reset port after 8 byte descriptor osal_task_delay(RESET_DELAY); -// hcd_port_reset_end(dev0->rhport); -// osal_task_delay(RESET_DELAY); } - #if CFG_TUH_HUB +#if CFG_TUH_HUB else { // connected via a hub @@ -555,7 +548,7 @@ bool enum_task(hcd_event_t* event) (void) hub_status_pipe_queue( dev0->hub_addr ); // done with hub, waiting for next data on status pipe } - #endif +#endif // CFG_TUH_HUB //------------- Set new address -------------// TU_LOG2("Set Address \r\n"); From 828f720207d4ded25ed533ea6c52da49c799b476 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 20:20:45 +0700 Subject: [PATCH 09/25] refactor hub class - separate connect/disconnect handling - hub work with full speed, but doesn't seem to work with Low speed device (with mcb1800) - need to update msc host after migrating from isr to xfer_cb (blocked at inquiry) --- examples/host/cdc_msc_hid/src/tusb_config.h | 2 +- src/host/ehci/ehci.c | 2 +- src/host/hcd.h | 3 +- src/host/hub.c | 106 +++++++++----------- src/host/hub.h | 32 +++--- src/host/usbh.c | 106 ++++++++------------ 6 files changed, 114 insertions(+), 137 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/tusb_config.h b/examples/host/cdc_msc_hid/src/tusb_config.h index 6604623b1..d8cf993be 100644 --- a/examples/host/cdc_msc_hid/src/tusb_config.h +++ b/examples/host/cdc_msc_hid/src/tusb_config.h @@ -69,7 +69,7 @@ // CONFIGURATION //-------------------------------------------------------------------- -#define CFG_TUH_HUB 0 +#define CFG_TUH_HUB 1 #define CFG_TUH_CDC 1 #define CFG_TUH_HID_KEYBOARD 1 #define CFG_TUH_HID_MOUSE 1 diff --git a/src/host/ehci/ehci.c b/src/host/ehci/ehci.c index c2d5ebf7b..13e9b0edc 100644 --- a/src/host/ehci/ehci.c +++ b/src/host/ehci/ehci.c @@ -533,7 +533,7 @@ static void async_list_xfer_complete_isr(ehci_qhd_t * const async_head) static void period_list_xfer_complete_isr(uint8_t hostid, uint8_t interval_ms) { - uint8_t max_loop = 0; + uint16_t max_loop = 0; uint32_t const period_1ms_addr = (uint32_t) get_period_head(hostid, 1); ehci_link_t next_item = * get_period_head(hostid, interval_ms); diff --git a/src/host/hcd.h b/src/host/hcd.h index eebf2c801..ba3035300 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -55,10 +55,11 @@ typedef struct union { + // Attach, Remove struct { uint8_t hub_addr; uint8_t hub_port; - } attach, remove; + } connection; // XFER_COMPLETE struct { diff --git a/src/host/hub.c b/src/host/hub.c index f88056c92..db1ca0786 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -33,6 +33,8 @@ //--------------------------------------------------------------------+ #include "hub.h" +extern void osal_task_delay(uint32_t msec); // TODO remove + //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ @@ -53,7 +55,7 @@ TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t hub_enum_buffer[sizeof(de //--------------------------------------------------------------------+ // HUB //--------------------------------------------------------------------+ -bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature) +bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature) { TU_ASSERT(HUB_FEATURE_PORT_CONNECTION_CHANGE <= feature && feature <= HUB_FEATURE_PORT_RESET_CHANGE); @@ -65,33 +67,35 @@ bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t .wLength = 0 }; - //------------- Clear Port Feature request -------------// TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); + return true; +} - //------------- Get Port Status to check if feature is cleared -------------// - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN }, - .bRequest = HUB_REQUEST_GET_STATUS, - .wValue = 0, - .wIndex = hub_port, - .wLength = 4 +bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) +{ + tusb_control_request_t request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_OTHER, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + + .bRequest = HUB_REQUEST_GET_STATUS, + .wValue = 0, + .wIndex = hub_port, + .wLength = 4 }; TU_ASSERT( usbh_control_xfer( hub_addr, &request, hub_enum_buffer ) ); - //------------- Check if feature is cleared -------------// - hub_port_status_response_t * p_port_status; - p_port_status = (hub_port_status_response_t *) hub_enum_buffer; - - TU_ASSERT( !tu_bit_test(p_port_status->status_change.value, feature-16) ); - + memcpy(resp, hub_enum_buffer, sizeof(hub_port_status_response_t)); return true; } -bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port) +bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port) { - enum { RESET_DELAY = 200 }; // USB specs say only 50ms but many devices require much longer - //------------- Set Port Reset -------------// tusb_control_request_t request = { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, @@ -102,37 +106,9 @@ bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port) }; TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); - - osal_task_delay(RESET_DELAY); // TODO Hub wait for Status Endpoint on Reset Change - - //------------- Get Port Status to check if port is enabled, powered and reset_change -------------// - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN }, - .bRequest = HUB_REQUEST_GET_STATUS, - .wValue = 0, - .wIndex = hub_port, - .wLength = 4 - }; - - TU_ASSERT( usbh_control_xfer( hub_addr, &request, hub_enum_buffer ) ); - - hub_port_status_response_t * p_port_status; - p_port_status = (hub_port_status_response_t *) hub_enum_buffer; - - TU_ASSERT ( p_port_status->status_change.reset && p_port_status->status_current.connect_status && - p_port_status->status_current.port_power && p_port_status->status_current.port_enable); - return true; } -// can only get the speed RIGHT AFTER hub_port_reset_subtask call -tusb_speed_t hub_port_get_speed(void) -{ - hub_port_status_response_t * p_port_status = (hub_port_status_response_t *) hub_enum_buffer; - return (p_port_status->status_current.high_speed_device_attached) ? TUSB_SPEED_HIGH : - (p_port_status->status_current.low_speed_device_attached ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; -} - //--------------------------------------------------------------------+ // CLASS-USBH API (don't require to verify parameters) //--------------------------------------------------------------------+ @@ -199,31 +175,49 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf // is the response of interrupt endpoint polling #include "usbh_hcd.h" // FIXME remove -void hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +void hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports (void) ep_addr; usbh_hub_t * p_hub = &hub_data[dev_addr-1]; - if ( event == XFER_RESULT_SUCCESS ) + if ( result == XFER_RESULT_SUCCESS ) { + TU_LOG2("Port Status Change = 0x%02X\r\n", p_hub->status_change); for (uint8_t port=1; port <= p_hub->port_number; port++) { // TODO HUB ignore bit0 hub_status_change if ( tu_bit_test(p_hub->status_change, port) ) { - hcd_event_t event = + hub_port_status_response_t port_status; + hub_port_get_status(dev_addr, port, &port_status); + + // Connection change + if (port_status.change.connection) { - .rhport = _usbh_devices[dev_addr].rhport, - .event_id = HCD_EVENT_DEVICE_ATTACH - }; + // Port is powered and enabled + //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, ); - event.attach.hub_addr = dev_addr; - event.attach.hub_port = port; + // Acknowledge Port Connection Change + hub_port_clear_feature(dev_addr, port, HUB_FEATURE_PORT_CONNECTION_CHANGE); - hcd_event_handler(&event, true); - break; // TODO handle one port at a time, next port if any will be handled in the next cycle + // Reset port if attach event + if ( port_status.status.connection ) hub_port_reset(dev_addr, port); + + hcd_event_t event = + { + .rhport = _usbh_devices[dev_addr].rhport, + .event_id = port_status.status.connection ? HCD_EVENT_DEVICE_ATTACH : HCD_EVENT_DEVICE_REMOVE, + .connection = + { + .hub_addr = dev_addr, + .hub_port = port + } + }; + + hcd_event_handler(&event, true); + } } } // NOTE: next status transfer is queued by usbh.c after handling this request diff --git a/src/host/hub.h b/src/host/hub.h index 8f307190b..71dd39b8d 100644 --- a/src/host/hub.h +++ b/src/host/hub.h @@ -142,7 +142,7 @@ typedef struct { }; uint16_t value; - } status, status_change; + } status, change; } hub_status_response_t; TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct"); @@ -151,30 +151,30 @@ TU_VERIFY_STATIC( sizeof(hub_status_response_t) == 4, "size is not correct"); typedef struct { union { struct TU_ATTR_PACKED { - uint16_t connect_status : 1; - uint16_t port_enable : 1; - uint16_t suspend : 1; - uint16_t over_current : 1; - uint16_t reset : 1; + uint16_t connection : 1; + uint16_t port_enable : 1; + uint16_t suspend : 1; + uint16_t over_current : 1; + uint16_t reset : 1; - uint16_t : 3; - uint16_t port_power : 1; - uint16_t low_speed_device_attached : 1; - uint16_t high_speed_device_attached : 1; - uint16_t port_test_mode : 1; - uint16_t port_indicator_control : 1; + uint16_t : 3; + uint16_t port_power : 1; + uint16_t low_speed : 1; + uint16_t high_speed : 1; + uint16_t port_test_mode : 1; + uint16_t port_indicator_control : 1; uint16_t : 0; }; uint16_t value; - } status_current, status_change; + } status, change; } hub_port_status_response_t; TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct"); -bool hub_port_reset_subtask(uint8_t hub_addr, uint8_t hub_port); -bool hub_port_clear_feature_subtask(uint8_t hub_addr, uint8_t hub_port, uint8_t feature); -tusb_speed_t hub_port_get_speed(void); +bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port); +bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp); +bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature); bool hub_status_pipe_queue(uint8_t dev_addr); //--------------------------------------------------------------------+ diff --git a/src/host/usbh.c b/src/host/usbh.c index 2e1fed5e3..fd0e9ee18 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -137,7 +137,7 @@ tusb_device_state_t tuh_device_get_state (uint8_t const dev_addr) return (tusb_device_state_t) _usbh_devices[dev_addr].state; } -static inline void osal_task_delay(uint32_t msec) +void osal_task_delay(uint32_t msec) { (void) msec; @@ -305,8 +305,8 @@ void hcd_event_device_attach(uint8_t rhport, bool in_isr) .event_id = HCD_EVENT_DEVICE_ATTACH }; - event.attach.hub_addr = 0; - event.attach.hub_port = 0; + event.connection.hub_addr = 0; + event.connection.hub_port = 0; hcd_event_handler(&event, in_isr); } @@ -319,8 +319,8 @@ void hcd_event_device_remove(uint8_t hostid, bool in_isr) .event_id = HCD_EVENT_DEVICE_REMOVE }; - event.attach.hub_addr = 0; - event.attach.hub_port = 0; + event.connection.hub_addr = 0; + event.connection.hub_port = 0; hcd_event_handler(&event, in_isr); } @@ -434,78 +434,44 @@ bool enum_task(hcd_event_t* event) tusb_control_request_t request; dev0->rhport = event->rhport; // TODO refractor integrate to device_pool - dev0->hub_addr = event->attach.hub_addr; - dev0->hub_port = event->attach.hub_port; + dev0->hub_addr = event->connection.hub_addr; + dev0->hub_port = event->connection.hub_port; dev0->state = TUSB_DEVICE_STATE_UNPLUG; //------------- connected/disconnected directly with roothub -------------// if ( dev0->hub_addr == 0) { - if( hcd_port_connect_status(dev0->rhport) ) - { - TU_LOG2("Device connect \r\n"); + // wait until device is stable. Increase this if the first 8 bytes is failed to get + osal_task_delay(POWER_STABLE_DELAY); - // connection event - osal_task_delay(POWER_STABLE_DELAY); // wait until device is stable. Increase this if the first 8 bytes is failed to get + // device unplugged while delaying + if ( !hcd_port_connect_status(dev0->rhport) ) return true; - // exit if device unplugged while delaying - if ( !hcd_port_connect_status(dev0->rhport) ) return true; + hcd_port_reset( dev0->rhport ); // port must be reset to have correct speed operation + osal_task_delay(RESET_DELAY); - hcd_port_reset( dev0->rhport ); // port must be reset to have correct speed operation - osal_task_delay(RESET_DELAY); - - dev0->speed = hcd_port_speed_get( dev0->rhport ); - } - else - { - TU_LOG2("Device disconnect \r\n"); - - // disconnection event - usbh_device_unplugged(dev0->rhport, 0, 0); - return true; // restart task - } + dev0->speed = hcd_port_speed_get( dev0->rhport ); } #if CFG_TUH_HUB //------------- connected/disconnected via hub -------------// else { - //------------- Get Port Status -------------// - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN }, - .bRequest = HUB_REQUEST_GET_STATUS, - .wValue = 0, - .wIndex = dev0->hub_port, - .wLength = 4 - }; - // TODO hub refractor - TU_VERIFY_HDLR( usbh_control_xfer( dev0->hub_addr, &request, _usbh_ctrl_buf ), hub_status_pipe_queue( dev0->hub_addr) ); + // TODO wait for PORT reset change instead + osal_task_delay(POWER_STABLE_DELAY); - // Acknowledge Port Connection Change - hub_port_clear_feature_subtask(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_CONNECTION_CHANGE); + hub_port_status_response_t port_status; + TU_VERIFY_HDLR( hub_port_get_status(dev0->hub_addr, dev0->hub_port, &port_status), hub_status_pipe_queue( dev0->hub_addr) ); - hub_port_status_response_t * p_port_status; - p_port_status = ((hub_port_status_response_t *) _usbh_ctrl_buf); + // device unplugged while delaying + if ( !port_status.status.connection ) return true; - if ( ! p_port_status->status_change.connect_status ) return true; // only handle connection change + dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; - if ( ! p_port_status->status_current.connect_status ) + // Acknowledge Port Reset Change + if (port_status.change.reset) { - // Disconnection event - usbh_device_unplugged(dev0->rhport, dev0->hub_addr, dev0->hub_port); - - (void) hub_status_pipe_queue( dev0->hub_addr ); // done with hub, waiting for next data on status pipe - return true; // restart task - } - else - { - // Connection Event - TU_VERIFY_HDLR(hub_port_reset_subtask(dev0->hub_addr, dev0->hub_port), - hub_status_pipe_queue( dev0->hub_addr) ); // TODO hub refractor - - dev0->speed = hub_port_get_speed(); - - // Acknowledge Port Reset Change - hub_port_clear_feature_subtask(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); + hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); } } #endif // CFG_TUH_HUB @@ -540,10 +506,12 @@ bool enum_task(hcd_event_t* event) // connected via a hub TU_VERIFY_HDLR(is_ok, hub_status_pipe_queue( dev0->hub_addr) ); // TODO hub refractor - if ( hub_port_reset_subtask(dev0->hub_addr, dev0->hub_port) ) + if ( hub_port_reset(dev0->hub_addr, dev0->hub_port) ) { + osal_task_delay(RESET_DELAY); + // Acknowledge Port Reset Change if Reset Successful - hub_port_clear_feature_subtask(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); + hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); } (void) hub_status_pipe_queue( dev0->hub_addr ); // done with hub, waiting for next data on status pipe @@ -676,10 +644,24 @@ void tuh_task(void) switch (event.event_id) { case HCD_EVENT_DEVICE_ATTACH: - case HCD_EVENT_DEVICE_REMOVE: + TU_LOG2("USBH DEVICE ATTACH\r\n"); enum_task(&event); break; + case HCD_EVENT_DEVICE_REMOVE: + TU_LOG2("USBH DEVICE REMOVED\r\n"); + usbh_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port); + + #if CFG_TUH_HUB + // TODO remove + if ( event.connection.hub_addr != 0) + { + // done with hub, waiting for next data on status pipe + (void) hub_status_pipe_queue( event.connection.hub_addr ); + } + #endif + break; + case HCD_EVENT_XFER_COMPLETE: { usbh_device_t* dev = &_usbh_devices[event.dev_addr]; From 9a6d7c648e3f41529fad2e2af7e01dc5c56003ac Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 5 Sep 2020 20:34:45 +0700 Subject: [PATCH 10/25] clean up enum task --- src/host/ehci/ehci.c | 3 +++ src/host/usbh.c | 33 ++++++++++----------------------- src/host/usbh.h | 2 +- src/host/usbh_hcd.h | 1 - 4 files changed, 14 insertions(+), 25 deletions(-) diff --git a/src/host/ehci/ehci.c b/src/host/ehci/ehci.c index 13e9b0edc..3c02086c9 100644 --- a/src/host/ehci/ehci.c +++ b/src/host/ehci/ehci.c @@ -326,6 +326,9 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * // attach TD qhd->qtd_overlay.next.address = (uint32_t) qtd; + }else + { + // TODO implement later } return true; diff --git a/src/host/usbh.c b/src/host/usbh.c index fd0e9ee18..f669cac05 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -122,11 +122,8 @@ static osal_queue_t _usbh_q; CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _usbh_ctrl_buf[CFG_TUSB_HOST_ENUM_BUFFER_SIZE]; -//------------- Reporter Task Data -------------// - //------------- Helper Function Prototypes -------------// static inline uint8_t get_new_address(void); -static inline uint8_t get_configure_number_for_device(tusb_desc_device_t* dev_desc); //--------------------------------------------------------------------+ // PUBLIC API (Parameter Verification is required) @@ -557,19 +554,22 @@ bool enum_task(hcd_event_t* event) TU_ASSERT(usbh_control_xfer(new_addr, &request, _usbh_ctrl_buf)); // update device info TODO alignment issue - new_dev->vendor_id = ((tusb_desc_device_t*) _usbh_ctrl_buf)->idVendor; - new_dev->product_id = ((tusb_desc_device_t*) _usbh_ctrl_buf)->idProduct; - new_dev->configure_count = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bNumConfigurations; + tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; - uint8_t const configure_selected = get_configure_number_for_device((tusb_desc_device_t*) _usbh_ctrl_buf); - TU_ASSERT(configure_selected <= new_dev->configure_count); // TODO notify application when invalid configuration + if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); + + new_dev->vendor_id = desc_device->idVendor; + new_dev->product_id = desc_device->idProduct; + TU_ASSERT(desc_device->bNumConfigurations > 0); + + enum { CONFIG_NUM = 1 }; // default to use configuration 1 //------------- Get 9 bytes of configuration descriptor -------------// TU_LOG2("Get 9 bytes of Configuration Descriptor\r\n"); request = (tusb_control_request_t ) { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_IN }, .bRequest = TUSB_REQ_GET_DESCRIPTOR, - .wValue = (TUSB_DESC_CONFIGURATION << 8) | (configure_selected - 1), + .wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1), .wIndex = 0, .wLength = 9 }; @@ -591,7 +591,7 @@ bool enum_task(hcd_event_t* event) request = (tusb_control_request_t ) { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_OUT }, .bRequest = TUSB_REQ_SET_CONFIGURATION, - .wValue = configure_selected, + .wValue = CONFIG_NUM, .wIndex = 0, .wLength = 0 }; @@ -702,17 +702,4 @@ static inline uint8_t get_new_address(void) return CFG_TUSB_HOST_DEVICE_MAX+1; } -static inline uint8_t get_configure_number_for_device(tusb_desc_device_t* dev_desc) -{ - uint8_t config_num = 1; - - // invoke callback to ask user which configuration to select - if (tuh_device_attached_cb) - { - config_num = tu_min8(1, tuh_device_attached_cb(dev_desc) ); - } - - return config_num; -} - #endif diff --git a/src/host/usbh.h b/src/host/usbh.h index 56a5ce72f..1774666f1 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -90,7 +90,7 @@ static inline bool tuh_device_is_configured(uint8_t dev_addr) //--------------------------------------------------------------------+ // APPLICATION CALLBACK //--------------------------------------------------------------------+ -TU_ATTR_WEAK uint8_t tuh_device_attached_cb (tusb_desc_device_t const *p_desc_device); +TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device); /** Callback invoked when device is mounted (configured) */ TU_ATTR_WEAK void tuh_mount_cb (uint8_t dev_addr); diff --git a/src/host/usbh_hcd.h b/src/host/usbh_hcd.h index 019b9f037..435af96bb 100644 --- a/src/host/usbh_hcd.h +++ b/src/host/usbh_hcd.h @@ -53,7 +53,6 @@ typedef struct { //------------- device descriptor -------------// uint16_t vendor_id; uint16_t product_id; - uint8_t configure_count; // bNumConfigurations alias //------------- configuration descriptor -------------// uint8_t interface_count; // bNumInterfaces alias From 15ad585e674f14e247aa7e5f42fb84f90f14be8b Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 6 Sep 2020 11:49:00 +0700 Subject: [PATCH 11/25] replacing hcd_pipe_xfer by usbh_edpt_xfer --- hw/bsp/ea4088qs/ea4088qs.c | 15 +++++++++++---- src/class/hid/hid_host.c | 2 +- src/host/ehci/ehci.c | 15 ++++++++++++++- src/host/hub.c | 4 ++-- src/host/ohci/ohci.c | 24 ++++++++++++++++++++++-- src/host/usbh.c | 6 ++++++ src/host/usbh.h | 2 ++ 7 files changed, 58 insertions(+), 10 deletions(-) diff --git a/hw/bsp/ea4088qs/ea4088qs.c b/hw/bsp/ea4088qs/ea4088qs.c index f164526d7..b25f9101c 100644 --- a/hw/bsp/ea4088qs/ea4088qs.c +++ b/hw/bsp/ea4088qs/ea4088qs.c @@ -98,6 +98,11 @@ void SystemInit(void) Chip_IOCON_Init(LPC_IOCON); Chip_IOCON_SetPinMuxing(LPC_IOCON, pinmuxing, sizeof(pinmuxing) / sizeof(PINMUX_GRP_T)); + + /* CPU clock source starts with IRC */ + /* Enable PBOOST for CPU clock over 100MHz */ + Chip_SYSCTL_EnableBoost(); + Chip_SetupXtalClocking(); } @@ -130,13 +135,15 @@ void board_init(void) Chip_USB_Init(); enum { - USBCLK = 0x1B // Host + Device + OTG + AHB + USBCLK_DEVCIE = 0x12, // AHB + Device + USBCLK_HOST = 0x19 , // AHB + OTG + Host + USBCLK_ALL = 0x1B // Host + Device + OTG + AHB }; - LPC_USB->OTGClkCtrl = USBCLK; - while ( (LPC_USB->OTGClkSt & USBCLK) != USBCLK ) {} + LPC_USB->OTGClkCtrl = USBCLK_ALL; + while ( (LPC_USB->OTGClkSt & USBCLK_ALL) != USBCLK_ALL ) {} - // USB1 = host, USB2 = device + // set portfunc: USB1 = host, USB2 = device LPC_USB->StCtrl = 0x3; } diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index d9ed1f651..5ea8cc7e9 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -71,7 +71,7 @@ tusb_error_t hidh_interface_get_report(uint8_t dev_addr, void * report, hidh_int TU_VERIFY(report, TUSB_ERROR_INVALID_PARA); TU_ASSERT(!hcd_edpt_busy(dev_addr, p_hid->ep_in), TUSB_ERROR_INTERFACE_IS_BUSY); - TU_ASSERT( hcd_pipe_xfer(dev_addr, p_hid->ep_in, report, p_hid->report_size, true) ) ; + TU_ASSERT( usbh_edpt_xfer(dev_addr, p_hid->ep_in, report, p_hid->report_size) ) ; return TUSB_ERROR_NONE; } diff --git a/src/host/ehci/ehci.c b/src/host/ehci/ehci.c index 3c02086c9..23c8ea9ee 100644 --- a/src/host/ehci/ehci.c +++ b/src/host/ehci/ehci.c @@ -328,7 +328,20 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * qhd->qtd_overlay.next.address = (uint32_t) qtd; }else { - // TODO implement later + ehci_qhd_t *p_qhd = qhd_get_from_addr(dev_addr, ep_addr); + ehci_qtd_t *p_qtd = qtd_find_free(); + TU_ASSERT(p_qtd); + + qtd_init(p_qtd, buffer, buflen); + p_qtd->pid = p_qhd->pid; + + // Insert TD to QH + qtd_insert_to_qhd(p_qhd, p_qtd); + + p_qhd->p_qtd_list_tail->int_on_complete = 1; + + // attach head QTD to QHD start transferring + p_qhd->qtd_overlay.next.address = (uint32_t) p_qhd->p_qtd_list_head; } return true; diff --git a/src/host/hub.c b/src/host/hub.c index db1ca0786..abec20d06 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -167,8 +167,8 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) ); } - //------------- Queue the initial Status endpoint transfer -------------// - TU_ASSERT( hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true) ); + // Queue notification status endpoint + TU_ASSERT( usbh_edpt_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1) ); return true; } diff --git a/src/host/ohci/ohci.c b/src/host/ohci/ohci.c index 87da374d5..d9bbfc8c6 100644 --- a/src/host/ohci/ohci.c +++ b/src/host/ohci/ohci.c @@ -306,6 +306,11 @@ bool hcd_setup_send(uint8_t rhport, uint8_t dev_addr, uint8_t const setup_packet return true; } +// TODO move around +static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr); +static ohci_gtd_t * gtd_find_free(void); +static void td_insert_to_ed(ohci_ed_t* p_ed, ohci_gtd_t * p_gtd); + bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) { (void) rhport; @@ -329,6 +334,21 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * p_ed->td_head.address = (uint32_t) p_data; OHCI_REG->command_status_bit.control_list_filled = 1; + }else + { + ohci_ed_t * p_ed = ed_from_addr(dev_addr, ep_addr); + ohci_gtd_t* p_gtd = gtd_find_free(); + + TU_ASSERT(p_gtd); + + gtd_init(p_gtd, buffer, buflen); + p_gtd->index = p_ed-ohci_data.ed_pool; + p_gtd->delay_interrupt = OHCI_INT_ON_COMPLETE_YES; + + td_insert_to_ed(p_ed, p_gtd); + + tusb_xfer_type_t xfer_type = ed_get_xfer_type( ed_from_addr(dev_addr, ep_addr) ); + if (TUSB_XFER_BULK == xfer_type) OHCI_REG->command_status_bit.bulk_list_filled = 1; } return true; @@ -337,7 +357,7 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr, uint8_t * //--------------------------------------------------------------------+ // BULK/INT/ISO PIPE API //--------------------------------------------------------------------+ -static inline ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr) +static ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr) { if ( tu_edpt_number(ep_addr) == 0 ) return &ohci_data.control[dev_addr].ed; @@ -355,7 +375,7 @@ static inline ohci_ed_t * ed_from_addr(uint8_t dev_addr, uint8_t ep_addr) return NULL; } -static inline ohci_ed_t * ed_find_free(void) +static ohci_ed_t * ed_find_free(void) { ohci_ed_t* ed_pool = ohci_data.ed_pool; diff --git a/src/host/usbh.c b/src/host/usbh.c index f669cac05..da35340ce 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -208,6 +208,12 @@ bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8 return true; } +bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + usbh_device_t* dev = &_usbh_devices[dev_addr]; + return hcd_edpt_xfer(dev->rhport, dev_addr, ep_addr, buffer, total_bytes); +} + bool usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) { osal_semaphore_reset( _usbh_devices[dev_addr].control.sem_hdl ); diff --git a/src/host/usbh.h b/src/host/usbh.h index 1774666f1..10e0c21be 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -105,6 +105,8 @@ TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr); bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data); bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); +bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); + #ifdef __cplusplus } #endif From b3e81673c0582a07a764981604a560ee3d310ef9 Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 6 Sep 2020 12:11:07 +0700 Subject: [PATCH 12/25] change xfer_cb return type from void to bool --- src/class/cdc/cdc_host.c | 3 ++- src/class/cdc/cdc_host.h | 2 +- src/class/hid/hid_host.c | 8 +++++--- src/class/hid/hid_host.h | 2 +- src/class/msc/msc_host.c | 6 +++++- src/class/msc/msc_host.h | 2 +- src/host/hub.c | 4 +++- src/host/hub.h | 2 +- src/host/usbh.c | 4 ++-- src/host/usbh.h | 7 +++++-- 10 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index 23e342134..ae1eef8a7 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -209,10 +209,11 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it return true; } -void cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { (void) ep_addr; tuh_cdc_xfer_isr( dev_addr, event, 0, xferred_bytes ); + return true; } void cdch_close(uint8_t dev_addr) diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index 0e2820fef..f28a0a713 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -113,7 +113,7 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i //--------------------------------------------------------------------+ void cdch_init(void); bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length); -void cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +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 diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 5ea8cc7e9..6002ead3c 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -233,7 +233,7 @@ bool hidh_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c return true; } -void hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +bool hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { (void) xferred_bytes; // TODO may need to use this para later @@ -241,7 +241,7 @@ void hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 if ( ep_addr == keyboardh_data[dev_addr-1].ep_in ) { tuh_hid_keyboard_isr(dev_addr, event); - return; + return true; } #endif @@ -249,13 +249,15 @@ void hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 if ( ep_addr == mouseh_data[dev_addr-1].ep_in ) { tuh_hid_mouse_isr(dev_addr, event); - return; + return true; } #endif #if CFG_TUSB_HOST_HID_GENERIC #endif + + return true; } void hidh_close(uint8_t dev_addr) diff --git a/src/class/hid/hid_host.h b/src/class/hid/hid_host.h index 54542de55..324dad203 100644 --- a/src/class/hid/hid_host.h +++ b/src/class/hid/hid_host.h @@ -197,7 +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); -void hidh_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +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); #ifdef __cplusplus diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index b129d538f..f47bbd163 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -336,6 +336,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it enum { SCSI_XFER_TIMEOUT = 2000 }; //------------- SCSI Inquiry -------------// + TU_LOG2("SCSI Inquiry\r\n"); tusbh_msc_inquiry(dev_addr, 0, msch_buffer); TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT) ); @@ -343,6 +344,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it memcpy(p_msc->product_id, ((scsi_inquiry_resp_t*) msch_buffer)->product_id, 16); //------------- SCSI Read Capacity 10 -------------// + TU_LOG2("SCSI Read Capacity 10\r\n"); tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer); TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT)); @@ -383,7 +385,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it return true; } -void msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { msch_interface_t* p_msc = &msch_data[dev_addr-1]; if ( ep_addr == p_msc->ep_in ) @@ -396,6 +398,8 @@ void msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 osal_semaphore_post(msch_sem_hdl, true); } } + + return true; } void msch_close(uint8_t dev_addr) diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 3eb45e6fc..a32134215 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -193,7 +193,7 @@ typedef struct 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); -void msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +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); #ifdef __cplusplus diff --git a/src/host/hub.c b/src/host/hub.c index abec20d06..ed96713e2 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -175,7 +175,7 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf // is the response of interrupt endpoint polling #include "usbh_hcd.h" // FIXME remove -void hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports (void) ep_addr; @@ -227,6 +227,8 @@ void hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32 // TODO [HUB] check if hub is still plugged before polling status endpoint since failed usually mean hub unplugged // TU_ASSERT ( hub_status_pipe_queue(dev_addr) ); } + + return true; } void hub_close(uint8_t dev_addr) diff --git a/src/host/hub.h b/src/host/hub.h index 71dd39b8d..f00f13de7 100644 --- a/src/host/hub.h +++ b/src/host/hub.h @@ -182,7 +182,7 @@ bool hub_status_pipe_queue(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 *p_length); -void hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes); +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 diff --git a/src/host/usbh.c b/src/host/usbh.c index da35340ce..a7f6397cd 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -48,7 +48,7 @@ #define DRIVER_NAME(_name) #endif -static host_class_driver_t const usbh_class_drivers[] = +static usbh_class_driver_t const usbh_class_drivers[] = { #if CFG_TUH_CDC { @@ -442,7 +442,7 @@ bool enum_task(hcd_event_t* event) dev0->state = TUSB_DEVICE_STATE_UNPLUG; //------------- connected/disconnected directly with roothub -------------// - if ( dev0->hub_addr == 0) + if (dev0->hub_addr == 0) { // wait until device is stable. Increase this if the first 8 bytes is failed to get osal_task_delay(POWER_STABLE_DELAY); diff --git a/src/host/usbh.h b/src/host/usbh.h index 10e0c21be..91afb90a3 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -60,9 +60,9 @@ typedef struct { void (* const init) (void); bool (* const open)(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const * itf_desc, uint16_t* outlen); - void (* const xfer_cb) (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t len); + 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); -} host_class_driver_t; +} usbh_class_driver_t; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ @@ -107,6 +107,9 @@ bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); + +bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, uint8_t* buffer, uint16_t buflen); + #ifdef __cplusplus } #endif From 66a10ec9c8042a48053b4af67a932f3cfe9470c2 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 7 Sep 2020 15:19:20 +0700 Subject: [PATCH 13/25] rework usbh control transfer use series of complete callback instead of blocking semaphore, which is more noOS friendly. still working with hid host --- examples/host/cdc_msc_hid/Makefile | 3 +- .../cdc_msc_hid/ses/lpc18xx/lpc18xx.emProject | 1 + src/class/hid/hid_host.c | 22 +- src/common/tusb_types.h | 4 +- src/host/usbh.c | 305 +++++++++++++++--- src/host/usbh.h | 9 +- src/host/usbh_control.c | 135 ++++++++ src/host/usbh_hcd.h | 11 +- 8 files changed, 438 insertions(+), 52 deletions(-) create mode 100644 src/host/usbh_control.c diff --git a/examples/host/cdc_msc_hid/Makefile b/examples/host/cdc_msc_hid/Makefile index 35de0a9a0..b49c4c75c 100644 --- a/examples/host/cdc_msc_hid/Makefile +++ b/examples/host/cdc_msc_hid/Makefile @@ -16,8 +16,9 @@ SRC_C += \ src/class/cdc/cdc_host.c \ src/class/hid/hid_host.c \ src/class/msc/msc_host.c \ - src/host/usbh.c \ src/host/hub.c \ + src/host/usbh.c \ + src/host/usbh_control.c \ src/host/ehci/ehci.c \ src/host/ohci/ohci.c \ src/portable/nxp/lpc18_43/hcd_lpc18_43.c \ diff --git a/examples/host/cdc_msc_hid/ses/lpc18xx/lpc18xx.emProject b/examples/host/cdc_msc_hid/ses/lpc18xx/lpc18xx.emProject index 2b5538957..271076b5c 100644 --- a/examples/host/cdc_msc_hid/ses/lpc18xx/lpc18xx.emProject +++ b/examples/host/cdc_msc_hid/ses/lpc18xx/lpc18xx.emProject @@ -23,6 +23,7 @@ debug_target_connection="J-Link" gcc_entry_point="Reset_Handler" linker_memory_map_file="$(ProjectDir)/LPC1857_MemoryMap.xml" + linker_printf_width_precision_supported="Yes" linker_section_placement_file="$(ProjectDir)/flash_placement.xml" macros="DeviceFamily=LPC1800;DeviceSubFamily=LPC185x;Target=LPC1857;Placement=Flash;rootDir=../../../../..;lpcDir=../../../../../hw/mcu/nxp/lpcopen/lpc18xx/lpc_chip_18xx" package_dependencies="LPC1800" diff --git a/src/class/hid/hid_host.c b/src/class/hid/hid_host.c index 6002ead3c..5058191f4 100644 --- a/src/class/hid/hid_host.c +++ b/src/class/hid/hid_host.c @@ -175,14 +175,22 @@ bool hidh_open_subtask(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t c // SET IDLE = 0 request // Device can stall if not support this request - tusb_control_request_t request = { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, - .bRequest = HID_REQ_CONTROL_SET_IDLE, - .wValue = 0, // idle_rate = 0 - .wIndex = p_interface_desc->bInterfaceNumber, - .wLength = 0 + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HID_REQ_CONTROL_SET_IDLE, + .wValue = 0, // idle_rate = 0 + .wIndex = p_interface_desc->bInterfaceNumber, + .wLength = 0 }; - usbh_control_xfer( dev_addr, &request, NULL ); // TODO stall is valid + + // stall is a valid response for SET_IDLE, therefore we could ignore result of this request + tuh_control_xfer(dev_addr, &request, NULL, NULL); #if 0 //------------- Get Report Descriptor TODO HID parser -------------// diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index 70d0db942..d6b6ea627 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -276,6 +276,8 @@ typedef struct TU_ATTR_PACKED uint8_t bNumConfigurations ; ///< Number of possible configurations. } tusb_desc_device_t; +TU_VERIFY_STATIC( sizeof(tusb_desc_device_t) == 18, "size is not correct"); + // USB Binary Device Object Store (BOS) Descriptor typedef struct TU_ATTR_PACKED { @@ -431,7 +433,7 @@ typedef struct TU_ATTR_PACKED{ uint16_t wLength; } tusb_control_request_t; -TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "mostly compiler option issue"); +TU_VERIFY_STATIC( sizeof(tusb_control_request_t) == 8, "size is not correct"); // TODO move to somewhere suitable static inline uint8_t bm_request_type(uint8_t direction, uint8_t type, uint8_t recipient) diff --git a/src/host/usbh.c b/src/host/usbh.c index a7f6397cd..592eac267 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -108,6 +108,11 @@ static usbh_class_driver_t const usbh_class_drivers[] = enum { USBH_CLASS_DRIVER_COUNT = TU_ARRAY_SIZE(usbh_class_drivers) }; +enum { RESET_DELAY = 500 }; // 200 USB specs say only 50ms but many devices require much longer + +enum { CONFIG_NUM = 1 }; // default to use configuration 1 + + //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ @@ -125,6 +130,9 @@ CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _usbh_ctrl_buf[CFG_TUSB_H //------------- Helper Function Prototypes -------------// static inline uint8_t get_new_address(void); +// 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); + //--------------------------------------------------------------------+ // PUBLIC API (Parameter Verification is required) //--------------------------------------------------------------------+ @@ -281,23 +289,21 @@ void hcd_event_xfer_complete(uint8_t dev_addr, uint8_t ep_addr, uint32_t xferred // usbh_devices[ pipe_hdl.dev_addr ].control.xferred_bytes = xferred_bytes; not yet neccessary osal_semaphore_post( dev->control.sem_hdl, true ); // FIXME post within ISR } - else - { - hcd_event_t event = - { - .rhport = 0, - .event_id = HCD_EVENT_XFER_COMPLETE, - .dev_addr = dev_addr, - .xfer_complete = - { - .ep_addr = ep_addr, - .result = result, - .len = xferred_bytes - } - }; - hcd_event_handler(&event, in_isr); - } + hcd_event_t event = + { + .rhport = 0, // TODO correct rhport + .event_id = HCD_EVENT_XFER_COMPLETE, + .dev_addr = dev_addr, + .xfer_complete = + { + .ep_addr = ep_addr, + .result = result, + .len = xferred_bytes + } + }; + + hcd_event_handler(&event, in_isr); } void hcd_event_device_attach(uint8_t rhport, bool in_isr) @@ -373,8 +379,6 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura uint8_t const* p_desc = (uint8_t const*) desc_cfg; p_desc = tu_desc_next(p_desc); - TU_LOG2_MEM(desc_cfg, desc_cfg->wTotalLength, 0); - // parse each interfaces while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength ) { @@ -426,16 +430,226 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura return true; } -bool enum_task(hcd_event_t* event) +static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { - enum { - POWER_STABLE_DELAY = 100, - RESET_DELAY = 500, // 200 USB specs say only 50ms but many devices require much longer + TU_LOG2_LOCATION(); + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + TU_LOG2("Device configured\r\n"); + usbh_device_t* dev = &_usbh_devices[dev_addr]; + dev->state = TUSB_DEVICE_STATE_CONFIGURED; + + // Parse configuration & set up drivers + parse_configuration_descriptor(dev_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf); + + return true; +} + +static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + TU_LOG2("Set Configuration Descriptor\r\n"); + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_OUT + }, + .bRequest = TUSB_REQ_SET_CONFIGURATION, + .wValue = CONFIG_NUM, + .wIndex = 0, + .wLength = 0 }; - usbh_device_t* dev0 = &_usbh_devices[0]; - tusb_control_request_t request; + TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, enum_set_config_complete) ); + return true; +} + +static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + // TODO not enough buffer to hold configuration descriptor + tusb_desc_configuration_t const * desc_config = (tusb_desc_configuration_t const*) _usbh_ctrl_buf; + uint16_t total_len; + + // Use offsetof to avoid pointer to the odd/misaligned address + memcpy(&total_len, (uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength), 2); + + TU_ASSERT(total_len <= CFG_TUSB_HOST_ENUM_BUFFER_SIZE); + + //Get full configuration descriptor + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_IN + }, + .bRequest = TUSB_REQ_GET_DESCRIPTOR, + .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) ); + + return true; +} + +static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; + usbh_device_t* dev = &_usbh_devices[dev_addr]; + + dev->vendor_id = desc_device->idVendor; + dev->product_id = desc_device->idProduct; + +// if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); + + TU_LOG2("Get 9 bytes of Configuration Descriptor\r\n"); + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_IN + }, + .bRequest = TUSB_REQ_GET_DESCRIPTOR, + .wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1), + .wIndex = 0, + .wLength = 9 + }; + + TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_9byte_config_desc_complete) ); + + return true; +} + +// After SET_ADDRESS is complete +static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(0 == dev_addr); + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + uint8_t const new_addr = (uint8_t const) request->wValue; + + usbh_device_t* new_dev = &_usbh_devices[new_addr]; + new_dev->addressed = 1; + + // TODO close device 0, may not be needed + usbh_device_t* dev0 = &_usbh_devices[0]; + hcd_device_close(dev0->rhport, 0); + dev0->state = TUSB_DEVICE_STATE_UNPLUG; + + // open control pipe for new address + TU_ASSERT ( usbh_pipe_control_open(new_addr, new_dev->ep0_packet_size) ); + + // Get full device descriptor + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_IN + }, + .bRequest = TUSB_REQ_GET_DESCRIPTOR, + .wValue = TUSB_DESC_DEVICE << 8, + .wIndex = 0, + .wLength = sizeof(tusb_desc_device_t) + }; + + TU_ASSERT(tuh_control_xfer(new_addr, &new_request, _usbh_ctrl_buf, enum_get_device_desc_complete)); + + return true; +} + +// After Get Device Descriptor of Address 0 +static bool enum_get_dev0_devic_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(0 == dev_addr); + + usbh_device_t* dev0 = &_usbh_devices[0]; + + if (XFER_RESULT_SUCCESS != result) + { +#if CFG_TUH_HUB + // TODO remove, waiting for next data on status pipe + if (dev0->hub_addr != 0) hub_status_pipe_queue( dev0->hub_addr); +#endif + + return false; + } + + // Reset device again before Set Address + TU_LOG2("Port reset \r\n"); + + if (dev0->hub_addr == 0) + { + // connected directly to roothub + hcd_port_reset( dev0->rhport ); // reset port after 8 byte descriptor + osal_task_delay(RESET_DELAY); + } +#if CFG_TUH_HUB + else + { + // FIXME hub_port_reset use usbh_control_xfer + if ( hub_port_reset(dev0->hub_addr, dev0->hub_port) ) + { + osal_task_delay(RESET_DELAY); + + // Acknowledge Port Reset Change if Reset Successful + hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); + } + + (void) hub_status_pipe_queue( dev0->hub_addr ); // done with hub, waiting for next data on status pipe + } +#endif // CFG_TUH_HUB + + // Set Address + TU_LOG2("Set Address \r\n"); + uint8_t const new_addr = get_new_address(); + TU_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices + + usbh_device_t* new_dev = &_usbh_devices[new_addr]; + new_dev->rhport = dev0->rhport; + new_dev->hub_addr = dev0->hub_addr; + new_dev->hub_port = dev0->hub_port; + new_dev->speed = dev0->speed; + new_dev->connected = 1; + new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0; + + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_OUT + }, + .bRequest = TUSB_REQ_SET_ADDRESS, + .wValue = new_addr, + .wIndex = 0, + .wLength = 0 + }; + + TU_ASSERT(tuh_control_xfer(0, &new_request, NULL, enum_set_address_complete)); + + return true; +} + +bool enum_task(hcd_event_t* event) +{ + usbh_device_t* dev0 = &_usbh_devices[0]; dev0->rhport = event->rhport; // TODO refractor integrate to device_pool dev0->hub_addr = event->connection.hub_addr; dev0->hub_port = event->connection.hub_port; @@ -445,14 +659,11 @@ bool enum_task(hcd_event_t* event) if (dev0->hub_addr == 0) { // wait until device is stable. Increase this if the first 8 bytes is failed to get - osal_task_delay(POWER_STABLE_DELAY); + osal_task_delay(RESET_DELAY); // device unplugged while delaying if ( !hcd_port_connect_status(dev0->rhport) ) return true; - hcd_port_reset( dev0->rhport ); // port must be reset to have correct speed operation - osal_task_delay(RESET_DELAY); - dev0->speed = hcd_port_speed_get( dev0->rhport ); } #if CFG_TUH_HUB @@ -460,8 +671,9 @@ bool enum_task(hcd_event_t* event) else { // TODO wait for PORT reset change instead - osal_task_delay(POWER_STABLE_DELAY); + osal_task_delay(RESET_DELAY); + // FIXME hub API use usbh_control_xfer hub_port_status_response_t port_status; TU_VERIFY_HDLR( hub_port_get_status(dev0->hub_addr, dev0->hub_port, &port_status), hub_status_pipe_queue( dev0->hub_addr) ); @@ -479,19 +691,27 @@ bool enum_task(hcd_event_t* event) } #endif // CFG_TUH_HUB + // TODO probably doesn't need to open/close each enumeration TU_ASSERT( usbh_pipe_control_open(0, 8) ); //------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------// TU_LOG2("Get 8 byte of Device Descriptor\r\n"); - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_IN }, - .bRequest = TUSB_REQ_GET_DESCRIPTOR, - .wValue = TUSB_DESC_DEVICE << 8, - .wIndex = 0, - .wLength = 8 + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_IN + }, + .bRequest = TUSB_REQ_GET_DESCRIPTOR, + .wValue = TUSB_DESC_DEVICE << 8, + .wIndex = 0, + .wLength = 8 }; - bool is_ok = usbh_control_xfer(0, &request, _usbh_ctrl_buf); + TU_ASSERT(tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_dev0_devic_desc_complete)); +#if 0 //------------- Reset device again before Set Address -------------// TU_LOG2("Port reset \r\n"); @@ -526,6 +746,14 @@ bool enum_task(hcd_event_t* event) uint8_t const new_addr = get_new_address(); TU_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices + usbh_device_t* new_dev = &_usbh_devices[new_addr]; + new_dev->rhport = dev0->rhport; + new_dev->hub_addr = dev0->hub_addr; + new_dev->hub_port = dev0->hub_port; + new_dev->speed = dev0->speed; + new_dev->connected = 1; + new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0; + request = (tusb_control_request_t ) { .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_OUT }, .bRequest = TUSB_REQ_SET_ADDRESS, @@ -533,7 +761,7 @@ bool enum_task(hcd_event_t* event) .wIndex = 0, .wLength = 0 }; - TU_ASSERT(usbh_control_xfer(0, &request, NULL)); + TU_ASSERT(tuh_control_xfer(0, &request, NULL, enum_set_address_complete)); //------------- update port info & close control pipe of addr0 -------------// usbh_device_t* new_dev = &_usbh_devices[new_addr]; @@ -613,6 +841,7 @@ bool enum_task(hcd_event_t* event) // Invoke callback if available if (tuh_mount_cb) tuh_mount_cb(new_addr); +#endif return true; } @@ -679,7 +908,7 @@ void tuh_task(void) if ( 0 == epnum ) { - // TODO control transfer + usbh_control_xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len); }else { uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; diff --git a/src/host/usbh.h b/src/host/usbh.h index 91afb90a3..814770722 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -63,6 +63,8 @@ typedef struct { 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); } 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); //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ @@ -87,10 +89,12 @@ static inline bool tuh_device_is_configured(uint8_t dev_addr) return tuh_device_get_state(dev_addr) == TUSB_DEVICE_STATE_CONFIGURED; } +bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb); + //--------------------------------------------------------------------+ // APPLICATION CALLBACK //--------------------------------------------------------------------+ -TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device); +//TU_ATTR_WEAK uint8_t tuh_attach_cb (tusb_desc_device_t const *desc_device); /** Callback invoked when device is mounted (configured) */ TU_ATTR_WEAK void tuh_mount_cb (uint8_t dev_addr); @@ -107,9 +111,6 @@ bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); - -bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, uint8_t* buffer, uint16_t buflen); - #ifdef __cplusplus } #endif diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c new file mode 100644 index 000000000..595c011f5 --- /dev/null +++ b/src/host/usbh_control.c @@ -0,0 +1,135 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2020, Ha Thach (tinyusb.org) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * This file is part of the TinyUSB stack. + */ + +#include "tusb_option.h" + +#if TUSB_OPT_HOST_ENABLED + +#include "tusb.h" +#include "usbh_hcd.h" + +enum +{ + STAGE_SETUP, + STAGE_DATA, + STAGE_ACK +}; + +typedef struct +{ + tusb_control_request_t request TU_ATTR_ALIGNED(4); + + uint8_t stage; + uint8_t* buffer; + tuh_control_complete_cb_t complete_cb; +} usbh_control_xfer_t; + +static usbh_control_xfer_t _ctrl_xfer; + +//CFG_TUSB_MEM_SECTION CFG_TUSB_MEM_ALIGN +//static uint8_t _tuh_ctrl_buf[CFG_TUSB_HOST_ENUM_BUFFER_SIZE]; + +//--------------------------------------------------------------------+ +// MACRO TYPEDEF CONSTANT ENUM DECLARATION +//--------------------------------------------------------------------+ + +bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb) +{ + usbh_device_t* dev = &_usbh_devices[dev_addr]; + const uint8_t rhport = dev->rhport; + + _ctrl_xfer.request = (*request); + _ctrl_xfer.buffer = buffer; + _ctrl_xfer.stage = STAGE_SETUP; + _ctrl_xfer.complete_cb = complete_cb; + + TU_LOG2("Control Setup: "); + TU_LOG2_VAR(request); + TU_LOG2("\r\n"); + + // Send setup packet + TU_ASSERT( hcd_setup_send(rhport, dev_addr, (uint8_t const*) &_ctrl_xfer.request) ); + + return true; +} + +static void _xfer_complete(uint8_t dev_addr, xfer_result_t result) +{ + if (_ctrl_xfer.complete_cb) _ctrl_xfer.complete_cb(dev_addr, &_ctrl_xfer.request, result); +} + +bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) +{ + usbh_device_t* dev = &_usbh_devices[dev_addr]; + const uint8_t rhport = dev->rhport; + + tusb_control_request_t const * request = &_ctrl_xfer.request; + + if (XFER_RESULT_SUCCESS != result) + { + TU_LOG2("Control failed: result = %d\r\n", result); + + // terminate transfer if any stage failed + _xfer_complete(dev_addr, result); + }else + { + switch(_ctrl_xfer.stage) + { + case STAGE_SETUP: + _ctrl_xfer.stage = STAGE_DATA; + if (request->wLength) + { + // Note: initial data toggle is always 1 + hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength); + return true; + } + __attribute__((fallthrough)); + + case STAGE_DATA: + _ctrl_xfer.stage = STAGE_ACK; + + if (request->wLength) + { + TU_LOG2("Control data:\r\n"); + TU_LOG2_MEM(_ctrl_xfer.buffer, request->wLength, 2); + } + + // data toggle is always 1 + hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0); + break; + + case STAGE_ACK: + _xfer_complete(dev_addr, result); + break; + + default: return false; + } + } + + return true; +} + +#endif diff --git a/src/host/usbh_hcd.h b/src/host/usbh_hcd.h index 435af96bb..f203f3baa 100644 --- a/src/host/usbh_hcd.h +++ b/src/host/usbh_hcd.h @@ -53,11 +53,20 @@ typedef struct { //------------- device descriptor -------------// uint16_t vendor_id; uint16_t product_id; + uint8_t ep0_packet_size; //------------- configuration descriptor -------------// - uint8_t interface_count; // bNumInterfaces alias + // uint8_t interface_count; // bNumInterfaces alias //------------- device -------------// + struct TU_ATTR_PACKED + { + uint8_t connected : 1; + uint8_t addressed : 1; + uint8_t configured : 1; + uint8_t suspended : 1; + }; + volatile uint8_t state; // device state, value from enum tusbh_device_state_t //------------- control pipe -------------// From 7a3b24827ed97c71a19c5add9e3ad6af5f08cf4b Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 7 Sep 2020 15:25:03 +0700 Subject: [PATCH 14/25] clean up --- src/host/usbh.c | 147 ++++-------------------------------------------- 1 file changed, 12 insertions(+), 135 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index 592eac267..d8b3d6535 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -432,21 +432,27 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { - TU_LOG2_LOCATION(); + (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); TU_LOG2("Device configured\r\n"); usbh_device_t* dev = &_usbh_devices[dev_addr]; + 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); + return true; } static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { + (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); TU_LOG2("Set Configuration Descriptor\r\n"); @@ -471,6 +477,7 @@ static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { + (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); // TODO not enough buffer to hold configuration descriptor @@ -504,6 +511,7 @@ static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_r static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { + (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; @@ -576,6 +584,7 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c // After Get Device Descriptor of Address 0 static bool enum_get_dev0_devic_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { + (void) request; TU_ASSERT(0 == dev_addr); usbh_device_t* dev0 = &_usbh_devices[0]; @@ -647,7 +656,7 @@ static bool enum_get_dev0_devic_desc_complete(uint8_t dev_addr, tusb_control_req return true; } -bool enum_task(hcd_event_t* event) +static bool enum_device_attached(hcd_event_t* event) { usbh_device_t* dev0 = &_usbh_devices[0]; dev0->rhport = event->rhport; // TODO refractor integrate to device_pool @@ -711,138 +720,6 @@ bool enum_task(hcd_event_t* event) }; TU_ASSERT(tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_dev0_devic_desc_complete)); -#if 0 - //------------- Reset device again before Set Address -------------// - TU_LOG2("Port reset \r\n"); - - if (dev0->hub_addr == 0) - { - TU_ASSERT(is_ok); - - // connected directly to roothub - hcd_port_reset( dev0->rhport ); // reset port after 8 byte descriptor - osal_task_delay(RESET_DELAY); - } -#if CFG_TUH_HUB - else - { - // connected via a hub - TU_VERIFY_HDLR(is_ok, hub_status_pipe_queue( dev0->hub_addr) ); // TODO hub refractor - - if ( hub_port_reset(dev0->hub_addr, dev0->hub_port) ) - { - osal_task_delay(RESET_DELAY); - - // Acknowledge Port Reset Change if Reset Successful - hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); - } - - (void) hub_status_pipe_queue( dev0->hub_addr ); // done with hub, waiting for next data on status pipe - } -#endif // CFG_TUH_HUB - - //------------- Set new address -------------// - TU_LOG2("Set Address \r\n"); - uint8_t const new_addr = get_new_address(); - TU_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices - - usbh_device_t* new_dev = &_usbh_devices[new_addr]; - new_dev->rhport = dev0->rhport; - new_dev->hub_addr = dev0->hub_addr; - new_dev->hub_port = dev0->hub_port; - new_dev->speed = dev0->speed; - new_dev->connected = 1; - new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0; - - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_OUT }, - .bRequest = TUSB_REQ_SET_ADDRESS, - .wValue = new_addr, - .wIndex = 0, - .wLength = 0 - }; - TU_ASSERT(tuh_control_xfer(0, &request, NULL, enum_set_address_complete)); - - //------------- update port info & close control pipe of addr0 -------------// - usbh_device_t* new_dev = &_usbh_devices[new_addr]; - new_dev->rhport = dev0->rhport; - new_dev->hub_addr = dev0->hub_addr; - new_dev->hub_port = dev0->hub_port; - new_dev->speed = dev0->speed; - - hcd_device_close(dev0->rhport, 0); // close device 0 - dev0->state = TUSB_DEVICE_STATE_UNPLUG; - - // open control pipe for new address - TU_ASSERT ( usbh_pipe_control_open(new_addr, ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0 ) ); - - //------------- Get full device descriptor -------------// - TU_LOG2("Get Device Descriptor \r\n"); - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_IN }, - .bRequest = TUSB_REQ_GET_DESCRIPTOR, - .wValue = TUSB_DESC_DEVICE << 8, - .wIndex = 0, - .wLength = 18 - }; - TU_ASSERT(usbh_control_xfer(new_addr, &request, _usbh_ctrl_buf)); - - // update device info TODO alignment issue - tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; - - if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); - - new_dev->vendor_id = desc_device->idVendor; - new_dev->product_id = desc_device->idProduct; - TU_ASSERT(desc_device->bNumConfigurations > 0); - - enum { CONFIG_NUM = 1 }; // default to use configuration 1 - - //------------- Get 9 bytes of configuration descriptor -------------// - TU_LOG2("Get 9 bytes of Configuration Descriptor\r\n"); - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_IN }, - .bRequest = TUSB_REQ_GET_DESCRIPTOR, - .wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1), - .wIndex = 0, - .wLength = 9 - }; - TU_ASSERT( usbh_control_xfer(new_addr, &request, _usbh_ctrl_buf)); - - // TODO not enough buffer to hold configuration descriptor - TU_ASSERT( CFG_TUSB_HOST_ENUM_BUFFER_SIZE >= ((tusb_desc_configuration_t*)_usbh_ctrl_buf)->wTotalLength ); - - //------------- Get full configuration descriptor -------------// - TU_LOG2("Get full Configuration Descriptor\r\n"); - request.wLength = ((tusb_desc_configuration_t*)_usbh_ctrl_buf)->wTotalLength; // full length - TU_ASSERT( usbh_control_xfer( new_addr, &request, _usbh_ctrl_buf ) ); - - // update configuration info - new_dev->interface_count = ((tusb_desc_configuration_t*) _usbh_ctrl_buf)->bNumInterfaces; - - //------------- Set Configure -------------// - TU_LOG2("Set Configuration Descriptor\r\n"); - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_OUT }, - .bRequest = TUSB_REQ_SET_CONFIGURATION, - .wValue = CONFIG_NUM, - .wIndex = 0, - .wLength = 0 - }; - TU_ASSERT(usbh_control_xfer( new_addr, &request, NULL )); - - TU_LOG2("Device configured\r\n"); - new_dev->state = TUSB_DEVICE_STATE_CONFIGURED; - - //------------- TODO Get String Descriptors -------------// - - // Parse configuration & set up drivers - parse_configuration_descriptor(new_addr, (tusb_desc_configuration_t*) _usbh_ctrl_buf); - - // Invoke callback if available - if (tuh_mount_cb) tuh_mount_cb(new_addr); -#endif - return true; } @@ -880,7 +757,7 @@ void tuh_task(void) { case HCD_EVENT_DEVICE_ATTACH: TU_LOG2("USBH DEVICE ATTACH\r\n"); - enum_task(&event); + enum_device_attached(&event); break; case HCD_EVENT_DEVICE_REMOVE: From 2b54dcb9f621e52c5fd15a485a6ee423e208b186 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 7 Sep 2020 15:38:54 +0700 Subject: [PATCH 15/25] move functions around --- src/host/usbh.c | 627 ++++++++++++++++++++++++------------------------ 1 file changed, 319 insertions(+), 308 deletions(-) diff --git a/src/host/usbh.c b/src/host/usbh.c index d8b3d6535..4932e662c 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -128,7 +128,7 @@ static osal_queue_t _usbh_q; CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t _usbh_ctrl_buf[CFG_TUSB_HOST_ENUM_BUFFER_SIZE]; //------------- Helper Function Prototypes -------------// -static inline uint8_t get_new_address(void); +static bool enum_new_device(hcd_event_t* event); // 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); @@ -370,199 +370,161 @@ static void usbh_device_unplugged(uint8_t rhport, uint8_t hub_addr, uint8_t hub_ } } -//--------------------------------------------------------------------+ -// ENUMERATION TASK -//--------------------------------------------------------------------+ -static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) -{ - usbh_device_t* dev = &_usbh_devices[dev_addr]; - uint8_t const* p_desc = (uint8_t const*) desc_cfg; - p_desc = tu_desc_next(p_desc); - - // parse each interfaces - while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength ) - { - // skip until we see interface descriptor - if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) +/* USB Host Driver task + * This top level thread manages all host controller event and delegates events to class-specific drivers. + * This should be called periodically within the mainloop or rtos thread. + * + @code + int main(void) { - p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length - }else - { - tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; + application_init(); + tusb_init(); - // Check if class is supported - uint8_t drv_id; - for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) + while(1) // the mainloop { - if ( usbh_class_drivers[drv_id].class_code == desc_itf->bInterfaceClass ) break; - } - - if( drv_id >= USBH_CLASS_DRIVER_COUNT ) - { - // skip unsupported class - p_desc = tu_desc_next(p_desc); - } - else - { - // 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) - { - // TODO Attach hub to Hub is not currently supported - // skip this interface - p_desc = tu_desc_next(p_desc); - } - else - { - uint16_t itf_len = 0; - - TU_LOG2("%s open\r\n", usbh_class_drivers[drv_id].name); - TU_ASSERT( usbh_class_drivers[drv_id].open(dev->rhport, dev_addr, desc_itf, &itf_len) ); - TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); - p_desc += itf_len; - } + application_code(); + tuh_task(); // tinyusb host task } } + @endcode + */ +void tuh_task(void) +{ + // Skip if stack is not initialized + if ( !tusb_inited() ) return; + + // Loop until there is no more events in the queue + while (1) + { + hcd_event_t event; + if ( !osal_queue_receive(_usbh_q, &event) ) return; + + switch (event.event_id) + { + case HCD_EVENT_DEVICE_ATTACH: + TU_LOG2("USBH DEVICE ATTACH\r\n"); + enum_new_device(&event); + break; + + case HCD_EVENT_DEVICE_REMOVE: + TU_LOG2("USBH DEVICE REMOVED\r\n"); + usbh_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port); + + #if CFG_TUH_HUB + // TODO remove + if ( event.connection.hub_addr != 0) + { + // done with hub, waiting for next data on status pipe + (void) hub_status_pipe_queue( event.connection.hub_addr ); + } + #endif + break; + + case HCD_EVENT_XFER_COMPLETE: + { + usbh_device_t* dev = &_usbh_devices[event.dev_addr]; + uint8_t const ep_addr = event.xfer_complete.ep_addr; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const ep_dir = tu_edpt_dir(ep_addr); + + TU_LOG2("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); + + if ( 0 == epnum ) + { + usbh_control_xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len); + }else + { + uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; + TU_ASSERT(drv_id < USBH_CLASS_DRIVER_COUNT, ); + + TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name); + usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len); + } + } + break; + + default: break; + } } - - return true; } -static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +//--------------------------------------------------------------------+ +// INTERNAL HELPER +//--------------------------------------------------------------------+ +static uint8_t get_new_address(void) { - (void) request; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - TU_LOG2("Device configured\r\n"); - usbh_device_t* dev = &_usbh_devices[dev_addr]; - 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); - - return true; -} - -static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) -{ - (void) request; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - TU_LOG2("Set Configuration Descriptor\r\n"); - tusb_control_request_t const new_request = + for (uint8_t addr=1; addr <= CFG_TUSB_HOST_DEVICE_MAX; addr++) { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_STANDARD, - .direction = TUSB_DIR_OUT - }, - .bRequest = TUSB_REQ_SET_CONFIGURATION, - .wValue = CONFIG_NUM, - .wIndex = 0, - .wLength = 0 - }; - - TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, enum_set_config_complete) ); - - return true; + if (_usbh_devices[addr].state == TUSB_DEVICE_STATE_UNPLUG) return addr; + } + return CFG_TUSB_HOST_DEVICE_MAX+1; } -static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +//--------------------------------------------------------------------+ +// Enumeration Process +// is a lengthy process with a seires of control transfer to configure +// newly attached device. Each step is handled by a function in this +// section +//--------------------------------------------------------------------+ + +static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool enum_set_address_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool enum_get_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool enum_get_9byte_config_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool enum_get_config_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool enum_set_config_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg); + +static bool enum_new_device(hcd_event_t* event) { - (void) request; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - // TODO not enough buffer to hold configuration descriptor - tusb_desc_configuration_t const * desc_config = (tusb_desc_configuration_t const*) _usbh_ctrl_buf; - uint16_t total_len; - - // Use offsetof to avoid pointer to the odd/misaligned address - memcpy(&total_len, (uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength), 2); - - TU_ASSERT(total_len <= CFG_TUSB_HOST_ENUM_BUFFER_SIZE); - - //Get full configuration descriptor - tusb_control_request_t const new_request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_STANDARD, - .direction = TUSB_DIR_IN - }, - .bRequest = TUSB_REQ_GET_DESCRIPTOR, - .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) ); - - return true; -} - -static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) -{ - (void) request; - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; - usbh_device_t* dev = &_usbh_devices[dev_addr]; - - dev->vendor_id = desc_device->idVendor; - dev->product_id = desc_device->idProduct; - -// if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); - - TU_LOG2("Get 9 bytes of Configuration Descriptor\r\n"); - tusb_control_request_t const new_request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_STANDARD, - .direction = TUSB_DIR_IN - }, - .bRequest = TUSB_REQ_GET_DESCRIPTOR, - .wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1), - .wIndex = 0, - .wLength = 9 - }; - - TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_9byte_config_desc_complete) ); - - return true; -} - -// After SET_ADDRESS is complete -static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) -{ - TU_ASSERT(0 == dev_addr); - TU_ASSERT(XFER_RESULT_SUCCESS == result); - - uint8_t const new_addr = (uint8_t const) request->wValue; - - usbh_device_t* new_dev = &_usbh_devices[new_addr]; - new_dev->addressed = 1; - - // TODO close device 0, may not be needed usbh_device_t* dev0 = &_usbh_devices[0]; - hcd_device_close(dev0->rhport, 0); - dev0->state = TUSB_DEVICE_STATE_UNPLUG; + dev0->rhport = event->rhport; // TODO refractor integrate to device_pool + dev0->hub_addr = event->connection.hub_addr; + dev0->hub_port = event->connection.hub_port; + dev0->state = TUSB_DEVICE_STATE_UNPLUG; - // open control pipe for new address - TU_ASSERT ( usbh_pipe_control_open(new_addr, new_dev->ep0_packet_size) ); + //------------- connected/disconnected directly with roothub -------------// + if (dev0->hub_addr == 0) + { + // wait until device is stable. Increase this if the first 8 bytes is failed to get + osal_task_delay(RESET_DELAY); - // Get full device descriptor - tusb_control_request_t const new_request = + // device unplugged while delaying + if ( !hcd_port_connect_status(dev0->rhport) ) return true; + + dev0->speed = hcd_port_speed_get( dev0->rhport ); + } +#if CFG_TUH_HUB + //------------- connected/disconnected via hub -------------// + else + { + // TODO wait for PORT reset change instead + osal_task_delay(RESET_DELAY); + + // FIXME hub API use usbh_control_xfer + hub_port_status_response_t port_status; + TU_VERIFY_HDLR( hub_port_get_status(dev0->hub_addr, dev0->hub_port, &port_status), hub_status_pipe_queue( dev0->hub_addr) ); + + // device unplugged while delaying + if ( !port_status.status.connection ) return true; + + dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; + + // Acknowledge Port Reset Change + if (port_status.change.reset) + { + hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); + } + } +#endif // CFG_TUH_HUB + + // TODO probably doesn't need to open/close each enumeration + TU_ASSERT( usbh_pipe_control_open(0, 8) ); + + //------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------// + TU_LOG2("Get 8 byte of Device Descriptor\r\n"); + tusb_control_request_t const request = { .bmRequestType_bit = { @@ -573,16 +535,15 @@ static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t c .bRequest = TUSB_REQ_GET_DESCRIPTOR, .wValue = TUSB_DESC_DEVICE << 8, .wIndex = 0, - .wLength = sizeof(tusb_desc_device_t) + .wLength = 8 }; - - TU_ASSERT(tuh_control_xfer(new_addr, &new_request, _usbh_ctrl_buf, enum_get_device_desc_complete)); + TU_ASSERT(tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete)); return true; } // After Get Device Descriptor of Address 0 -static bool enum_get_dev0_devic_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { (void) request; TU_ASSERT(0 == dev_addr); @@ -656,56 +617,27 @@ static bool enum_get_dev0_devic_desc_complete(uint8_t dev_addr, tusb_control_req return true; } -static bool enum_device_attached(hcd_event_t* event) +// After SET_ADDRESS is complete +static bool enum_set_address_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { + TU_ASSERT(0 == dev_addr); + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + uint8_t const new_addr = (uint8_t const) request->wValue; + + usbh_device_t* new_dev = &_usbh_devices[new_addr]; + new_dev->addressed = 1; + + // TODO close device 0, may not be needed usbh_device_t* dev0 = &_usbh_devices[0]; - dev0->rhport = event->rhport; // TODO refractor integrate to device_pool - dev0->hub_addr = event->connection.hub_addr; - dev0->hub_port = event->connection.hub_port; - dev0->state = TUSB_DEVICE_STATE_UNPLUG; + hcd_device_close(dev0->rhport, 0); + dev0->state = TUSB_DEVICE_STATE_UNPLUG; - //------------- connected/disconnected directly with roothub -------------// - if (dev0->hub_addr == 0) - { - // wait until device is stable. Increase this if the first 8 bytes is failed to get - osal_task_delay(RESET_DELAY); + // open control pipe for new address + TU_ASSERT ( usbh_pipe_control_open(new_addr, new_dev->ep0_packet_size) ); - // device unplugged while delaying - if ( !hcd_port_connect_status(dev0->rhport) ) return true; - - dev0->speed = hcd_port_speed_get( dev0->rhport ); - } -#if CFG_TUH_HUB - //------------- connected/disconnected via hub -------------// - else - { - // TODO wait for PORT reset change instead - osal_task_delay(RESET_DELAY); - - // FIXME hub API use usbh_control_xfer - hub_port_status_response_t port_status; - TU_VERIFY_HDLR( hub_port_get_status(dev0->hub_addr, dev0->hub_port, &port_status), hub_status_pipe_queue( dev0->hub_addr) ); - - // device unplugged while delaying - if ( !port_status.status.connection ) return true; - - dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : - (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; - - // Acknowledge Port Reset Change - if (port_status.change.reset) - { - hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); - } - } -#endif // CFG_TUH_HUB - - // TODO probably doesn't need to open/close each enumeration - TU_ASSERT( usbh_pipe_control_open(0, 8) ); - - //------------- Get first 8 bytes of device descriptor to get Control Endpoint Size -------------// - TU_LOG2("Get 8 byte of Device Descriptor\r\n"); - tusb_control_request_t const request = + // Get full device descriptor + tusb_control_request_t const new_request = { .bmRequestType_bit = { @@ -716,102 +648,181 @@ static bool enum_device_attached(hcd_event_t* event) .bRequest = TUSB_REQ_GET_DESCRIPTOR, .wValue = TUSB_DESC_DEVICE << 8, .wIndex = 0, - .wLength = 8 + .wLength = sizeof(tusb_desc_device_t) }; - TU_ASSERT(tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_dev0_devic_desc_complete)); + + TU_ASSERT(tuh_control_xfer(new_addr, &new_request, _usbh_ctrl_buf, enum_get_device_desc_complete)); return true; } -/* USB Host Driver task - * This top level thread manages all host controller event and delegates events to class-specific drivers. - * This should be called periodically within the mainloop or rtos thread. - *_usbh_devices[dev_addr]. - @code - int main(void) - { - application_init(); - tusb_init(); - - while(1) // the mainloop - { - application_code(); - - tuh_task(); // tinyusb host task - } - } - @endcode - */ -void tuh_task(void) +static bool enum_get_device_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { - // Skip if stack is not initialized - if ( !tusb_inited() ) return; + (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); - // Loop until there is no more events in the queue - while (1) + tusb_desc_device_t const * desc_device = (tusb_desc_device_t const*) _usbh_ctrl_buf; + usbh_device_t* dev = &_usbh_devices[dev_addr]; + + dev->vendor_id = desc_device->idVendor; + dev->product_id = desc_device->idProduct; + +// if (tuh_attach_cb) tuh_attach_cb((tusb_desc_device_t*) _usbh_ctrl_buf); + + TU_LOG2("Get 9 bytes of Configuration Descriptor\r\n"); + tusb_control_request_t const new_request = { - hcd_event_t event; - if ( !osal_queue_receive(_usbh_q, &event) ) return; - - switch (event.event_id) + .bmRequestType_bit = { - case HCD_EVENT_DEVICE_ATTACH: - TU_LOG2("USBH DEVICE ATTACH\r\n"); - enum_device_attached(&event); - break; + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_IN + }, + .bRequest = TUSB_REQ_GET_DESCRIPTOR, + .wValue = (TUSB_DESC_CONFIGURATION << 8) | (CONFIG_NUM - 1), + .wIndex = 0, + .wLength = 9 + }; - case HCD_EVENT_DEVICE_REMOVE: - TU_LOG2("USBH DEVICE REMOVED\r\n"); - usbh_device_unplugged(event.rhport, event.connection.hub_addr, event.connection.hub_port); + TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, _usbh_ctrl_buf, enum_get_9byte_config_desc_complete) ); - #if CFG_TUH_HUB - // TODO remove - if ( event.connection.hub_addr != 0) - { - // done with hub, waiting for next data on status pipe - (void) hub_status_pipe_queue( event.connection.hub_addr ); - } - #endif - break; - - case HCD_EVENT_XFER_COMPLETE: - { - usbh_device_t* dev = &_usbh_devices[event.dev_addr]; - uint8_t const ep_addr = event.xfer_complete.ep_addr; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const ep_dir = tu_edpt_dir(ep_addr); - - TU_LOG2("on EP %02X with %u bytes\r\n", ep_addr, (unsigned int) event.xfer_complete.len); - - if ( 0 == epnum ) - { - usbh_control_xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len); - }else - { - uint8_t drv_id = dev->ep2drv[epnum][ep_dir]; - TU_ASSERT(drv_id < USBH_CLASS_DRIVER_COUNT, ); - - TU_LOG2("%s xfer callback\r\n", usbh_class_drivers[drv_id].name); - usbh_class_drivers[drv_id].xfer_cb(event.dev_addr, ep_addr, event.xfer_complete.result, event.xfer_complete.len); - } - } - break; - - default: break; - } - } + return true; } -//--------------------------------------------------------------------+ -// INTERNAL HELPER -//--------------------------------------------------------------------+ -static inline uint8_t get_new_address(void) +static bool enum_get_9byte_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { - for (uint8_t addr=1; addr <= CFG_TUSB_HOST_DEVICE_MAX; addr++) + (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + // TODO not enough buffer to hold configuration descriptor + tusb_desc_configuration_t const * desc_config = (tusb_desc_configuration_t const*) _usbh_ctrl_buf; + uint16_t total_len; + + // Use offsetof to avoid pointer to the odd/misaligned address + memcpy(&total_len, (uint8_t*) desc_config + offsetof(tusb_desc_configuration_t, wTotalLength), 2); + + TU_ASSERT(total_len <= CFG_TUSB_HOST_ENUM_BUFFER_SIZE); + + //Get full configuration descriptor + tusb_control_request_t const new_request = { - if (_usbh_devices[addr].state == TUSB_DEVICE_STATE_UNPLUG) return addr; + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_IN + }, + .bRequest = TUSB_REQ_GET_DESCRIPTOR, + .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) ); + + return true; +} + +static bool enum_get_config_desc_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + TU_LOG2("Set Configuration Descriptor\r\n"); + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_OUT + }, + .bRequest = TUSB_REQ_SET_CONFIGURATION, + .wValue = CONFIG_NUM, + .wIndex = 0, + .wLength = 0 + }; + + TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, enum_set_config_complete) ); + + return true; +} + +static bool enum_set_config_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); + + TU_LOG2("Device configured\r\n"); + usbh_device_t* dev = &_usbh_devices[dev_addr]; + 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); + + return true; +} + +static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg) +{ + usbh_device_t* dev = &_usbh_devices[dev_addr]; + uint8_t const* p_desc = (uint8_t const*) desc_cfg; + p_desc = tu_desc_next(p_desc); + + // parse each interfaces + while( p_desc < _usbh_ctrl_buf + desc_cfg->wTotalLength ) + { + // skip until we see interface descriptor + if ( TUSB_DESC_INTERFACE != tu_desc_type(p_desc) ) + { + p_desc = tu_desc_next(p_desc); // skip the descriptor, increase by the descriptor's length + }else + { + tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; + + // Check if class is supportedVe + 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; + } + + if( drv_id >= USBH_CLASS_DRIVER_COUNT ) + { + // skip unsupported class + p_desc = tu_desc_next(p_desc); + } + else + { + // 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) + { + // TODO Attach hub to Hub is not currently supported + // skip this interface + p_desc = tu_desc_next(p_desc); + } + else + { + uint16_t itf_len = 0; + + TU_LOG2("%s open\r\n", usbh_class_drivers[drv_id].name); + TU_ASSERT( usbh_class_drivers[drv_id].open(dev->rhport, dev_addr, desc_itf, &itf_len) ); + TU_ASSERT( itf_len >= sizeof(tusb_desc_interface_t) ); + p_desc += itf_len; + } + } + } } - return CFG_TUSB_HOST_DEVICE_MAX+1; + + return true; } #endif From 87b989e8b4b497713cc4b88103dc6dfadc43e149 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 12 Oct 2020 00:35:38 +0700 Subject: [PATCH 16/25] add usbh_edpt_claim/release implement USBH_EVENT_FUNC_CALL --- src/device/dcd.h | 2 +- src/host/hcd.h | 11 ++++++ src/host/usbh.c | 75 +++++++++++++++++++++++++++++++++++++++-- src/host/usbh.h | 9 +++-- src/host/usbh_control.c | 8 ++++- src/host/usbh_hcd.h | 23 ++++++++++++- 6 files changed, 120 insertions(+), 8 deletions(-) diff --git a/src/device/dcd.h b/src/device/dcd.h index a5c485f9e..b7e5a8da0 100644 --- a/src/device/dcd.h +++ b/src/device/dcd.h @@ -77,7 +77,7 @@ typedef struct TU_ATTR_ALIGNED(4) uint32_t len; }xfer_complete; - // USBD_EVENT_FUNC_CALL + // FUNC_CALL struct { void (*func) (void*); void* param; diff --git a/src/host/hcd.h b/src/host/hcd.h index ba3035300..db98f6110 100644 --- a/src/host/hcd.h +++ b/src/host/hcd.h @@ -45,6 +45,11 @@ typedef enum HCD_EVENT_DEVICE_ATTACH, HCD_EVENT_DEVICE_REMOVE, HCD_EVENT_XFER_COMPLETE, + + // Not an HCD event, just a convenient way to defer ISR function + USBH_EVENT_FUNC_CALL, + + HCD_EVENT_COUNT } hcd_eventid_t; typedef struct @@ -67,6 +72,12 @@ typedef struct uint8_t result; uint32_t len; } xfer_complete; + + // FUNC_CALL + struct { + void (*func) (void*); + void* param; + }func_call; }; } hcd_event_t; diff --git a/src/host/usbh.c b/src/host/usbh.c index 4932e662c..595024b9c 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -169,6 +169,11 @@ bool tuh_init(void) dev->control.sem_hdl = osal_semaphore_create(&dev->control.sem_def); TU_ASSERT(dev->control.sem_hdl != NULL); +#if CFG_TUSB_OS != OPT_OS_NONE + dev->mutex = osal_mutex_create(&dev->mutexdef); + TU_ASSERT(dev->mutex); +#endif + memset(dev->itf2drv, 0xff, sizeof(dev->itf2drv)); // invalid mapping memset(dev->ep2drv , 0xff, sizeof(dev->ep2drv )); // invalid mapping } @@ -187,6 +192,8 @@ bool tuh_init(void) } //------------- USBH control transfer -------------// + +// TODO remove bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data) { usbh_device_t* dev = &_usbh_devices[dev_addr]; @@ -216,6 +223,58 @@ bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8 return true; } +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; +} + +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; +} + bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { usbh_device_t* dev = &_usbh_devices[dev_addr]; @@ -402,6 +461,8 @@ void tuh_task(void) switch (event.event_id) { case HCD_EVENT_DEVICE_ATTACH: + // TODO due to the shared _usbh_ctrl_buf, we must complete enumerating + // one device before enumerating another one. TU_LOG2("USBH DEVICE ATTACH\r\n"); enum_new_device(&event); break; @@ -443,6 +504,10 @@ void tuh_task(void) } break; + case USBH_EVENT_FUNC_CALL: + if ( event.func_call.func ) event.func_call.func(event.func_call.param); + break; + default: break; } } @@ -465,6 +530,8 @@ static uint8_t get_new_address(void) // is a lengthy process with a seires of control transfer to configure // newly attached device. Each step is handled by a function in this // section +// TODO due to the shared _usbh_ctrl_buf, we must complete enumerating +// one device before enumerating another one. //--------------------------------------------------------------------+ static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); @@ -785,7 +852,7 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura { tusb_desc_interface_t const* desc_itf = (tusb_desc_interface_t const*) p_desc; - // Check if class is supportedVe + // Check if class is supported uint8_t drv_id; for (drv_id = 0; drv_id < USBH_CLASS_DRIVER_COUNT; drv_id++) { @@ -799,6 +866,8 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura } 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; @@ -813,8 +882,8 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura { uint16_t itf_len = 0; - TU_LOG2("%s open\r\n", usbh_class_drivers[drv_id].name); - TU_ASSERT( usbh_class_drivers[drv_id].open(dev->rhport, dev_addr, desc_itf, &itf_len) ); + TU_LOG2("%s open\r\n", driver->name); + 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 814770722..fde1dd11c 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -65,6 +65,7 @@ typedef struct { } 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); + //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION //--------------------------------------------------------------------+ @@ -106,11 +107,15 @@ TU_ATTR_WEAK void tuh_umount_cb(uint8_t dev_addr); // CLASS-USBH & INTERNAL API //--------------------------------------------------------------------+ -bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data); bool usbh_edpt_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_endpoint_t const * ep_desc); - bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes); +// Claim an endpoint before submitting a transfer. +// 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_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data); // TODO remove later + #ifdef __cplusplus } #endif diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c index 595c011f5..70800eba6 100644 --- a/src/host/usbh_control.c +++ b/src/host/usbh_control.c @@ -58,6 +58,8 @@ static usbh_control_xfer_t _ctrl_xfer; bool tuh_control_xfer (uint8_t dev_addr, tusb_control_request_t const* request, void* buffer, tuh_control_complete_cb_t complete_cb) { + // TODO need to claim the endpoint first + usbh_device_t* dev = &_usbh_devices[dev_addr]; const uint8_t rhport = dev->rhport; @@ -83,6 +85,10 @@ static void _xfer_complete(uint8_t dev_addr, xfer_result_t result) bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) { + (void) ep_addr; + (void) xferred_bytes; + + usbh_device_t* dev = &_usbh_devices[dev_addr]; const uint8_t rhport = dev->rhport; @@ -106,7 +112,7 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), _ctrl_xfer.buffer, request->wLength); return true; } - __attribute__((fallthrough)); + __attribute__((fallthrough)); case STAGE_DATA: _ctrl_xfer.stage = STAGE_ACK; diff --git a/src/host/usbh_hcd.h b/src/host/usbh_hcd.h index f203f3baa..20348eed1 100644 --- a/src/host/usbh_hcd.h +++ b/src/host/usbh_hcd.h @@ -40,6 +40,10 @@ #include "common/tusb_common.h" #include "osal/osal.h" +#ifndef CFG_TUH_EP_MAX +#define CFG_TUH_EP_MAX 9 +#endif + //--------------------------------------------------------------------+ // USBH-HCD common data structure //--------------------------------------------------------------------+ @@ -80,7 +84,24 @@ typedef struct { } control; uint8_t itf2drv[16]; // map interface number to driver (0xff is invalid) - uint8_t ep2drv[8][2]; // map endpoint to driver ( 0xff is invalid ) + uint8_t ep2drv[CFG_TUH_EP_MAX][2]; // map endpoint to driver ( 0xff is invalid ) + + struct TU_ATTR_PACKED + { + volatile bool busy : 1; + volatile bool stalled : 1; + volatile bool claimed : 1; + + // 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; + osal_mutex_t mutex; +#endif + } usbh_device_t; extern usbh_device_t _usbh_devices[CFG_TUSB_HOST_DEVICE_MAX+1]; // including zero-address From 9c07a2a4e23e4d82e3cbb28e92bf1234e4a6ce09 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 Oct 2020 00:07:51 +0700 Subject: [PATCH 17/25] rework msc host - msc host enum is now async - implement async tuh_msc_scsi_command() / tuh_msc_request_sense() / tuh_msc_test_unit_ready() --- examples/host/cdc_msc_hid/src/msc_app.c | 15 +- src/class/msc/msc_host.c | 427 +++++++++++++----------- src/class/msc/msc_host.h | 75 +---- src/host/usbh_control.c | 1 - 4 files changed, 262 insertions(+), 256 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c index 62bd961c1..53f0e6ac2 100644 --- a/examples/host/cdc_msc_hid/src/msc_app.c +++ b/examples/host/cdc_msc_hid/src/msc_app.c @@ -38,6 +38,7 @@ void tuh_msc_mounted_cb(uint8_t dev_addr) printf("A MassStorage device is mounted\r\n"); //------------- Disk Information -------------// +#if 0 // SCSI VendorID[8] & ProductID[16] from Inquiry Command uint8_t const* p_vendor = tuh_msc_get_vendor_name(dev_addr); uint8_t const* p_product = tuh_msc_get_product_name(dev_addr); @@ -47,6 +48,7 @@ void tuh_msc_mounted_cb(uint8_t dev_addr) putchar(' '); for(uint8_t i=0; i<16; i++) putchar(p_product[i]); putchar('\n'); +#endif uint32_t last_lba = 0; uint32_t block_size = 0; @@ -103,12 +105,11 @@ void tuh_msc_unmounted_cb(uint8_t dev_addr) // } } -// invoked ISR context -void tuh_msc_isr(uint8_t dev_addr, xfer_result_t event, uint32_t xferred_bytes) -{ - (void) dev_addr; - (void) event; - (void) xferred_bytes; -} +//void tuh_msc_scsi_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +//{ +// (void) dev_addr; +// (void) cbw; +// (void) csw; +//} #endif diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index f47bbd163..e8bed989c 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -37,19 +37,41 @@ //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ -CFG_TUSB_MEM_SECTION static msch_interface_t msch_data[CFG_TUSB_HOST_DEVICE_MAX]; +enum +{ + MSC_STAGE_IDLE = 0, + MSC_STAGE_CMD, + MSC_STAGE_DATA, + MSC_STAGE_STATUS, +}; -//------------- Initalization Data -------------// -static osal_semaphore_def_t msch_sem_def; -static osal_semaphore_t msch_sem_hdl; +typedef struct +{ + uint8_t itf_num; + uint8_t ep_in; + uint8_t ep_out; + + uint8_t max_lun; + + scsi_read_capacity10_resp_t capacity; + + volatile bool is_initialized; + uint8_t vendor_id[8]; + uint8_t product_id[16]; + + uint8_t stage; + void* buffer; + tuh_msc_complete_cb_t complete_cb; + + msc_cbw_t cbw; + msc_csw_t csw; +}msch_interface_t; + +CFG_TUSB_MEM_SECTION static msch_interface_t msch_data[CFG_TUSB_HOST_DEVICE_MAX]; // buffer used to read scsi information when mounted, largest response data currently is inquiry CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msch_buffer[sizeof(scsi_inquiry_resp_t)]; -//--------------------------------------------------------------------+ -// INTERNAL OBJECT & FUNCTION DECLARATION -//--------------------------------------------------------------------+ - //--------------------------------------------------------------------+ // PUBLIC API //--------------------------------------------------------------------+ @@ -65,25 +87,17 @@ bool tuh_msc_is_busy(uint8_t dev_addr) hcd_edpt_busy(dev_addr, msch_data[dev_addr-1].ep_in); } -uint8_t const* tuh_msc_get_vendor_name(uint8_t dev_addr) +bool tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size) { - return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].vendor_id : NULL; -} + msch_interface_t* p_msc = &msch_data[dev_addr-1]; -uint8_t const* tuh_msc_get_product_name(uint8_t dev_addr) -{ - return msch_data[dev_addr-1].is_initialized ? msch_data[dev_addr-1].product_id : NULL; -} + if ( !p_msc->is_initialized ) return false; + TU_ASSERT(p_last_lba != NULL && p_block_size != NULL); -tusb_error_t tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size) -{ - if ( !msch_data[dev_addr-1].is_initialized ) return TUSB_ERROR_MSCH_DEVICE_NOT_MOUNTED; - TU_ASSERT(p_last_lba != NULL && p_block_size != NULL, TUSB_ERROR_INVALID_PARA); + (*p_last_lba) = p_msc->capacity.last_lba; + (*p_block_size) = p_msc->capacity.block_size; - (*p_last_lba) = msch_data[dev_addr-1].last_lba; - (*p_block_size) = (uint32_t) msch_data[dev_addr-1].block_size; - - return TUSB_ERROR_NONE; + return true; } //--------------------------------------------------------------------+ @@ -92,30 +106,27 @@ tusb_error_t tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32 static inline void msc_cbw_add_signature(msc_cbw_t *p_cbw, uint8_t lun) { p_cbw->signature = MSC_CBW_SIGNATURE; - p_cbw->tag = 0xCAFECAFE; + p_cbw->tag = 0x54555342; // TUSB p_cbw->lun = lun; } -static tusb_error_t msch_command_xfer(uint8_t dev_addr, msch_interface_t * p_msch, void* p_buffer) +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb) { - if ( NULL != p_buffer) - { // there is data phase - if (p_msch->cbw.dir & TUSB_DIR_IN_MASK) - { - TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t), false), TUSB_ERROR_FAILED ); - TU_ASSERT( hcd_pipe_queue_xfer(dev_addr, p_msch->ep_in , p_buffer, p_msch->cbw.total_bytes), TUSB_ERROR_FAILED ); - }else - { - TU_ASSERT( hcd_pipe_queue_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t)), TUSB_ERROR_FAILED ); - TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_out , p_buffer, p_msch->cbw.total_bytes, false), TUSB_ERROR_FAILED ); - } - } + msch_interface_t* p_msc = &msch_data[dev_addr-1]; - TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_in , (uint8_t*) &p_msch->csw, sizeof(msc_csw_t), true), TUSB_ERROR_FAILED); + // TODO claim endpoint - return TUSB_ERROR_NONE; + p_msc->cbw = *cbw; + p_msc->stage = MSC_STAGE_CMD; + p_msc->buffer = data; + p_msc->complete_cb = complete_cb; + + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_out, (uint8_t*) &p_msc->cbw, sizeof(msc_cbw_t))); + + return true; } +#if 0 tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) { msch_interface_t* p_msch = &msch_data[dev_addr-1]; @@ -127,7 +138,7 @@ tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) p_msch->cbw.cmd_len = sizeof(scsi_inquiry_t); //------------- SCSI command -------------// - scsi_inquiry_t cmd_inquiry = + scsi_inquiry_t const cmd_inquiry = { .cmd_code = SCSI_CMD_INQUIRY, .alloc_length = sizeof(scsi_inquiry_resp_t) @@ -135,88 +146,51 @@ tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) memcpy(p_msch->cbw.command, &cmd_inquiry, p_msch->cbw.cmd_len); - TU_ASSERT_ERR ( msch_command_xfer(dev_addr, p_msch, p_data) ); + TU_ASSERT_ERR ( send_cbw(dev_addr, p_msch, p_data) ); return TUSB_ERROR_NONE; } +#endif -tusb_error_t tusbh_msc_read_capacity10(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) { - msch_interface_t* p_msch = &msch_data[dev_addr-1]; + msc_cbw_t cbw = { 0 }; + msc_cbw_add_signature(&cbw, lun); - //------------- Command Block Wrapper -------------// - msc_cbw_add_signature(&p_msch->cbw, lun); - p_msch->cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t); - p_msch->cbw.dir = TUSB_DIR_IN_MASK; - p_msch->cbw.cmd_len = sizeof(scsi_read_capacity10_t); + cbw.total_bytes = 0; // Number of bytes + cbw.dir = TUSB_DIR_OUT; + cbw.cmd_len = sizeof(scsi_test_unit_ready_t); + cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; + cbw.command[1] = lun; // according to wiki TODO need verification - //------------- SCSI command -------------// - scsi_read_capacity10_t cmd_read_capacity10 = + TU_ASSERT(tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb)); + + return true; +} + +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb) +{ + msc_cbw_t cbw = { 0 }; + msc_cbw_add_signature(&cbw, lun); + + cbw.total_bytes = 18; // TODO sense response + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_request_sense_t); + + scsi_request_sense_t const cmd_request_sense = { - .cmd_code = SCSI_CMD_READ_CAPACITY_10, - .lba = 0, - .partial_medium_indicator = 0 + .cmd_code = SCSI_CMD_REQUEST_SENSE, + .alloc_length = 18 }; - memcpy(p_msch->cbw.command, &cmd_read_capacity10, p_msch->cbw.cmd_len); + memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); - TU_ASSERT_ERR ( msch_command_xfer(dev_addr, p_msch, p_data) ); + TU_ASSERT(tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb)); - return TUSB_ERROR_NONE; -} - -tusb_error_t tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) -{ - (void) lun; // TODO [MSCH] multiple lun support - - msch_interface_t* p_msch = &msch_data[dev_addr-1]; - - //------------- Command Block Wrapper -------------// - p_msch->cbw.total_bytes = 18; - p_msch->cbw.dir = TUSB_DIR_IN_MASK; - p_msch->cbw.cmd_len = sizeof(scsi_request_sense_t); - - //------------- SCSI command -------------// - scsi_request_sense_t cmd_request_sense = - { - .cmd_code = SCSI_CMD_REQUEST_SENSE, - .alloc_length = 18 - }; - - memcpy(p_msch->cbw.command, &cmd_request_sense, p_msch->cbw.cmd_len); - - TU_ASSERT_ERR ( msch_command_xfer(dev_addr, p_msch, p_data) ); - - return TUSB_ERROR_NONE; -} - -tusb_error_t tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, msc_csw_t * p_csw) -{ - msch_interface_t* p_msch = &msch_data[dev_addr-1]; - - //------------- Command Block Wrapper -------------// - msc_cbw_add_signature(&p_msch->cbw, lun); - - p_msch->cbw.total_bytes = 0; // Number of bytes - p_msch->cbw.dir = TUSB_DIR_OUT; - p_msch->cbw.cmd_len = sizeof(scsi_test_unit_ready_t); - - //------------- SCSI command -------------// - scsi_test_unit_ready_t cmd_test_unit_ready = - { - .cmd_code = SCSI_CMD_TEST_UNIT_READY, - .lun = lun // according to wiki - }; - - memcpy(p_msch->cbw.command, &cmd_test_unit_ready, p_msch->cbw.cmd_len); - - // TODO MSCH refractor test uinit ready - TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_out, (uint8_t*) &p_msch->cbw, sizeof(msc_cbw_t), false), TUSB_ERROR_FAILED ); - TU_ASSERT( hcd_pipe_xfer(dev_addr, p_msch->ep_in , (uint8_t*) p_csw, sizeof(msc_csw_t), true), TUSB_ERROR_FAILED ); - - return TUSB_ERROR_NONE; + return true; } +#if 0 tusb_error_t tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * p_buffer, uint32_t lba, uint16_t block_count) { msch_interface_t* p_msch = &msch_data[dev_addr-1]; @@ -229,7 +203,7 @@ tusb_error_t tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * p_buffer, uin p_msch->cbw.cmd_len = sizeof(scsi_read10_t); //------------- SCSI command -------------// - scsi_read10_t cmd_read10 = + scsi_read10_t cmd_read10 =msch_sem_hdl { .cmd_code = SCSI_CMD_READ_10, .lba = tu_htonl(lba), @@ -238,7 +212,7 @@ tusb_error_t tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * p_buffer, uin memcpy(p_msch->cbw.command, &cmd_read10, p_msch->cbw.cmd_len); - TU_ASSERT_ERR ( msch_command_xfer(dev_addr, p_msch, p_buffer)); + TU_ASSERT_ERR ( send_cbw(dev_addr, p_msch, p_buffer)); return TUSB_ERROR_NONE; } @@ -264,10 +238,11 @@ tusb_error_t tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffe memcpy(p_msch->cbw.command, &cmd_write10, p_msch->cbw.cmd_len); - TU_ASSERT_ERR ( msch_command_xfer(dev_addr, p_msch, (void*) p_buffer)); + TU_ASSERT_ERR ( send_cbw(dev_addr, p_msch, (void*) p_buffer)); return TUSB_ERROR_NONE; } +#endif //--------------------------------------------------------------------+ // CLASS-USBH API (don't require to verify parameters) @@ -275,9 +250,75 @@ tusb_error_t tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffe void msch_init(void) { tu_memclr(msch_data, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX); - msch_sem_hdl = osal_semaphore_create(&msch_sem_def); } + +void msch_close(uint8_t dev_addr) +{ + tu_memclr(&msch_data[dev_addr-1], sizeof(msch_interface_t)); + tuh_msc_unmounted_cb(dev_addr); // invoke Application Callback +} + +static bool get_csw(uint8_t dev_addr, msch_interface_t * p_msc) +{ + p_msc->stage = MSC_STAGE_STATUS; + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, sizeof(msc_csw_t))); + return true; +} + +bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) +{ + msch_interface_t* p_msc = &msch_data[dev_addr-1]; + msc_cbw_t const * cbw = &p_msc->cbw; + msc_csw_t * csw = &p_msc->csw; + + switch (p_msc->stage) + { + case MSC_STAGE_CMD: + // Must be Command Block + TU_ASSERT(ep_addr == p_msc->ep_out && event == XFER_RESULT_SUCCESS && xferred_bytes == sizeof(msc_cbw_t)); + + if ( cbw->total_bytes && p_msc->buffer ) + { + // Data stage if any + p_msc->stage = MSC_STAGE_DATA; + + uint8_t const ep_data = (cbw->dir & TUSB_DIR_IN_MASK) ? p_msc->ep_in : p_msc->ep_out; + TU_ASSERT(usbh_edpt_xfer(dev_addr, ep_data, p_msc->buffer, cbw->total_bytes)); + }else + { + // Status stage + get_csw(dev_addr, p_msc); + } + break; + + case MSC_STAGE_DATA: + get_csw(dev_addr, p_msc); + break; + + case MSC_STAGE_STATUS: + // SCSI op is complete + p_msc->stage = MSC_STAGE_IDLE; + + if (p_msc->complete_cb) p_msc->complete_cb(dev_addr, cbw, csw); + break; + + // unknown state + default: break; + } + + return true; +} + +//--------------------------------------------------------------------+ +// 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 open_read_capacity10_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) { TU_VERIFY (MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass && @@ -311,30 +352,52 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it //------------- Get Max Lun -------------// TU_LOG2("MSC Get Max Lun\r\n"); - tusb_control_request_t request = { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN }, - .bRequest = MSC_REQ_GET_MAX_LUN, - .wValue = 0, - .wIndex = p_msc->itf_num, - .wLength = 1 + tusb_control_request_t request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = MSC_REQ_GET_MAX_LUN, + .wValue = 0, + .wIndex = p_msc->itf_num, + .wLength = 1 }; - // TODO STALL means zero - TU_ASSERT( usbh_control_xfer( dev_addr, &request, msch_buffer ) ); - p_msc->max_lun = msch_buffer[0]; + TU_ASSERT(tuh_control_xfer(dev_addr, &request, msch_buffer, open_get_maxlun_complete)); -#if 0 - //------------- Reset -------------// - request = (tusb_control_request_t) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, - .bRequest = MSC_REQ_RESET, - .wValue = 0, - .wIndex = p_msc->itf_num, - .wLength = 0 + return true; +} + +static bool open_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + (void) request; + + msch_interface_t* p_msc = &msch_data[dev_addr-1]; + + // STALL means zero + p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? msch_buffer[0] : 0; + + // MSCU Reset +#if 0 // not really needed + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = MSC_REQ_RESET, + .wValue = 0, + .wIndex = p_msc->itf_num, + .wLength = 0 }; - TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) ); + TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) ); #endif - enum { SCSI_XFER_TIMEOUT = 2000 }; +#if 0 //------------- SCSI Inquiry -------------// TU_LOG2("SCSI Inquiry\r\n"); tusbh_msc_inquiry(dev_addr, 0, msch_buffer); @@ -342,77 +405,63 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it memcpy(p_msc->vendor_id , ((scsi_inquiry_resp_t*) msch_buffer)->vendor_id , 8); memcpy(p_msc->product_id, ((scsi_inquiry_resp_t*) msch_buffer)->product_id, 16); +#endif - //------------- SCSI Read Capacity 10 -------------// - TU_LOG2("SCSI Read Capacity 10\r\n"); - tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer); - TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT)); + // 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); - // NOTE: my toshiba thumb-drive stall the first Read Capacity and require the sequence - // Read Capacity --> Stalled --> Clear Stall --> Request Sense --> Read Capacity (2) to work - if ( hcd_edpt_stalled(dev_addr, p_msc->ep_in) ) + return true; +} + +static bool open_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + if (csw->status == 0) { - // clear stall TODO abstract clear stall function - request = (tusb_control_request_t) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_ENDPOINT, .type = TUSB_REQ_TYPE_STANDARD, .direction = TUSB_DIR_OUT }, - .bRequest = TUSB_REQ_CLEAR_FEATURE, - .wValue = 0, - .wIndex = p_msc->ep_in, - .wLength = 0 - }; + TU_LOG2("SCSI Read Capacity 10\r\n"); - TU_ASSERT(usbh_control_xfer( dev_addr, &request, NULL )); + msch_interface_t* p_msc = &msch_data[dev_addr-1]; + msc_cbw_t new_cbw = { 0 }; - hcd_edpt_clear_stall(dev_addr, p_msc->ep_in); - TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT) ); // wait for SCSI status + msc_cbw_add_signature(&new_cbw, cbw->lun); + new_cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t); + new_cbw.dir = TUSB_DIR_IN_MASK; + new_cbw.cmd_len = sizeof(scsi_read_capacity10_t); + new_cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; - //------------- SCSI Request Sense -------------// - (void) tuh_msc_request_sense(dev_addr, 0, msch_buffer); - TU_ASSERT(osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT)); - - //------------- Re-read SCSI Read Capactity -------------// - tusbh_msc_read_capacity10(dev_addr, 0, msch_buffer); - TU_ASSERT(osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT)); + TU_ASSERT(tuh_msc_scsi_command(dev_addr, &new_cbw, &p_msc->capacity, open_read_capacity10_complete)); + }else + { + // 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)); } - p_msc->last_lba = tu_ntohl( ((scsi_read_capacity10_resp_t*)msch_buffer)->last_lba ); - p_msc->block_size = (uint16_t) tu_ntohl( ((scsi_read_capacity10_resp_t*)msch_buffer)->block_size ); + return true; +} - p_msc->is_initialized = true; +static bool open_request_sense_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + TU_ASSERT(tuh_msc_test_unit_ready(dev_addr, cbw->lun, open_test_unit_ready_complete)); + return true; +} +static bool open_read_capacity10_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + TU_ASSERT(csw->status == 0); + + msch_interface_t* p_msc = &msch_data[dev_addr-1]; + + // Note: Block size and last LBA are big-endian + p_msc->capacity.last_lba = tu_ntohl(p_msc->capacity.last_lba); + p_msc->capacity.block_size = tu_ntohl(p_msc->capacity.block_size); + + // Enumeration is complete + p_msc->is_initialized = true; // open complete TODO remove tuh_msc_mounted_cb(dev_addr); return true; } -bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) -{ - msch_interface_t* p_msc = &msch_data[dev_addr-1]; - if ( ep_addr == p_msc->ep_in ) - { - if (p_msc->is_initialized) - { - tuh_msc_isr(dev_addr, event, xferred_bytes); - }else - { // still initializing under open subtask - osal_semaphore_post(msch_sem_hdl, true); - } - } - - return true; -} - -void msch_close(uint8_t dev_addr) -{ - tu_memclr(&msch_data[dev_addr-1], sizeof(msch_interface_t)); - osal_semaphore_reset(msch_sem_hdl); - - tuh_msc_unmounted_cb(dev_addr); // invoke Application Callback -} - -//--------------------------------------------------------------------+ -// INTERNAL & HELPER -//--------------------------------------------------------------------+ - - #endif diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index a32134215..03231d17f 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -40,6 +40,9 @@ * \defgroup MSC_Host Host * The interface API includes status checking function, data transferring function and callback functions * @{ */ + +typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); + //--------------------------------------------------------------------+ // MASS STORAGE Application API //--------------------------------------------------------------------+ @@ -60,23 +63,9 @@ bool tuh_msc_is_mounted(uint8_t dev_addr); */ bool tuh_msc_is_busy(uint8_t dev_addr); -/** \brief Get SCSI vendor's name of MassStorage device - * \param[in] dev_addr device address - * \return pointer to vendor's name or NULL if specified device does not support MassStorage - * \note SCSI vendor's name is 8-byte length field in \ref scsi_inquiry_data_t. During enumeration, the stack has already - * retrieved (via SCSI INQUIRY) and store this information internally. There is no need for application to re-send SCSI INQUIRY - * command or allocate buffer for this. - */ -uint8_t const* tuh_msc_get_vendor_name(uint8_t dev_addr); +bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb); -/** \brief Get SCSI product's name of MassStorage device - * \param[in] dev_addr device address - * \return pointer to product's name or NULL if specified device does not support MassStorage - * \note SCSI product's name is 16-byte length field in \ref scsi_inquiry_data_t. During enumeration, the stack has already - * retrieved (via SCSI INQUIRY) and store this information internally. There is no need for application to re-send SCSI INQUIRY - * command or allocate buffer for this. - */ -uint8_t const* tuh_msc_get_product_name(uint8_t dev_addr); +bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, void* response, uint32_t len); /** \brief Get SCSI Capacity of MassStorage device * \param[in] dev_addr device address @@ -87,8 +76,10 @@ uint8_t const* tuh_msc_get_product_name(uint8_t dev_addr); * retrieved (via SCSI READ CAPACITY 10) and store this information internally. There is no need for application * to re-send SCSI READ CAPACITY 10 command */ -tusb_error_t tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size); +bool tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size); + +#if 0 /** \brief Perform SCSI READ 10 command to read data from MassStorage device * \param[in] dev_addr device address * \param[in] lun Targeted Logical Unit @@ -116,29 +107,25 @@ tusb_error_t tuh_msc_read10 (uint8_t dev_addr, uint8_t lun, void * p_buffer, uin * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the interface's callback function */ tusb_error_t tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffer, uint32_t lba, uint16_t block_count); +#endif /** \brief Perform SCSI REQUEST SENSE command, used to retrieve sense data from MassStorage device * \param[in] dev_addr device address * \param[in] lun Targeted Logical Unit * \param[in] p_data Buffer to store response's data from device. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the interface's callback function + * \note This function is non-blocking and returns immediately. + * Callback is invoked when command is complete */ -tusb_error_t tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, uint8_t *p_data); +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb); /** \brief Perform SCSI TEST UNIT READY command to test if MassStorage device is ready * \param[in] dev_addr device address * \param[in] lun Targeted Logical Unit - * \retval TUSB_ERROR_NONE on success - * \retval TUSB_ERROR_INTERFACE_IS_BUSY if the interface is already transferring data with device - * \retval TUSB_ERROR_DEVICE_NOT_READY if device is not yet configured (by SET CONFIGURED request) - * \retval TUSB_ERROR_INVALID_PARA if input parameters are not correct - * \note This function is non-blocking and returns immediately. The result of USB transfer will be reported by the interface's callback function + * \note This function is non-blocking and returns immediately. + * Callback is invoked when command is complete */ -tusb_error_t tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, msc_csw_t * p_csw); // TODO to be refractor +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb); + //tusb_error_t tusbh_msc_scsi_send(uint8_t dev_addr, uint8_t lun, bool is_direction_in, // uint8_t const * p_command, uint8_t cmd_len, @@ -157,39 +144,9 @@ void tuh_msc_mounted_cb(uint8_t dev_addr); */ void tuh_msc_unmounted_cb(uint8_t dev_addr); -/** \brief Callback function that is invoked when an transferring event occurred - * \param[in] dev_addr Address of device - * \param[in] event an value from \ref xfer_result_t - * \param[in] xferred_bytes Number of bytes transferred via USB bus - * \note event can be one of following - * - XFER_RESULT_SUCCESS : previously scheduled transfer completes successfully. - * - XFER_RESULT_FAILED : previously scheduled transfer encountered a transaction error. - * - XFER_RESULT_STALLED : previously scheduled transfer is stalled by device. - * \note - */ -void tuh_msc_isr(uint8_t dev_addr, xfer_result_t event, uint32_t xferred_bytes); - - //--------------------------------------------------------------------+ // Internal Class Driver API //--------------------------------------------------------------------+ -typedef struct -{ - uint8_t itf_num; - uint8_t ep_in; - uint8_t ep_out; - - uint8_t max_lun; - uint16_t block_size; - uint32_t last_lba; // last logical block address - - volatile bool is_initialized; - uint8_t vendor_id[8]; - uint8_t product_id[16]; - - msc_cbw_t cbw; - msc_csw_t csw; -}msch_interface_t; 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); diff --git a/src/host/usbh_control.c b/src/host/usbh_control.c index 70800eba6..de55bd5e1 100644 --- a/src/host/usbh_control.c +++ b/src/host/usbh_control.c @@ -88,7 +88,6 @@ bool usbh_control_xfer_cb (uint8_t dev_addr, uint8_t ep_addr, xfer_result_t resu (void) ep_addr; (void) xferred_bytes; - usbh_device_t* dev = &_usbh_devices[dev_addr]; const uint8_t rhport = dev->rhport; From 437ccac6968b9c31446756c49524f7306ef2acd8 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 Oct 2020 13:23:33 +0700 Subject: [PATCH 18/25] implement tuh_msc_scsi_inquiry() / tuh_msc_read_capacity() / tuh_msc_get_maxlun() --- examples/host/cdc_msc_hid/src/msc_app.c | 62 +++++++--- examples/obsolete/host/src/msc_host_app.c | 2 +- src/class/msc/msc_host.c | 131 ++++++++-------------- src/class/msc/msc_host.h | 6 +- 4 files changed, 96 insertions(+), 105 deletions(-) diff --git a/examples/host/cdc_msc_hid/src/msc_app.c b/examples/host/cdc_msc_hid/src/msc_app.c index 53f0e6ac2..a45fba737 100644 --- a/examples/host/cdc_msc_hid/src/msc_app.c +++ b/examples/host/cdc_msc_hid/src/msc_app.c @@ -30,31 +30,59 @@ //--------------------------------------------------------------------+ // MACRO TYPEDEF CONSTANT ENUM DECLARATION //--------------------------------------------------------------------+ +static scsi_inquiry_resp_t inquiry_resp; +static scsi_read_capacity10_resp_t capacity_resp; +uint32_t block_size; +uint32_t block_count; + +bool capacity_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + (void) dev_addr; + (void) cbw; + + if (csw->status != 0) + { + printf("Read Capacity (10) failed\r\n"); + return false; + } + + // Capacity response field: Block size and Last LBA are both Big-Endian + block_count = tu_ntohl(capacity_resp.last_lba) + 1; + block_size = tu_ntohl(capacity_resp.block_size); + + printf("Disk Size: %lu MB\r\n", block_count / ((1024*1024)/block_size)); + printf("Block Count = %lu, Block Size: %lu\r\n", block_count, block_size); + + return true; +} + +bool inquiry_complete_cb(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) +{ + if (csw->status != 0) + { + printf("Inquiry failed\r\n"); + return false; + } + + // Print out Vendor ID, Product ID and Rev + printf("%.8s %.16s rev %.4s\r\n", inquiry_resp.vendor_id, inquiry_resp.product_id, inquiry_resp.product_rev); + + // Read capacity of device + tuh_msc_read_capacity(dev_addr, cbw->lun, &capacity_resp, capacity_complete_cb); + + return true; +} //------------- IMPLEMENTATION -------------// void tuh_msc_mounted_cb(uint8_t dev_addr) { printf("A MassStorage device is mounted\r\n"); - //------------- Disk Information -------------// -#if 0 - // SCSI VendorID[8] & ProductID[16] from Inquiry Command - uint8_t const* p_vendor = tuh_msc_get_vendor_name(dev_addr); - uint8_t const* p_product = tuh_msc_get_product_name(dev_addr); + block_size = block_count = 0; - for(uint8_t i=0; i<8; i++) putchar(p_vendor[i]); - - putchar(' '); - for(uint8_t i=0; i<16; i++) putchar(p_product[i]); - putchar('\n'); -#endif - - uint32_t last_lba = 0; - uint32_t block_size = 0; - tuh_msc_get_capacity(dev_addr, &last_lba, &block_size); - printf("Disk Size: %ld MB\r\n", (last_lba+1)/ ((1024*1024)/block_size) ); - printf("LBA 0-0x%lX Block Size: %ld\r\n", last_lba, block_size); + uint8_t const lun = 0; + tuh_msc_scsi_inquiry(dev_addr, lun, &inquiry_resp, inquiry_complete_cb); // // //------------- file system (only 1 LUN support) -------------// // uint8_t phy_disk = dev_addr-1; diff --git a/examples/obsolete/host/src/msc_host_app.c b/examples/obsolete/host/src/msc_host_app.c index 77747b536..8afb6ede8 100644 --- a/examples/obsolete/host/src/msc_host_app.c +++ b/examples/obsolete/host/src/msc_host_app.c @@ -64,7 +64,7 @@ void tuh_msc_mounted_cb(uint8_t dev_addr) putchar('\n'); uint32_t last_lba, block_size; - tuh_msc_get_capacity(dev_addr, &last_lba, &block_size); + tuh_msc_read_capacity(dev_addr, &last_lba, &block_size); printf("Disk Size: %d MB\n", (last_lba+1)/ ((1024*1024)/block_size) ); printf("LBA 0-0x%X Block Size: %d\n", last_lba, block_size); diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index e8bed989c..7a46b6866 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -53,11 +53,7 @@ typedef struct uint8_t max_lun; - scsi_read_capacity10_resp_t capacity; - volatile bool is_initialized; - uint8_t vendor_id[8]; - uint8_t product_id[16]; uint8_t stage; void* buffer; @@ -75,6 +71,11 @@ CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msch_buffer[sizeof(scsi_i //--------------------------------------------------------------------+ // PUBLIC API //--------------------------------------------------------------------+ +uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) +{ + return msch_data[dev_addr-1].max_lun; +} + bool tuh_msc_is_mounted(uint8_t dev_addr) { return tuh_device_is_configured(dev_addr) && // is configured can be omitted @@ -87,19 +88,6 @@ bool tuh_msc_is_busy(uint8_t dev_addr) hcd_edpt_busy(dev_addr, msch_data[dev_addr-1].ep_in); } -bool tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size) -{ - msch_interface_t* p_msc = &msch_data[dev_addr-1]; - - if ( !p_msc->is_initialized ) return false; - TU_ASSERT(p_last_lba != NULL && p_block_size != NULL); - - (*p_last_lba) = p_msc->capacity.last_lba; - (*p_block_size) = p_msc->capacity.block_size; - - return true; -} - //--------------------------------------------------------------------+ // PUBLIC API: SCSI COMMAND //--------------------------------------------------------------------+ @@ -126,33 +114,46 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu return true; } -#if 0 -tusb_error_t tusbh_msc_inquiry(uint8_t dev_addr, uint8_t lun, uint8_t *p_data) +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb) { - msch_interface_t* p_msch = &msch_data[dev_addr-1]; + msch_interface_t* p_msc = &msch_data[dev_addr-1]; + if ( !p_msc->is_initialized ) return false; - //------------- Command Block Wrapper -------------// - msc_cbw_add_signature(&p_msch->cbw, lun); - p_msch->cbw.total_bytes = sizeof(scsi_inquiry_resp_t); - p_msch->cbw.dir = TUSB_DIR_IN_MASK; - p_msch->cbw.cmd_len = sizeof(scsi_inquiry_t); + msc_cbw_t cbw = { 0 }; + + msc_cbw_add_signature(&cbw, lun); + cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t); + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_read_capacity10_t); + cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; + + TU_ASSERT(tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb)); + + return true; +} + +bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb) +{ + msc_cbw_t cbw = { 0 }; + + msc_cbw_add_signature(&cbw, lun); + cbw.total_bytes = sizeof(scsi_inquiry_resp_t); + cbw.dir = TUSB_DIR_IN_MASK; + cbw.cmd_len = sizeof(scsi_inquiry_t); - //------------- SCSI command -------------// scsi_inquiry_t const cmd_inquiry = { - .cmd_code = SCSI_CMD_INQUIRY, - .alloc_length = sizeof(scsi_inquiry_resp_t) + .cmd_code = SCSI_CMD_INQUIRY, + .alloc_length = sizeof(scsi_inquiry_resp_t) }; + memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); - memcpy(p_msch->cbw.command, &cmd_inquiry, p_msch->cbw.cmd_len); + TU_ASSERT(tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb)); - TU_ASSERT_ERR ( send_cbw(dev_addr, p_msch, p_data) ); - - return TUSB_ERROR_NONE; + return true; } -#endif -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) { msc_cbw_t cbw = { 0 }; msc_cbw_add_signature(&cbw, lun); @@ -252,20 +253,12 @@ void msch_init(void) tu_memclr(msch_data, sizeof(msch_interface_t)*CFG_TUSB_HOST_DEVICE_MAX); } - void msch_close(uint8_t dev_addr) { tu_memclr(&msch_data[dev_addr-1], sizeof(msch_interface_t)); tuh_msc_unmounted_cb(dev_addr); // invoke Application Callback } -static bool get_csw(uint8_t dev_addr, msch_interface_t * p_msc) -{ - p_msc->stage = MSC_STAGE_STATUS; - TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, sizeof(msc_csw_t))); - return true; -} - bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes) { msch_interface_t* p_msc = &msch_data[dev_addr-1]; @@ -288,12 +281,15 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 }else { // Status stage - get_csw(dev_addr, p_msc); + p_msc->stage = MSC_STAGE_STATUS; + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, sizeof(msc_csw_t))); } break; case MSC_STAGE_DATA: - get_csw(dev_addr, p_msc); + // Status stage + p_msc->stage = MSC_STAGE_STATUS; + TU_ASSERT(usbh_edpt_xfer(dev_addr, p_msc->ep_in, (uint8_t*) &p_msc->csw, sizeof(msc_csw_t))); break; case MSC_STAGE_STATUS: @@ -317,7 +313,6 @@ bool msch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 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 open_read_capacity10_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) { @@ -331,9 +326,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it for(uint32_t i=0; i<2; i++) { - TU_ASSERT(TUSB_DESC_ENDPOINT == ep_desc->bDescriptorType); - TU_ASSERT(TUSB_XFER_BULK == ep_desc->bmAttributes.xfer); - + 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 ) @@ -378,6 +371,7 @@ static bool open_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t c // STALL means zero p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? msch_buffer[0] : 0; + p_msc->max_lun++; // MAX LUN is minus 1 by specs // MSCU Reset #if 0 // not really needed @@ -397,16 +391,6 @@ static bool open_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t c TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) ); #endif -#if 0 - //------------- SCSI Inquiry -------------// - TU_LOG2("SCSI Inquiry\r\n"); - tusbh_msc_inquiry(dev_addr, 0, msch_buffer); - TU_ASSERT( osal_semaphore_wait(msch_sem_hdl, SCSI_XFER_TIMEOUT) ); - - memcpy(p_msc->vendor_id , ((scsi_inquiry_resp_t*) msch_buffer)->vendor_id , 8); - memcpy(p_msc->product_id, ((scsi_inquiry_resp_t*) msch_buffer)->product_id, 16); -#endif - // 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); @@ -418,18 +402,11 @@ static bool open_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw { if (csw->status == 0) { - TU_LOG2("SCSI Read Capacity 10\r\n"); - msch_interface_t* p_msc = &msch_data[dev_addr-1]; - msc_cbw_t new_cbw = { 0 }; - msc_cbw_add_signature(&new_cbw, cbw->lun); - new_cbw.total_bytes = sizeof(scsi_read_capacity10_resp_t); - new_cbw.dir = TUSB_DIR_IN_MASK; - new_cbw.cmd_len = sizeof(scsi_read_capacity10_t); - new_cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; - - TU_ASSERT(tuh_msc_scsi_command(dev_addr, &new_cbw, &p_msc->capacity, open_read_capacity10_complete)); + // Unit is ready, Enumeration is complete + p_msc->is_initialized = true; // open complete TODO remove + tuh_msc_mounted_cb(dev_addr); }else { // Note: During enumeration, some device fails Test Unit Ready and require a few retries @@ -443,25 +420,9 @@ static bool open_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw static bool open_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)); return true; } -static bool open_read_capacity10_complete(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw) -{ - TU_ASSERT(csw->status == 0); - - msch_interface_t* p_msc = &msch_data[dev_addr-1]; - - // Note: Block size and last LBA are big-endian - p_msc->capacity.last_lba = tu_ntohl(p_msc->capacity.last_lba); - p_msc->capacity.block_size = tu_ntohl(p_msc->capacity.block_size); - - // Enumeration is complete - p_msc->is_initialized = true; // open complete TODO remove - tuh_msc_mounted_cb(dev_addr); - - return true; -} - #endif diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 03231d17f..63b4753b1 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -63,9 +63,11 @@ bool tuh_msc_is_mounted(uint8_t dev_addr); */ bool tuh_msc_is_busy(uint8_t dev_addr); +uint8_t tuh_msc_get_maxlun(uint8_t dev_addr); + bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb); -bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, void* response, uint32_t len); +bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb); /** \brief Get SCSI Capacity of MassStorage device * \param[in] dev_addr device address @@ -77,7 +79,7 @@ bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, void* response, uint32_ * to re-send SCSI READ CAPACITY 10 command */ -bool tuh_msc_get_capacity(uint8_t dev_addr, uint32_t* p_last_lba, uint32_t* p_block_size); +bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb); #if 0 /** \brief Perform SCSI READ 10 command to read data from MassStorage device From d92d1a03ca2df69856f02c64ae88d805d60ad088 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 Oct 2020 13:45:22 +0700 Subject: [PATCH 19/25] clean up --- src/class/msc/msc_host.c | 97 +++++++++++++++++++++------------------- src/class/msc/msc_host.h | 5 ++- 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 7a46b6866..8bf240ac7 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -53,7 +53,7 @@ typedef struct uint8_t max_lun; - volatile bool is_initialized; + volatile bool mounted; uint8_t stage; void* buffer; @@ -68,24 +68,32 @@ CFG_TUSB_MEM_SECTION static msch_interface_t msch_data[CFG_TUSB_HOST_DEVICE_MAX] // buffer used to read scsi information when mounted, largest response data currently is inquiry CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(4) static uint8_t msch_buffer[sizeof(scsi_inquiry_resp_t)]; +static inline msch_interface_t* get_itf(uint8_t dev_addr) +{ + return &msch_data[dev_addr-1]; +} + //--------------------------------------------------------------------+ // PUBLIC API //--------------------------------------------------------------------+ uint8_t tuh_msc_get_maxlun(uint8_t dev_addr) { - return msch_data[dev_addr-1].max_lun; + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->max_lun; } -bool tuh_msc_is_mounted(uint8_t dev_addr) +bool tuh_msc_mounted(uint8_t dev_addr) { - return tuh_device_is_configured(dev_addr) && // is configured can be omitted - msch_data[dev_addr-1].is_initialized; + msch_interface_t* p_msc = get_itf(dev_addr); + + // is configured can be omitted + return tuh_device_is_configured(dev_addr) && p_msc->mounted; } bool tuh_msc_is_busy(uint8_t dev_addr) { - return msch_data[dev_addr-1].is_initialized && - hcd_edpt_busy(dev_addr, msch_data[dev_addr-1].ep_in); + msch_interface_t* p_msc = get_itf(dev_addr); + return p_msc->mounted && hcd_edpt_busy(dev_addr, p_msc->ep_in); } //--------------------------------------------------------------------+ @@ -100,7 +108,8 @@ static inline void msc_cbw_add_signature(msc_cbw_t *p_cbw, uint8_t lun) bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb) { - msch_interface_t* p_msc = &msch_data[dev_addr-1]; + msch_interface_t* p_msc = get_itf(dev_addr); + TU_VERIFY(p_msc->mounted); // TODO claim endpoint @@ -116,8 +125,8 @@ bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tu bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb) { - msch_interface_t* p_msc = &msch_data[dev_addr-1]; - if ( !p_msc->is_initialized ) return false; + msch_interface_t* p_msc = get_itf(dev_addr); + if ( !p_msc->mounted ) return false; msc_cbw_t cbw = { 0 }; @@ -127,9 +136,7 @@ bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_r cbw.cmd_len = sizeof(scsi_read_capacity10_t); cbw.command[0] = SCSI_CMD_READ_CAPACITY_10; - TU_ASSERT(tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb)); - - return true; + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); } bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb) @@ -148,9 +155,7 @@ bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* re }; memcpy(cbw.command, &cmd_inquiry, cbw.cmd_len); - TU_ASSERT(tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb)); - - return true; + return tuh_msc_scsi_command(dev_addr, &cbw, response, complete_cb); } bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb) @@ -164,9 +169,7 @@ bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_ cbw.command[0] = SCSI_CMD_TEST_UNIT_READY; cbw.command[1] = lun; // according to wiki TODO need verification - TU_ASSERT(tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb)); - - return true; + return tuh_msc_scsi_command(dev_addr, &cbw, NULL, complete_cb); } bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb) @@ -186,12 +189,11 @@ bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_ms memcpy(cbw.command, &cmd_request_sense, cbw.cmd_len); - TU_ASSERT(tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb)); - - return true; + return tuh_msc_scsi_command(dev_addr, &cbw, resposne, complete_cb); } #if 0 + tusb_error_t tuh_msc_read10(uint8_t dev_addr, uint8_t lun, void * p_buffer, uint32_t lba, uint16_t block_count) { msch_interface_t* p_msch = &msch_data[dev_addr-1]; @@ -245,6 +247,27 @@ tusb_error_t tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffe } #endif +#if 0 +// MSC interface Reset (not used now) +bool tuh_msc_reset(uint8_t dev_addr) +{ + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = MSC_REQ_RESET, + .wValue = 0, + .wIndex = p_msc->itf_num, + .wLength = 0 + }; + TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) ); +} +#endif + //--------------------------------------------------------------------+ // CLASS-USBH API (don't require to verify parameters) //--------------------------------------------------------------------+ @@ -261,7 +284,7 @@ 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) { - msch_interface_t* p_msc = &msch_data[dev_addr-1]; + msch_interface_t* p_msc = get_itf(dev_addr); msc_cbw_t const * cbw = &p_msc->cbw; msc_csw_t * csw = &p_msc->csw; @@ -319,7 +342,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it TU_VERIFY (MSC_SUBCLASS_SCSI == itf_desc->bInterfaceSubClass && MSC_PROTOCOL_BOT == itf_desc->bInterfaceProtocol); - msch_interface_t* p_msc = &msch_data[dev_addr-1]; + msch_interface_t* p_msc = get_itf(dev_addr); //------------- Open Data Pipe -------------// tusb_desc_endpoint_t const * ep_desc = (tusb_desc_endpoint_t const *) tu_desc_next(itf_desc); @@ -358,7 +381,7 @@ bool msch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it .wIndex = p_msc->itf_num, .wLength = 1 }; - TU_ASSERT(tuh_control_xfer(dev_addr, &request, msch_buffer, open_get_maxlun_complete)); + TU_ASSERT(tuh_control_xfer(dev_addr, &request, &p_msc->max_lun, open_get_maxlun_complete)); return true; } @@ -367,30 +390,12 @@ static bool open_get_maxlun_complete (uint8_t dev_addr, tusb_control_request_t c { (void) request; - msch_interface_t* p_msc = &msch_data[dev_addr-1]; + msch_interface_t* p_msc = get_itf(dev_addr); // STALL means zero p_msc->max_lun = (XFER_RESULT_SUCCESS == result) ? msch_buffer[0] : 0; p_msc->max_lun++; // MAX LUN is minus 1 by specs - // MSCU Reset -#if 0 // not really needed - tusb_control_request_t const new_request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_INTERFACE, - .type = TUSB_REQ_TYPE_CLASS, - .direction = TUSB_DIR_OUT - }, - .bRequest = MSC_REQ_RESET, - .wValue = 0, - .wIndex = p_msc->itf_num, - .wLength = 0 - }; - TU_ASSERT( usbh_control_xfer( dev_addr, &new_request, NULL ) ); -#endif - // 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); @@ -402,10 +407,10 @@ static bool open_test_unit_ready_complete(uint8_t dev_addr, msc_cbw_t const* cbw { if (csw->status == 0) { - msch_interface_t* p_msc = &msch_data[dev_addr-1]; + msch_interface_t* p_msc = get_itf(dev_addr); // Unit is ready, Enumeration is complete - p_msc->is_initialized = true; // open complete TODO remove + p_msc->mounted = true; tuh_msc_mounted_cb(dev_addr); }else { diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 63b4753b1..827311063 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -51,7 +51,10 @@ typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, ms * \retval true if device supports * \retval false if device does not support or is not mounted */ -bool tuh_msc_is_mounted(uint8_t dev_addr); + +// Check if device supports MassStorage interface. +// This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb() +bool tuh_msc_mounted(uint8_t dev_addr); /** \brief Check if the interface is currently busy or not * \param[in] dev_addr device address From 3623f578a4b9c75b61b1c7a7d0c0c3ff2440e690 Mon Sep 17 00:00:00 2001 From: hathach Date: Tue, 13 Oct 2020 14:00:25 +0700 Subject: [PATCH 20/25] more clean up --- src/class/msc/msc_host.c | 5 ++-- src/class/msc/msc_host.h | 60 ++++++++++------------------------------ src/host/usbh.c | 5 +++- 3 files changed, 22 insertions(+), 48 deletions(-) diff --git a/src/class/msc/msc_host.c b/src/class/msc/msc_host.c index 8bf240ac7..83423cfc7 100644 --- a/src/class/msc/msc_host.c +++ b/src/class/msc/msc_host.c @@ -109,7 +109,7 @@ static inline void msc_cbw_add_signature(msc_cbw_t *p_cbw, uint8_t lun) bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb) { msch_interface_t* p_msc = get_itf(dev_addr); - TU_VERIFY(p_msc->mounted); + // TU_VERIFY(p_msc->mounted); // TODO part of the enumeration also use scsi command // TODO claim endpoint @@ -278,7 +278,8 @@ void msch_init(void) void msch_close(uint8_t dev_addr) { - tu_memclr(&msch_data[dev_addr-1], sizeof(msch_interface_t)); + msch_interface_t* p_msc = get_itf(dev_addr); + tu_memclr(p_msc, sizeof(msch_interface_t)); tuh_msc_unmounted_cb(dev_addr); // invoke Application Callback } diff --git a/src/class/msc/msc_host.h b/src/class/msc/msc_host.h index 827311063..06b1067cc 100644 --- a/src/class/msc/msc_host.h +++ b/src/class/msc/msc_host.h @@ -44,13 +44,8 @@ typedef bool (*tuh_msc_complete_cb_t)(uint8_t dev_addr, msc_cbw_t const* cbw, msc_csw_t const* csw); //--------------------------------------------------------------------+ -// MASS STORAGE Application API +// Application API //--------------------------------------------------------------------+ -/** \brief Check if device supports MassStorage interface or not - * \param[in] dev_addr device address - * \retval true if device supports - * \retval false if device does not support or is not mounted - */ // Check if device supports MassStorage interface. // This function true after tuh_msc_mounted_cb() and false after tuh_msc_unmounted_cb() @@ -66,22 +61,24 @@ bool tuh_msc_mounted(uint8_t dev_addr); */ bool tuh_msc_is_busy(uint8_t dev_addr); +// Get Max Lun uint8_t tuh_msc_get_maxlun(uint8_t dev_addr); +// Carry out a full SCSI command (cbw, data, csw) in non-blocking manner. +// `complete_cb` callback is invoked when SCSI op is complete. +// return true if success, false if there is already pending operation. bool tuh_msc_scsi_command(uint8_t dev_addr, msc_cbw_t const* cbw, void* data, tuh_msc_complete_cb_t complete_cb); +// Carry out SCSI INQUIRY command in non-blocking manner. bool tuh_msc_scsi_inquiry(uint8_t dev_addr, uint8_t lun, scsi_inquiry_resp_t* response, tuh_msc_complete_cb_t complete_cb); -/** \brief Get SCSI Capacity of MassStorage device - * \param[in] dev_addr device address - * \param[out] p_last_lba Last Logical Block Address of device - * \param[out] p_block_size Block Size of device in bytes - * \retval pointer to product's name or NULL if specified device does not support MassStorage - * \note MassStorage's capacity can be computed by last LBA x block size (in bytes). During enumeration, the stack has already - * retrieved (via SCSI READ CAPACITY 10) and store this information internally. There is no need for application - * to re-send SCSI READ CAPACITY 10 command - */ +// Carry out SCSI REQUEST SENSE (10) command in non-blocking manner. +bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb); +// Carry out SCSI REQUEST SENSE (10) command in non-blocking manner. +bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb); + +// Carry out SCSI READ CAPACITY (10) command in non-blocking manner. bool tuh_msc_read_capacity(uint8_t dev_addr, uint8_t lun, scsi_read_capacity10_resp_t* response, tuh_msc_complete_cb_t complete_cb); #if 0 @@ -114,39 +111,12 @@ tusb_error_t tuh_msc_read10 (uint8_t dev_addr, uint8_t lun, void * p_buffer, uin tusb_error_t tuh_msc_write10(uint8_t dev_addr, uint8_t lun, void const * p_buffer, uint32_t lba, uint16_t block_count); #endif -/** \brief Perform SCSI REQUEST SENSE command, used to retrieve sense data from MassStorage device - * \param[in] dev_addr device address - * \param[in] lun Targeted Logical Unit - * \param[in] p_data Buffer to store response's data from device. Must be accessible by USB controller (see \ref CFG_TUSB_MEM_SECTION) - * \note This function is non-blocking and returns immediately. - * Callback is invoked when command is complete - */ -bool tuh_msc_request_sense(uint8_t dev_addr, uint8_t lun, void *resposne, tuh_msc_complete_cb_t complete_cb); - -/** \brief Perform SCSI TEST UNIT READY command to test if MassStorage device is ready - * \param[in] dev_addr device address - * \param[in] lun Targeted Logical Unit - * \note This function is non-blocking and returns immediately. - * Callback is invoked when command is complete - */ -bool tuh_msc_test_unit_ready(uint8_t dev_addr, uint8_t lun, tuh_msc_complete_cb_t complete_cb); - - -//tusb_error_t tusbh_msc_scsi_send(uint8_t dev_addr, uint8_t lun, bool is_direction_in, -// uint8_t const * p_command, uint8_t cmd_len, -// uint8_t * p_response, uint32_t resp_len); - //------------- Application Callback -------------// -/** \brief Callback function that will be invoked when a device with MassStorage interface is mounted - * \param[in] dev_addr Address of newly mounted device - * \note This callback should be used by Application to set-up interface-related data - */ + +// Invoked when a device with MassStorage interface is mounted void tuh_msc_mounted_cb(uint8_t dev_addr); -/** \brief Callback function that will be invoked when a device with MassStorage interface is unmounted - * \param[in] dev_addr Address of newly unmounted device - * \note This callback should be used by Application to tear-down interface-related data - */ +// Invoked when a device with MassStorage interface is unmounted void tuh_msc_unmounted_cb(uint8_t dev_addr); //--------------------------------------------------------------------+ diff --git a/src/host/usbh.c b/src/host/usbh.c index 595024b9c..7d1201aa4 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -880,9 +880,12 @@ static bool parse_configuration_descriptor(uint8_t dev_addr, tusb_desc_configura } else { + TU_LOG2("%s open\r\n", driver->name); + uint16_t itf_len = 0; - TU_LOG2("%s open\r\n", driver->name); + // 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; From e029d6d7263f4a848c5150a567512f3990358b3f Mon Sep 17 00:00:00 2001 From: hathach Date: Sun, 1 Nov 2020 17:46:46 +0700 Subject: [PATCH 21/25] added host set_config driver to resolve control conflict with SET_CONFIGURE for class driver - open will be called to open endpoint only - set_config called later to initialized class driver --- src/class/hid/hid_host.c | 99 ++++++++++++++++++++++++---------------- src/class/hid/hid_host.h | 1 + src/class/msc/msc_host.c | 32 ++++++++----- src/class/msc/msc_host.h | 1 + src/host/usbh.c | 46 +++++++++++++++---- src/host/usbh.h | 12 +++-- src/host/usbh_hcd.h | 3 +- 7 files changed, 130 insertions(+), 64 deletions(-) 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; From 6eafdfab935be976ba3198f63a576ed0add05cb6 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 2 Nov 2020 00:54:04 +0700 Subject: [PATCH 22/25] update usbh with hub to use async control transfer work ok with msc + hub, but definitely need more testing. --- src/host/hub.c | 311 ++++++++++++++++++++++++++++++-------------- src/host/hub.h | 9 +- src/host/usbh.c | 169 ++++++++++++++++-------- src/host/usbh.h | 2 + src/host/usbh_hcd.h | 2 +- 5 files changed, 334 insertions(+), 159 deletions(-) diff --git a/src/host/hub.c b/src/host/hub.c index ed96713e2..f778ef203 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -33,21 +33,21 @@ //--------------------------------------------------------------------+ #include "hub.h" -extern void osal_task_delay(uint32_t msec); // TODO remove - //--------------------------------------------------------------------+ // MACRO CONSTANT TYPEDEF //--------------------------------------------------------------------+ typedef struct { uint8_t itf_num; - uint8_t ep_status; - uint8_t port_number; + uint8_t ep_in; + uint8_t port_count; uint8_t status_change; // data from status change interrupt endpoint + + hub_port_status_response_t port_status; }usbh_hub_t; CFG_TUSB_MEM_SECTION static usbh_hub_t hub_data[CFG_TUSB_HOST_DEVICE_MAX]; -TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t hub_enum_buffer[sizeof(descriptor_hub_desc_t)]; +TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t _hub_buffer[sizeof(descriptor_hub_desc_t)]; //OSAL_SEM_DEF(hub_enum_semaphore); //static osal_semaphore_handle_t hub_enum_sem_hdl; @@ -55,25 +55,30 @@ TU_ATTR_ALIGNED(4) CFG_TUSB_MEM_SECTION static uint8_t hub_enum_buffer[sizeof(de //--------------------------------------------------------------------+ // HUB //--------------------------------------------------------------------+ -bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature) +bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb) { - TU_ASSERT(HUB_FEATURE_PORT_CONNECTION_CHANGE <= feature && feature <= HUB_FEATURE_PORT_RESET_CHANGE); - - tusb_control_request_t request = { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, - .bRequest = HUB_REQUEST_CLEAR_FEATURE, - .wValue = feature, - .wIndex = hub_port, - .wLength = 0 + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_OTHER, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HUB_REQUEST_CLEAR_FEATURE, + .wValue = feature, + .wIndex = hub_port, + .wLength = 0 }; - TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); + TU_LOG2("HUB Clear Port Feature: addr = 0x%02X, port = %u, feature = %u\r\n", hub_addr, hub_port, feature); + TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) ); return true; } -bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp) +bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb) { - tusb_control_request_t request = + tusb_control_request_t const request = { .bmRequestType_bit = { @@ -81,31 +86,35 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, hub_port_status_res .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN }, - .bRequest = HUB_REQUEST_GET_STATUS, .wValue = 0, .wIndex = hub_port, .wLength = 4 }; - TU_ASSERT( usbh_control_xfer( hub_addr, &request, hub_enum_buffer ) ); - - memcpy(resp, hub_enum_buffer, sizeof(hub_port_status_response_t)); + TU_LOG2("HUB Get Port Status: addr = 0x%02X, port = %u\r\n", hub_addr, hub_port); + TU_ASSERT( tuh_control_xfer( hub_addr, &request, resp, complete_cb) ); return true; } -bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port) +bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb) { - //------------- Set Port Reset -------------// - tusb_control_request_t request = { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, - .bRequest = HUB_REQUEST_SET_FEATURE, - .wValue = HUB_FEATURE_PORT_RESET, - .wIndex = hub_port, - .wLength = 0 + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_OTHER, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HUB_REQUEST_SET_FEATURE, + .wValue = HUB_FEATURE_PORT_RESET, + .wIndex = hub_port, + .wLength = 0 }; - TU_ASSERT( usbh_control_xfer( hub_addr, &request, NULL ) ); + TU_LOG2("HUB Reset Port: addr = 0x%02X, port = %u\r\n", hub_addr, hub_port); + TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) ); return true; } @@ -133,42 +142,179 @@ bool hub_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf TU_ASSERT(usbh_edpt_open(rhport, dev_addr, ep_desc)); hub_data[dev_addr-1].itf_num = itf_desc->bInterfaceNumber; - hub_data[dev_addr-1].ep_status = ep_desc->bEndpointAddress; + hub_data[dev_addr-1].ep_in = ep_desc->bEndpointAddress; (*p_length) = sizeof(tusb_desc_interface_t) + sizeof(tusb_desc_endpoint_t); - //------------- Get Hub Descriptor -------------// - tusb_control_request_t request = { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_DEVICE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_IN }, - .bRequest = HUB_REQUEST_GET_DESCRIPTOR, - .wValue = 0, - .wIndex = 0, - .wLength = sizeof(descriptor_hub_desc_t) - }; + return true; +} - TU_ASSERT( usbh_control_xfer( dev_addr, &request, hub_enum_buffer ) ); +static bool config_get_hub_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); - // only care about this field in hub descriptor - hub_data[dev_addr-1].port_number = ((descriptor_hub_desc_t*) hub_enum_buffer)->bNbrPorts; +static bool config_get_hub_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); - //------------- Set Port_Power on all ports -------------// - // TODO may only power port with attached - request = (tusb_control_request_t ) { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_OTHER, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, - .bRequest = HUB_REQUEST_SET_FEATURE, - .wValue = HUB_FEATURE_PORT_POWER, - .wIndex = 0, - .wLength = 0 - }; + usbh_hub_t* p_hub = &hub_data[dev_addr-1]; - for(uint8_t i=1; i <= hub_data[dev_addr-1].port_number; i++) + // only use number of ports in hub descriptor + descriptor_hub_desc_t const* desc_hub = (descriptor_hub_desc_t const*) _hub_buffer; + p_hub->port_count = desc_hub->bNbrPorts; + + // May need to GET_STATUS + + // Ports must be powered on to be able to detect connection + tusb_control_request_t const new_request = { - request.wIndex = i; - TU_ASSERT( usbh_control_xfer( dev_addr, &request, NULL ) ); + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_OTHER, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = HUB_REQUEST_SET_FEATURE, + .wValue = HUB_FEATURE_PORT_POWER, + .wIndex = 1, // starting with port 1 + .wLength = 0 + }; + + TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_port_power_complete) ); + + return true; +} + +static bool config_port_power_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(XFER_RESULT_SUCCESS == result); + usbh_hub_t* p_hub = &hub_data[dev_addr-1]; + + if (request->wIndex == p_hub->port_count) + { + // All ports are power -> queue notification status endpoint and + // complete the SET CONFIGURATION + TU_ASSERT( usbh_edpt_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1) ); + + usbh_driver_set_config_complete(dev_addr, p_hub->itf_num); + }else + { + tusb_control_request_t new_request = *request; + new_request.wIndex++; // power next port + + TU_ASSERT( tuh_control_xfer(dev_addr, &new_request, NULL, config_port_power_complete) ); } - // Queue notification status endpoint - TU_ASSERT( usbh_edpt_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1) ); + return true; +} + +bool hub_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + usbh_hub_t* p_hub = &hub_data[dev_addr-1]; + TU_ASSERT(itf_num == p_hub->itf_num); + + //------------- Get Hub Descriptor -------------// + tusb_control_request_t request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_IN + }, + .bRequest = HUB_REQUEST_GET_DESCRIPTOR, + .wValue = 0, + .wIndex = 0, + .wLength = sizeof(descriptor_hub_desc_t) + }; + + TU_ASSERT( tuh_control_xfer(dev_addr, &request, _hub_buffer, config_get_hub_desc_complete) ); + + return true; +} + +static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); +static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); + +static bool connection_port_reset_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(result == XFER_RESULT_SUCCESS); + + // usbh_hub_t * p_hub = &hub_data[dev_addr-1]; + uint8_t const port_num = (uint8_t) request->wIndex; + + // submit attach event + hcd_event_t event = + { + .rhport = usbh_get_rhport(dev_addr), + .event_id = HCD_EVENT_DEVICE_ATTACH, + .connection = + { + .hub_addr = dev_addr, + .hub_port = port_num + } + }; + + hcd_event_handler(&event, false); + + return true; +} + +static bool connection_clear_conn_change_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(result == XFER_RESULT_SUCCESS); + + usbh_hub_t * p_hub = &hub_data[dev_addr-1]; + uint8_t const port_num = (uint8_t) request->wIndex; + + if ( p_hub->port_status.status.connection ) + { + // Reset port if attach event + hub_port_reset(dev_addr, port_num, connection_port_reset_complete); + }else + { + // submit detach event + hcd_event_t event = + { + .rhport = usbh_get_rhport(dev_addr), + .event_id = HCD_EVENT_DEVICE_REMOVE, + .connection = + { + .hub_addr = dev_addr, + .hub_port = port_num + } + }; + + hcd_event_handler(&event, false); + } + + return true; +} + +static bool connection_get_status_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + TU_ASSERT(result == XFER_RESULT_SUCCESS); + usbh_hub_t * p_hub = &hub_data[dev_addr-1]; + uint8_t const port_num = (uint8_t) request->wIndex; + + // Connection change + if (p_hub->port_status.change.connection) + { + // Port is powered and enabled + //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, ); + + // Acknowledge Port Connection Change + hub_port_clear_feature(dev_addr, port_num, HUB_FEATURE_PORT_CONNECTION_CHANGE, connection_clear_conn_change_complete); + }else + { + // Other changes are: Enable, Suspend, Over Current, Reset, L1 state + // TODO clear change + + // prepare for next hub status + // TODO continue with status_change, or maybe we can do it again with status + hub_status_pipe_queue(dev_addr); + } return true; } @@ -179,55 +325,23 @@ bool hub_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t result, uint32 { (void) xferred_bytes; // TODO can be more than 1 for hub with lots of ports (void) ep_addr; + TU_ASSERT( result == XFER_RESULT_SUCCESS); usbh_hub_t * p_hub = &hub_data[dev_addr-1]; - if ( result == XFER_RESULT_SUCCESS ) + TU_LOG2("Port Status Change = 0x%02X\r\n", p_hub->status_change); + for (uint8_t port=1; port <= p_hub->port_count; port++) { - TU_LOG2("Port Status Change = 0x%02X\r\n", p_hub->status_change); - for (uint8_t port=1; port <= p_hub->port_number; port++) + // TODO HUB ignore bit0 hub_status_change + if ( tu_bit_test(p_hub->status_change, port) ) { - // TODO HUB ignore bit0 hub_status_change - if ( tu_bit_test(p_hub->status_change, port) ) - { - hub_port_status_response_t port_status; - hub_port_get_status(dev_addr, port, &port_status); - - // Connection change - if (port_status.change.connection) - { - // Port is powered and enabled - //TU_VERIFY(port_status.status_current.port_power && port_status.status_current.port_enable, ); - - // Acknowledge Port Connection Change - hub_port_clear_feature(dev_addr, port, HUB_FEATURE_PORT_CONNECTION_CHANGE); - - // Reset port if attach event - if ( port_status.status.connection ) hub_port_reset(dev_addr, port); - - hcd_event_t event = - { - .rhport = _usbh_devices[dev_addr].rhport, - .event_id = port_status.status.connection ? HCD_EVENT_DEVICE_ATTACH : HCD_EVENT_DEVICE_REMOVE, - .connection = - { - .hub_addr = dev_addr, - .hub_port = port - } - }; - - hcd_event_handler(&event, true); - } - } + hub_port_get_status(dev_addr, port, &p_hub->port_status, connection_get_status_complete); + break; } - // NOTE: next status transfer is queued by usbh.c after handling this request - } - else - { - // TODO [HUB] check if hub is still plugged before polling status endpoint since failed usually mean hub unplugged -// TU_ASSERT ( hub_status_pipe_queue(dev_addr) ); } + // NOTE: next status transfer is queued by usbh.c after handling this request + return true; } @@ -239,7 +353,8 @@ void hub_close(uint8_t dev_addr) bool hub_status_pipe_queue(uint8_t dev_addr) { - return hcd_pipe_xfer(dev_addr, hub_data[dev_addr-1].ep_status, &hub_data[dev_addr-1].status_change, 1, true); + usbh_hub_t * p_hub = &hub_data[dev_addr-1]; + return hcd_pipe_xfer(dev_addr, p_hub->ep_in, &p_hub->status_change, 1, true); } diff --git a/src/host/hub.h b/src/host/hub.h index f00f13de7..35d8ad629 100644 --- a/src/host/hub.h +++ b/src/host/hub.h @@ -36,7 +36,7 @@ #ifndef _TUSB_HUB_H_ #define _TUSB_HUB_H_ -#include +#include "common/tusb_common.h" #include "usbh.h" #ifdef __cplusplus @@ -172,9 +172,9 @@ typedef struct { TU_VERIFY_STATIC( sizeof(hub_port_status_response_t) == 4, "size is not correct"); -bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port); -bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, hub_port_status_response_t* resp); -bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature); +bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_t complete_cb); +bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_control_complete_cb_t complete_cb); +bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, tuh_control_complete_cb_t complete_cb); bool hub_status_pipe_queue(uint8_t dev_addr); //--------------------------------------------------------------------+ @@ -182,6 +182,7 @@ bool hub_status_pipe_queue(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 *p_length); +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); diff --git a/src/host/usbh.c b/src/host/usbh.c index 3e321652b..4239cd1ec 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -91,6 +91,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_HUB, .init = hub_init, .open = hub_open, + .set_config = hub_set_config, .xfer_cb = hub_xfer_cb, .close = hub_close }, @@ -135,6 +136,11 @@ static bool enum_new_device(hcd_event_t* event); // 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); +uint8_t usbh_get_rhport(uint8_t dev_addr) +{ + return _usbh_devices[dev_addr].rhport; +} + //--------------------------------------------------------------------+ // PUBLIC API (Parameter Verification is required) //--------------------------------------------------------------------+ @@ -562,6 +568,9 @@ void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num) // one device before enumerating another one. //--------------------------------------------------------------------+ +static bool enum_request_addr0_device_desc(void); +static bool enum_request_set_addr(void); + static bool enum_get_addr0_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static bool enum_set_address_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static bool enum_get_device_desc_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); @@ -570,6 +579,92 @@ static bool enum_get_config_desc_complete (uint8_t dev_addr, tusb_control_ static bool enum_set_config_complete (uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result); static bool parse_configuration_descriptor (uint8_t dev_addr, tusb_desc_configuration_t const* desc_cfg); +static bool enum_hub_clear_reset0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + (void) dev_addr; (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); + enum_request_addr0_device_desc(); + return true; +} + +static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + (void) dev_addr; (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); + usbh_device_t* dev0 = &_usbh_devices[0]; + + enum_request_set_addr(); + + // done with hub, waiting for next data on status pipe + (void) hub_status_pipe_queue( dev0->hub_addr ); + + return true; +} + +static bool enum_hub_get_status_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + (void) dev_addr; (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); + usbh_device_t* dev0 = &_usbh_devices[0]; + + hub_port_status_response_t port_status; + memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); + + if ( !port_status.status.connection ) + { + // device unplugged while delaying, nothing else to do, queue hub status + return hub_status_pipe_queue(dev_addr); + } + + dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : + (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; + + // Acknowledge Port Reset Change + if (port_status.change.reset) + { + hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset0_complete); + } + + return true; +} + + +static bool enum_request_set_addr(void) +{ + // Set Address + TU_LOG2("Set Address \r\n"); + uint8_t const new_addr = get_new_address(); + TU_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices + + usbh_device_t* dev0 = &_usbh_devices[0]; + usbh_device_t* new_dev = &_usbh_devices[new_addr]; + + new_dev->rhport = dev0->rhport; + new_dev->hub_addr = dev0->hub_addr; + new_dev->hub_port = dev0->hub_port; + new_dev->speed = dev0->speed; + new_dev->connected = 1; + new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0; + + tusb_control_request_t const new_request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_DEVICE, + .type = TUSB_REQ_TYPE_STANDARD, + .direction = TUSB_DIR_OUT + }, + .bRequest = TUSB_REQ_SET_ADDRESS, + .wValue = new_addr, + .wIndex = 0, + .wLength = 0 + }; + + TU_ASSERT( tuh_control_xfer(0, &new_request, NULL, enum_set_address_complete) ); + + return true; +} + static bool enum_new_device(hcd_event_t* event) { usbh_device_t* dev0 = &_usbh_devices[0]; @@ -581,39 +676,31 @@ static bool enum_new_device(hcd_event_t* event) //------------- connected/disconnected directly with roothub -------------// if (dev0->hub_addr == 0) { - // wait until device is stable. Increase this if the first 8 bytes is failed to get + // wait until device is stable osal_task_delay(RESET_DELAY); // device unplugged while delaying if ( !hcd_port_connect_status(dev0->rhport) ) return true; dev0->speed = hcd_port_speed_get( dev0->rhport ); + + enum_request_addr0_device_desc(); } #if CFG_TUH_HUB //------------- connected/disconnected via hub -------------// else { - // TODO wait for PORT reset change instead + // wait until device is stable osal_task_delay(RESET_DELAY); - - // FIXME hub API use usbh_control_xfer - hub_port_status_response_t port_status; - TU_VERIFY_HDLR( hub_port_get_status(dev0->hub_addr, dev0->hub_port, &port_status), hub_status_pipe_queue( dev0->hub_addr) ); - - // device unplugged while delaying - if ( !port_status.status.connection ) return true; - - dev0->speed = (port_status.status.high_speed) ? TUSB_SPEED_HIGH : - (port_status.status.low_speed ) ? TUSB_SPEED_LOW : TUSB_SPEED_FULL; - - // Acknowledge Port Reset Change - if (port_status.change.reset) - { - hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); - } + TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status_complete) ); } #endif // CFG_TUH_HUB + return true; +} + +static bool enum_request_addr0_device_desc(void) +{ // TODO probably doesn't need to open/close each enumeration TU_ASSERT( usbh_pipe_control_open(0, 8) ); @@ -632,7 +719,7 @@ static bool enum_new_device(hcd_event_t* event) .wIndex = 0, .wLength = 8 }; - TU_ASSERT(tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete)); + TU_ASSERT( tuh_control_xfer(0, &request, _usbh_ctrl_buf, enum_get_addr0_device_desc_complete) ); return true; } @@ -663,52 +750,22 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r // connected directly to roothub hcd_port_reset( dev0->rhport ); // reset port after 8 byte descriptor osal_task_delay(RESET_DELAY); + + enum_request_set_addr(); } #if CFG_TUH_HUB else { - // FIXME hub_port_reset use usbh_control_xfer - if ( hub_port_reset(dev0->hub_addr, dev0->hub_port) ) - { - osal_task_delay(RESET_DELAY); + // after RESET_DELAY the hub_port_reset() already complete + TU_ASSERT( hub_port_reset(dev0->hub_addr, dev0->hub_port, NULL) ); - // Acknowledge Port Reset Change if Reset Successful - hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE); - } + osal_task_delay(RESET_DELAY); - (void) hub_status_pipe_queue( dev0->hub_addr ); // done with hub, waiting for next data on status pipe + // Acknowledge Port Reset Change if Reset Successful + TU_ASSERT( hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) ); } #endif // CFG_TUH_HUB - // Set Address - TU_LOG2("Set Address \r\n"); - uint8_t const new_addr = get_new_address(); - TU_ASSERT(new_addr <= CFG_TUSB_HOST_DEVICE_MAX); // TODO notify application we reach max devices - - usbh_device_t* new_dev = &_usbh_devices[new_addr]; - new_dev->rhport = dev0->rhport; - new_dev->hub_addr = dev0->hub_addr; - new_dev->hub_port = dev0->hub_port; - new_dev->speed = dev0->speed; - new_dev->connected = 1; - new_dev->ep0_packet_size = ((tusb_desc_device_t*) _usbh_ctrl_buf)->bMaxPacketSize0; - - tusb_control_request_t const new_request = - { - .bmRequestType_bit = - { - .recipient = TUSB_REQ_RCPT_DEVICE, - .type = TUSB_REQ_TYPE_STANDARD, - .direction = TUSB_DIR_OUT - }, - .bRequest = TUSB_REQ_SET_ADDRESS, - .wValue = new_addr, - .wIndex = 0, - .wLength = 0 - }; - - TU_ASSERT(tuh_control_xfer(0, &new_request, NULL, enum_set_address_complete)); - return true; } diff --git a/src/host/usbh.h b/src/host/usbh.h index 19ab72f54..7db918348 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -120,6 +120,8 @@ bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8 void usbh_driver_set_config_complete(uint8_t dev_addr, uint8_t itf_num); +uint8_t usbh_get_rhport(uint8_t dev_addr); + #ifdef __cplusplus } #endif diff --git a/src/host/usbh_hcd.h b/src/host/usbh_hcd.h index 79b547fb3..dd0616704 100644 --- a/src/host/usbh_hcd.h +++ b/src/host/usbh_hcd.h @@ -97,7 +97,7 @@ 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 + // Mutex for claiming endpoint, only needed when using with preempted RTOS #if CFG_TUSB_OS != OPT_OS_NONE osal_mutex_def_t mutexdef; osal_mutex_t mutex; From 2efdc2fb64fec2cba26dc3fd4651583bc0dcf7b3 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 2 Nov 2020 08:46:24 +0700 Subject: [PATCH 23/25] get hub work more reliably --- src/host/hub.c | 6 +++--- src/host/usbh.c | 32 +++++++++++++++++++++++++------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/host/hub.c b/src/host/hub.c index f778ef203..2191c4560 100644 --- a/src/host/hub.c +++ b/src/host/hub.c @@ -71,7 +71,7 @@ bool hub_port_clear_feature(uint8_t hub_addr, uint8_t hub_port, uint8_t feature, .wLength = 0 }; - TU_LOG2("HUB Clear Port Feature: addr = 0x%02X, port = %u, feature = %u\r\n", hub_addr, hub_port, feature); + TU_LOG2("HUB Clear Port Feature: addr = %u port = %u, feature = %u\r\n", hub_addr, hub_port, feature); TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) ); return true; } @@ -92,7 +92,7 @@ bool hub_port_get_status(uint8_t hub_addr, uint8_t hub_port, void* resp, tuh_con .wLength = 4 }; - TU_LOG2("HUB Get Port Status: addr = 0x%02X, port = %u\r\n", hub_addr, hub_port); + TU_LOG2("HUB Get Port Status: addr = %u port = %u\r\n", hub_addr, hub_port); TU_ASSERT( tuh_control_xfer( hub_addr, &request, resp, complete_cb) ); return true; } @@ -113,7 +113,7 @@ bool hub_port_reset(uint8_t hub_addr, uint8_t hub_port, tuh_control_complete_cb_ .wLength = 0 }; - TU_LOG2("HUB Reset Port: addr = 0x%02X, port = %u\r\n", hub_addr, hub_port); + TU_LOG2("HUB Reset Port: addr = %u port = %u\r\n", hub_addr, hub_port); TU_ASSERT( tuh_control_xfer(hub_addr, &request, NULL, complete_cb) ); return true; } diff --git a/src/host/usbh.c b/src/host/usbh.c index 4239cd1ec..61db0d8b0 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -601,7 +601,25 @@ static bool enum_hub_clear_reset1_complete(uint8_t dev_addr, tusb_control_reques return true; } -static bool enum_hub_get_status_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +static bool enum_hub_get_status1_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) +{ + (void) dev_addr; (void) request; + TU_ASSERT(XFER_RESULT_SUCCESS == result); + usbh_device_t* dev0 = &_usbh_devices[0]; + + hub_port_status_response_t port_status; + memcpy(&port_status, _usbh_ctrl_buf, sizeof(hub_port_status_response_t)); + + // Acknowledge Port Reset Change if Reset Successful + if (port_status.change.reset) + { + TU_ASSERT( hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) ); + } + + return true; +} + +static bool enum_hub_get_status0_complete(uint8_t dev_addr, tusb_control_request_t const * request, xfer_result_t result) { (void) dev_addr; (void) request; TU_ASSERT(XFER_RESULT_SUCCESS == result); @@ -692,7 +710,7 @@ static bool enum_new_device(hcd_event_t* event) { // wait until device is stable osal_task_delay(RESET_DELAY); - TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status_complete) ); + TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status0_complete) ); } #endif // CFG_TUH_HUB @@ -736,7 +754,7 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r { #if CFG_TUH_HUB // TODO remove, waiting for next data on status pipe - if (dev0->hub_addr != 0) hub_status_pipe_queue( dev0->hub_addr); + if (dev0->hub_addr != 0) hub_status_pipe_queue(dev0->hub_addr); #endif return false; @@ -758,13 +776,13 @@ static bool enum_get_addr0_device_desc_complete(uint8_t dev_addr, tusb_control_r { // after RESET_DELAY the hub_port_reset() already complete TU_ASSERT( hub_port_reset(dev0->hub_addr, dev0->hub_port, NULL) ); - osal_task_delay(RESET_DELAY); - // Acknowledge Port Reset Change if Reset Successful - TU_ASSERT( hub_port_clear_feature(dev0->hub_addr, dev0->hub_port, HUB_FEATURE_PORT_RESET_CHANGE, enum_hub_clear_reset1_complete) ); + tuh_task(); // FIXME temporarily to clean up port_reset control transfer + + TU_ASSERT( hub_port_get_status(dev0->hub_addr, dev0->hub_port, _usbh_ctrl_buf, enum_hub_get_status1_complete) ); } -#endif // CFG_TUH_HUB +#endif return true; } From 14461beffa4f2e12bc37d523701be65fabd0d8ce Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 2 Nov 2020 09:19:34 +0700 Subject: [PATCH 24/25] remove legacy blocking usbh_control_xfer() reworking cdc host driver --- src/class/cdc/cdc_host.c | 50 ++++++++++++++++++++++++++++------------ src/class/cdc/cdc_host.h | 13 +++++++++++ src/host/usbh.c | 48 +------------------------------------- src/host/usbh_hcd.h | 10 -------- 4 files changed, 49 insertions(+), 72 deletions(-) diff --git a/src/class/cdc/cdc_host.c b/src/class/cdc/cdc_host.c index ae1eef8a7..a897fb58a 100644 --- a/src/class/cdc/cdc_host.c +++ b/src/class/cdc/cdc_host.c @@ -51,9 +51,14 @@ typedef struct { //--------------------------------------------------------------------+ static cdch_data_t cdch_data[CFG_TUSB_HOST_DEVICE_MAX]; +static inline cdch_data_t* get_itf(uint8_t dev_addr) +{ + return &cdch_data[dev_addr-1]; +} + bool tuh_cdc_mounted(uint8_t dev_addr) { - cdch_data_t* cdc = &cdch_data[dev_addr-1]; + cdch_data_t* cdc = get_itf(dev_addr); return cdc->ep_in && cdc->ep_out; } @@ -61,7 +66,7 @@ bool tuh_cdc_is_busy(uint8_t dev_addr, cdc_pipeid_t pipeid) { if ( !tuh_cdc_mounted(dev_addr) ) return false; - cdch_data_t const * p_cdc = &cdch_data[dev_addr-1]; + cdch_data_t const * p_cdc = get_itf(dev_addr); switch (pipeid) { @@ -111,6 +116,27 @@ bool tuh_cdc_receive(uint8_t dev_addr, void * p_buffer, uint32_t length, bool is return hcd_pipe_xfer(dev_addr, ep_in, p_buffer, length, is_notify); } +bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_complete_cb_t complete_cb) +{ + cdch_data_t const * p_cdc = get_itf(dev_addr); + tusb_control_request_t const request = + { + .bmRequestType_bit = + { + .recipient = TUSB_REQ_RCPT_INTERFACE, + .type = TUSB_REQ_TYPE_CLASS, + .direction = TUSB_DIR_OUT + }, + .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, + .wValue = (rts ? 2 : 0) | (dtr ? 1 : 0), + .wIndex = p_cdc->itf_num, + .wLength = 0 + }; + + TU_ASSERT( tuh_control_xfer(dev_addr, &request, NULL, complete_cb) ); + return true; +} + //--------------------------------------------------------------------+ // USBH-CLASS DRIVER API //--------------------------------------------------------------------+ @@ -132,7 +158,7 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it cdch_data_t * p_cdc; p_desc = tu_desc_next(itf_desc); - p_cdc = &cdch_data[dev_addr-1]; + p_cdc = get_itf(dev_addr); p_cdc->itf_num = itf_desc->bInterfaceNumber; p_cdc->itf_protocol = itf_desc->bInterfaceProtocol; // TODO 0xff is consider as rndis candidate, other is virtual Com @@ -194,18 +220,12 @@ bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *it } } - // FIXME move to seperate API : connect - tusb_control_request_t request = - { - .bmRequestType_bit = { .recipient = TUSB_REQ_RCPT_INTERFACE, .type = TUSB_REQ_TYPE_CLASS, .direction = TUSB_DIR_OUT }, - .bRequest = CDC_REQUEST_SET_CONTROL_LINE_STATE, - .wValue = 0x03, // dtr on, cst on - .wIndex = p_cdc->itf_num, - .wLength = 0 - }; - - TU_ASSERT( usbh_control_xfer(dev_addr, &request, NULL) ); + return true; +} +bool cdch_set_config(uint8_t dev_addr, uint8_t itf_num) +{ + (void) dev_addr; (void) itf_num; return true; } @@ -218,7 +238,7 @@ bool cdch_xfer_cb(uint8_t dev_addr, uint8_t ep_addr, xfer_result_t event, uint32 void cdch_close(uint8_t dev_addr) { - cdch_data_t * p_cdc = &cdch_data[dev_addr-1]; + cdch_data_t * p_cdc = get_itf(dev_addr); tu_memclr(p_cdc, sizeof(cdch_data_t)); } diff --git a/src/class/cdc/cdc_host.h b/src/class/cdc/cdc_host.h index f28a0a713..66c2f0727 100644 --- a/src/class/cdc/cdc_host.h +++ b/src/class/cdc/cdc_host.h @@ -44,6 +44,18 @@ * \defgroup CDC_Serial_Host Host * @{ */ +bool tuh_cdc_set_control_line_state(uint8_t dev_addr, bool dtr, bool rts, tuh_control_complete_cb_t complete_cb); + +static inline bool tuh_cdc_connect(uint8_t dev_addr, tuh_control_complete_cb_t complete_cb) +{ + return tuh_cdc_set_control_line_state(dev_addr, true, true, complete_cb); +} + +static inline bool tuh_cdc_disconnect(uint8_t dev_addr, tuh_control_complete_cb_t complete_cb) +{ + return tuh_cdc_set_control_line_state(dev_addr, false, false, complete_cb); +} + /** \brief Check if device support CDC Serial interface or not * \param[in] dev_addr device address * \retval true if device supports @@ -113,6 +125,7 @@ void tuh_cdc_xfer_isr(uint8_t dev_addr, xfer_result_t event, cdc_pipeid_t pipe_i //--------------------------------------------------------------------+ void cdch_init(void); bool cdch_open(uint8_t rhport, uint8_t dev_addr, tusb_desc_interface_t const *itf_desc, uint16_t *p_length); +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); diff --git a/src/host/usbh.c b/src/host/usbh.c index 61db0d8b0..e7347ff56 100644 --- a/src/host/usbh.c +++ b/src/host/usbh.c @@ -56,6 +56,7 @@ static usbh_class_driver_t const usbh_class_drivers[] = .class_code = TUSB_CLASS_CDC, .init = cdch_init, .open = cdch_open, + .set_config = cdch_set_config, .xfer_cb = cdch_xfer_cb, .close = cdch_close }, @@ -174,9 +175,6 @@ bool tuh_init(void) { usbh_device_t * const dev = &_usbh_devices[i]; - dev->control.sem_hdl = osal_semaphore_create(&dev->control.sem_def); - TU_ASSERT(dev->control.sem_hdl != NULL); - #if CFG_TUSB_OS != OPT_OS_NONE dev->mutex = osal_mutex_create(&dev->mutexdef); TU_ASSERT(dev->mutex); @@ -199,38 +197,6 @@ bool tuh_init(void) return true; } -//------------- USBH control transfer -------------// - -// TODO remove -bool usbh_control_xfer (uint8_t dev_addr, tusb_control_request_t* request, uint8_t* data) -{ - usbh_device_t* dev = &_usbh_devices[dev_addr]; - const uint8_t rhport = dev->rhport; - - dev->control.request = *request; - dev->control.pipe_status = 0; - - // Setup Stage - hcd_setup_send(rhport, dev_addr, (uint8_t*) &dev->control.request); - TU_VERIFY(osal_semaphore_wait(dev->control.sem_hdl, OSAL_TIMEOUT_NORMAL)); - - // Data stage : first data toggle is always 1 - if ( request->wLength ) - { - hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, request->bmRequestType_bit.direction), data, request->wLength); - TU_VERIFY(osal_semaphore_wait(dev->control.sem_hdl, OSAL_TIMEOUT_NORMAL)); - } - - // Status : data toggle is always 1 - hcd_edpt_xfer(rhport, dev_addr, tu_edpt_addr(0, 1-request->bmRequestType_bit.direction), NULL, 0); - TU_VERIFY(osal_semaphore_wait(dev->control.sem_hdl, OSAL_TIMEOUT_NORMAL)); - - if ( XFER_RESULT_STALLED == dev->control.pipe_status ) return false; - if ( XFER_RESULT_FAILED == dev->control.pipe_status ) return false; - - return true; -} - bool usbh_edpt_claim(uint8_t dev_addr, uint8_t ep_addr) { uint8_t const epnum = tu_edpt_number(ep_addr); @@ -291,9 +257,6 @@ bool usbh_edpt_xfer(uint8_t dev_addr, uint8_t ep_addr, uint8_t * buffer, uint16_ bool usbh_pipe_control_open(uint8_t dev_addr, uint8_t max_packet_size) { - osal_semaphore_reset( _usbh_devices[dev_addr].control.sem_hdl ); - //osal_mutex_reset( usbh_devices[dev_addr].control.mutex_hdl ); - tusb_desc_endpoint_t ep0_desc = { .bLength = sizeof(tusb_desc_endpoint_t), @@ -349,15 +312,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) { - usbh_device_t* dev = &_usbh_devices[ dev_addr ]; - - if (0 == tu_edpt_number(ep_addr)) - { - dev->control.pipe_status = result; -// usbh_devices[ pipe_hdl.dev_addr ].control.xferred_bytes = xferred_bytes; not yet neccessary - osal_semaphore_post( dev->control.sem_hdl, true ); // FIXME post within ISR - } - hcd_event_t event = { .rhport = 0, // TODO correct rhport diff --git a/src/host/usbh_hcd.h b/src/host/usbh_hcd.h index dd0616704..abc7fd250 100644 --- a/src/host/usbh_hcd.h +++ b/src/host/usbh_hcd.h @@ -75,16 +75,6 @@ typedef struct { volatile uint8_t state; // device state, value from enum tusbh_device_state_t - //------------- control pipe -------------// - struct { - volatile uint8_t pipe_status; -// uint8_t xferred_bytes; TODO not yet necessary - tusb_control_request_t request; - - osal_semaphore_def_t sem_def; - osal_semaphore_t sem_hdl; // used to synchronize with HCD when control xfer complete - } control; - 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 ) From 2907b1e4382df313ba8eb713fa4d0e3d3bc6e7cf Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 7 Nov 2020 10:37:33 +0700 Subject: [PATCH 25/25] clean up --- src/host/usbh.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/host/usbh.h b/src/host/usbh.h index 7db918348..12c9164dd 100644 --- a/src/host/usbh.h +++ b/src/host/usbh.h @@ -116,8 +116,6 @@ 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_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); uint8_t usbh_get_rhport(uint8_t dev_addr);