From 97c9001d401b217b383046b6af3b8fd957e835f4 Mon Sep 17 00:00:00 2001 From: hathach Date: Wed, 13 Mar 2013 10:57:30 +0700 Subject: [PATCH] add hard fault handler to bsp.c rename class_install_subtask to class_open_subtask add class_close for unmount adding code for usbh_device_unplugged_isr & invoke it in hcd_isr --- demos/bsp/boards/board.c | 86 ++++++++++++++++++++++++++++ tests/test/host/ehci/test_ehci_isr.c | 10 ++++ tests/test/host/test_enum_task.c | 2 +- tests/test/host/test_usbh.c | 19 ++++++ tests/test/support/ehci_controller.c | 9 +++ tests/test/support/ehci_controller.h | 1 + tinyusb/class/hid_host.h | 3 +- tinyusb/class/msc_host.h | 4 +- tinyusb/host/ehci/ehci.c | 3 +- tinyusb/host/usbh.c | 33 +++++++++-- tinyusb/host/usbh.h | 3 +- 11 files changed, 161 insertions(+), 12 deletions(-) diff --git a/demos/bsp/boards/board.c b/demos/bsp/boards/board.c index c75203278..22d4c0971 100644 --- a/demos/bsp/boards/board.c +++ b/demos/bsp/boards/board.c @@ -50,3 +50,89 @@ void check_failed(uint8_t *file, uint32_t line) (void) file; (void) line; } + +/** + * HardFault_HandlerAsm: + * Alternative Hard Fault handler to help debug the reason for a fault. + * To use, edit the vector table to reference this function in the HardFault vector + * This code is suitable for Cortex-M3 and Cortex-M0 cores + */ + +// Use the 'naked' attribute so that C stacking is not used. +__attribute__((naked)) +void HardFault_HandlerAsm(void){ + /* + * Get the appropriate stack pointer, depending on our mode, + * and use it as the parameter to the C handler. This function + * will never return + */ + + __asm( ".syntax unified\n" + "MOVS R0, #4 \n" + "MOV R1, LR \n" + "TST R0, R1 \n" + "BEQ _MSP \n" + "MRS R0, PSP \n" + "B HardFault_HandlerC \n" + "_MSP: \n" + "MRS R0, MSP \n" + "B HardFault_HandlerC \n" + ".syntax divided\n") ; +} + +/** + * HardFaultHandler_C: + * This is called from the HardFault_HandlerAsm with a pointer the Fault stack + * as the parameter. We can then read the values from the stack and place them + * into local variables for ease of reading. + * We then read the various Fault Status and Address Registers to help decode + * cause of the fault. + * The function ends with a BKPT instruction to force control back into the debugger + */ +void HardFault_HandlerC(unsigned long *hardfault_args){ + volatile unsigned long stacked_r0 ; + volatile unsigned long stacked_r1 ; + volatile unsigned long stacked_r2 ; + volatile unsigned long stacked_r3 ; + volatile unsigned long stacked_r12 ; + volatile unsigned long stacked_lr ; + volatile unsigned long stacked_pc ; + volatile unsigned long stacked_psr ; + volatile unsigned long _CFSR ; + volatile unsigned long _HFSR ; + volatile unsigned long _DFSR ; + volatile unsigned long _AFSR ; + volatile unsigned long _BFAR ; + volatile unsigned long _MMAR ; + + stacked_r0 = ((unsigned long)hardfault_args[0]) ; + stacked_r1 = ((unsigned long)hardfault_args[1]) ; + stacked_r2 = ((unsigned long)hardfault_args[2]) ; + stacked_r3 = ((unsigned long)hardfault_args[3]) ; + stacked_r12 = ((unsigned long)hardfault_args[4]) ; + stacked_lr = ((unsigned long)hardfault_args[5]) ; + stacked_pc = ((unsigned long)hardfault_args[6]) ; + stacked_psr = ((unsigned long)hardfault_args[7]) ; + + // Configurable Fault Status Register + // Consists of MMSR, BFSR and UFSR + _CFSR = (*((volatile unsigned long *)(0xE000ED28))) ; + + // Hard Fault Status Register + _HFSR = (*((volatile unsigned long *)(0xE000ED2C))) ; + + // Debug Fault Status Register + _DFSR = (*((volatile unsigned long *)(0xE000ED30))) ; + + // Auxiliary Fault Status Register + _AFSR = (*((volatile unsigned long *)(0xE000ED3C))) ; + + // Read the Fault Address Registers. These may not contain valid values. + // Check BFARVALID/MMARVALID to see if they are valid values + // MemManage Fault Address Register + _MMAR = (*((volatile unsigned long *)(0xE000ED34))) ; + // Bus Fault Address Register + _BFAR = (*((volatile unsigned long *)(0xE000ED38))) ; + + __asm("BKPT #0\n") ; // Break into the debugger +} diff --git a/tests/test/host/ehci/test_ehci_isr.c b/tests/test/host/ehci/test_ehci_isr.c index 44eb503cf..95cbbcb5b 100644 --- a/tests/test/host/ehci/test_ehci_isr.c +++ b/tests/test/host/ehci/test_ehci_isr.c @@ -97,3 +97,13 @@ void test_isr_device_connect_slowspeed(void) //------------- Code Under Test -------------// hcd_isr(hostid); } + +void test_isr_device_disconnect(void) +{ + ehci_controller_device_unplug(hostid); + usbh_device_unplugged_isr_Expect(hostid); + + //------------- Code Under Test -------------// + hcd_isr(hostid); + +} diff --git a/tests/test/host/test_enum_task.c b/tests/test/host/test_enum_task.c index 30d99692f..00df47833 100644 --- a/tests/test/host/test_enum_task.c +++ b/tests/test/host/test_enum_task.c @@ -232,7 +232,7 @@ void test_enum_failed_get_full_config_desc(void) void class_install_expect(void) { - hidh_install_subtask_StubWithCallback(hidh_install_stub); + hidh_open_subtask_StubWithCallback(hidh_install_stub); } void test_enum_parse_config_desc(void) diff --git a/tests/test/host/test_usbh.c b/tests/test/host/test_usbh.c index 27bceb697..f69e32a5f 100644 --- a/tests/test/host/test_usbh.c +++ b/tests/test/host/test_usbh.c @@ -156,3 +156,22 @@ void test_usbh_init_ok(void) TEST_ASSERT_EQUAL_MEMORY(device_info_zero, usbh_device_info_pool, sizeof(usbh_device_info_t)*(TUSB_CFG_HOST_DEVICE_MAX+1)); } + +void class_close_expect(void) +{ + hidh_close_Expect(1); +} + +void test_usbh_device_unplugged_isr(void) +{ + usbh_device_info_pool[1].status = TUSB_DEVICE_STATUS_READY; + usbh_device_info_pool[1].core_id = 0; + usbh_device_info_pool[1].hub_addr = 0; + usbh_device_info_pool[1].hub_port = 0; + + class_close_expect(); + + usbh_device_unplugged_isr(0); + + TEST_ASSERT_EQUAL(TUSB_DEVICE_STATUS_REMOVING, usbh_device_info_pool[1].status); +} diff --git a/tests/test/support/ehci_controller.c b/tests/test/support/ehci_controller.c index 0bc09f53a..484348566 100644 --- a/tests/test/support/ehci_controller.c +++ b/tests/test/support/ehci_controller.c @@ -86,3 +86,12 @@ void ehci_controller_device_plug(uint8_t hostid, tusb_speed_t speed) regs->portsc_bit.current_connect_status = 1; regs->portsc_bit.nxp_port_speed = speed; } + +void ehci_controller_device_unplug(uint8_t hostid) +{ + ehci_registers_t* const regs = get_operational_register(hostid); + + regs->usb_sts_bit.port_change_detect = 1; + regs->portsc_bit.connect_status_change = 1; + regs->portsc_bit.current_connect_status = 0; +} diff --git a/tests/test/support/ehci_controller.h b/tests/test/support/ehci_controller.h index aee3f0116..cb5c69313 100644 --- a/tests/test/support/ehci_controller.h +++ b/tests/test/support/ehci_controller.h @@ -57,6 +57,7 @@ void ehci_controller_run(uint8_t hostid); void ehci_controller_device_plug(uint8_t hostid, tusb_speed_t speed); +void ehci_controller_device_unplug(uint8_t hostid); #ifdef __cplusplus } diff --git a/tinyusb/class/hid_host.h b/tinyusb/class/hid_host.h index 8d9b268c9..f85beef67 100644 --- a/tinyusb/class/hid_host.h +++ b/tinyusb/class/hid_host.h @@ -88,8 +88,9 @@ tusb_error_t hidh_keyboard_install(uint8_t dev_addr, uint8_t const *descriptor) // CLASS DRIVER FUNCTION (all declared with WEAK) //--------------------------------------------------------------------+ void hidh_init(void) ATTR_WEAK; -tusb_error_t hidh_install_subtask(uint8_t dev_addr, uint8_t const *descriptor, uint16_t *p_length) ATTR_WEAK ATTR_WARN_UNUSED_RESULT; +tusb_error_t hidh_open_subtask(uint8_t dev_addr, uint8_t const *descriptor, uint16_t *p_length) ATTR_WEAK ATTR_WARN_UNUSED_RESULT; void hidh_isr(pipe_handle_t pipe_hdl) ATTR_WEAK; +void hidh_close(uint8_t dev_addr) ATTR_WEAK; #endif diff --git a/tinyusb/class/msc_host.h b/tinyusb/class/msc_host.h index 7fc1ce48c..021d30412 100644 --- a/tinyusb/class/msc_host.h +++ b/tinyusb/class/msc_host.h @@ -69,9 +69,9 @@ #ifdef _TINY_USB_SOURCE_FILE_ void msch_init(void) ATTR_WEAK; -tusb_error_t msch_install_subtask(uint8_t dev_addr, uint8_t const *descriptor, uint16_t *p_length) ATTR_WEAK ATTR_WARN_UNUSED_RESULT; +tusb_error_t msch_open_subtask(uint8_t dev_addr, uint8_t const *descriptor, uint16_t *p_length) ATTR_WEAK ATTR_WARN_UNUSED_RESULT; void msch_isr(pipe_handle_t pipe_hdl) ATTR_WEAK; - +void msch_close(uint8_t dev_addr) ATTR_WEAK; #endif #ifdef __cplusplus diff --git a/tinyusb/host/ehci/ehci.c b/tinyusb/host/ehci/ehci.c index 8577195f5..2696033f3 100644 --- a/tinyusb/host/ehci/ehci.c +++ b/tinyusb/host/ehci/ehci.c @@ -175,7 +175,7 @@ void port_connect_status_isr(uint8_t hostid) usbh_device_plugged_isr(hostid, regs->portsc_bit.nxp_port_speed); // NXP specific port speed }else // device unplugged { -// usbh_device_ + usbh_device_unplugged_isr(hostid); } } @@ -578,6 +578,7 @@ static inline ehci_qtd_t* get_control_qtds(uint8_t dev_addr) static void init_qhd(ehci_qhd_t *p_qhd, uint8_t dev_addr, uint16_t max_packet_size, uint8_t endpoint_addr, uint8_t xfer_type) { + // address 0 uses async head, which always on the list --> cannot be cleared (ehci halted otherwise) if (dev_addr != 0) { memclr_(p_qhd, sizeof(ehci_qhd_t)); diff --git a/tinyusb/host/usbh.c b/tinyusb/host/usbh.c index dc37b9e3c..5f679facf 100644 --- a/tinyusb/host/usbh.c +++ b/tinyusb/host/usbh.c @@ -65,14 +65,16 @@ class_driver_t const usbh_class_drivers[TUSB_CLASS_MAX_CONSEC_NUMBER] = { [TUSB_CLASS_HID] = { .init = hidh_init, - .install_subtask = hidh_install_subtask, - .isr = hidh_isr + .open_subtask = hidh_open_subtask, + .isr = hidh_isr, + .close = hidh_close }, [TUSB_CLASS_MSC] = { .init = msch_init, - .install_subtask = msch_install_subtask, - .isr = msch_isr + .open_subtask = msch_open_subtask, + .isr = msch_isr, + .close = msch_close } }; @@ -190,7 +192,23 @@ void usbh_device_plugged_isr(uint8_t hostid, tusb_speed_t speed) void usbh_device_unplugged_isr(uint8_t hostid) { + uint8_t dev_addr=1; + while ( dev_addr <= TUSB_CFG_HOST_DEVICE_MAX && ! (usbh_device_info_pool[dev_addr].core_id == hostid && + usbh_device_info_pool[dev_addr].hub_addr == 0 && + usbh_device_info_pool[dev_addr].hub_port ==0)) + { + dev_addr++; + } + ASSERT(dev_addr <= TUSB_CFG_HOST_DEVICE_MAX, (void) 0 ); + + for (uint8_t class_code = 1; class_code < TUSB_CLASS_MAX_CONSEC_NUMBER; class_code++) + { + if (usbh_class_drivers[class_code].close) + usbh_class_drivers[class_code].close(dev_addr); + } + + usbh_device_info_pool[dev_addr].status = TUSB_DEVICE_STATUS_REMOVING; } @@ -260,6 +278,8 @@ OSAL_TASK_DECLARE(usbh_enumeration_task) usbh_device_info_pool[new_addr].status = TUSB_DEVICE_STATUS_ADDRESSED; hcd_pipe_control_close(0); +// hcd_port_reset( usbh_device_info_pool[new_addr].core_id ); TODO verified + // open control pipe for new address TASK_ASSERT_STATUS ( usbh_pipe_control_open(new_addr, ((tusb_descriptor_device_t*) enum_data_buffer)->bMaxPacketSize0 ) ); @@ -335,11 +355,11 @@ OSAL_TASK_DECLARE(usbh_enumeration_task) TASK_ASSERT( false ); // corrupted data, abort enumeration } else if ( class_code < TUSB_CLASS_MAX_CONSEC_NUMBER) { - if ( usbh_class_drivers[class_code].install_subtask ) + if ( usbh_class_drivers[class_code].open_subtask ) { uint16_t length; OSAL_SUBTASK_INVOKED_AND_WAIT ( // parameters in task/sub_task must be static storage (static or global) - usbh_class_drivers[ ((tusb_descriptor_interface_t*) p_desc)->bInterfaceClass ].install_subtask(new_addr, p_desc, &length) ); + usbh_class_drivers[ ((tusb_descriptor_interface_t*) p_desc)->bInterfaceClass ].open_subtask(new_addr, p_desc, &length) ); p_desc += length; } } else // unsupported class (not enable or yet implemented) @@ -366,6 +386,7 @@ OSAL_TASK_DECLARE(usbh_enumeration_task) ) ); + usbh_device_info_pool[new_addr].status = TUSB_DEVICE_STATUS_READY; tusbh_device_mount_succeed_cb(new_addr); // TODO invoke mounted callback diff --git a/tinyusb/host/usbh.h b/tinyusb/host/usbh.h index b89cc3bb9..2d74cd359 100644 --- a/tinyusb/host/usbh.h +++ b/tinyusb/host/usbh.h @@ -151,8 +151,9 @@ typedef uint8_t tusbh_device_status_t; typedef struct { void (* const init) (void); - tusb_error_t (* const install_subtask)(uint8_t, uint8_t const *, uint16_t*); + tusb_error_t (* const open_subtask)(uint8_t, uint8_t const *, uint16_t*); void (* const isr) (pipe_handle_t); + void (* const close) (uint8_t) } class_driver_t; //--------------------------------------------------------------------+ // INTERNAL OBJECT & FUNCTION DECLARATION