From 864d8381a7acbd89053b6d478c064872b4871ed9 Mon Sep 17 00:00:00 2001 From: MasterPhi Date: Sat, 26 Jun 2021 19:53:57 +0200 Subject: dcd_transmission xfer_fifo support. --- .../nxp/transdimension/dcd_transdimension.c | 114 ++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index 42047ef92..156695fc4 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -128,7 +128,8 @@ typedef struct /// Due to the fact QHD is 64 bytes aligned but occupies only 48 bytes /// thus there are 16 bytes padding free that we can make use of. //--------------------------------------------------------------------+ - uint8_t reserved[16]; + tu_fifo_t * ff; + uint8_t reserved[12]; } dcd_qhd_t; TU_VERIFY_STATIC( sizeof(dcd_qhd_t) == 64, "size is not correct"); @@ -314,6 +315,39 @@ static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes) } } +static void qtd_init_fifo(dcd_qtd_t* p_qtd, tu_fifo_buffer_info_t *info, uint16_t total_bytes) +{ + tu_memclr(p_qtd, sizeof(dcd_qtd_t)); + + p_qtd->next = QTD_NEXT_INVALID; + p_qtd->active = 1; + p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; + + // Fifo length has been trimmed to total_bytes + int16_t len_lin = info->len_lin; + + if (len_lin != 0) + { + p_qtd->buffer[0] = (uint32_t) info->ptr_lin; + + len_lin -= 4096 - ((uint32_t) info->ptr_lin - tu_align4k((uint32_t) info->ptr_lin)); + + // Set linear part + uint8_t i = 1; + for(; i<5; i++) + { + if (len_lin <= 0) break; + p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096; + len_lin -= 4096; + } + // Set wrapped part + for(uint8_t page = 0; i<5; i++, page++) + { + p_qtd->buffer[i] |= (uint32_t) info->ptr_wrap + 4096 * page; + } + } +} + //--------------------------------------------------------------------+ // DCD Endpoint Port //--------------------------------------------------------------------+ @@ -407,6 +441,67 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t return true; } +// fifo has to be aligned to 4k boundary +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +{ + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const ep_idx = 2*epnum + dir; + + if ( epnum == 0 ) + { + // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism + // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out + while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {} + } + + dcd_qhd_t * p_qhd = &_dcd_data.qhd[ep_idx]; + dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_idx]; + + tu_fifo_buffer_info_t fifo_info; + + if(dir == TUSB_DIR_IN) + { + tu_fifo_get_read_info(ff, &fifo_info); + } + else + { + tu_fifo_get_write_info(ff, &fifo_info); + } + + if(total_bytes <= fifo_info.len_lin) + { + // Limit transfer length to total_bytes + fifo_info.len_wrap = 0; + fifo_info.len_lin = total_bytes; + } + else + { + // Class driver ensure at least total_bytes elements in fifo + fifo_info.len_wrap = total_bytes - fifo_info.len_lin; + } + // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the + // address to 32-byte boundaries. + // void* cast to suppress cast-align warning, buffer must be + CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_lin, 4), fifo_info.len_lin + 31); + if(fifo_info.len_wrap > 0) + CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), fifo_info.len_wrap + 31); + + //------------- Prepare qtd -------------// + qtd_init_fifo(p_qtd, &fifo_info, total_bytes); + p_qtd->int_on_complete = true; + p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd + p_qhd->ff = ff; + + CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); + + // start transfer + dcd_reg->ENDPTPRIME = TU_BIT( ep_idx2bit(ep_idx) ) ; + + return true; +} + //--------------------------------------------------------------------+ // ISR //--------------------------------------------------------------------+ @@ -474,13 +569,28 @@ void dcd_int_handler(uint8_t rhport) if ( tu_bit_test(edpt_complete, ep_idx2bit(ep_idx)) ) { // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set + dcd_qhd_t * p_qhd = &_dcd_data.qhd[ep_idx]; dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_idx]; uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED : ( p_qtd->xact_err ||p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS; uint8_t const ep_addr = (ep_idx/2) | ( (ep_idx & 0x01) ? TUSB_DIR_IN_MASK : 0 ); - dcd_event_xfer_complete(rhport, ep_addr, p_qtd->expected_bytes - p_qtd->total_bytes, result, true); // only number of bytes in the IOC qtd + + uint16_t xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes; + + if (p_qhd->ff) + { + if(tu_edpt_dir(ep_addr) == TUSB_DIR_IN) + { + tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes); + } + else + { + tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes); + } + } + dcd_event_xfer_complete(rhport, ep_addr, xferred_bytes, result, true); // only number of bytes in the IOC qtd } } } -- cgit v1.3.1 From 16b802d50cff6118952767b8fefa33dd0447ea91 Mon Sep 17 00:00:00 2001 From: MasterPhi Date: Sat, 26 Jun 2021 23:13:01 +0200 Subject: add dcd_edpt_close and iso xfer. --- .../nxp/transdimension/dcd_transdimension.c | 75 ++++++++++++++-------- 1 file changed, 49 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index 156695fc4..a4d6c5d48 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -239,8 +239,9 @@ void dcd_init(uint8_t rhport) dcd_reg->USBMODE = USBMODE_CM_DEVICE; dcd_reg->OTGSC = OTGSC_VBUS_DISCHARGE | OTGSC_OTG_TERMINATION; - // TODO Force fullspeed on non-highspeed port - // dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED; +#if !TUD_OPT_HIGH_SPEED + dcd_reg->PORTSC1 = PORTSC1_FORCE_FULL_SPEED; +#endif CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); @@ -329,22 +330,22 @@ static void qtd_init_fifo(dcd_qtd_t* p_qtd, tu_fifo_buffer_info_t *info, uint16_ if (len_lin != 0) { p_qtd->buffer[0] = (uint32_t) info->ptr_lin; - + len_lin -= 4096 - ((uint32_t) info->ptr_lin - tu_align4k((uint32_t) info->ptr_lin)); - + // Set linear part uint8_t i = 1; for(; i<5; i++) { if (len_lin <= 0) break; p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096; - len_lin -= 4096; + len_lin -= 4096; } // Set wrapped part for(uint8_t page = 0; i<5; i++, page++) { p_qtd->buffer[i] |= (uint32_t) info->ptr_wrap + 4096 * page; - } + } } } @@ -373,9 +374,6 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) { - // TODO not support ISO yet - TU_VERIFY ( p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); - uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); uint8_t const ep_idx = 2*epnum + dir; @@ -387,14 +385,25 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) dcd_qhd_t * p_qhd = &_dcd_data.qhd[ep_idx]; tu_memclr(p_qhd, sizeof(dcd_qhd_t)); - p_qhd->zero_length_termination = 1; p_qhd->max_package_size = p_endpoint_desc->wMaxPacketSize.size; p_qhd->qtd_overlay.next = QTD_NEXT_INVALID; + if (p_endpoint_desc->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS) + { + p_qhd->iso_mult = 1; + } else + { + p_qhd->zero_length_termination = 1; + } + CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); // Enable EP Control dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + + // Clear EP type + dcd_reg->ENDPTCTRL[epnum] &=~(0x03 << (dir ? 18 : 2)); + dcd_reg->ENDPTCTRL[epnum] |= ((p_endpoint_desc->bmAttributes.xfer << 2) | ENDPTCTRL_ENABLE | ENDPTCTRL_TOGGLE_RESET) << (dir ? 16 : 0); return true; @@ -406,6 +415,22 @@ void dcd_edpt_close_all (uint8_t rhport) // TODO implement dcd_edpt_close_all() } +void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + + // Flush EP + uint32_t flush_mask = TU_BIT(epnum) << (dir ? 16 : 0); + dcd_reg->ENDPTFLUSH = flush_mask; + while(dcd_reg->ENDPTFLUSH & flush_mask); + + // Clear EP enable + dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0)); +} + bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) { dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; @@ -442,7 +467,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t } // fifo has to be aligned to 4k boundary -bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) +bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; uint8_t const epnum = tu_edpt_number(ep_addr); @@ -460,34 +485,33 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_idx]; tu_fifo_buffer_info_t fifo_info; - - if(dir == TUSB_DIR_IN) + + if (dir) { tu_fifo_get_read_info(ff, &fifo_info); - } - else + } else { tu_fifo_get_write_info(ff, &fifo_info); } - + if(total_bytes <= fifo_info.len_lin) { // Limit transfer length to total_bytes fifo_info.len_wrap = 0; fifo_info.len_lin = total_bytes; - } - else + } else { - // Class driver ensure at least total_bytes elements in fifo + // Class driver need to ensure at least total_bytes elements in fifo fifo_info.len_wrap = total_bytes - fifo_info.len_lin; } // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the // address to 32-byte boundaries. // void* cast to suppress cast-align warning, buffer must be CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_lin, 4), fifo_info.len_lin + 31); - if(fifo_info.len_wrap > 0) + if (fifo_info.len_wrap > 0) + { CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), fifo_info.len_wrap + 31); - + } //------------- Prepare qtd -------------// qtd_init_fifo(p_qtd, &fifo_info, total_bytes); p_qtd->int_on_complete = true; @@ -576,20 +600,19 @@ void dcd_int_handler(uint8_t rhport) ( p_qtd->xact_err ||p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS; uint8_t const ep_addr = (ep_idx/2) | ( (ep_idx & 0x01) ? TUSB_DIR_IN_MASK : 0 ); - + uint16_t xferred_bytes = p_qtd->expected_bytes - p_qtd->total_bytes; if (p_qhd->ff) { - if(tu_edpt_dir(ep_addr) == TUSB_DIR_IN) + if (tu_edpt_dir(ep_addr)) { tu_fifo_advance_read_pointer(p_qhd->ff, xferred_bytes); - } - else + } else { tu_fifo_advance_write_pointer(p_qhd->ff, xferred_bytes); } - } + } dcd_event_xfer_complete(rhport, ep_addr, xferred_bytes, result, true); // only number of bytes in the IOC qtd } } -- cgit v1.3.1 From f81368174b613f4168ddb0e2ec1822c8dbc31d59 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 9 Sep 2021 14:34:03 +0700 Subject: add other speed descriptor callback tud_descriptor_other_speed_configuration_cb() example implement tud_descriptor_device_qualifier_cb() and tud_descriptor_other_speed_configuration_cb() on high speed device to fully compliant to usbcv --- .../device/cdc_dual_ports/src/usb_descriptors.c | 48 ++++++++++- examples/device/cdc_msc/src/usb_descriptors.c | 92 +++++++++++++++++----- .../device/cdc_msc_freertos/src/usb_descriptors.c | 63 +++++++++++++-- .../device/hid_composite/src/usb_descriptors.c | 57 +++++++++++++- .../hid_composite_freertos/src/usb_descriptors.c | 55 ++++++++++++- src/common/tusb_types.h | 5 +- src/device/usbd.c | 40 +++++----- src/device/usbd.h | 9 ++- 8 files changed, 315 insertions(+), 54 deletions(-) (limited to 'src') diff --git a/examples/device/cdc_dual_ports/src/usb_descriptors.c b/examples/device/cdc_dual_ports/src/usb_descriptors.c index 02ccbcc9e..aa400d486 100644 --- a/examples/device/cdc_dual_ports/src/usb_descriptors.c +++ b/examples/device/cdc_dual_ports/src/usb_descriptors.c @@ -35,6 +35,9 @@ #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) +#define USB_VID 0xCafe +#define USB_BCD 0x0200 + //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ @@ -42,7 +45,7 @@ tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = USB_BCD, // Use Interface Association Descriptor (IAD) for CDC // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) @@ -51,7 +54,7 @@ tusb_desc_device_t const desc_device = .bDeviceProtocol = MISC_PROTOCOL_IAD, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0xCafe, + .idVendor = USB_VID, .idProduct = USB_PID, .bcdDevice = 0x0100, @@ -128,6 +131,8 @@ uint8_t const desc_fs_configuration[] = }; #if TUD_OPT_HIGH_SPEED +// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration + uint8_t const desc_hs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA @@ -139,7 +144,44 @@ uint8_t const desc_hs_configuration[] = // 2nd CDC: Interface number, string index, EP notification address and size, EP data address (out, in) and size. TUD_CDC_DESCRIPTOR(ITF_NUM_CDC_1, 4, EPNUM_CDC_1_NOTIF, 8, EPNUM_CDC_1_OUT, EPNUM_CDC_1_IN, 512), }; -#endif + +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = +{ + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = USB_BCD, + + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 +}; + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const* tud_descriptor_device_qualifier_cb(void) +{ + return (uint8_t const*) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + + // if link speed is high return fullspeed config, and vice versa + return (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration; +} + +#endif // highspeed // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor diff --git a/examples/device/cdc_msc/src/usb_descriptors.c b/examples/device/cdc_msc/src/usb_descriptors.c index 3cf1eaf91..34537b8f0 100644 --- a/examples/device/cdc_msc/src/usb_descriptors.c +++ b/examples/device/cdc_msc/src/usb_descriptors.c @@ -35,32 +35,35 @@ #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) +#define USB_VID 0xCafe +#define USB_BCD 0x0200 + //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ tusb_desc_device_t const desc_device = { - .bLength = sizeof(tusb_desc_device_t), - .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, + .bLength = sizeof(tusb_desc_device_t), + .bDescriptorType = TUSB_DESC_DEVICE, + .bcdUSB = USB_BCD, - // Use Interface Association Descriptor (IAD) for CDC - // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) - .bDeviceClass = TUSB_CLASS_MISC, - .bDeviceSubClass = MISC_SUBCLASS_COMMON, - .bDeviceProtocol = MISC_PROTOCOL_IAD, + // Use Interface Association Descriptor (IAD) for CDC + // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, - .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0xCafe, - .idProduct = USB_PID, - .bcdDevice = 0x0100, + .idVendor = USB_VID, + .idProduct = USB_PID, + .bcdDevice = 0x0100, - .iManufacturer = 0x01, - .iProduct = 0x02, - .iSerialNumber = 0x03, + .iManufacturer = 0x01, + .iProduct = 0x02, + .iSerialNumber = 0x03, - .bNumConfigurations = 0x01 + .bNumConfigurations = 0x01 }; // Invoked when received GET DEVICE DESCRIPTOR @@ -82,8 +85,6 @@ enum ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN) - #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ... @@ -126,6 +127,9 @@ enum #endif +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN) + +// full speed configuration uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA @@ -139,6 +143,9 @@ uint8_t const desc_fs_configuration[] = }; #if TUD_OPT_HIGH_SPEED +// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration + +// high speed configuration uint8_t const desc_hs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA @@ -150,7 +157,54 @@ uint8_t const desc_hs_configuration[] = // Interface number, string index, EP Out & EP In address, EP size TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512), }; -#endif + +// other speed configuration +uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN]; + +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = +{ + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = USB_BCD, + + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 +}; + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const* tud_descriptor_device_qualifier_cb(void) +{ + return (uint8_t const*) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + + // if link speed is high return fullspeed config, and vice versa + // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG + memcpy(desc_other_speed_config, + (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration, + CONFIG_TOTAL_LEN); + + desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; + + return desc_other_speed_config; +} + +#endif // highspeed // Invoked when received GET CONFIGURATION DESCRIPTOR diff --git a/examples/device/cdc_msc_freertos/src/usb_descriptors.c b/examples/device/cdc_msc_freertos/src/usb_descriptors.c index c8dbcd415..f3ff305f8 100644 --- a/examples/device/cdc_msc_freertos/src/usb_descriptors.c +++ b/examples/device/cdc_msc_freertos/src/usb_descriptors.c @@ -35,6 +35,9 @@ #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) +#define USB_VID 0xCafe +#define USB_BCD 0x0200 + //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ @@ -42,7 +45,7 @@ tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = USB_BCD, // Use Interface Association Descriptor (IAD) for CDC // As required by USB Specs IAD's subclass must be common class (2) and protocol must be IAD (1) @@ -52,7 +55,7 @@ tusb_desc_device_t const desc_device = .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0xCafe, + .idVendor = USB_VID, .idProduct = USB_PID, .bcdDevice = 0x0100, @@ -82,8 +85,6 @@ enum ITF_NUM_TOTAL }; -#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN) - #if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX // LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number // 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ... @@ -114,6 +115,8 @@ enum #endif +#define CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_DESC_LEN + TUD_MSC_DESC_LEN) + uint8_t const desc_fs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA @@ -127,6 +130,9 @@ uint8_t const desc_fs_configuration[] = }; #if TUD_OPT_HIGH_SPEED +// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration + +// high speed configuration uint8_t const desc_hs_configuration[] = { // Config number, interface count, string index, total length, attribute, power in mA @@ -138,7 +144,54 @@ uint8_t const desc_hs_configuration[] = // Interface number, string index, EP Out & EP In address, EP size TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 5, EPNUM_MSC_OUT, EPNUM_MSC_IN, 512), }; -#endif + +// other speed configuration +uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN]; + +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = +{ + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = USB_BCD, + + .bDeviceClass = TUSB_CLASS_MISC, + .bDeviceSubClass = MISC_SUBCLASS_COMMON, + .bDeviceProtocol = MISC_PROTOCOL_IAD, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 +}; + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const* tud_descriptor_device_qualifier_cb(void) +{ + return (uint8_t const*) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + + // if link speed is high return fullspeed config, and vice versa + // Note: the descriptor type is OHER_SPEED_CONFIG instead of CONFIG + memcpy(desc_other_speed_config, + (tud_speed_get() == TUSB_SPEED_HIGH) ? desc_fs_configuration : desc_hs_configuration, + CONFIG_TOTAL_LEN); + + desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; + + return desc_other_speed_config; +} + +#endif // highspeed // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor diff --git a/examples/device/hid_composite/src/usb_descriptors.c b/examples/device/hid_composite/src/usb_descriptors.c index b9a6e7292..e760b20ba 100644 --- a/examples/device/hid_composite/src/usb_descriptors.c +++ b/examples/device/hid_composite/src/usb_descriptors.c @@ -36,6 +36,9 @@ #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) +#define USB_VID 0xCafe +#define USB_BCD 0x0200 + //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ @@ -43,13 +46,13 @@ tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = USB_BCD, .bDeviceClass = 0x00, .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0xCafe, + .idVendor = USB_VID, .idProduct = USB_PID, .bcdDevice = 0x0100, @@ -111,12 +114,62 @@ uint8_t const desc_configuration[] = TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5) }; +#if TUD_OPT_HIGH_SPEED +// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration + +// other speed configuration +uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN]; + +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = +{ + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = USB_BCD, + + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 +}; + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const* tud_descriptor_device_qualifier_cb(void) +{ + return (uint8_t const*) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + + // other speed config is basically configuration with type = OHER_SPEED_CONFIG + memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN); + desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; + + // this example use the same configuration for both high and full speed mode + return desc_other_speed_config; +} + +#endif // highspeed + // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete uint8_t const * tud_descriptor_configuration_cb(uint8_t index) { (void) index; // for multiple configurations + + // This example use the same configuration for both high and full speed mode return desc_configuration; } diff --git a/examples/device/hid_composite_freertos/src/usb_descriptors.c b/examples/device/hid_composite_freertos/src/usb_descriptors.c index b9a6e7292..791813fdf 100644 --- a/examples/device/hid_composite_freertos/src/usb_descriptors.c +++ b/examples/device/hid_composite_freertos/src/usb_descriptors.c @@ -36,6 +36,9 @@ #define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \ _PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) ) +#define USB_VID 0xCafe +#define USB_BCD 0x0200 + //--------------------------------------------------------------------+ // Device Descriptors //--------------------------------------------------------------------+ @@ -43,13 +46,13 @@ tusb_desc_device_t const desc_device = { .bLength = sizeof(tusb_desc_device_t), .bDescriptorType = TUSB_DESC_DEVICE, - .bcdUSB = 0x0200, + .bcdUSB = USB_BCD, .bDeviceClass = 0x00, .bDeviceSubClass = 0x00, .bDeviceProtocol = 0x00, .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, - .idVendor = 0xCafe, + .idVendor = USB_VID, .idProduct = USB_PID, .bcdDevice = 0x0100, @@ -111,6 +114,54 @@ uint8_t const desc_configuration[] = TUD_HID_DESCRIPTOR(ITF_NUM_HID, 0, HID_ITF_PROTOCOL_NONE, sizeof(desc_hid_report), EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 5) }; +#if TUD_OPT_HIGH_SPEED +// Per USB specs: high speed capable device must report device_qualifier and other_speed_configuration + +// other speed configuration +uint8_t desc_other_speed_config[CONFIG_TOTAL_LEN]; + +// device qualifier is mostly similar to device descriptor since we don't change configuration based on speed +tusb_desc_device_qualifier_t const desc_device_qualifier = +{ + .bLength = sizeof(tusb_desc_device_qualifier_t), + .bDescriptorType = TUSB_DESC_DEVICE_QUALIFIER, + .bcdUSB = USB_BCD, + + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + + .bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE, + .bNumConfigurations = 0x01, + .bReserved = 0x00 +}; + +// Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. +uint8_t const* tud_descriptor_device_qualifier_cb(void) +{ + return (uint8_t const*) &desc_device_qualifier; +} + +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index) +{ + (void) index; // for multiple configurations + + // other speed config is basically configuration with type = OHER_SPEED_CONFIG + memcpy(desc_other_speed_config, desc_configuration, CONFIG_TOTAL_LEN); + desc_other_speed_config[1] = TUSB_DESC_OTHER_SPEED_CONFIG; + + // this example use the same configuration for both high and full speed mode + return desc_other_speed_config; +} + +#endif // highspeed + // Invoked when received GET CONFIGURATION DESCRIPTOR // Application return pointer to descriptor // Descriptor contents must exist long enough for transfer to complete diff --git a/src/common/tusb_types.h b/src/common/tusb_types.h index d23c6b2dd..f26983a74 100644 --- a/src/common/tusb_types.h +++ b/src/common/tusb_types.h @@ -372,7 +372,7 @@ typedef struct TU_ATTR_PACKED uint8_t bNumInterfaces ; ///< Number of interfaces supported by this speed configuration uint8_t bConfigurationValue ; ///< Value to use to select configuration - uint8_t IConfiguration ; ///< Index of string descriptor + uint8_t iConfiguration ; ///< Index of string descriptor uint8_t bmAttributes ; ///< Same as Configuration descriptor uint8_t bMaxPower ; ///< Same as Configuration descriptor } tusb_desc_other_speed_t; @@ -387,11 +387,14 @@ typedef struct TU_ATTR_PACKED uint8_t bDeviceClass ; ///< Class Code uint8_t bDeviceSubClass ; ///< SubClass Code uint8_t bDeviceProtocol ; ///< Protocol Code + uint8_t bMaxPacketSize0 ; ///< Maximum packet size for other speed uint8_t bNumConfigurations ; ///< Number of Other-speed Configurations uint8_t bReserved ; ///< Reserved for future use, must be zero } tusb_desc_device_qualifier_t; +TU_VERIFY_STATIC( sizeof(tusb_desc_device_qualifier_t) == 10, "size is not correct"); + /// USB Interface Association Descriptor (IAD ECN) typedef struct TU_ATTR_PACKED { diff --git a/src/device/usbd.c b/src/device/usbd.c index a52ea9afe..58b3a5701 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1002,10 +1002,22 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const break; case TUSB_DESC_CONFIGURATION: + case TUSB_DESC_OTHER_SPEED_CONFIG: { - TU_LOG2(" Configuration[%u]\r\n", desc_index); + tusb_desc_configuration_t const* desc_config; + + if ( desc_type == TUSB_DESC_CONFIGURATION ) + { + TU_LOG2(" Configuration[%u]\r\n", desc_index); + desc_config = (tusb_desc_configuration_t const*) tud_descriptor_configuration_cb(desc_index); + }else + { + // Host only request this after getting Device Qualifier descriptor + TU_LOG2(" Other Speed Configuration\r\n"); + TU_VERIFY( tud_descriptor_other_speed_configuration_cb ); + desc_config = (tusb_desc_configuration_t const*) tud_descriptor_other_speed_configuration_cb(desc_index); + } - tusb_desc_configuration_t const* desc_config = (tusb_desc_configuration_t const*) tud_descriptor_configuration_cb(desc_index); TU_ASSERT(desc_config); // Use offsetof to avoid pointer to the odd/misaligned address @@ -1031,27 +1043,13 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const case TUSB_DESC_DEVICE_QUALIFIER: TU_LOG2(" Device Qualifier\r\n"); - // Host sends this request to ask why our device with USB BCD from 2.0 - // but is running at Full/Low Speed. If not highspeed capable stall this request, - // otherwise return the descriptor that could work in highspeed mode - if ( tud_descriptor_device_qualifier_cb ) - { - uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb(); - TU_ASSERT(desc_qualifier); + TU_VERIFY( tud_descriptor_device_qualifier_cb ); - // first byte of descriptor is its size - return tud_control_xfer(rhport, p_request, (void*) desc_qualifier, desc_qualifier[0]); - }else - { - return false; - } - break; + uint8_t const* desc_qualifier = tud_descriptor_device_qualifier_cb(); + TU_VERIFY(desc_qualifier); - case TUSB_DESC_OTHER_SPEED_CONFIG: - TU_LOG2(" Other Speed Configuration\r\n"); - - // After Device Qualifier descriptor is received host will ask for this descriptor - return false; // not supported + // first byte of descriptor is its size + return tud_control_xfer(rhport, p_request, (void*) desc_qualifier, desc_qualifier[0]); break; default: return false; diff --git a/src/device/usbd.h b/src/device/usbd.h index 9becf2d0d..638d93094 100644 --- a/src/device/usbd.h +++ b/src/device/usbd.h @@ -113,9 +113,16 @@ uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid); TU_ATTR_WEAK uint8_t const * tud_descriptor_bos_cb(void); // Invoked when received GET DEVICE QUALIFIER DESCRIPTOR request -// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete. +// device_qualifier descriptor describes information about a high-speed capable device that would +// change if the device were operating at the other speed. If not highspeed capable stall this request. TU_ATTR_WEAK uint8_t const* tud_descriptor_device_qualifier_cb(void); +// Invoked when received GET OTHER SEED CONFIGURATION DESCRIPTOR request +// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete +// Configuration descriptor in the other speed e.g if high speed then this is for full speed and vice versa +TU_ATTR_WEAK uint8_t const* tud_descriptor_other_speed_configuration_cb(uint8_t index); + // Invoked when device is mounted (configured) TU_ATTR_WEAK void tud_mount_cb(void); -- cgit v1.3.1 From 27800f7e4f39c856d2fe82e6320e855d8c283518 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 9 Sep 2021 16:01:05 +0700 Subject: remove connected check for DCD_EVENT_UNPLUGGED since previous bus reset can clear this implement unplugged detection for trans dimension dcd --- src/device/usbd.c | 14 ++++------- .../nxp/transdimension/dcd_transdimension.c | 28 ++++++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) (limited to 'src') diff --git a/src/device/usbd.c b/src/device/usbd.c index 58b3a5701..4ab60569b 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1064,15 +1064,11 @@ void dcd_event_handler(dcd_event_t const * event, bool in_isr) switch (event->event_id) { case DCD_EVENT_UNPLUGGED: - // UNPLUGGED event can be bouncing, only processing if we are currently connected - if ( _usbd_dev.connected ) - { - _usbd_dev.connected = 0; - _usbd_dev.addressed = 0; - _usbd_dev.cfg_num = 0; - _usbd_dev.suspended = 0; - osal_queue_send(_usbd_q, event, in_isr); - } + _usbd_dev.connected = 0; + _usbd_dev.addressed = 0; + _usbd_dev.cfg_num = 0; + _usbd_dev.suspended = 0; + osal_queue_send(_usbd_q, event, in_isr); break; case DCD_EVENT_SUSPEND: diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index 42047ef92..da766afa1 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -245,7 +245,7 @@ void dcd_init(uint8_t rhport) dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment dcd_reg->USBSTS = dcd_reg->USBSTS; - dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_RESET | INTR_SUSPEND /*| INTR_SOF*/; + dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_RESET | INTR_SUSPEND; dcd_reg->USBCMD &= ~0x00FF0000; // Interrupt Threshold Interval = 0 dcd_reg->USBCMD |= USBCMD_RUN_STOP; // Connect @@ -272,7 +272,9 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) void dcd_remote_wakeup(uint8_t rhport) { - (void) rhport; + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + (void) dcd_reg; +// dcd_reg->PORTSC1 = } void dcd_connect(uint8_t rhport) @@ -412,7 +414,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t //--------------------------------------------------------------------+ void dcd_int_handler(uint8_t rhport) { - dcd_registers_t* const dcd_reg = _dcd_controller[rhport].regs; + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; uint32_t const int_enable = dcd_reg->USBINTR; uint32_t const int_status = dcd_reg->USBSTS & int_enable; @@ -433,6 +435,7 @@ void dcd_int_handler(uint8_t rhport) if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND) { // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. + // Skip suspend event if we are not addressed if ((dcd_reg->DEVICEADDR >> 25) & 0x0f) { dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); @@ -440,19 +443,18 @@ void dcd_int_handler(uint8_t rhport) } } + // Set if the port controller enters the full or high-speed operational state. + if (int_status & INTR_PORT_CHANGE) + { + if ( !(dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) ) + { + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); + } + } + // Make sure we read the latest version of _dcd_data. CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); - // TODO disconnection does not generate interrupt !!!!!! -// if (int_status & INTR_PORT_CHANGE) -// { -// if ( !(dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) ) -// { -// dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_UNPLUGGED }; -// dcd_event_handler(&event, true); -// } -// } - if (int_status & INTR_USB) { uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE; -- cgit v1.3.1 From f948cbe4710c800cd168de793cc1c4fb80a55dd7 Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 9 Sep 2021 17:04:04 +0700 Subject: nxp tdi implement remote wakeup enhance bus reset, unplugged, suspend, resume detection --- .../nxp/transdimension/dcd_transdimension.c | 53 ++++++++++++++-------- 1 file changed, 35 insertions(+), 18 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index da766afa1..4a8205162 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -245,7 +245,7 @@ void dcd_init(uint8_t rhport) dcd_reg->ENDPTLISTADDR = (uint32_t) _dcd_data.qhd; // Endpoint List Address has to be 2K alignment dcd_reg->USBSTS = dcd_reg->USBSTS; - dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_RESET | INTR_SUSPEND; + dcd_reg->USBINTR = INTR_USB | INTR_ERROR | INTR_PORT_CHANGE | INTR_SUSPEND; dcd_reg->USBCMD &= ~0x00FF0000; // Interrupt Threshold Interval = 0 dcd_reg->USBCMD |= USBCMD_RUN_STOP; // Connect @@ -273,8 +273,7 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) void dcd_remote_wakeup(uint8_t rhport) { dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; - (void) dcd_reg; -// dcd_reg->PORTSC1 = + dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME; } void dcd_connect(uint8_t rhport) @@ -423,15 +422,42 @@ void dcd_int_handler(uint8_t rhport) // disabled interrupt sources if (int_status == 0) return; - if (int_status & INTR_RESET) - { - bus_reset(rhport); - uint32_t speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS; - dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true); - } + // Set if the port controller enters the full or high-speed operational state. + // either from Bus Reset or Suspended state + if (int_status & INTR_PORT_CHANGE) + { + // TU_LOG2("PortChange %08lx\r\n", dcd_reg->PORTSC1); + + // Reset interrupt is not enabled, we manually check if Port Change is due + // to connection / disconnection + if ( dcd_reg->USBSTS & INTR_RESET ) + { + dcd_reg->USBSTS = INTR_RESET; + + if (dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) + { + uint32_t const speed = (dcd_reg->PORTSC1 & PORTSC1_PORT_SPEED) >> PORTSC1_PORT_SPEED_POS; + bus_reset(rhport); + dcd_event_bus_reset(rhport, (tusb_speed_t) speed, true); + }else + { + dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); + } + } + else + { + // Triggered by resuming from suspended state + if ( !(dcd_reg->PORTSC1 & PORTSC1_SUSPEND) ) + { + dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true); + } + } + } if (int_status & INTR_SUSPEND) { + // TU_LOG2("Suspend %08lx\r\n", dcd_reg->PORTSC1); + if (dcd_reg->PORTSC1 & PORTSC1_SUSPEND) { // Note: Host may delay more than 3 ms before and/or after bus reset before doing enumeration. @@ -443,15 +469,6 @@ void dcd_int_handler(uint8_t rhport) } } - // Set if the port controller enters the full or high-speed operational state. - if (int_status & INTR_PORT_CHANGE) - { - if ( !(dcd_reg->PORTSC1 & PORTSC1_CURRENT_CONNECT_STATUS) ) - { - dcd_event_bus_signal(rhport, DCD_EVENT_UNPLUGGED, true); - } - } - // Make sure we read the latest version of _dcd_data. CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); -- cgit v1.3.1 From ad8c0ee8182f6c6120bf8124dbdcd2883f285f8f Mon Sep 17 00:00:00 2001 From: hathach Date: Thu, 9 Sep 2021 20:26:03 +0700 Subject: nxp tdi: enhance qhd using DCD_ATTR_ENDPOINT_MAX --- src/common/tusb_common.h | 2 +- .../nxp/transdimension/dcd_transdimension.c | 87 +++++++++++----------- 2 files changed, 44 insertions(+), 45 deletions(-) (limited to 'src') diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index 687f980be..d0cc41285 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -372,7 +372,7 @@ typedef struct static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint32_t key) { - static char not_found[10]; + static char not_found[11]; for(uint16_t i=0; icount; i++) { diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index 4a8205162..35f824112 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -145,10 +145,6 @@ typedef struct }dcd_controller_t; #if CFG_TUSB_MCU == OPT_MCU_MIMXRT10XX - // Each endpoint with direction (IN/OUT) occupies a queue head - // Therefore QHD_MAX is 2 x max endpoint count - #define QHD_MAX (8*2) - static const dcd_controller_t _dcd_controller[] = { // RT1010 and RT1020 only has 1 USB controller @@ -161,8 +157,6 @@ typedef struct }; #else - #define QHD_MAX (6*2) - static const dcd_controller_t _dcd_controller[] = { { .regs = (dcd_registers_t*) LPC_USB0_BASE, .irqnum = USB0_IRQn, .ep_count = 6 }, @@ -174,8 +168,10 @@ typedef struct typedef struct { // Must be at 2K alignment - dcd_qhd_t qhd[QHD_MAX] TU_ATTR_ALIGNED(64); - dcd_qtd_t qtd[QHD_MAX] TU_ATTR_ALIGNED(32); // for portability, TinyUSB only queue 1 TD for each Qhd + // Each endpoint with direction (IN/OUT) occupies a queue head + // for portability, TinyUSB only queue 1 TD for each Qhd + dcd_qhd_t qhd[DCD_ATTR_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(64); + dcd_qtd_t qtd[DCD_ATTR_ENDPOINT_MAX][2] TU_ATTR_ALIGNED(32); }dcd_data_t; CFG_TUSB_MEM_SECTION TU_ATTR_ALIGNED(2048) @@ -217,11 +213,11 @@ static void bus_reset(uint8_t rhport) tu_memclr(&_dcd_data, sizeof(dcd_data_t)); //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------// - _dcd_data.qhd[0].zero_length_termination = _dcd_data.qhd[1].zero_length_termination = 1; - _dcd_data.qhd[0].max_package_size = _dcd_data.qhd[1].max_package_size = CFG_TUD_ENDPOINT0_SIZE; - _dcd_data.qhd[0].qtd_overlay.next = _dcd_data.qhd[1].qtd_overlay.next = QTD_NEXT_INVALID; + _dcd_data.qhd[0][0].zero_length_termination = _dcd_data.qhd[0][1].zero_length_termination = 1; + _dcd_data.qhd[0][0].max_package_size = _dcd_data.qhd[0][1].max_package_size = CFG_TUD_ENDPOINT0_SIZE; + _dcd_data.qhd[0][0].qtd_overlay.next = _dcd_data.qhd[0][1].qtd_overlay.next = QTD_NEXT_INVALID; - _dcd_data.qhd[0].int_on_setup = 1; // OUT only + _dcd_data.qhd[0][0].int_on_setup = 1; // OUT only } void dcd_init(uint8_t rhport) @@ -291,11 +287,6 @@ void dcd_disconnect(uint8_t rhport) //--------------------------------------------------------------------+ // HELPER //--------------------------------------------------------------------+ -// index to bit position in register -static inline uint8_t ep_idx2bit(uint8_t ep_idx) -{ - return ep_idx/2 + ( (ep_idx%2) ? 16 : 0); -} static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes) { @@ -325,12 +316,15 @@ void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; dcd_reg->ENDPTCTRL[epnum] |= ENDPTCTRL_STALL << (dir ? 16 : 0); + + // flush to abort any primed buffer + dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0)); } void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); // data toggle also need to be reset dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; @@ -343,15 +337,14 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) // TODO not support ISO yet TU_VERIFY ( p_endpoint_desc->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS); - uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); - uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); - uint8_t const ep_idx = 2*epnum + dir; + uint8_t const epnum = tu_edpt_number(p_endpoint_desc->bEndpointAddress); + uint8_t const dir = tu_edpt_dir(p_endpoint_desc->bEndpointAddress); // Must not exceed max endpoint number TU_ASSERT( epnum < _dcd_controller[rhport].ep_count ); //------------- Prepare Queue Head -------------// - dcd_qhd_t * p_qhd = &_dcd_data.qhd[ep_idx]; + dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir]; tu_memclr(p_qhd, sizeof(dcd_qhd_t)); p_qhd->zero_length_termination = 1; @@ -378,7 +371,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - uint8_t const ep_idx = 2*epnum + dir; if ( epnum == 0 ) { @@ -387,8 +379,8 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {} } - dcd_qhd_t * p_qhd = &_dcd_data.qhd[ep_idx]; - dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_idx]; + dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir]; + dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir]; // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the // address to 32-byte boundaries. @@ -403,7 +395,7 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); // start transfer - dcd_reg->ENDPTPRIME = TU_BIT( ep_idx2bit(ep_idx) ) ; + dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0)); return true; } @@ -411,6 +403,18 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t //--------------------------------------------------------------------+ // ISR //--------------------------------------------------------------------+ + +static void process_edpt_complete_isr(uint8_t rhport, uint8_t ep_num, uint8_t dir) +{ + dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_num][dir]; + + uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED : + ( p_qtd->xact_err || p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS; + + // only number of bytes in the IOC qtd + dcd_event_xfer_complete(rhport, tu_edpt_addr(ep_num, dir), p_qtd->expected_bytes - p_qtd->total_bytes, result, true); +} + void dcd_int_handler(uint8_t rhport) { dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; @@ -481,26 +485,24 @@ void dcd_int_handler(uint8_t rhport) { //------------- Set up Received -------------// // 23.10.10.2 Operational model for setup transfers - dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT;// acknowledge + dcd_reg->ENDPTSETUPSTAT = dcd_reg->ENDPTSETUPSTAT; - dcd_event_setup_received(rhport, (uint8_t*) &_dcd_data.qhd[0].setup_request, true); + dcd_event_setup_received(rhport, (uint8_t*) &_dcd_data.qhd[0][0].setup_request, true); + } + + // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set + if (int_status & INTR_ERROR) + { + TU_LOG_HEX(1, int_status); + TU_LOG_HEX(1, edpt_complete); } if ( edpt_complete ) { - for(uint8_t ep_idx = 0; ep_idx < QHD_MAX; ep_idx++) + for(uint8_t ep_num = 0; ep_num < DCD_ATTR_ENDPOINT_MAX; ep_num++) { - if ( tu_bit_test(edpt_complete, ep_idx2bit(ep_idx)) ) - { - // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set - dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_idx]; - - uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED : - ( p_qtd->xact_err ||p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS; - - uint8_t const ep_addr = (ep_idx/2) | ( (ep_idx & 0x01) ? TUSB_DIR_IN_MASK : 0 ); - dcd_event_xfer_complete(rhport, ep_addr, p_qtd->expected_bytes - p_qtd->total_bytes, result, true); // only number of bytes in the IOC qtd - } + if ( tu_bit_test(edpt_complete, ep_num) ) process_edpt_complete_isr(rhport, ep_num, TUSB_DIR_OUT); + if ( tu_bit_test(edpt_complete, ep_num+16) ) process_edpt_complete_isr(rhport, ep_num, TUSB_DIR_IN); } } } @@ -509,9 +511,6 @@ void dcd_int_handler(uint8_t rhport) { dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); } - - if (int_status & INTR_NAK) {} - if (int_status & INTR_ERROR) TU_ASSERT(false, ); } #endif -- cgit v1.3.1 From 283783c082d2253984066cb475714217c63454d6 Mon Sep 17 00:00:00 2001 From: Mengsk Date: Thu, 9 Sep 2021 16:45:18 +0200 Subject: dcd_edpt_xfer_fifo: use qtd_init if restriction not met. --- src/portable/nxp/transdimension/dcd_transdimension.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index a4d6c5d48..0a18e711e 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -494,7 +494,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 tu_fifo_get_write_info(ff, &fifo_info); } - if(total_bytes <= fifo_info.len_lin) + if (total_bytes <= fifo_info.len_lin) { // Limit transfer length to total_bytes fifo_info.len_wrap = 0; @@ -508,12 +508,20 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 // address to 32-byte boundaries. // void* cast to suppress cast-align warning, buffer must be CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_lin, 4), fifo_info.len_lin + 31); - if (fifo_info.len_wrap > 0) + + //------------- Prepare qtd -------------// + + // In case of : wrapped part is present & buffer is aligned to 4k & buffer size is multiple of 4k + if (total_bytes > fifo_info.len_lin && (uint32_t)fifo_info.ptr_wrap == tu_align4k((uint32_t)fifo_info.ptr_wrap) && tu_fifo_depth(ff) == tu_align4k(tu_fifo_depth(ff))) { - CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), fifo_info.len_wrap + 31); + CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), fifo_info.len_wrap + 31); + qtd_init_fifo(p_qtd, &fifo_info, total_bytes); } - //------------- Prepare qtd -------------// - qtd_init_fifo(p_qtd, &fifo_info, total_bytes); + else + { + qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes); + } + p_qtd->int_on_complete = true; p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd p_qhd->ff = ff; -- cgit v1.3.1 From 580893b3fe802d0aaeefa6c851dda828289c806c Mon Sep 17 00:00:00 2001 From: MasterPhi Date: Fri, 10 Sep 2021 11:17:33 +0200 Subject: Shorter expr. --- src/portable/nxp/transdimension/dcd_transdimension.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index 0a18e711e..d669791dc 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -512,7 +512,7 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 //------------- Prepare qtd -------------// // In case of : wrapped part is present & buffer is aligned to 4k & buffer size is multiple of 4k - if (total_bytes > fifo_info.len_lin && (uint32_t)fifo_info.ptr_wrap == tu_align4k((uint32_t)fifo_info.ptr_wrap) && tu_fifo_depth(ff) == tu_align4k(tu_fifo_depth(ff))) + if (total_bytes > fifo_info.len_lin && !tu_offset4k((uint32_t)fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff))) { CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), fifo_info.len_wrap + 31); qtd_init_fifo(p_qtd, &fifo_info, total_bytes); -- cgit v1.3.1 From 8886de0d8a14daa70d1fcf4101e3fdeda12a1b26 Mon Sep 17 00:00:00 2001 From: MasterPhi Date: Fri, 10 Sep 2021 13:05:15 +0200 Subject: Fix remote_wakeup --- src/portable/nuvoton/nuc121/dcd_nuc121.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 7edafe5d3..d101550b6 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -252,10 +252,23 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr) // do it at dcd_edpt0_status_complete() } +static void remote_wakeup_delay(void) +{ + // try to delay for 1 ms + uint32_t count = SystemCoreClock / 1000; + while(count--) __NOP(); +} + void dcd_remote_wakeup(uint8_t rhport) { (void) rhport; - USBD->ATTR = USBD_ATTR_RWAKEUP_Msk; + // Enable PHY before sending Resume('K') state + USBD->ATTR |= USBD_ATTR_PHYEN_Msk; + USBD->ATTR |= USBD_ATTR_RWAKEUP_Msk; + + // Per specs: remote wakeup signal bit must be clear within 1-15ms + remote_wakeup_delay(); + USBD->ATTR &=~USBD_ATTR_RWAKEUP_Msk; } bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) @@ -374,7 +387,8 @@ void dcd_int_handler(uint8_t rhport) { (void) rhport; - uint32_t status = USBD->INTSTS; + // Mask non-enabled irqs, ex. SOF + uint32_t status = USBD->INTSTS & (enabled_irqs | 0xffffff00); #ifdef SUPPORT_LPM uint32_t state = USBD->ATTR & 0x300f; #else -- cgit v1.3.1 From 22571ec98ef89a76239b27c86cbdac3db3c42f09 Mon Sep 17 00:00:00 2001 From: MasterPhi Date: Fri, 10 Sep 2021 16:04:47 +0200 Subject: reset PID to DATA0 on clear_stall. --- src/portable/nuvoton/nuc121/dcd_nuc121.c | 1 + 1 file changed, 1 insertion(+) (limited to 'src') diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index d101550b6..5dfc77bb7 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -381,6 +381,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) (void) rhport; USBD_EP_T *ep = ep_entry(ep_addr, false); ep->CFG |= USBD_CFG_CSTALL_Msk; + ep->CFG &=~USBD_CFG_DSQSYNC_Msk; } void dcd_int_handler(uint8_t rhport) -- cgit v1.3.1 From 1f7ade2b751d899a73e58c2b7f0d17a00dbf6899 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 11 Sep 2021 19:27:37 +0700 Subject: nxp tdi: fix error td prevent further transfer --- .../nxp/transdimension/dcd_transdimension.c | 54 +++++++++++++--------- 1 file changed, 31 insertions(+), 23 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index 35f824112..ee1a50db3 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -91,12 +91,15 @@ typedef struct uint32_t : 3 ; uint32_t int_on_complete : 1 ; volatile uint32_t total_bytes : 15 ; - uint32_t : 0 ; + uint32_t : 1 ; // Word 2-6: Buffer Page Pointer List, Each element in the list is a 4K page aligned, physical memory address. The lower 12 bits in each pointer are reserved (except for the first one) as each memory pointer must reference the start of a 4K page uint32_t buffer[5]; ///< buffer1 has frame_n for TODO Isochronous - //------------- DCD Area -------------// + //--------------------------------------------------------------------+ + // TD is 32 bytes aligned but occupies only 28 bytes + // Therefore there are 4 bytes padding that we can use. + //--------------------------------------------------------------------+ uint16_t expected_bytes; uint8_t reserved[2]; } dcd_qtd_t; @@ -109,11 +112,10 @@ typedef struct // Word 0: Capabilities and Characteristics uint32_t : 15 ; ///< Number of packets executed per transaction descriptor 00 - Execute N transactions as demonstrated by the USB variable length protocol where N is computed using Max_packet_length and the Total_bytes field in the dTD. 01 - Execute one transaction 10 - Execute two transactions 11 - Execute three transactions Remark: Non-isochronous endpoints must set MULT = 00. Remark: Isochronous endpoints must set MULT = 01, 10, or 11 as needed. uint32_t int_on_setup : 1 ; ///< Interrupt on setup This bit is used on control type endpoints to indicate if USBINT is set in response to a setup being received. - uint32_t max_package_size : 11 ; ///< This directly corresponds to the maximum packet size of the associated endpoint (wMaxPacketSize) + uint32_t max_packet_size : 11 ; ///< Endpoint's wMaxPacketSize uint32_t : 2 ; uint32_t zero_length_termination : 1 ; ///< This bit is used for non-isochronous endpoints to indicate when a zero-length packet is received to terminate transfers in case the total transfer length is “multiple”. 0 - Enable zero-length packet to terminate transfers equal to a multiple of Max_packet_length (default). 1 - Disable zero-length packet on transfers that are equal in length to a multiple Max_packet_length. uint32_t iso_mult : 2 ; ///< - uint32_t : 0 ; // Word 1: Current qTD Pointer volatile uint32_t qtd_addr; @@ -125,8 +127,8 @@ typedef struct volatile tusb_control_request_t setup_request; //--------------------------------------------------------------------+ - /// Due to the fact QHD is 64 bytes aligned but occupies only 48 bytes - /// thus there are 16 bytes padding free that we can make use of. + // QHD is 64 bytes aligned but occupies only 48 bytes + // Therefore there are 16 bytes padding that we can use. //--------------------------------------------------------------------+ uint8_t reserved[16]; } dcd_qhd_t; @@ -214,7 +216,7 @@ static void bus_reset(uint8_t rhport) //------------- Set up Control Endpoints (0 OUT, 1 IN) -------------// _dcd_data.qhd[0][0].zero_length_termination = _dcd_data.qhd[0][1].zero_length_termination = 1; - _dcd_data.qhd[0][0].max_package_size = _dcd_data.qhd[0][1].max_package_size = CFG_TUD_ENDPOINT0_SIZE; + _dcd_data.qhd[0][0].max_packet_size = _dcd_data.qhd[0][1].max_packet_size = CFG_TUD_ENDPOINT0_SIZE; _dcd_data.qhd[0][0].qtd_overlay.next = _dcd_data.qhd[0][1].qtd_overlay.next = QTD_NEXT_INVALID; _dcd_data.qhd[0][0].int_on_setup = 1; // OUT only @@ -348,7 +350,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) tu_memclr(p_qhd, sizeof(dcd_qhd_t)); p_qhd->zero_length_termination = 1; - p_qhd->max_package_size = p_endpoint_desc->wMaxPacketSize.size; + p_qhd->max_packet_size = p_endpoint_desc->wMaxPacketSize.size; p_qhd->qtd_overlay.next = QTD_NEXT_INVALID; CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); @@ -390,7 +392,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t //------------- Prepare qtd -------------// qtd_init(p_qtd, buffer, total_bytes); p_qtd->int_on_complete = true; - p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd + + p_qhd->qtd_overlay.halted = false; // clear any previous error + p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // activate by linking qtd to qhd CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); @@ -404,15 +408,22 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t // ISR //--------------------------------------------------------------------+ -static void process_edpt_complete_isr(uint8_t rhport, uint8_t ep_num, uint8_t dir) +static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir) { - dcd_qtd_t * p_qtd = &_dcd_data.qtd[ep_num][dir]; + dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir]; uint8_t result = p_qtd->halted ? XFER_RESULT_STALLED : ( p_qtd->xact_err || p_qtd->buffer_err ) ? XFER_RESULT_FAILED : XFER_RESULT_SUCCESS; + if ( result != XFER_RESULT_SUCCESS ) + { + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + // flush to abort error buffer + dcd_reg->ENDPTFLUSH = TU_BIT(epnum + (dir ? 16 : 0)); + } + // only number of bytes in the IOC qtd - dcd_event_xfer_complete(rhport, tu_edpt_addr(ep_num, dir), p_qtd->expected_bytes - p_qtd->total_bytes, result, true); + dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), p_qtd->expected_bytes - p_qtd->total_bytes, result, true); } void dcd_int_handler(uint8_t rhport) @@ -473,11 +484,11 @@ void dcd_int_handler(uint8_t rhport) } } - // Make sure we read the latest version of _dcd_data. - CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); - if (int_status & INTR_USB) { + // Make sure we read the latest version of _dcd_data. + CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); + uint32_t const edpt_complete = dcd_reg->ENDPTCOMPLETE; dcd_reg->ENDPTCOMPLETE = edpt_complete; // acknowledge @@ -491,18 +502,15 @@ void dcd_int_handler(uint8_t rhport) } // 23.10.12.3 Failed QTD also get ENDPTCOMPLETE set - if (int_status & INTR_ERROR) - { - TU_LOG_HEX(1, int_status); - TU_LOG_HEX(1, edpt_complete); - } + // nothing to do, we will submit xfer as error to usbd + // if (int_status & INTR_ERROR) { } if ( edpt_complete ) { - for(uint8_t ep_num = 0; ep_num < DCD_ATTR_ENDPOINT_MAX; ep_num++) + for(uint8_t epnum = 0; epnum < DCD_ATTR_ENDPOINT_MAX; epnum++) { - if ( tu_bit_test(edpt_complete, ep_num) ) process_edpt_complete_isr(rhport, ep_num, TUSB_DIR_OUT); - if ( tu_bit_test(edpt_complete, ep_num+16) ) process_edpt_complete_isr(rhport, ep_num, TUSB_DIR_IN); + if ( tu_bit_test(edpt_complete, epnum) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_OUT); + if ( tu_bit_test(edpt_complete, epnum+16) ) process_edpt_complete_isr(rhport, epnum, TUSB_DIR_IN); } } } -- cgit v1.3.1 From dd60ce784c635addf01ae3039d3be55a74f3d506 Mon Sep 17 00:00:00 2001 From: hathach Date: Sat, 11 Sep 2021 21:29:04 +0700 Subject: nxp tdi: implement dcd edpt close all --- .../nxp/transdimension/dcd_transdimension.c | 23 +++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index ee1a50db3..07009ff50 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -57,11 +57,15 @@ // ENDPTCTRL enum { ENDPTCTRL_STALL = TU_BIT(0), - ENDPTCTRL_TOGGLE_INHIBIT = TU_BIT(5), ///< used for test only + ENDPTCTRL_TOGGLE_INHIBIT = TU_BIT(5), // used for test only ENDPTCTRL_TOGGLE_RESET = TU_BIT(6), ENDPTCTRL_ENABLE = TU_BIT(7) }; +enum { + ENDPTCTRL_TYPE_POS = 2, // Endpoint type is 2-bit field +}; + // USBSTS, USBINTR enum { INTR_USB = TU_BIT(0), @@ -193,9 +197,9 @@ static void bus_reset(uint8_t rhport) // endpoint type of the unused direction must be changed from the control type to any other // type (e.g. bulk). Leaving an un-configured endpoint control will cause undefined behavior // for the data PID tracking on the active endpoint. - for( int i=1; i < _dcd_controller[rhport].ep_count; i++) + for( uint8_t i=1; i < _dcd_controller[rhport].ep_count; i++) { - dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << 2) | (TUSB_XFER_BULK << 18); + dcd_reg->ENDPTCTRL[i] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS)); } //------------- Clear All Registers -------------// @@ -364,8 +368,17 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const * p_endpoint_desc) void dcd_edpt_close_all (uint8_t rhport) { - (void) rhport; - // TODO implement dcd_edpt_close_all() + dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; + + // Disable all non-control endpoints + for( uint8_t epnum=1; epnum < _dcd_controller[rhport].ep_count; epnum++) + { + _dcd_data.qhd[epnum][TUSB_DIR_OUT].qtd_overlay.halted = 1; + _dcd_data.qhd[epnum][TUSB_DIR_IN ].qtd_overlay.halted = 1; + + dcd_reg->ENDPTFLUSH = TU_BIT(epnum) | TU_BIT(epnum+16); + dcd_reg->ENDPTCTRL[epnum] = (TUSB_XFER_BULK << ENDPTCTRL_TYPE_POS) | (TUSB_XFER_BULK << (16+ENDPTCTRL_TYPE_POS)); + } } bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) -- cgit v1.3.1 From 9bed4e2e21dda8c6aac89852492bd178916d6be0 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 13 Sep 2021 00:45:15 +0700 Subject: refactor nxp TDI dcd_edpt_xfer_fifo --- .../nxp/transdimension/dcd_transdimension.c | 161 +++++++++------------ 1 file changed, 70 insertions(+), 91 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index 294f88c56..a61f503f6 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -298,51 +298,30 @@ void dcd_disconnect(uint8_t rhport) static void qtd_init(dcd_qtd_t* p_qtd, void * data_ptr, uint16_t total_bytes) { + // Force the CPU to flush the buffer. We increase the size by 31 because the call aligns the + // address to 32-byte boundaries. Buffer must be word aligned + CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) data_ptr, 4), total_bytes + 31); + tu_memclr(p_qtd, sizeof(dcd_qtd_t)); - p_qtd->next = QTD_NEXT_INVALID; - p_qtd->active = 1; - p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; + p_qtd->next = QTD_NEXT_INVALID; + p_qtd->active = 1; + p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; + p_qtd->int_on_complete = true; if (data_ptr != NULL) { - p_qtd->buffer[0] = (uint32_t) data_ptr; + p_qtd->buffer[0] = (uint32_t) data_ptr; + + uint32_t const bufend = p_qtd->buffer[0] + total_bytes; for(uint8_t i=1; i<5; i++) { - p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096; - } - } -} - -static void qtd_init_fifo(dcd_qtd_t* p_qtd, tu_fifo_buffer_info_t *info, uint16_t total_bytes) -{ - tu_memclr(p_qtd, sizeof(dcd_qtd_t)); + uint32_t const next_page = tu_align4k( p_qtd->buffer[i-1] ) + 4096; + if ( bufend <= next_page ) break; - p_qtd->next = QTD_NEXT_INVALID; - p_qtd->active = 1; - p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; + p_qtd->buffer[i] = next_page; - // Fifo length has been trimmed to total_bytes - int16_t len_lin = info->len_lin; - - if (len_lin != 0) - { - p_qtd->buffer[0] = (uint32_t) info->ptr_lin; - - len_lin -= 4096 - ((uint32_t) info->ptr_lin - tu_align4k((uint32_t) info->ptr_lin)); - - // Set linear part - uint8_t i = 1; - for(; i<5; i++) - { - if (len_lin <= 0) break; - p_qtd->buffer[i] |= tu_align4k( p_qtd->buffer[i-1] ) + 4096; - len_lin -= 4096; - } - // Set wrapped part - for(uint8_t page = 0; i<5; i++, page++) - { - p_qtd->buffer[i] |= (uint32_t) info->ptr_wrap + 4096 * page; + // TODO page[1] FRAME_N for ISO transfer } } } @@ -445,11 +424,17 @@ void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) dcd_reg->ENDPTCTRL[epnum] &=~(ENDPTCTRL_ENABLE << (dir ? 16 : 0)); } -bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +static void qhd_start_xfer(uint8_t rhport, uint8_t epnum, uint8_t dir) { dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); + dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir]; + dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir]; + + p_qhd->qtd_overlay.halted = false; // clear any previous error + p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd + + // flush cache + CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); if ( epnum == 0 ) { @@ -458,26 +443,24 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {} } - dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir]; - dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir]; + // start transfer + dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0)); +} - // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the - // address to 32-byte boundaries. - // void* cast to suppress cast-align warning, buffer must be - CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) buffer, 4), total_bytes + 31); +bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t total_bytes) +{ + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); - //------------- Prepare qtd -------------// + dcd_qhd_t* p_qhd = &_dcd_data.qhd[epnum][dir]; + dcd_qtd_t* p_qtd = &_dcd_data.qtd[epnum][dir]; + + // Prepare qtd qtd_init(p_qtd, buffer, total_bytes); - p_qtd->int_on_complete = true; + // Start qhd transfer p_qhd->ff = NULL; - p_qhd->qtd_overlay.halted = false; // clear any previous error - p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // activate by linking qtd to qhd - - CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); - - // start transfer - dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0)); + qhd_start_xfer(rhport, epnum, dir); return true; } @@ -485,17 +468,9 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t t // fifo has to be aligned to 4k boundary bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { - dcd_registers_t* dcd_reg = _dcd_controller[rhport].regs; uint8_t const epnum = tu_edpt_number(ep_addr); uint8_t const dir = tu_edpt_dir(ep_addr); - if ( epnum == 0 ) - { - // follows UM 24.10.8.1.1 Setup packet handling using setup lockout mechanism - // wait until ENDPTSETUPSTAT before priming data/status in response TODO add time out - while(dcd_reg->ENDPTSETUPSTAT & TU_BIT(0)) {} - } - dcd_qhd_t * p_qhd = &_dcd_data.qhd[epnum][dir]; dcd_qtd_t * p_qtd = &_dcd_data.qtd[epnum][dir]; @@ -509,42 +484,45 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 tu_fifo_get_write_info(ff, &fifo_info); } - if (total_bytes <= fifo_info.len_lin) - { - // Limit transfer length to total_bytes - fifo_info.len_wrap = 0; - fifo_info.len_lin = total_bytes; - } else - { - // Class driver need to ensure at least total_bytes elements in fifo - fifo_info.len_wrap = total_bytes - fifo_info.len_lin; - } - // Force the CPU to flush the buffer. We increase the size by 32 because the call aligns the - // address to 32-byte boundaries. - // void* cast to suppress cast-align warning, buffer must be - CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_lin, 4), fifo_info.len_lin + 31); - - //------------- Prepare qtd -------------// - - // In case of : wrapped part is present & buffer is aligned to 4k & buffer size is multiple of 4k - if (total_bytes > fifo_info.len_lin && !tu_offset4k((uint32_t)fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff))) + if ( fifo_info.len_lin >= total_bytes ) { - CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), fifo_info.len_wrap + 31); - qtd_init_fifo(p_qtd, &fifo_info, total_bytes); + // Linear length is enough for this transfer + qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes); } else { - qtd_init(p_qtd, fifo_info.ptr_lin, total_bytes); - } + // linear part is not enough - p_qtd->int_on_complete = true; - p_qhd->qtd_overlay.next = (uint32_t) p_qtd; // link qtd to qhd - p_qhd->ff = ff; + // prepare TD up to linear length + qtd_init(p_qtd, fifo_info.ptr_lin, fifo_info.len_lin); - CleanInvalidateDCache_by_Addr((uint32_t*) &_dcd_data, sizeof(dcd_data_t)); + if ( !tu_offset4k((uint32_t) fifo_info.ptr_wrap) && !tu_offset4k(tu_fifo_depth(ff)) ) + { + // If buffer is aligned to 4K & buffer size is multiple of 4K + // We can make use of buffer page array to also combine the linear + wrapped length + p_qtd->total_bytes = p_qtd->expected_bytes = total_bytes; - // start transfer - dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0)); + for(uint8_t i = 1, page = 0; i < 5; i++) + { + // pick up buffer array where linear ends + if (p_qtd->buffer[i] == 0) + { + p_qtd->buffer[i] = (uint32_t) fifo_info.ptr_wrap + 4096 * page; + page++; + } + } + + CleanInvalidateDCache_by_Addr((uint32_t*) tu_align((uint32_t) fifo_info.ptr_wrap, 4), total_bytes - fifo_info.len_wrap + 31); + } + else + { + // TODO we need to carry the wrapped length after the linear part complete + } + } + + // Start qhd transfer + p_qhd->ff = ff; + qhd_start_xfer(rhport, epnum, dir); return true; } @@ -582,6 +560,7 @@ static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir } // only number of bytes in the IOC qtd + // TODO there is still a case with xfer_fifo with additional wrapped buffer to fullfil the requested length dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true); } -- cgit v1.3.1 From d5f2c34eaa3e840b32817829031b95c6b7780314 Mon Sep 17 00:00:00 2001 From: szymonh <12231135+szymonh@users.noreply.github.com> Date: Sun, 12 Sep 2021 20:09:58 +0200 Subject: Prevent buffer overflow in bth_device.c --- src/class/bth/bth_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index 1d27ae7c5..09fab953e 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -214,7 +214,7 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c } else return false; - return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, request->wLength); + return tud_control_xfer(rhport, request, &_btd_itf.hci_cmd, sizeof(_btd_itf.hci_cmd)); } else if ( stage == CONTROL_STAGE_DATA ) { -- cgit v1.3.1 From ce5db06ba03f356b2049edc3b36aea398fa50036 Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 13 Sep 2021 12:05:49 +0700 Subject: clear PID along with clear stall --- src/portable/nuvoton/nuc121/dcd_nuc121.c | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/portable/nuvoton/nuc121/dcd_nuc121.c b/src/portable/nuvoton/nuc121/dcd_nuc121.c index 5dfc77bb7..dbc5cd18a 100644 --- a/src/portable/nuvoton/nuc121/dcd_nuc121.c +++ b/src/portable/nuvoton/nuc121/dcd_nuc121.c @@ -200,11 +200,10 @@ static void bus_reset(void) } /* centralized location for USBD interrupt enable bit mask */ -#if USE_SOF -static const uint32_t enabled_irqs = USBD_INTSTS_VBDETIF_Msk | USBD_INTSTS_BUSIF_Msk | USBD_INTSTS_SETUP_Msk | USBD_INTSTS_USBIF_Msk | USBD_INTSTS_SOFIF_Msk; -#else -static const uint32_t enabled_irqs = USBD_INTSTS_VBDETIF_Msk | USBD_INTSTS_BUSIF_Msk | USBD_INTSTS_SETUP_Msk | USBD_INTSTS_USBIF_Msk; -#endif +enum { + ENABLED_IRQS = USBD_INTSTS_VBDETIF_Msk | USBD_INTSTS_BUSIF_Msk | USBD_INTSTS_SETUP_Msk | + USBD_INTSTS_USBIF_Msk | (USE_SOF ? USBD_INTSTS_SOFIF_Msk : 0) +}; /* NUC121/NUC125/NUC126 TinyUSB API driver implementation @@ -226,8 +225,8 @@ void dcd_init(uint8_t rhport) usb_attach(); - USBD->INTSTS = enabled_irqs; - USBD->INTEN = enabled_irqs; + USBD->INTSTS = ENABLED_IRQS; + USBD->INTEN = ENABLED_IRQS; } void dcd_int_enable(uint8_t rhport) @@ -380,8 +379,7 @@ void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) { (void) rhport; USBD_EP_T *ep = ep_entry(ep_addr, false); - ep->CFG |= USBD_CFG_CSTALL_Msk; - ep->CFG &=~USBD_CFG_DSQSYNC_Msk; + ep->CFG = (ep->CFG & ~USBD_CFG_DSQSYNC_Msk) | USBD_CFG_CSTALL_Msk; } void dcd_int_handler(uint8_t rhport) @@ -389,7 +387,8 @@ void dcd_int_handler(uint8_t rhport) (void) rhport; // Mask non-enabled irqs, ex. SOF - uint32_t status = USBD->INTSTS & (enabled_irqs | 0xffffff00); + uint32_t status = USBD->INTSTS & (ENABLED_IRQS | 0xffffff00); + #ifdef SUPPORT_LPM uint32_t state = USBD->ATTR & 0x300f; #else @@ -520,7 +519,7 @@ void dcd_int_handler(uint8_t rhport) } /* acknowledge all interrupts */ - USBD->INTSTS = status & enabled_irqs; + USBD->INTSTS = status & ENABLED_IRQS; } // Invoked when a control transfer's status stage is complete. -- cgit v1.3.1 From 43e6555fd03906c4524f2f212199cdf32cb5fb0f Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 13 Sep 2021 13:09:38 +0700 Subject: clean up --- src/portable/nxp/transdimension/dcd_transdimension.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/portable/nxp/transdimension/dcd_transdimension.c b/src/portable/nxp/transdimension/dcd_transdimension.c index a61f503f6..a7c4545c2 100644 --- a/src/portable/nxp/transdimension/dcd_transdimension.c +++ b/src/portable/nxp/transdimension/dcd_transdimension.c @@ -516,7 +516,8 @@ bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16 } else { - // TODO we need to carry the wrapped length after the linear part complete + // TODO we may need to carry the wrapped length after the linear part complete + // for now only transfer up to linear part } } @@ -560,7 +561,6 @@ static void process_edpt_complete_isr(uint8_t rhport, uint8_t epnum, uint8_t dir } // only number of bytes in the IOC qtd - // TODO there is still a case with xfer_fifo with additional wrapped buffer to fullfil the requested length dcd_event_xfer_complete(rhport, tu_edpt_addr(epnum, dir), xferred_bytes, result, true); } -- cgit v1.3.1 From 50e3c0054f8d26340863667a50aae5a798f6aefc Mon Sep 17 00:00:00 2001 From: szymonh <12231135+szymonh@users.noreply.github.com> Date: Mon, 13 Sep 2021 10:23:03 +0200 Subject: Add size check to tud_bt_hci_cmd_cb call in bth_device.c --- src/class/bth/bth_device.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/class/bth/bth_device.c b/src/class/bth/bth_device.c index 09fab953e..b73f829cc 100755 --- a/src/class/bth/bth_device.c +++ b/src/class/bth/bth_device.c @@ -221,7 +221,7 @@ bool btd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t c // Handle class request only TU_VERIFY(request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS); - if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, request->wLength); + if (tud_bt_hci_cmd_cb) tud_bt_hci_cmd_cb(&_btd_itf.hci_cmd, tu_min16(request->wLength, sizeof(_btd_itf.hci_cmd))); } return true; -- cgit v1.3.1 From e64bfb9ff53647e21ba755c4ae4aa6bb3f2677ac Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 13 Sep 2021 16:16:37 +0700 Subject: implement dcd_edpt_close_all(), pass chapter9 test suite (without remote wakeup) --- src/portable/espressif/esp32sx/dcd_esp32sx.c | 79 ++++++++++------------------ 1 file changed, 28 insertions(+), 51 deletions(-) (limited to 'src') diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c index a5ada0da8..541f7d586 100644 --- a/src/portable/espressif/esp32sx/dcd_esp32sx.c +++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c @@ -92,11 +92,12 @@ static void bus_reset(void) USB0.out_ep_reg[ep_num].doepctl |= USB_DO_SNAK0_M; // DOEPCTL0_SNAK } - USB0.dcfg &= ~USB_DEVADDR_M; // reset address + // clear device address + USB0.dcfg &= ~USB_DEVADDR_M; - USB0.daintmsk |= USB_OUTEPMSK0_M | USB_INEPMSK0_M; - USB0.doepmsk |= USB_SETUPMSK_M | USB_XFERCOMPLMSK; - USB0.diepmsk |= USB_TIMEOUTMSK_M | USB_DI_XFERCOMPLMSK_M /*| USB_INTKNTXFEMPMSK_M*/; + USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M; + USB0.doepmsk = USB_SETUPMSK_M | USB_XFERCOMPLMSK; + USB0.diepmsk = USB_TIMEOUTMSK_M | USB_DI_XFERCOMPLMSK_M /*| USB_INTKNTXFEMPMSK_M*/; // "USB Data FIFOs" section in reference manual // Peripheral FIFO architecture @@ -260,9 +261,10 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) xfer->max_size = desc_edpt->wMaxPacketSize.size; if (dir == TUSB_DIR_OUT) { - out_ep[epnum].doepctl |= USB_USBACTEP0_M | - desc_edpt->bmAttributes.xfer << USB_EPTYPE0_S | - desc_edpt->wMaxPacketSize.size << USB_MPS0_S; + out_ep[epnum].doepctl |= USB_USBACTEP1_M | + desc_edpt->bmAttributes.xfer << USB_EPTYPE1_S | + (desc_edpt->bmAttributes.xfer != TUSB_XFER_ISOCHRONOUS ? USB_DO_SETD0PID1_M : 0) | + desc_edpt->wMaxPacketSize.size << USB_MPS1_S; USB0.daintmsk |= (1 << (16 + epnum)); } else { // "USB Data FIFOs" section in reference manual @@ -315,7 +317,25 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) void dcd_edpt_close_all(uint8_t rhport) { (void) rhport; - // TODO implement dcd_edpt_close_all() + + usb_out_endpoint_t *out_ep = &(USB0.out_ep_reg[0]); + usb_in_endpoint_t *in_ep = &(USB0.in_ep_reg[0]); + + // Disable non-control interrupt + USB0.daintmsk = USB_OUTEPMSK0_M | USB_INEPMSK0_M; + + for(uint8_t n = 1; n < EP_MAX; n++) + { + // disable OUT endpoint + out_ep[n].doepctl = 0; + xfer_status[n][TUSB_DIR_OUT].max_size = 0; + + // disable IN endpoint + in_ep[n].diepctl = 0; + xfer_status[n][TUSB_DIR_IN].max_size = 0; + } + + _allocated_fifos = 1; } bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) @@ -367,49 +387,6 @@ bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t to bool dcd_edpt_xfer_fifo (uint8_t rhport, uint8_t ep_addr, tu_fifo_t * ff, uint16_t total_bytes) { (void)rhport; - - // USB buffers always work in bytes so to avoid unnecessary divisions we demand item_size = 1 - TU_ASSERT(ff->item_size == 1); - - uint8_t const epnum = tu_edpt_number(ep_addr); - uint8_t const dir = tu_edpt_dir(ep_addr); - - xfer_ctl_t * xfer = XFER_CTL_BASE(epnum, dir); - xfer->buffer = NULL; - xfer->ff = ff; - xfer->total_len = total_bytes; - xfer->queued_len = 0; - xfer->short_packet = false; - - uint16_t num_packets = (total_bytes / xfer->max_size); - uint8_t short_packet_size = total_bytes % xfer->max_size; - - // Zero-size packet is special case. - if (short_packet_size > 0 || (total_bytes == 0)) { - num_packets++; - } - - ESP_LOGV(TAG, "Transfer <-> EP%i, %s, pkgs: %i, bytes: %i", - epnum, ((dir == TUSB_DIR_IN) ? "USB0.HOST (in)" : "HOST->DEV (out)"), - num_packets, total_bytes); - - // IN and OUT endpoint xfers are interrupt-driven, we just schedule them - // here. - if (dir == TUSB_DIR_IN) { - // A full IN transfer (multiple packets, possibly) triggers XFRC. - USB0.in_ep_reg[epnum].dieptsiz = (num_packets << USB_D_PKTCNT0_S) | total_bytes; - USB0.in_ep_reg[epnum].diepctl |= USB_D_EPENA1_M | USB_D_CNAK1_M; // Enable | CNAK - - // Enable fifo empty interrupt only if there are something to put in the fifo. - if(total_bytes != 0) { - USB0.dtknqr4_fifoemptymsk |= (1 << epnum); - } - } else { - // Each complete packet for OUT xfers triggers XFRC. - USB0.out_ep_reg[epnum].doeptsiz |= USB_PKTCNT0_M | ((xfer->max_size & USB_XFERSIZE0_V) << USB_XFERSIZE0_S); - USB0.out_ep_reg[epnum].doepctl |= USB_EPENA0_M | USB_CNAK0_M; - } - return true; } #endif -- cgit v1.3.1 From cdc63459ebf5bd979d1e98253abd3d75693dcdaf Mon Sep 17 00:00:00 2001 From: hathach Date: Mon, 13 Sep 2021 16:49:38 +0700 Subject: esp32sx implement dcd_remote_wakeup(), fully compliance to chapter9 test suite --- .../hid_composite_freertos/src/tusb_config.h | 5 ++-- src/common/tusb_common.h | 2 +- src/portable/espressif/esp32sx/dcd_esp32sx.c | 33 +++++++++++++--------- 3 files changed, 23 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/examples/device/hid_composite_freertos/src/tusb_config.h b/examples/device/hid_composite_freertos/src/tusb_config.h index 4b0458ef0..4fbccc294 100644 --- a/examples/device/hid_composite_freertos/src/tusb_config.h +++ b/examples/device/hid_composite_freertos/src/tusb_config.h @@ -67,8 +67,9 @@ // This examples use FreeRTOS #define CFG_TUSB_OS OPT_OS_FREERTOS -// CFG_TUSB_DEBUG is defined by compiler in DEBUG build -// #define CFG_TUSB_DEBUG 0 +#ifndef CFG_TUSB_DEBUG +#define CFG_TUSB_DEBUG 0 +#endif /* USB DMA on some MCUs can only access a specific SRAM region with restriction on alignment. * Tinyusb use follows macros to declare transferring memory so that they can be put diff --git a/src/common/tusb_common.h b/src/common/tusb_common.h index d0cc41285..1899b35cc 100644 --- a/src/common/tusb_common.h +++ b/src/common/tusb_common.h @@ -380,7 +380,7 @@ static inline const char* tu_lookup_find(tu_lookup_table_t const* p_table, uint3 } // not found return the key value in hex - sprintf(not_found, "0x%08lX", key); + sprintf(not_found, "0x%08lX", (unsigned long) key); return not_found; } diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c index 541f7d586..cfbbab233 100644 --- a/src/portable/espressif/esp32sx/dcd_esp32sx.c +++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c @@ -42,10 +42,6 @@ #include "device/dcd.h" -// Since TinyUSB doesn't use SOF for now, and this interrupt too often (1ms interval) -// We disable SOF for now until needed later on -#define USE_SOF 0 - // Max number of bi-directional endpoints including EP0 // Note: ESP32S2 specs say there are only up to 5 IN active endpoints include EP0 // We should probably prohibit enabling Endpoint IN > 4 (not done yet) @@ -194,9 +190,6 @@ void dcd_init(uint8_t rhport) USB0.gintsts = ~0U; //clear pending ints USB0.gintmsk = USB_OTGINTMSK_M | USB_MODEMISMSK_M | - #if USE_SOF - USB_SOFMSK_M | - #endif USB_RXFLVIMSK_M | USB_ERLYSUSPMSK_M | USB_USBSUSPMSK_M | @@ -221,8 +214,17 @@ void dcd_remote_wakeup(uint8_t rhport) { (void)rhport; - // TODO must manually clear this bit after 1-15 ms - // USB0.DCTL |= USB_RMTWKUPSIG_M; + // set remote wakeup + USB0.dctl |= USB_RMTWKUPSIG_M; + + // enable SOF to detect bus resume + USB0.gintsts = USB_SOF_M; + USB0.gintmsk |= USB_SOFMSK_M; + + // Per specs: remote wakeup signal bit must be clear within 1-15ms + vTaskDelay(pdMS_TO_TICKS(1)); + + USB0.dctl &= ~USB_RMTWKUPSIG_M; } // connect by enabling internal pull-up resistor on D+/D- @@ -731,8 +733,8 @@ static void _dcd_int_handler(void* arg) (void) arg; uint8_t const rhport = 0; - const uint32_t int_status = USB0.gintsts; - //const uint32_t int_msk = USB0.gintmsk; + const uint32_t int_msk = USB0.gintmsk; + const uint32_t int_status = USB0.gintsts & int_msk; if (int_status & USB_USBRST_M) { // start of reset @@ -785,12 +787,15 @@ static void _dcd_int_handler(void* arg) USB0.gotgint = otg_int; } -#if USE_SOF if (int_status & USB_SOF_M) { USB0.gintsts = USB_SOF_M; - dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); // do nothing actually + + // Disable SOF interrupt since currently only used for remote wakeup detection + USB0.gintmsk &= ~USB_SOFMSK_M; + + dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true); } -#endif + if (int_status & USB_RXFLVI_M) { // RXFLVL bit is read-only -- cgit v1.3.1 From 36391680660f1ec0960003eece7e7605c29574af Mon Sep 17 00:00:00 2001 From: MasterPhi Date: Tue, 14 Sep 2021 11:58:22 +0200 Subject: Fix warning. --- src/device/usbd.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/device/usbd.c b/src/device/usbd.c index 4ab60569b..1184f8e47 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1041,6 +1041,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const break; case TUSB_DESC_DEVICE_QUALIFIER: + { TU_LOG2(" Device Qualifier\r\n"); TU_VERIFY( tud_descriptor_device_qualifier_cb ); @@ -1050,6 +1051,7 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const // first byte of descriptor is its size return tud_control_xfer(rhport, p_request, (void*) desc_qualifier, desc_qualifier[0]); + } break; default: return false; -- cgit v1.3.1 From 0ded1c5bacfba180bb5f6fef2f7cb469adbe19f6 Mon Sep 17 00:00:00 2001 From: MasterPhi Date: Tue, 14 Sep 2021 21:08:12 +0200 Subject: Reset EP flags on close. --- src/device/usbd.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'src') diff --git a/src/device/usbd.c b/src/device/usbd.c index 1184f8e47..3043fc7bc 100644 --- a/src/device/usbd.c +++ b/src/device/usbd.c @@ -1379,7 +1379,13 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) TU_ASSERT(dcd_edpt_close, /**/); TU_LOG2(" CLOSING Endpoint: 0x%02X\r\n", ep_addr); + uint8_t const epnum = tu_edpt_number(ep_addr); + uint8_t const dir = tu_edpt_dir(ep_addr); + dcd_edpt_close(rhport, ep_addr); + _usbd_dev.ep_status[epnum][dir].stalled = false; + _usbd_dev.ep_status[epnum][dir].busy = false; + _usbd_dev.ep_status[epnum][dir].claimed = false; return; } -- cgit v1.3.1