Merge pull request #1089 from hathach/imxrt-compliance
Imxrt compliance
This commit is contained in:
		| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -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; i<p_table->count; i++) | ||||
|   { | ||||
|   | ||||
| @@ -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 | ||||
| { | ||||
|   | ||||
| @@ -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; | ||||
| @@ -1066,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: | ||||
|   | ||||
| @@ -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); | ||||
|  | ||||
|   | ||||
| @@ -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), | ||||
| @@ -91,12 +95,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 +116,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 +131,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; | ||||
| @@ -145,10 +151,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 +163,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 +174,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) | ||||
| @@ -195,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 -------------// | ||||
| @@ -217,11 +219,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_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].int_on_setup = 1; // OUT only | ||||
|   _dcd_data.qhd[0][0].int_on_setup = 1; // OUT only | ||||
| } | ||||
|  | ||||
| void dcd_init(uint8_t rhport) | ||||
| @@ -245,7 +247,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_SUSPEND; | ||||
|  | ||||
|   dcd_reg->USBCMD &= ~0x00FF0000;     // Interrupt Threshold Interval = 0 | ||||
|   dcd_reg->USBCMD |= USBCMD_RUN_STOP; // Connect | ||||
| @@ -272,7 +274,8 @@ 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; | ||||
|   dcd_reg->PORTSC1 |= PORTSC1_FORCE_PORT_RESUME; | ||||
| } | ||||
|  | ||||
| void dcd_connect(uint8_t rhport) | ||||
| @@ -290,11 +293,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) | ||||
| { | ||||
| @@ -324,12 +322,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; | ||||
| @@ -342,19 +343,18 @@ 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; | ||||
|   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)); | ||||
| @@ -368,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) | ||||
| @@ -377,7 +386,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 ) | ||||
|   { | ||||
| @@ -386,8 +394,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. | ||||
| @@ -397,12 +405,14 @@ 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)); | ||||
|  | ||||
|   // start transfer | ||||
|   dcd_reg->ENDPTPRIME = TU_BIT( ep_idx2bit(ep_idx) ) ; | ||||
|   dcd_reg->ENDPTPRIME = TU_BIT(epnum + (dir ? 16 : 0)); | ||||
|  | ||||
|   return true; | ||||
| } | ||||
| @@ -410,9 +420,28 @@ 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 epnum, uint8_t 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(epnum, dir), p_qtd->expected_bytes - p_qtd->total_bytes, result, true); | ||||
| } | ||||
|  | ||||
| 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; | ||||
| @@ -421,18 +450,46 @@ 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. | ||||
|       // Skip suspend event if we are not addressed | ||||
|       if ((dcd_reg->DEVICEADDR >> 25) & 0x0f) | ||||
|       { | ||||
|         dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true); | ||||
| @@ -440,21 +497,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)); | ||||
|  | ||||
|   // 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) | ||||
|   { | ||||
|     // 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 | ||||
|  | ||||
| @@ -462,26 +509,21 @@ 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 | ||||
|     // nothing to do, we will submit xfer as error to usbd | ||||
|     // if (int_status & INTR_ERROR) { } | ||||
|  | ||||
|     if ( edpt_complete ) | ||||
|     { | ||||
|       for(uint8_t ep_idx = 0; ep_idx < QHD_MAX; ep_idx++) | ||||
|       for(uint8_t epnum = 0; epnum < DCD_ATTR_ENDPOINT_MAX; epnum++) | ||||
|       { | ||||
|         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, 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); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -490,9 +532,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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ha Thach
					Ha Thach