summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorHiFiPhile <[email protected]>2024-06-27 20:49:40 +0200
committerHiFiPhile <[email protected]>2024-06-27 20:49:40 +0200
commiteefca229b64bddf07ae862248f4a1071984a7fe1 (patch)
tree57e8686adc49dda0d19a8fc1b34e45548ec399ed /src
parent02ec4866105eca3f95e7392e538caf97ebb902b4 (diff)
parent13dedddd1963e67251f75b3e3ebd654d74d8aa56 (diff)
Merge branch 'master' of https://github.com/hathach/tinyusb into dwc2_dma
Diffstat (limited to 'src')
-rw-r--r--src/class/audio/audio_device.c4
-rw-r--r--src/class/cdc/cdc_device.c2
-rw-r--r--src/class/cdc/cdc_device.h6
-rw-r--r--src/class/hid/hid.h485
-rw-r--r--src/class/hid/hid_device.c361
-rw-r--r--src/class/hid/hid_device.h175
-rw-r--r--src/class/msc/msc_device.c18
-rw-r--r--src/class/msc/msc_device.h3
-rw-r--r--src/class/net/ncm.h116
-rw-r--r--src/class/net/ncm_device.c1105
-rw-r--r--src/class/net/net_device.h26
-rw-r--r--src/class/usbtmc/usbtmc.h25
-rw-r--r--src/class/usbtmc/usbtmc_device.c33
-rw-r--r--src/class/usbtmc/usbtmc_device.h29
-rw-r--r--src/class/vendor/vendor_device.c16
-rw-r--r--src/common/tusb_compiler.h1
-rw-r--r--src/common/tusb_fifo.c31
-rw-r--r--src/common/tusb_fifo.h16
-rw-r--r--src/common/tusb_mcu.h99
-rw-r--r--src/common/tusb_verify.h5
-rw-r--r--src/device/dcd.h33
-rw-r--r--src/device/usbd.c166
-rw-r--r--src/device/usbd.h12
-rw-r--r--src/device/usbd_pvt.h18
-rw-r--r--src/host/usbh.c2
-rw-r--r--src/portable/analog/max3421/hcd_max3421.c84
-rw-r--r--src/portable/chipidea/ci_hs/dcd_ci_hs.c13
-rw-r--r--src/portable/espressif/esp32sx/dcd_esp32sx.c3
-rw-r--r--src/portable/microchip/samd/dcd_samd.c11
-rw-r--r--src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c11
-rw-r--r--src/portable/nordic/nrf5x/dcd_nrf5x.c32
-rw-r--r--src/portable/nxp/khci/dcd_khci.c2
-rw-r--r--src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c11
-rw-r--r--src/portable/renesas/rusb2/dcd_rusb2.c40
-rw-r--r--src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c232
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_ch32.h242
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_common.h (renamed from src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h)272
-rw-r--r--src/portable/st/stm32_fsdev/fsdev_stm32.h323
-rw-r--r--src/portable/sunxi/dcd_sunxi_musb.c14
-rw-r--r--src/portable/synopsys/dwc2/dcd_dwc2.c21
-rw-r--r--src/portable/synopsys/dwc2/dwc2_esp32.h1
-rw-r--r--src/portable/synopsys/dwc2/dwc2_type.h33
-rw-r--r--src/portable/wch/ch32_usbfs_reg.h175
-rw-r--r--src/portable/wch/ch32_usbhs_reg.h82
-rw-r--r--src/portable/wch/dcd_ch32_usbfs.c344
-rw-r--r--src/portable/wch/dcd_ch32_usbhs.c559
-rw-r--r--src/tusb.h2
-rw-r--r--src/tusb_option.h81
48 files changed, 3651 insertions, 1724 deletions
diff --git a/src/class/audio/audio_device.c b/src/class/audio/audio_device.c
index b7af0259a..4a383c3c7 100644
--- a/src/class/audio/audio_device.c
+++ b/src/class/audio/audio_device.c
@@ -1837,7 +1837,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
audio->feedback.frame_shift = desc_ep->bInterval -1;
// Enable SOF interrupt if callback is implemented
- if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, true);
+ if (tud_audio_feedback_interval_isr) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, true);
}
#endif
#endif // CFG_TUD_AUDIO_ENABLE_EP_OUT
@@ -1911,7 +1911,7 @@ static bool audiod_set_interface(uint8_t rhport, tusb_control_request_t const *
break;
}
}
- if (disable) usbd_sof_enable(rhport, false);
+ if (disable) usbd_sof_enable(rhport, SOF_CONSUMER_AUDIO, false);
#endif
#if CFG_TUD_AUDIO_ENABLE_EP_IN && CFG_TUD_AUDIO_EP_IN_FLOW_CONTROL
diff --git a/src/class/cdc/cdc_device.c b/src/class/cdc/cdc_device.c
index 2e0a0c30d..f36725eba 100644
--- a/src/class/cdc/cdc_device.c
+++ b/src/class/cdc/cdc_device.c
@@ -295,7 +295,9 @@ void cdcd_reset(uint8_t rhport)
tu_memclr(p_cdc, ITF_MEM_RESET_SIZE);
tu_fifo_clear(&p_cdc->rx_ff);
+ #if !CFG_TUD_CDC_PERSISTENT_TX_BUFF
tu_fifo_clear(&p_cdc->tx_ff);
+ #endif
tu_fifo_set_overwritable(&p_cdc->tx_ff, true);
}
}
diff --git a/src/class/cdc/cdc_device.h b/src/class/cdc/cdc_device.h
index 20e908451..db709b3bc 100644
--- a/src/class/cdc/cdc_device.h
+++ b/src/class/cdc/cdc_device.h
@@ -41,6 +41,12 @@
#define CFG_TUD_CDC_EP_BUFSIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
#endif
+// By default the TX fifo buffer is cleared on connect / bus reset.
+// Enable this to persist any data in the fifo instead.
+#ifndef CFG_TUD_CDC_PERSISTENT_TX_BUFF
+ #define CFG_TUD_CDC_PERSISTENT_TX_BUFF (0)
+#endif
+
#ifdef __cplusplus
extern "C" {
#endif
diff --git a/src/class/hid/hid.h b/src/class/hid/hid.h
index fcaab7a50..c2b5a8a48 100644
--- a/src/class/hid/hid.h
+++ b/src/class/hid/hid.h
@@ -366,177 +366,224 @@ typedef enum
//--------------------------------------------------------------------+
// HID KEYCODE
//--------------------------------------------------------------------+
-#define HID_KEY_NONE 0x00
-#define HID_KEY_A 0x04
-#define HID_KEY_B 0x05
-#define HID_KEY_C 0x06
-#define HID_KEY_D 0x07
-#define HID_KEY_E 0x08
-#define HID_KEY_F 0x09
-#define HID_KEY_G 0x0A
-#define HID_KEY_H 0x0B
-#define HID_KEY_I 0x0C
-#define HID_KEY_J 0x0D
-#define HID_KEY_K 0x0E
-#define HID_KEY_L 0x0F
-#define HID_KEY_M 0x10
-#define HID_KEY_N 0x11
-#define HID_KEY_O 0x12
-#define HID_KEY_P 0x13
-#define HID_KEY_Q 0x14
-#define HID_KEY_R 0x15
-#define HID_KEY_S 0x16
-#define HID_KEY_T 0x17
-#define HID_KEY_U 0x18
-#define HID_KEY_V 0x19
-#define HID_KEY_W 0x1A
-#define HID_KEY_X 0x1B
-#define HID_KEY_Y 0x1C
-#define HID_KEY_Z 0x1D
-#define HID_KEY_1 0x1E
-#define HID_KEY_2 0x1F
-#define HID_KEY_3 0x20
-#define HID_KEY_4 0x21
-#define HID_KEY_5 0x22
-#define HID_KEY_6 0x23
-#define HID_KEY_7 0x24
-#define HID_KEY_8 0x25
-#define HID_KEY_9 0x26
-#define HID_KEY_0 0x27
-#define HID_KEY_ENTER 0x28
-#define HID_KEY_ESCAPE 0x29
-#define HID_KEY_BACKSPACE 0x2A
-#define HID_KEY_TAB 0x2B
-#define HID_KEY_SPACE 0x2C
-#define HID_KEY_MINUS 0x2D
-#define HID_KEY_EQUAL 0x2E
-#define HID_KEY_BRACKET_LEFT 0x2F
-#define HID_KEY_BRACKET_RIGHT 0x30
-#define HID_KEY_BACKSLASH 0x31
-#define HID_KEY_EUROPE_1 0x32
-#define HID_KEY_SEMICOLON 0x33
-#define HID_KEY_APOSTROPHE 0x34
-#define HID_KEY_GRAVE 0x35
-#define HID_KEY_COMMA 0x36
-#define HID_KEY_PERIOD 0x37
-#define HID_KEY_SLASH 0x38
-#define HID_KEY_CAPS_LOCK 0x39
-#define HID_KEY_F1 0x3A
-#define HID_KEY_F2 0x3B
-#define HID_KEY_F3 0x3C
-#define HID_KEY_F4 0x3D
-#define HID_KEY_F5 0x3E
-#define HID_KEY_F6 0x3F
-#define HID_KEY_F7 0x40
-#define HID_KEY_F8 0x41
-#define HID_KEY_F9 0x42
-#define HID_KEY_F10 0x43
-#define HID_KEY_F11 0x44
-#define HID_KEY_F12 0x45
-#define HID_KEY_PRINT_SCREEN 0x46
-#define HID_KEY_SCROLL_LOCK 0x47
-#define HID_KEY_PAUSE 0x48
-#define HID_KEY_INSERT 0x49
-#define HID_KEY_HOME 0x4A
-#define HID_KEY_PAGE_UP 0x4B
-#define HID_KEY_DELETE 0x4C
-#define HID_KEY_END 0x4D
-#define HID_KEY_PAGE_DOWN 0x4E
-#define HID_KEY_ARROW_RIGHT 0x4F
-#define HID_KEY_ARROW_LEFT 0x50
-#define HID_KEY_ARROW_DOWN 0x51
-#define HID_KEY_ARROW_UP 0x52
-#define HID_KEY_NUM_LOCK 0x53
-#define HID_KEY_KEYPAD_DIVIDE 0x54
-#define HID_KEY_KEYPAD_MULTIPLY 0x55
-#define HID_KEY_KEYPAD_SUBTRACT 0x56
-#define HID_KEY_KEYPAD_ADD 0x57
-#define HID_KEY_KEYPAD_ENTER 0x58
-#define HID_KEY_KEYPAD_1 0x59
-#define HID_KEY_KEYPAD_2 0x5A
-#define HID_KEY_KEYPAD_3 0x5B
-#define HID_KEY_KEYPAD_4 0x5C
-#define HID_KEY_KEYPAD_5 0x5D
-#define HID_KEY_KEYPAD_6 0x5E
-#define HID_KEY_KEYPAD_7 0x5F
-#define HID_KEY_KEYPAD_8 0x60
-#define HID_KEY_KEYPAD_9 0x61
-#define HID_KEY_KEYPAD_0 0x62
-#define HID_KEY_KEYPAD_DECIMAL 0x63
-#define HID_KEY_EUROPE_2 0x64
-#define HID_KEY_APPLICATION 0x65
-#define HID_KEY_POWER 0x66
-#define HID_KEY_KEYPAD_EQUAL 0x67
-#define HID_KEY_F13 0x68
-#define HID_KEY_F14 0x69
-#define HID_KEY_F15 0x6A
-#define HID_KEY_F16 0x6B
-#define HID_KEY_F17 0x6C
-#define HID_KEY_F18 0x6D
-#define HID_KEY_F19 0x6E
-#define HID_KEY_F20 0x6F
-#define HID_KEY_F21 0x70
-#define HID_KEY_F22 0x71
-#define HID_KEY_F23 0x72
-#define HID_KEY_F24 0x73
-#define HID_KEY_EXECUTE 0x74
-#define HID_KEY_HELP 0x75
-#define HID_KEY_MENU 0x76
-#define HID_KEY_SELECT 0x77
-#define HID_KEY_STOP 0x78
-#define HID_KEY_AGAIN 0x79
-#define HID_KEY_UNDO 0x7A
-#define HID_KEY_CUT 0x7B
-#define HID_KEY_COPY 0x7C
-#define HID_KEY_PASTE 0x7D
-#define HID_KEY_FIND 0x7E
-#define HID_KEY_MUTE 0x7F
-#define HID_KEY_VOLUME_UP 0x80
-#define HID_KEY_VOLUME_DOWN 0x81
-#define HID_KEY_LOCKING_CAPS_LOCK 0x82
-#define HID_KEY_LOCKING_NUM_LOCK 0x83
-#define HID_KEY_LOCKING_SCROLL_LOCK 0x84
-#define HID_KEY_KEYPAD_COMMA 0x85
-#define HID_KEY_KEYPAD_EQUAL_SIGN 0x86
-#define HID_KEY_KANJI1 0x87
-#define HID_KEY_KANJI2 0x88
-#define HID_KEY_KANJI3 0x89
-#define HID_KEY_KANJI4 0x8A
-#define HID_KEY_KANJI5 0x8B
-#define HID_KEY_KANJI6 0x8C
-#define HID_KEY_KANJI7 0x8D
-#define HID_KEY_KANJI8 0x8E
-#define HID_KEY_KANJI9 0x8F
-#define HID_KEY_LANG1 0x90
-#define HID_KEY_LANG2 0x91
-#define HID_KEY_LANG3 0x92
-#define HID_KEY_LANG4 0x93
-#define HID_KEY_LANG5 0x94
-#define HID_KEY_LANG6 0x95
-#define HID_KEY_LANG7 0x96
-#define HID_KEY_LANG8 0x97
-#define HID_KEY_LANG9 0x98
-#define HID_KEY_ALTERNATE_ERASE 0x99
-#define HID_KEY_SYSREQ_ATTENTION 0x9A
-#define HID_KEY_CANCEL 0x9B
-#define HID_KEY_CLEAR 0x9C
-#define HID_KEY_PRIOR 0x9D
-#define HID_KEY_RETURN 0x9E
-#define HID_KEY_SEPARATOR 0x9F
-#define HID_KEY_OUT 0xA0
-#define HID_KEY_OPER 0xA1
-#define HID_KEY_CLEAR_AGAIN 0xA2
-#define HID_KEY_CRSEL_PROPS 0xA3
-#define HID_KEY_EXSEL 0xA4
-// RESERVED 0xA5-DF
-#define HID_KEY_CONTROL_LEFT 0xE0
-#define HID_KEY_SHIFT_LEFT 0xE1
-#define HID_KEY_ALT_LEFT 0xE2
-#define HID_KEY_GUI_LEFT 0xE3
-#define HID_KEY_CONTROL_RIGHT 0xE4
-#define HID_KEY_SHIFT_RIGHT 0xE5
-#define HID_KEY_ALT_RIGHT 0xE6
-#define HID_KEY_GUI_RIGHT 0xE7
+#define HID_KEY_NONE 0x00
+#define HID_KEY_A 0x04
+#define HID_KEY_B 0x05
+#define HID_KEY_C 0x06
+#define HID_KEY_D 0x07
+#define HID_KEY_E 0x08
+#define HID_KEY_F 0x09
+#define HID_KEY_G 0x0A
+#define HID_KEY_H 0x0B
+#define HID_KEY_I 0x0C
+#define HID_KEY_J 0x0D
+#define HID_KEY_K 0x0E
+#define HID_KEY_L 0x0F
+#define HID_KEY_M 0x10
+#define HID_KEY_N 0x11
+#define HID_KEY_O 0x12
+#define HID_KEY_P 0x13
+#define HID_KEY_Q 0x14
+#define HID_KEY_R 0x15
+#define HID_KEY_S 0x16
+#define HID_KEY_T 0x17
+#define HID_KEY_U 0x18
+#define HID_KEY_V 0x19
+#define HID_KEY_W 0x1A
+#define HID_KEY_X 0x1B
+#define HID_KEY_Y 0x1C
+#define HID_KEY_Z 0x1D
+#define HID_KEY_1 0x1E
+#define HID_KEY_2 0x1F
+#define HID_KEY_3 0x20
+#define HID_KEY_4 0x21
+#define HID_KEY_5 0x22
+#define HID_KEY_6 0x23
+#define HID_KEY_7 0x24
+#define HID_KEY_8 0x25
+#define HID_KEY_9 0x26
+#define HID_KEY_0 0x27
+#define HID_KEY_ENTER 0x28
+#define HID_KEY_ESCAPE 0x29
+#define HID_KEY_BACKSPACE 0x2A
+#define HID_KEY_TAB 0x2B
+#define HID_KEY_SPACE 0x2C
+#define HID_KEY_MINUS 0x2D
+#define HID_KEY_EQUAL 0x2E
+#define HID_KEY_BRACKET_LEFT 0x2F
+#define HID_KEY_BRACKET_RIGHT 0x30
+#define HID_KEY_BACKSLASH 0x31
+#define HID_KEY_EUROPE_1 0x32
+#define HID_KEY_SEMICOLON 0x33
+#define HID_KEY_APOSTROPHE 0x34
+#define HID_KEY_GRAVE 0x35
+#define HID_KEY_COMMA 0x36
+#define HID_KEY_PERIOD 0x37
+#define HID_KEY_SLASH 0x38
+#define HID_KEY_CAPS_LOCK 0x39
+#define HID_KEY_F1 0x3A
+#define HID_KEY_F2 0x3B
+#define HID_KEY_F3 0x3C
+#define HID_KEY_F4 0x3D
+#define HID_KEY_F5 0x3E
+#define HID_KEY_F6 0x3F
+#define HID_KEY_F7 0x40
+#define HID_KEY_F8 0x41
+#define HID_KEY_F9 0x42
+#define HID_KEY_F10 0x43
+#define HID_KEY_F11 0x44
+#define HID_KEY_F12 0x45
+#define HID_KEY_PRINT_SCREEN 0x46
+#define HID_KEY_SCROLL_LOCK 0x47
+#define HID_KEY_PAUSE 0x48
+#define HID_KEY_INSERT 0x49
+#define HID_KEY_HOME 0x4A
+#define HID_KEY_PAGE_UP 0x4B
+#define HID_KEY_DELETE 0x4C
+#define HID_KEY_END 0x4D
+#define HID_KEY_PAGE_DOWN 0x4E
+#define HID_KEY_ARROW_RIGHT 0x4F
+#define HID_KEY_ARROW_LEFT 0x50
+#define HID_KEY_ARROW_DOWN 0x51
+#define HID_KEY_ARROW_UP 0x52
+#define HID_KEY_NUM_LOCK 0x53
+#define HID_KEY_KEYPAD_DIVIDE 0x54
+#define HID_KEY_KEYPAD_MULTIPLY 0x55
+#define HID_KEY_KEYPAD_SUBTRACT 0x56
+#define HID_KEY_KEYPAD_ADD 0x57
+#define HID_KEY_KEYPAD_ENTER 0x58
+#define HID_KEY_KEYPAD_1 0x59
+#define HID_KEY_KEYPAD_2 0x5A
+#define HID_KEY_KEYPAD_3 0x5B
+#define HID_KEY_KEYPAD_4 0x5C
+#define HID_KEY_KEYPAD_5 0x5D
+#define HID_KEY_KEYPAD_6 0x5E
+#define HID_KEY_KEYPAD_7 0x5F
+#define HID_KEY_KEYPAD_8 0x60
+#define HID_KEY_KEYPAD_9 0x61
+#define HID_KEY_KEYPAD_0 0x62
+#define HID_KEY_KEYPAD_DECIMAL 0x63
+#define HID_KEY_EUROPE_2 0x64
+#define HID_KEY_APPLICATION 0x65
+#define HID_KEY_POWER 0x66
+#define HID_KEY_KEYPAD_EQUAL 0x67
+#define HID_KEY_F13 0x68
+#define HID_KEY_F14 0x69
+#define HID_KEY_F15 0x6A
+#define HID_KEY_F16 0x6B
+#define HID_KEY_F17 0x6C
+#define HID_KEY_F18 0x6D
+#define HID_KEY_F19 0x6E
+#define HID_KEY_F20 0x6F
+#define HID_KEY_F21 0x70
+#define HID_KEY_F22 0x71
+#define HID_KEY_F23 0x72
+#define HID_KEY_F24 0x73
+#define HID_KEY_EXECUTE 0x74
+#define HID_KEY_HELP 0x75
+#define HID_KEY_MENU 0x76
+#define HID_KEY_SELECT 0x77
+#define HID_KEY_STOP 0x78
+#define HID_KEY_AGAIN 0x79
+#define HID_KEY_UNDO 0x7A
+#define HID_KEY_CUT 0x7B
+#define HID_KEY_COPY 0x7C
+#define HID_KEY_PASTE 0x7D
+#define HID_KEY_FIND 0x7E
+#define HID_KEY_MUTE 0x7F
+#define HID_KEY_VOLUME_UP 0x80
+#define HID_KEY_VOLUME_DOWN 0x81
+#define HID_KEY_LOCKING_CAPS_LOCK 0x82
+#define HID_KEY_LOCKING_NUM_LOCK 0x83
+#define HID_KEY_LOCKING_SCROLL_LOCK 0x84
+#define HID_KEY_KEYPAD_COMMA 0x85
+#define HID_KEY_KEYPAD_EQUAL_SIGN 0x86
+#define HID_KEY_KANJI1 0x87
+#define HID_KEY_KANJI2 0x88
+#define HID_KEY_KANJI3 0x89
+#define HID_KEY_KANJI4 0x8A
+#define HID_KEY_KANJI5 0x8B
+#define HID_KEY_KANJI6 0x8C
+#define HID_KEY_KANJI7 0x8D
+#define HID_KEY_KANJI8 0x8E
+#define HID_KEY_KANJI9 0x8F
+#define HID_KEY_LANG1 0x90
+#define HID_KEY_LANG2 0x91
+#define HID_KEY_LANG3 0x92
+#define HID_KEY_LANG4 0x93
+#define HID_KEY_LANG5 0x94
+#define HID_KEY_LANG6 0x95
+#define HID_KEY_LANG7 0x96
+#define HID_KEY_LANG8 0x97
+#define HID_KEY_LANG9 0x98
+#define HID_KEY_ALTERNATE_ERASE 0x99
+#define HID_KEY_SYSREQ_ATTENTION 0x9A
+#define HID_KEY_CANCEL 0x9B
+#define HID_KEY_CLEAR 0x9C
+#define HID_KEY_PRIOR 0x9D
+#define HID_KEY_RETURN 0x9E
+#define HID_KEY_SEPARATOR 0x9F
+#define HID_KEY_OUT 0xA0
+#define HID_KEY_OPER 0xA1
+#define HID_KEY_CLEAR_AGAIN 0xA2
+#define HID_KEY_CRSEL_PROPS 0xA3
+#define HID_KEY_EXSEL 0xA4
+// RESERVED 0xA5-AF
+#define HID_KEY_KEYPAD_00 0xB0
+#define HID_KEY_KEYPAD_000 0xB1
+#define HID_KEY_THOUSANDS_SEPARATOR 0xB2
+#define HID_KEY_DECIMAL_SEPARATOR 0xB3
+#define HID_KEY_CURRENCY_UNIT 0xB4
+#define HID_KEY_CURRENCY_SUBUNIT 0xB5
+#define HID_KEY_KEYPAD_LEFT_PARENTHESIS 0xB6
+#define HID_KEY_KEYPAD_RIGHT_PARENTHESIS 0xB7
+#define HID_KEY_KEYPAD_LEFT_BRACE 0xB8
+#define HID_KEY_KEYPAD_RIGHT_BRACE 0xB9
+#define HID_KEY_KEYPAD_TAB 0xBA
+#define HID_KEY_KEYPAD_BACKSPACE 0xBB
+#define HID_KEY_KEYPAD_A 0xBC
+#define HID_KEY_KEYPAD_B 0xBD
+#define HID_KEY_KEYPAD_C 0xBE
+#define HID_KEY_KEYPAD_D 0xBF
+#define HID_KEY_KEYPAD_E 0xC0
+#define HID_KEY_KEYPAD_F 0xC1
+#define HID_KEY_KEYPAD_XOR 0xC2
+#define HID_KEY_KEYPAD_CARET 0xC3
+#define HID_KEY_KEYPAD_PERCENT 0xC4
+#define HID_KEY_KEYPAD_LESS_THAN 0xC5
+#define HID_KEY_KEYPAD_GREATER_THAN 0xC6
+#define HID_KEY_KEYPAD_AMPERSAND 0xC7
+#define HID_KEY_KEYPAD_DOUBLE_AMPERSAND 0xC8
+#define HID_KEY_KEYPAD_VERTICAL_BAR 0xC9
+#define HID_KEY_KEYPAD_DOUBLE_VERTICAL_BAR 0xCA
+#define HID_KEY_KEYPAD_COLON 0xCB
+#define HID_KEY_KEYPAD_HASH 0xCC
+#define HID_KEY_KEYPAD_SPACE 0xCD
+#define HID_KEY_KEYPAD_AT 0xCE
+#define HID_KEY_KEYPAD_EXCLAMATION 0xCF
+#define HID_KEY_KEYPAD_MEMORY_STORE 0xD0
+#define HID_KEY_KEYPAD_MEMORY_RECALL 0xD1
+#define HID_KEY_KEYPAD_MEMORY_CLEAR 0xD2
+#define HID_KEY_KEYPAD_MEMORY_ADD 0xD3
+#define HID_KEY_KEYPAD_MEMORY_SUBTRACT 0xD4
+#define HID_KEY_KEYPAD_MEMORY_MULTIPLY 0xD5
+#define HID_KEY_KEYPAD_MEMORY_DIVIDE 0xD6
+#define HID_KEY_KEYPAD_PLUS_MINUS 0xD7
+#define HID_KEY_KEYPAD_CLEAR 0xD8
+#define HID_KEY_KEYPAD_CLEAR_ENTRY 0xD9
+#define HID_KEY_KEYPAD_BINARY 0xDA
+#define HID_KEY_KEYPAD_OCTAL 0xDB
+#define HID_KEY_KEYPAD_DECIMAL_2 0xDC
+#define HID_KEY_KEYPAD_HEXADECIMAL 0xDD
+// RESERVED 0xDE-DF
+#define HID_KEY_CONTROL_LEFT 0xE0
+#define HID_KEY_SHIFT_LEFT 0xE1
+#define HID_KEY_ALT_LEFT 0xE2
+#define HID_KEY_GUI_LEFT 0xE3
+#define HID_KEY_CONTROL_RIGHT 0xE4
+#define HID_KEY_SHIFT_RIGHT 0xE5
+#define HID_KEY_ALT_RIGHT 0xE6
+#define HID_KEY_GUI_RIGHT 0xE7
//--------------------------------------------------------------------+
@@ -697,32 +744,33 @@ enum {
/// HID Usage Table - Table 1: Usage Page Summary
enum {
- HID_USAGE_PAGE_DESKTOP = 0x01,
- HID_USAGE_PAGE_SIMULATE = 0x02,
- HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03,
- HID_USAGE_PAGE_SPORT = 0x04,
- HID_USAGE_PAGE_GAME = 0x05,
- HID_USAGE_PAGE_GENERIC_DEVICE = 0x06,
- HID_USAGE_PAGE_KEYBOARD = 0x07,
- HID_USAGE_PAGE_LED = 0x08,
- HID_USAGE_PAGE_BUTTON = 0x09,
- HID_USAGE_PAGE_ORDINAL = 0x0a,
- HID_USAGE_PAGE_TELEPHONY = 0x0b,
- HID_USAGE_PAGE_CONSUMER = 0x0c,
- HID_USAGE_PAGE_DIGITIZER = 0x0d,
- HID_USAGE_PAGE_PID = 0x0f,
- HID_USAGE_PAGE_UNICODE = 0x10,
- HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14,
- HID_USAGE_PAGE_MEDICAL = 0x40,
- HID_USAGE_PAGE_MONITOR = 0x80, //0x80 - 0x83
- HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87
- HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c,
- HID_USAGE_PAGE_SCALE = 0x8d,
- HID_USAGE_PAGE_MSR = 0x8e,
- HID_USAGE_PAGE_CAMERA = 0x90,
- HID_USAGE_PAGE_ARCADE = 0x91,
- HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page
- HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF
+ HID_USAGE_PAGE_DESKTOP = 0x01,
+ HID_USAGE_PAGE_SIMULATE = 0x02,
+ HID_USAGE_PAGE_VIRTUAL_REALITY = 0x03,
+ HID_USAGE_PAGE_SPORT = 0x04,
+ HID_USAGE_PAGE_GAME = 0x05,
+ HID_USAGE_PAGE_GENERIC_DEVICE = 0x06,
+ HID_USAGE_PAGE_KEYBOARD = 0x07,
+ HID_USAGE_PAGE_LED = 0x08,
+ HID_USAGE_PAGE_BUTTON = 0x09,
+ HID_USAGE_PAGE_ORDINAL = 0x0a,
+ HID_USAGE_PAGE_TELEPHONY = 0x0b,
+ HID_USAGE_PAGE_CONSUMER = 0x0c,
+ HID_USAGE_PAGE_DIGITIZER = 0x0d,
+ HID_USAGE_PAGE_PID = 0x0f,
+ HID_USAGE_PAGE_UNICODE = 0x10,
+ HID_USAGE_PAGE_ALPHA_DISPLAY = 0x14,
+ HID_USAGE_PAGE_MEDICAL = 0x40,
+ HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION = 0x59,
+ HID_USAGE_PAGE_MONITOR = 0x80, // 0x80 - 0x83
+ HID_USAGE_PAGE_POWER = 0x84, // 0x084 - 0x87
+ HID_USAGE_PAGE_BARCODE_SCANNER = 0x8c,
+ HID_USAGE_PAGE_SCALE = 0x8d,
+ HID_USAGE_PAGE_MSR = 0x8e,
+ HID_USAGE_PAGE_CAMERA = 0x90,
+ HID_USAGE_PAGE_ARCADE = 0x91,
+ HID_USAGE_PAGE_FIDO = 0xF1D0, // FIDO alliance HID usage page
+ HID_USAGE_PAGE_VENDOR = 0xFF00 // 0xFF00 - 0xFFFF
};
/// HID Usage Table - Table 6: Generic Desktop Page
@@ -801,8 +849,7 @@ enum {
/// HID Usage Table: Consumer Page (0x0C)
/// Only contains controls that supported by Windows (whole list is too long)
-enum
-{
+enum {
// Generic Control
HID_USAGE_CONSUMER_CONTROL = 0x0001,
@@ -858,9 +905,45 @@ enum
HID_USAGE_CONSUMER_AC_PAN = 0x0238,
};
+/// HID Usage Table - Lighting And Illumination Page (0x59)
+enum {
+ HID_USAGE_LIGHTING_LAMP_ARRAY = 0x01,
+ HID_USAGE_LIGHTING_LAMP_ARRAY_ATTRIBUTES_REPORT = 0x02,
+ HID_USAGE_LIGHTING_LAMP_COUNT = 0x03,
+ HID_USAGE_LIGHTING_BOUNDING_BOX_WIDTH_IN_MICROMETERS = 0x04,
+ HID_USAGE_LIGHTING_BOUNDING_BOX_HEIGHT_IN_MICROMETERS = 0x05,
+ HID_USAGE_LIGHTING_BOUNDING_BOX_DEPTH_IN_MICROMETERS = 0x06,
+ HID_USAGE_LIGHTING_LAMP_ARRAY_KIND = 0x07,
+ HID_USAGE_LIGHTING_MIN_UPDATE_INTERVAL_IN_MICROSECONDS = 0x08,
+ HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_REQUEST_REPORT = 0x20,
+ HID_USAGE_LIGHTING_LAMP_ID = 0x21,
+ HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_RESPONSE_REPORT = 0x22,
+ HID_USAGE_LIGHTING_POSITION_X_IN_MICROMETERS = 0x23,
+ HID_USAGE_LIGHTING_POSITION_Y_IN_MICROMETERS = 0x24,
+ HID_USAGE_LIGHTING_POSITION_Z_IN_MICROMETERS = 0x25,
+ HID_USAGE_LIGHTING_LAMP_PURPOSES = 0x26,
+ HID_USAGE_LIGHTING_UPDATE_LATENCY_IN_MICROSECONDS = 0x27,
+ HID_USAGE_LIGHTING_RED_LEVEL_COUNT = 0x28,
+ HID_USAGE_LIGHTING_GREEN_LEVEL_COUNT = 0x29,
+ HID_USAGE_LIGHTING_BLUE_LEVEL_COUNT = 0x2A,
+ HID_USAGE_LIGHTING_INTENSITY_LEVEL_COUNT = 0x2B,
+ HID_USAGE_LIGHTING_IS_PROGRAMMABLE = 0x2C,
+ HID_USAGE_LIGHTING_INPUT_BINDING = 0x2D,
+ HID_USAGE_LIGHTING_LAMP_MULTI_UPDATE_REPORT = 0x50,
+ HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL = 0x51,
+ HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL = 0x52,
+ HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL = 0x53,
+ HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL = 0x54,
+ HID_USAGE_LIGHTING_LAMP_UPDATE_FLAGS = 0x55,
+ HID_USAGE_LIGHTING_LAMP_RANGE_UPDATE_REPORT = 0x60,
+ HID_USAGE_LIGHTING_LAMP_ID_START = 0x61,
+ HID_USAGE_LIGHTING_LAMP_ID_END = 0x62,
+ HID_USAGE_LIGHTING_LAMP_ARRAY_CONTROL_REPORT = 0x70,
+ HID_USAGE_LIGHTING_AUTONOMOUS_MODE = 0x71,
+};
+
/// HID Usage Table: FIDO Alliance Page (0xF1D0)
-enum
-{
+enum {
HID_USAGE_FIDO_U2FHID = 0x01, // U2FHID usage for top-level collection
HID_USAGE_FIDO_DATA_IN = 0x20, // Raw IN data report
HID_USAGE_FIDO_DATA_OUT = 0x21 // Raw OUT data report
diff --git a/src/class/hid/hid_device.c b/src/class/hid/hid_device.c
index 5cc5a2488..ada01582e 100644
--- a/src/class/hid/hid_device.c
+++ b/src/class/hid/hid_device.c
@@ -39,23 +39,23 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
-typedef struct
-{
+typedef struct {
uint8_t itf_num;
uint8_t ep_in;
- uint8_t ep_out; // optional Out endpoint
- uint8_t itf_protocol; // Boot mouse or keyboard
+ uint8_t ep_out; // optional Out endpoint
+ uint8_t itf_protocol; // Boot mouse or keyboard
- uint8_t protocol_mode; // Boot (0) or Report protocol (1)
- uint8_t idle_rate; // up to application to handle idle rate
uint16_t report_desc_len;
+ CFG_TUSB_MEM_ALIGN uint8_t protocol_mode; // Boot (0) or Report protocol (1)
+ CFG_TUSB_MEM_ALIGN uint8_t idle_rate; // up to application to handle idle rate
CFG_TUSB_MEM_ALIGN uint8_t epin_buf[CFG_TUD_HID_EP_BUFSIZE];
CFG_TUSB_MEM_ALIGN uint8_t epout_buf[CFG_TUD_HID_EP_BUFSIZE];
+ CFG_TUSB_MEM_ALIGN uint8_t ctrl_buf[CFG_TUD_HID_EP_BUFSIZE];
// TODO save hid descriptor since host can specifically request this after enumeration
// Note: HID descriptor may be not available from application after enumeration
- tusb_hid_descriptor_hid_t const * hid_descriptor;
+ tusb_hid_descriptor_hid_t const *hid_descriptor;
} hidd_interface_t;
CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];
@@ -63,12 +63,12 @@ CFG_TUD_MEM_SECTION tu_static hidd_interface_t _hidd_itf[CFG_TUD_HID];
/*------------- Helpers -------------*/
static inline uint8_t get_index_by_itfnum(uint8_t itf_num)
{
- for (uint8_t i=0; i < CFG_TUD_HID; i++ )
- {
- if ( itf_num == _hidd_itf[i].itf_num ) return i;
- }
+ for (uint8_t i = 0; i < CFG_TUD_HID; i++) {
+ if (itf_num == _hidd_itf[i].itf_num)
+ return i;
+ }
- return 0xFF;
+ return 0xFF;
}
//--------------------------------------------------------------------+
@@ -81,37 +81,29 @@ bool tud_hid_n_ready(uint8_t instance)
return tud_ready() && (ep_in != 0) && !usbd_edpt_busy(rhport, ep_in);
}
-bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const* report, uint16_t len)
+bool tud_hid_n_report(uint8_t instance, uint8_t report_id, void const *report, uint16_t len)
{
uint8_t const rhport = 0;
- hidd_interface_t * p_hid = &_hidd_itf[instance];
+ hidd_interface_t *p_hid = &_hidd_itf[instance];
// claim endpoint
- TU_VERIFY( usbd_edpt_claim(rhport, p_hid->ep_in) );
+ TU_VERIFY(usbd_edpt_claim(rhport, p_hid->ep_in));
// prepare data
- if (report_id)
- {
+ if (report_id) {
p_hid->epin_buf[0] = report_id;
- TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf+1, CFG_TUD_HID_EP_BUFSIZE-1, report, len));
+ TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf + 1, CFG_TUD_HID_EP_BUFSIZE - 1, report, len));
len++;
- }else
- {
+ } else {
TU_VERIFY(0 == tu_memcpy_s(p_hid->epin_buf, CFG_TUD_HID_EP_BUFSIZE, report, len));
}
return usbd_edpt_xfer(rhport, p_hid->ep_in, p_hid->epin_buf, len);
}
-uint8_t tud_hid_n_interface_protocol(uint8_t instance)
-{
- return _hidd_itf[instance].itf_protocol;
-}
+uint8_t tud_hid_n_interface_protocol(uint8_t instance) { return _hidd_itf[instance].itf_protocol; }
-uint8_t tud_hid_n_get_protocol(uint8_t instance)
-{
- return _hidd_itf[instance].protocol_mode;
-}
+uint8_t tud_hid_n_get_protocol(uint8_t instance) { return _hidd_itf[instance].protocol_mode; }
bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modifier, uint8_t keycode[6])
{
@@ -120,27 +112,23 @@ bool tud_hid_n_keyboard_report(uint8_t instance, uint8_t report_id, uint8_t modi
report.modifier = modifier;
report.reserved = 0;
- if ( keycode )
- {
+ if (keycode) {
memcpy(report.keycode, keycode, sizeof(report.keycode));
- }else
- {
+ } else {
tu_memclr(report.keycode, 6);
}
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
-bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
- uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
+bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int8_t x, int8_t y, int8_t vertical, int8_t horizontal)
{
- hid_mouse_report_t report =
- {
+ hid_mouse_report_t report = {
.buttons = buttons,
- .x = x,
- .y = y,
- .wheel = vertical,
- .pan = horizontal
+ .x = x,
+ .y = y,
+ .wheel = vertical,
+ .pan = horizontal
};
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
@@ -148,29 +136,27 @@ bool tud_hid_n_mouse_report(uint8_t instance, uint8_t report_id,
bool tud_hid_n_abs_mouse_report(uint8_t instance, uint8_t report_id, uint8_t buttons, int16_t x, int16_t y, int8_t vertical, int8_t horizontal)
{
- hid_abs_mouse_report_t report =
- {
+ hid_abs_mouse_report_t report = {
.buttons = buttons,
- .x = x,
- .y = y,
- .wheel = vertical,
- .pan = horizontal
+ .x = x,
+ .y = y,
+ .wheel = vertical,
+ .pan = horizontal
};
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
}
-bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
- int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons) {
- hid_gamepad_report_t report =
- {
- .x = x,
- .y = y,
- .z = z,
- .rz = rz,
- .rx = rx,
- .ry = ry,
- .hat = hat,
- .buttons = buttons,
+bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id, int8_t x, int8_t y, int8_t z, int8_t rz, int8_t rx, int8_t ry, uint8_t hat, uint32_t buttons)
+{
+ hid_gamepad_report_t report = {
+ .x = x,
+ .y = y,
+ .z = z,
+ .rz = rz,
+ .rx = rx,
+ .ry = ry,
+ .hat = hat,
+ .buttons = buttons,
};
return tud_hid_n_report(instance, report_id, &report, sizeof(report));
@@ -179,67 +165,64 @@ bool tud_hid_n_gamepad_report(uint8_t instance, uint8_t report_id,
//--------------------------------------------------------------------+
// USBD-CLASS API
//--------------------------------------------------------------------+
-void hidd_init(void) {
+void hidd_init(void)
+{
hidd_reset(0);
}
-bool hidd_deinit(void) {
+bool hidd_deinit(void)
+{
return true;
}
void hidd_reset(uint8_t rhport)
{
- (void) rhport;
+ (void)rhport;
tu_memclr(_hidd_itf, sizeof(_hidd_itf));
}
-uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint16_t max_len)
- {
+uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const *desc_itf, uint16_t max_len)
+{
TU_VERIFY(TUSB_CLASS_HID == desc_itf->bInterfaceClass, 0);
// len = interface + hid + n*endpoints
- uint16_t const drv_len =
- (uint16_t) (sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) +
- desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
+ uint16_t const drv_len = (uint16_t)(sizeof(tusb_desc_interface_t) + sizeof(tusb_hid_descriptor_hid_t) + desc_itf->bNumEndpoints * sizeof(tusb_desc_endpoint_t));
TU_ASSERT(max_len >= drv_len, 0);
// Find available interface
- hidd_interface_t * p_hid = NULL;
+ hidd_interface_t *p_hid = NULL;
uint8_t hid_id;
- for(hid_id=0; hid_id<CFG_TUD_HID; hid_id++)
- {
- if ( _hidd_itf[hid_id].ep_in == 0 )
- {
+ for (hid_id = 0; hid_id < CFG_TUD_HID; hid_id++) {
+ if (_hidd_itf[hid_id].ep_in == 0) {
p_hid = &_hidd_itf[hid_id];
break;
}
}
TU_ASSERT(p_hid, 0);
- uint8_t const *p_desc = (uint8_t const *) desc_itf;
+ uint8_t const *p_desc = (uint8_t const *)desc_itf;
//------------- HID descriptor -------------//
p_desc = tu_desc_next(p_desc);
TU_ASSERT(HID_DESC_TYPE_HID == tu_desc_type(p_desc), 0);
- p_hid->hid_descriptor = (tusb_hid_descriptor_hid_t const *) p_desc;
+ p_hid->hid_descriptor = (tusb_hid_descriptor_hid_t const *)p_desc;
//------------- Endpoint Descriptor -------------//
p_desc = tu_desc_next(p_desc);
TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, desc_itf->bNumEndpoints, TUSB_XFER_INTERRUPT, &p_hid->ep_out, &p_hid->ep_in), 0);
- if ( desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT ) p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
+ if (desc_itf->bInterfaceSubClass == HID_SUBCLASS_BOOT)
+ p_hid->itf_protocol = desc_itf->bInterfaceProtocol;
p_hid->protocol_mode = HID_PROTOCOL_REPORT; // Per Specs: default is report mode
- p_hid->itf_num = desc_itf->bInterfaceNumber;
+ p_hid->itf_num = desc_itf->bInterfaceNumber;
// Use offsetof to avoid pointer to the odd/misaligned address
- p_hid->report_desc_len = tu_unaligned_read16((uint8_t const*) p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength));
+ p_hid->report_desc_len = tu_unaligned_read16((uint8_t const *)p_hid->hid_descriptor + offsetof(tusb_hid_descriptor_hid_t, wReportLength));
// Prepare for output endpoint
- if (p_hid->ep_out)
- {
- if ( !usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)) )
- {
+ if (p_hid->ep_out) {
+ if (!usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf))) {
TU_LOG_FAILED();
TU_BREAKPOINT();
}
@@ -251,144 +234,120 @@ uint16_t hidd_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, uint1
// Invoked when a control transfer occurred on an interface of this class
// Driver response accordingly to the request and the transfer stage (setup/data/ack)
// return false to stall control endpoint (e.g unsupported request)
-bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+bool hidd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request)
{
TU_VERIFY(request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_INTERFACE);
- uint8_t const hid_itf = get_index_by_itfnum((uint8_t) request->wIndex);
+ uint8_t const hid_itf = get_index_by_itfnum((uint8_t)request->wIndex);
TU_VERIFY(hid_itf < CFG_TUD_HID);
- hidd_interface_t* p_hid = &_hidd_itf[hid_itf];
+ hidd_interface_t *p_hid = &_hidd_itf[hid_itf];
- if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD)
- {
+ if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD) {
//------------- STD Request -------------//
- if ( stage == CONTROL_STAGE_SETUP )
- {
- uint8_t const desc_type = tu_u16_high(request->wValue);
- //uint8_t const desc_index = tu_u16_low (request->wValue);
+ if (stage == CONTROL_STAGE_SETUP) {
+ uint8_t const desc_type = tu_u16_high(request->wValue);
+ // uint8_t const desc_index = tu_u16_low (request->wValue);
- if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID)
- {
+ if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_HID) {
TU_VERIFY(p_hid->hid_descriptor);
- TU_VERIFY(tud_control_xfer(rhport, request, (void*)(uintptr_t) p_hid->hid_descriptor, p_hid->hid_descriptor->bLength));
- }
- else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT)
- {
- uint8_t const * desc_report = tud_hid_descriptor_report_cb(hid_itf);
- tud_control_xfer(rhport, request, (void*)(uintptr_t) desc_report, p_hid->report_desc_len);
- }
- else
- {
+ TU_VERIFY(tud_control_xfer(rhport, request, (void *)(uintptr_t)p_hid->hid_descriptor, p_hid->hid_descriptor->bLength));
+ } else if (request->bRequest == TUSB_REQ_GET_DESCRIPTOR && desc_type == HID_DESC_TYPE_REPORT) {
+ uint8_t const *desc_report = tud_hid_descriptor_report_cb(hid_itf);
+ tud_control_xfer(rhport, request, (void *)(uintptr_t)desc_report, p_hid->report_desc_len);
+ } else {
return false; // stall unsupported request
}
}
- }
- else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS)
- {
+ } else if (request->bmRequestType_bit.type == TUSB_REQ_TYPE_CLASS) {
//------------- Class Specific Request -------------//
- switch( request->bRequest )
- {
- case HID_REQ_CONTROL_GET_REPORT:
- if ( stage == CONTROL_STAGE_SETUP )
- {
- uint8_t const report_type = tu_u16_high(request->wValue);
- uint8_t const report_id = tu_u16_low(request->wValue);
+ switch (request->bRequest) {
+ case HID_REQ_CONTROL_GET_REPORT:
+ if (stage == CONTROL_STAGE_SETUP) {
+ uint8_t const report_type = tu_u16_high(request->wValue);
+ uint8_t const report_id = tu_u16_low(request->wValue);
- uint8_t* report_buf = p_hid->epin_buf;
- uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
+ uint8_t *report_buf = p_hid->ctrl_buf;
+ uint16_t req_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
- uint16_t xferlen = 0;
+ uint16_t xferlen = 0;
- // If host request a specific Report ID, add ID to as 1 byte of response
- if ( (report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1) )
- {
- *report_buf++ = report_id;
- req_len--;
+ // If host request a specific Report ID, add ID to as 1 byte of response
+ if ((report_id != HID_REPORT_TYPE_INVALID) && (req_len > 1)) {
+ *report_buf++ = report_id;
+ req_len--;
- xferlen++;
- }
+ xferlen++;
+ }
- xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, req_len);
- TU_ASSERT( xferlen > 0 );
+ xferlen += tud_hid_get_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, req_len);
+ TU_ASSERT(xferlen > 0);
- tud_control_xfer(rhport, request, p_hid->epin_buf, xferlen);
- }
+ tud_control_xfer(rhport, request, p_hid->ctrl_buf, xferlen);
+ }
break;
- case HID_REQ_CONTROL_SET_REPORT:
- if ( stage == CONTROL_STAGE_SETUP )
- {
- TU_VERIFY(request->wLength <= sizeof(p_hid->epout_buf));
- tud_control_xfer(rhport, request, p_hid->epout_buf, request->wLength);
- }
- else if ( stage == CONTROL_STAGE_ACK )
- {
- uint8_t const report_type = tu_u16_high(request->wValue);
- uint8_t const report_id = tu_u16_low(request->wValue);
-
- uint8_t const* report_buf = p_hid->epout_buf;
- uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
+ case HID_REQ_CONTROL_SET_REPORT:
+ if (stage == CONTROL_STAGE_SETUP) {
+ TU_VERIFY(request->wLength <= sizeof(p_hid->ctrl_buf));
+ tud_control_xfer(rhport, request, p_hid->ctrl_buf, request->wLength);
+ } else if (stage == CONTROL_STAGE_ACK) {
+ uint8_t const report_type = tu_u16_high(request->wValue);
+ uint8_t const report_id = tu_u16_low(request->wValue);
- // If host request a specific Report ID, extract report ID in buffer before invoking callback
- if ( (report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0]) )
- {
- report_buf++;
- report_len--;
- }
+ uint8_t const *report_buf = p_hid->ctrl_buf;
+ uint16_t report_len = tu_min16(request->wLength, CFG_TUD_HID_EP_BUFSIZE);
- tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t) report_type, report_buf, report_len);
+ // If host request a specific Report ID, extract report ID in buffer before invoking callback
+ if ((report_id != HID_REPORT_TYPE_INVALID) && (report_len > 1) && (report_id == report_buf[0])) {
+ report_buf++;
+ report_len--;
}
- break;
- case HID_REQ_CONTROL_SET_IDLE:
- if ( stage == CONTROL_STAGE_SETUP )
- {
- p_hid->idle_rate = tu_u16_high(request->wValue);
- if ( tud_hid_set_idle_cb )
- {
- // stall request if callback return false
- TU_VERIFY( tud_hid_set_idle_cb( hid_itf, p_hid->idle_rate) );
- }
+ tud_hid_set_report_cb(hid_itf, report_id, (hid_report_type_t)report_type, report_buf, report_len);
+ }
+ break;
- tud_control_status(rhport, request);
+ case HID_REQ_CONTROL_SET_IDLE:
+ if (stage == CONTROL_STAGE_SETUP) {
+ p_hid->idle_rate = tu_u16_high(request->wValue);
+ if (tud_hid_set_idle_cb) {
+ // stall request if callback return false
+ TU_VERIFY(tud_hid_set_idle_cb(hid_itf, p_hid->idle_rate));
}
+
+ tud_control_status(rhport, request);
+ }
break;
- case HID_REQ_CONTROL_GET_IDLE:
- if ( stage == CONTROL_STAGE_SETUP )
- {
- // TODO idle rate of report
- tud_control_xfer(rhport, request, &p_hid->idle_rate, 1);
- }
+ case HID_REQ_CONTROL_GET_IDLE:
+ if (stage == CONTROL_STAGE_SETUP) {
+ // TODO idle rate of report
+ tud_control_xfer(rhport, request, &p_hid->idle_rate, 1);
+ }
break;
- case HID_REQ_CONTROL_GET_PROTOCOL:
- if ( stage == CONTROL_STAGE_SETUP )
- {
- tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1);
- }
+ case HID_REQ_CONTROL_GET_PROTOCOL:
+ if (stage == CONTROL_STAGE_SETUP) {
+ tud_control_xfer(rhport, request, &p_hid->protocol_mode, 1);
+ }
break;
- case HID_REQ_CONTROL_SET_PROTOCOL:
- if ( stage == CONTROL_STAGE_SETUP )
- {
- tud_control_status(rhport, request);
- }
- else if ( stage == CONTROL_STAGE_ACK )
- {
- p_hid->protocol_mode = (uint8_t) request->wValue;
- if (tud_hid_set_protocol_cb)
- {
- tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode);
- }
+ case HID_REQ_CONTROL_SET_PROTOCOL:
+ if (stage == CONTROL_STAGE_SETUP) {
+ tud_control_status(rhport, request);
+ } else if (stage == CONTROL_STAGE_ACK) {
+ p_hid->protocol_mode = (uint8_t)request->wValue;
+ if (tud_hid_set_protocol_cb) {
+ tud_hid_set_protocol_cb(hid_itf, p_hid->protocol_mode);
}
+ }
break;
- default: return false; // stall unsupported request
+ default:
+ return false; // stall unsupported request
}
- }else
- {
+ } else {
return false; // stall unsupported request
}
@@ -397,31 +356,43 @@ bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t
bool hidd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
- (void) result;
+ (void)result;
uint8_t instance = 0;
- hidd_interface_t * p_hid = _hidd_itf;
+ hidd_interface_t *p_hid = _hidd_itf;
// Identify which interface to use
- for (instance = 0; instance < CFG_TUD_HID; instance++)
- {
+ for (instance = 0; instance < CFG_TUD_HID; instance++) {
p_hid = &_hidd_itf[instance];
- if ( (ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in) ) break;
+ if ((ep_addr == p_hid->ep_out) || (ep_addr == p_hid->ep_in))
+ break;
}
TU_ASSERT(instance < CFG_TUD_HID);
+ // Check if there was a problem
+ if (XFER_RESULT_SUCCESS != result) { // Inform application about the issue
+ if (tud_hid_report_fail_cb) {
+ tud_hid_report_fail_cb(instance, ep_addr, (uint16_t)xferred_bytes);
+ }
+
+ // Allow a new transfer to be received if issue happened on an OUT endpoint
+ if (ep_addr == p_hid->ep_out) {
+ // Prepare the OUT endpoint to be able to receive a new transfer
+ TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
+ }
+
+ return true;
+ }
+
// Sent report successfully
- if (ep_addr == p_hid->ep_in)
- {
- if (tud_hid_report_complete_cb)
- {
- tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t) xferred_bytes);
+ if (ep_addr == p_hid->ep_in) {
+ if (tud_hid_report_complete_cb) {
+ tud_hid_report_complete_cb(instance, p_hid->epin_buf, (uint16_t)xferred_bytes);
}
}
- // Received report
- else if (ep_addr == p_hid->ep_out)
- {
- tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_INVALID, p_hid->epout_buf, (uint16_t) xferred_bytes);
+ // Received report successfully
+ else if (ep_addr == p_hid->ep_out) {
+ tud_hid_set_report_cb(instance, 0, HID_REPORT_TYPE_OUTPUT, p_hid->epout_buf, (uint16_t)xferred_bytes);
TU_ASSERT(usbd_edpt_xfer(rhport, p_hid->ep_out, p_hid->epout_buf, sizeof(p_hid->epout_buf)));
}
diff --git a/src/class/hid/hid_device.h b/src/class/hid/hid_device.h
index 040cad162..fcbf161c4 100644
--- a/src/class/hid/hid_device.h
+++ b/src/class/hid/hid_device.h
@@ -128,6 +128,8 @@ TU_ATTR_WEAK bool tud_hid_set_idle_cb(uint8_t instance, uint8_t idle_rate);
// Note: For composite reports, report[0] is report ID
TU_ATTR_WEAK void tud_hid_report_complete_cb(uint8_t instance, uint8_t const* report, uint16_t len);
+// Invoked when a transfer wasn't successful
+TU_ATTR_WEAK void tud_hid_report_fail_cb(uint8_t instance, uint8_t ep_addr, uint16_t len);
//--------------------------------------------------------------------+
// Inline Functions
@@ -461,6 +463,178 @@ static inline bool tud_hid_gamepad_report(uint8_t report_id, int8_t x, int8_t y
HID_OUTPUT ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
HID_COLLECTION_END \
+// HID Lighting and Illumination Report Descriptor Template
+// - 1st parameter is report id (required)
+// Creates 6 report ids for lighting HID usages in the following order:
+// report_id+0: HID_USAGE_LIGHTING_LAMP_ARRAY_ATTRIBUTES_REPORT
+// report_id+1: HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_REQUEST_REPORT
+// report_id+2: HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_RESPONSE_REPORT
+// report_id+3: HID_USAGE_LIGHTING_LAMP_MULTI_UPDATE_REPORT
+// report_id+4: HID_USAGE_LIGHTING_LAMP_RANGE_UPDATE_REPORT
+// report_id+5: HID_USAGE_LIGHTING_LAMP_ARRAY_CONTROL_REPORT
+#define TUD_HID_REPORT_DESC_LIGHTING(report_id) \
+ HID_USAGE_PAGE ( HID_USAGE_PAGE_LIGHTING_AND_ILLUMINATION ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ARRAY ),\
+ HID_COLLECTION ( HID_COLLECTION_APPLICATION ),\
+ /* Lamp Array Attributes Report */ \
+ HID_REPORT_ID (report_id ) \
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ARRAY_ATTRIBUTES_REPORT ),\
+ HID_COLLECTION ( HID_COLLECTION_LOGICAL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_COUNT ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 65535, 3 ),\
+ HID_REPORT_SIZE ( 16 ),\
+ HID_REPORT_COUNT ( 1 ),\
+ HID_FEATURE ( HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BOUNDING_BOX_WIDTH_IN_MICROMETERS ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BOUNDING_BOX_HEIGHT_IN_MICROMETERS ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BOUNDING_BOX_DEPTH_IN_MICROMETERS ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ARRAY_KIND ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_MIN_UPDATE_INTERVAL_IN_MICROSECONDS ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 2147483647, 3 ),\
+ HID_REPORT_SIZE ( 32 ),\
+ HID_REPORT_COUNT ( 5 ),\
+ HID_FEATURE ( HID_CONSTANT | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_COLLECTION_END ,\
+ /* Lamp Attributes Request Report */ \
+ HID_REPORT_ID ( report_id + 1 ) \
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_REQUEST_REPORT ),\
+ HID_COLLECTION ( HID_COLLECTION_LOGICAL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ID ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 65535, 3 ),\
+ HID_REPORT_SIZE ( 16 ),\
+ HID_REPORT_COUNT ( 1 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_COLLECTION_END ,\
+ /* Lamp Attributes Response Report */ \
+ HID_REPORT_ID ( report_id + 2 ) \
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ATTRIBUTES_RESPONSE_REPORT ),\
+ HID_COLLECTION ( HID_COLLECTION_LOGICAL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ID ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 65535, 3 ),\
+ HID_REPORT_SIZE ( 16 ),\
+ HID_REPORT_COUNT ( 1 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_POSITION_X_IN_MICROMETERS ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_POSITION_Y_IN_MICROMETERS ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_POSITION_Z_IN_MICROMETERS ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_UPDATE_LATENCY_IN_MICROSECONDS ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_PURPOSES ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 2147483647, 3 ),\
+ HID_REPORT_SIZE ( 32 ),\
+ HID_REPORT_COUNT ( 5 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_LEVEL_COUNT ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_LEVEL_COUNT ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_LEVEL_COUNT ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_LEVEL_COUNT ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_IS_PROGRAMMABLE ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INPUT_BINDING ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 255, 2 ),\
+ HID_REPORT_SIZE ( 8 ),\
+ HID_REPORT_COUNT ( 6 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_COLLECTION_END ,\
+ /* Lamp Multi-Update Report */ \
+ HID_REPORT_ID ( report_id + 3 ) \
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_MULTI_UPDATE_REPORT ),\
+ HID_COLLECTION ( HID_COLLECTION_LOGICAL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_COUNT ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_UPDATE_FLAGS ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX ( 8 ),\
+ HID_REPORT_SIZE ( 8 ),\
+ HID_REPORT_COUNT ( 2 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ID ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 65535, 3 ),\
+ HID_REPORT_SIZE ( 16 ),\
+ HID_REPORT_COUNT ( 8 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 255, 2 ),\
+ HID_REPORT_SIZE ( 8 ),\
+ HID_REPORT_COUNT ( 32 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_COLLECTION_END ,\
+ /* Lamp Range Update Report */ \
+ HID_REPORT_ID ( report_id + 4 ) \
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_RANGE_UPDATE_REPORT ),\
+ HID_COLLECTION ( HID_COLLECTION_LOGICAL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_UPDATE_FLAGS ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX ( 8 ),\
+ HID_REPORT_SIZE ( 8 ),\
+ HID_REPORT_COUNT ( 1 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ID_START ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ID_END ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 65535, 3 ),\
+ HID_REPORT_SIZE ( 16 ),\
+ HID_REPORT_COUNT ( 2 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_RED_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_GREEN_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_BLUE_UPDATE_CHANNEL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_INTENSITY_UPDATE_CHANNEL ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX_N ( 255, 2 ),\
+ HID_REPORT_SIZE ( 8 ),\
+ HID_REPORT_COUNT ( 4 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_COLLECTION_END ,\
+ /* Lamp Array Control Report */ \
+ HID_REPORT_ID ( report_id + 5 ) \
+ HID_USAGE ( HID_USAGE_LIGHTING_LAMP_ARRAY_CONTROL_REPORT ),\
+ HID_COLLECTION ( HID_COLLECTION_LOGICAL ),\
+ HID_USAGE ( HID_USAGE_LIGHTING_AUTONOMOUS_MODE ),\
+ HID_LOGICAL_MIN ( 0 ),\
+ HID_LOGICAL_MAX ( 1 ),\
+ HID_REPORT_SIZE ( 8 ),\
+ HID_REPORT_COUNT ( 1 ),\
+ HID_FEATURE ( HID_DATA | HID_VARIABLE | HID_ABSOLUTE ),\
+ HID_COLLECTION_END ,\
+ HID_COLLECTION_END \
+
//--------------------------------------------------------------------+
// Internal Class Driver API
//--------------------------------------------------------------------+
@@ -471,6 +645,7 @@ uint16_t hidd_open (uint8_t rhport, tusb_desc_interface_t const * itf
bool hidd_control_xfer_cb (uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
bool hidd_xfer_cb (uint8_t rhport, uint8_t ep_addr, xfer_result_t event, uint32_t xferred_bytes);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/class/msc/msc_device.c b/src/class/msc/msc_device.c
index 588fcaaca..447560b4d 100644
--- a/src/class/msc/msc_device.c
+++ b/src/class/msc/msc_device.c
@@ -689,6 +689,24 @@ static int32_t proc_builtin_scsi(uint8_t lun, uint8_t const scsi_cmd[16], uint8_
}
break;
+ case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
+ resplen = 0;
+
+ if (tud_msc_prevent_allow_medium_removal_cb)
+ {
+ scsi_prevent_allow_medium_removal_t const * prevent_allow = (scsi_prevent_allow_medium_removal_t const *) scsi_cmd;
+ if ( !tud_msc_prevent_allow_medium_removal_cb(lun, prevent_allow->prohibit_removal, prevent_allow->control) )
+ {
+ // Failed status response
+ resplen = - 1;
+
+ // set default sense if not set by callback
+ if ( p_msc->sense_key == 0 ) set_sense_medium_not_present(lun);
+ }
+ }
+ break;
+
+
case SCSI_CMD_READ_CAPACITY_10:
{
uint32_t block_count;
diff --git a/src/class/msc/msc_device.h b/src/class/msc/msc_device.h
index 4247a40bd..29acd280a 100644
--- a/src/class/msc/msc_device.h
+++ b/src/class/msc/msc_device.h
@@ -131,6 +131,9 @@ TU_ATTR_WEAK uint8_t tud_msc_get_maxlun_cb(void);
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
TU_ATTR_WEAK bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject);
+//Invoked when we receive the Prevent / Allow Medium Removal command
+TU_ATTR_WEAK bool tud_msc_prevent_allow_medium_removal_cb(uint8_t lun, uint8_t prohibit_removal, uint8_t control);
+
// Invoked when received REQUEST_SENSE
TU_ATTR_WEAK int32_t tud_msc_request_sense_cb(uint8_t lun, void* buffer, uint16_t bufsize);
diff --git a/src/class/net/ncm.h b/src/class/net/ncm.h
index 96ba11fbc..1b987fca0 100644
--- a/src/class/net/ncm.h
+++ b/src/class/net/ncm.h
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2021, Ha Thach (tinyusb.org)
+ * Copyright (c) 2024, Hardy Griech
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -24,22 +25,58 @@
* This file is part of the TinyUSB stack.
*/
-
#ifndef _TUSB_NCM_H_
#define _TUSB_NCM_H_
#include "common/tusb_common.h"
-#ifdef __cplusplus
- extern "C" {
+// NTB buffers size for reception side, must be >> MTU to avoid TCP retransmission (driver issue ?)
+// Linux use 2048 as minimal size
+#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE
+ #define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200
#endif
-// Table 4.3 Data Class Interface Protocol Codes
-typedef enum
-{
- NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01
-} ncm_data_interface_protocol_code_t;
+// NTB buffers size for reception side, must be > MTU
+// Linux use 2048 as minimal size
+#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE
+ #define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200
+#endif
+
+// Number of NTB buffers for reception side
+// Depending on the configuration, this parameter could be increased with the cost of additional RAM requirements
+// On Full-Speed (RP2040) :
+// 1 - good performance
+// 2 - up to 30% more performance with iperf with small packets
+// >2 - no performance gain
+// On High-Speed (STM32F7) :
+// No performance gain
+#ifndef CFG_TUD_NCM_OUT_NTB_N
+ #define CFG_TUD_NCM_OUT_NTB_N 1
+#endif
+// Number of NTB buffers for transmission side
+// Depending on the configuration, this parameter could be increased with the cost of additional RAM requirements
+// On Full-Speed (RP2040) :
+// 1 - good performance but SystemView shows lost events (on load test)
+// 2 - up to 50% more performance with iperf with small packets, "tud_network_can_xmit: request blocked"
+// happens from time to time with SystemView
+// 3 - "tud_network_can_xmit: request blocked" never happens
+// >3 - no performance gain
+// On High-Speed (STM32F7) :
+// No performance gain
+#ifndef CFG_TUD_NCM_IN_NTB_N
+ #define CFG_TUD_NCM_IN_NTB_N 1
+#endif
+
+// How many datagrams it is allowed to put into an NTB for transmission side
+#ifndef CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB
+ #define CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB 8
+#endif
+
+// This tells the host how many datagrams it is allowed to put into an NTB
+#ifndef CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB
+ #define CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB 6
+#endif
// Table 6.2 Class-Specific Request Codes for Network Control Model subclass
typedef enum
@@ -62,8 +99,65 @@ typedef enum
NCM_SET_CRC_MODE = 0x8A,
} ncm_request_code_t;
-#ifdef __cplusplus
- }
-#endif
+#define NTH16_SIGNATURE 0x484D434E
+#define NDP16_SIGNATURE_NCM0 0x304D434E
+#define NDP16_SIGNATURE_NCM1 0x314D434E
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t wLength;
+ uint16_t bmNtbFormatsSupported;
+ uint32_t dwNtbInMaxSize;
+ uint16_t wNdbInDivisor;
+ uint16_t wNdbInPayloadRemainder;
+ uint16_t wNdbInAlignment;
+ uint16_t wReserved;
+ uint32_t dwNtbOutMaxSize;
+ uint16_t wNdbOutDivisor;
+ uint16_t wNdbOutPayloadRemainder;
+ uint16_t wNdbOutAlignment;
+ uint16_t wNtbOutMaxDatagrams;
+} ntb_parameters_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t dwSignature;
+ uint16_t wHeaderLength;
+ uint16_t wSequence;
+ uint16_t wBlockLength;
+ uint16_t wNdpIndex;
+} nth16_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint16_t wDatagramIndex;
+ uint16_t wDatagramLength;
+} ndp16_datagram_t;
+
+typedef struct TU_ATTR_PACKED {
+ uint32_t dwSignature;
+ uint16_t wLength;
+ uint16_t wNextNdpIndex;
+ //ndp16_datagram_t datagram[];
+} ndp16_t;
+
+typedef union TU_ATTR_PACKED {
+ struct {
+ nth16_t nth;
+ ndp16_t ndp;
+ ndp16_datagram_t ndp_datagram[CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB + 1];
+ };
+ uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE];
+} xmit_ntb_t;
+
+typedef union TU_ATTR_PACKED {
+ struct {
+ nth16_t nth;
+ // only the header is at a guaranteed position
+ };
+ uint8_t data[CFG_TUD_NCM_OUT_NTB_MAX_SIZE];
+} recv_ntb_t;
+
+struct ncm_notify_t {
+ tusb_control_request_t header;
+ uint32_t downlink, uplink;
+};
#endif
diff --git a/src/class/net/ncm_device.c b/src/class/net/ncm_device.c
index f84bd9f73..90d747185 100644
--- a/src/class/net/ncm_device.c
+++ b/src/class/net/ncm_device.c
@@ -1,9 +1,10 @@
/*
* The MIT License (MIT)
*
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Copyright (c) 2024 Hardy Griech
* Copyright (c) 2020 Jacob Berg Potter
* Copyright (c) 2020 Peter Lawrence
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,12 +27,37 @@
* This file is part of the TinyUSB stack.
*/
+/**
+ * Small Glossary (from the spec)
+ * --------------
+ * Datagram - A collection of bytes forming a single item of information, passed as a unit from source to destination.
+ * NCM - Network Control Model
+ * NDP - NCM Datagram Pointer: NTB structure that delineates Datagrams (typically Ethernet frames) within an NTB
+ * NTB - NCM Transfer Block: a data structure for efficient USB encapsulation of one or more datagrams
+ * Each NTB is designed to be a single USB transfer
+ * NTH - NTB Header: a data structure at the front of each NTB, which provides the information needed to validate
+ * the NTB and begin decoding
+ *
+ * Some explanations
+ * -----------------
+ * - rhport is the USB port of the device, in most cases "0"
+ * - itf_data_alt if != 0 -> data xmit/recv are allowed (see spec)
+ * - ep_in IN endpoints take data from the device intended to go in to the host (the device transmits)
+ * - ep_out OUT endpoints send data out of the host to the device (the device receives)
+ */
+
#include "tusb_option.h"
-#if ( CFG_TUD_ENABLED && CFG_TUD_NCM )
+#if (CFG_TUD_ENABLED && CFG_TUD_NCM)
+
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
#include "device/usbd.h"
#include "device/usbd_pvt.h"
+
+#include "ncm.h"
#include "net_device.h"
// Level where CFG_TUSB_DEBUG must be at least for this driver is logged
@@ -41,482 +67,829 @@
#define TU_LOG_DRV(...) TU_LOG(CFG_TUD_NCM_LOG_LEVEL, __VA_ARGS__)
-//--------------------------------------------------------------------+
-// MACRO CONSTANT TYPEDEF
-//--------------------------------------------------------------------+
+// Alignment must be 4
+#define TUD_NCM_ALIGNMENT 4
+// calculate alignment of xmit datagrams within an NTB
+#define XMIT_ALIGN_OFFSET(x) ((TUD_NCM_ALIGNMENT - ((x) & (TUD_NCM_ALIGNMENT - 1))) & (TUD_NCM_ALIGNMENT - 1))
-#define NTH16_SIGNATURE 0x484D434E
-#define NDP16_SIGNATURE_NCM0 0x304D434E
-#define NDP16_SIGNATURE_NCM1 0x314D434E
+//-----------------------------------------------------------------------------
+//
+// Module global things
+//
+#define XMIT_NTB_N CFG_TUD_NCM_IN_NTB_N
+#define RECV_NTB_N CFG_TUD_NCM_OUT_NTB_N
-typedef struct TU_ATTR_PACKED
-{
- uint16_t wLength;
- uint16_t bmNtbFormatsSupported;
- uint32_t dwNtbInMaxSize;
- uint16_t wNdbInDivisor;
- uint16_t wNdbInPayloadRemainder;
- uint16_t wNdbInAlignment;
- uint16_t wReserved;
- uint32_t dwNtbOutMaxSize;
- uint16_t wNdbOutDivisor;
- uint16_t wNdbOutPayloadRemainder;
- uint16_t wNdbOutAlignment;
- uint16_t wNtbOutMaxDatagrams;
-} ntb_parameters_t;
+typedef struct {
+ // general
+ uint8_t ep_in; // endpoint for outgoing datagrams (naming is a little bit confusing)
+ uint8_t ep_out; // endpoint for incoming datagrams (naming is a little bit confusing)
+ uint8_t ep_notif; // endpoint for notifications
+ uint8_t itf_num; // interface number
+ uint8_t itf_data_alt; // ==0 -> no endpoints, i.e. no network traffic, ==1 -> normal operation with two endpoints (spec, chapter 5.3)
+ uint8_t rhport; // storage of \a rhport because some callbacks are done without it
-typedef struct TU_ATTR_PACKED
-{
- uint32_t dwSignature;
- uint16_t wHeaderLength;
- uint16_t wSequence;
- uint16_t wBlockLength;
- uint16_t wNdpIndex;
-} nth16_t;
+ // recv handling
+ CFG_TUSB_MEM_ALIGN recv_ntb_t recv_ntb[RECV_NTB_N]; // actual recv NTBs
+ recv_ntb_t *recv_free_ntb[RECV_NTB_N]; // free list of recv NTBs
+ recv_ntb_t *recv_ready_ntb[RECV_NTB_N]; // NTBs waiting for transmission to glue logic
+ recv_ntb_t *recv_tinyusb_ntb; // buffer for the running transfer TinyUSB -> driver
+ recv_ntb_t *recv_glue_ntb; // buffer for the running transfer driver -> glue logic
+ uint16_t recv_glue_ntb_datagram_ndx; // index into \a recv_glue_ntb_datagram
-typedef struct TU_ATTR_PACKED
-{
- uint16_t wDatagramIndex;
- uint16_t wDatagramLength;
-} ndp16_datagram_t;
+ // xmit handling
+ CFG_TUSB_MEM_ALIGN xmit_ntb_t xmit_ntb[XMIT_NTB_N]; // actual xmit NTBs
+ xmit_ntb_t *xmit_free_ntb[XMIT_NTB_N]; // free list of xmit NTBs
+ xmit_ntb_t *xmit_ready_ntb[XMIT_NTB_N]; // NTBs waiting for transmission to TinyUSB
+ xmit_ntb_t *xmit_tinyusb_ntb; // buffer for the running transfer driver -> TinyUSB
+ xmit_ntb_t *xmit_glue_ntb; // buffer for the running transfer glue logic -> driver
+ uint16_t xmit_sequence; // NTB sequence counter
+ uint16_t xmit_glue_ntb_datagram_ndx; // index into \a xmit_glue_ntb_datagram
-typedef struct TU_ATTR_PACKED
-{
- uint32_t dwSignature;
- uint16_t wLength;
- uint16_t wNextNdpIndex;
- ndp16_datagram_t datagram[];
-} ndp16_t;
+ // notification handling
+ enum {
+ NOTIFICATION_SPEED,
+ NOTIFICATION_CONNECTED,
+ NOTIFICATION_DONE
+ } notification_xmit_state; // state of notification transmission
+ bool notification_xmit_is_running; // notification is currently transmitted
+} ncm_interface_t;
-typedef union TU_ATTR_PACKED {
- struct {
- nth16_t nth;
- ndp16_t ndp;
- };
- uint8_t data[CFG_TUD_NCM_IN_NTB_MAX_SIZE];
-} transmit_ntb_t;
+CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN tu_static ncm_interface_t ncm_interface;
-struct ecm_notify_struct
-{
- tusb_control_request_t header;
- uint32_t downlink, uplink;
+/**
+ * This is the NTB parameter structure
+ *
+ * \attention
+ * We are lucky, that byte order is correct
+ */
+CFG_TUD_MEM_SECTION CFG_TUD_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = {
+ .wLength = sizeof(ntb_parameters_t),
+ .bmNtbFormatsSupported = 0x01,// 16-bit NTB supported
+ .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE,
+ .wNdbInDivisor = 1,
+ .wNdbInPayloadRemainder = 0,
+ .wNdbInAlignment = TUD_NCM_ALIGNMENT,
+ .wReserved = 0,
+ .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE,
+ .wNdbOutDivisor = 1,
+ .wNdbOutPayloadRemainder = 0,
+ .wNdbOutAlignment = TUD_NCM_ALIGNMENT,
+ .wNtbOutMaxDatagrams = CFG_TUD_NCM_OUT_MAX_DATAGRAMS_PER_NTB,
};
-typedef struct
-{
- uint8_t itf_num; // Index number of Management Interface, +1 for Data Interface
- uint8_t itf_data_alt; // Alternate setting of Data Interface. 0 : inactive, 1 : active
+// Some confusing remarks about wNtbOutMaxDatagrams...
+// ==1 -> SystemView packets/s goes up to 2000 and events are lost during startup
+// ==0 -> SystemView runs fine, iperf shows in wireshark a lot of error
+// ==6 -> SystemView runs fine, iperf also
+// >6 -> iperf starts to show errors
+// -> 6 seems to be the best value. Why? Don't know, perhaps only on my system?
+//
+// iperf: for MSS in 100 200 400 800 1200 1450 1500; do iperf -c 192.168.14.1 -e -i 1 -M $MSS -l 8192 -P 1; sleep 2; done
+// sysview: SYSTICKS_PER_SEC=35000, IDLE_US=1000, PRINT_MOD=1000
+//
- uint8_t ep_notif;
- uint8_t ep_in;
- uint8_t ep_out;
+//-----------------------------------------------------------------------------
+//
+// everything about notifications
+//
+tu_static struct ncm_notify_t ncm_notify_connected = {
+ .header = {
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_CLASS,
+ .direction = TUSB_DIR_IN},
+ .bRequest = CDC_NOTIF_NETWORK_CONNECTION,
+ .wValue = 1 /* Connected */,
+ .wLength = 0,
+ },
+};
- const ndp16_t *ndp;
- uint8_t num_datagrams, current_datagram_index;
+tu_static struct ncm_notify_t ncm_notify_speed_change = {
+ .header = {
+ .bmRequestType_bit = {
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
+ .type = TUSB_REQ_TYPE_CLASS,
+ .direction = TUSB_DIR_IN},
+ .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE,
+ .wLength = 8,
+ },
+ .downlink = TUD_OPT_HIGH_SPEED ? 480000000 : 12000000,
+ .uplink = TUD_OPT_HIGH_SPEED ? 480000000 : 12000000,
+};
- enum {
- REPORT_SPEED,
- REPORT_CONNECTED,
- REPORT_DONE
- } report_state;
- bool report_pending;
+/**
+ * Transmit next notification to the host (if appropriate).
+ * Notifications are transferred to the host once during connection setup.
+ */
+static void notification_xmit(uint8_t rhport, bool force_next) {
+ TU_LOG_DRV("notification_xmit(%d, %d) - %d %d\n", force_next, rhport, ncm_interface.notification_xmit_state, ncm_interface.notification_xmit_is_running);
- uint8_t current_ntb; // Index in transmit_ntb[] that is currently being filled with datagrams
- uint8_t datagram_count; // Number of datagrams in transmit_ntb[current_ntb]
- uint16_t next_datagram_offset; // Offset in transmit_ntb[current_ntb].data to place the next datagram
- uint16_t ntb_in_size; // Maximum size of transmitted (IN to host) NTBs; initially CFG_TUD_NCM_IN_NTB_MAX_SIZE
- uint8_t max_datagrams_per_ntb; // Maximum number of datagrams per NTB; initially CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB
+ if (!force_next && ncm_interface.notification_xmit_is_running) {
+ return;
+ }
- uint16_t nth_sequence; // Sequence number counter for transmitted NTBs
+ if (ncm_interface.notification_xmit_state == NOTIFICATION_SPEED) {
+ TU_LOG_DRV(" NOTIFICATION_SPEED\n");
+ ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num;
+ usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change));
+ ncm_interface.notification_xmit_state = NOTIFICATION_CONNECTED;
+ ncm_interface.notification_xmit_is_running = true;
+ } else if (ncm_interface.notification_xmit_state == NOTIFICATION_CONNECTED) {
+ TU_LOG_DRV(" NOTIFICATION_CONNECTED\n");
+ ncm_notify_connected.header.wIndex = ncm_interface.itf_num;
+ usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected));
+ ncm_interface.notification_xmit_state = NOTIFICATION_DONE;
+ ncm_interface.notification_xmit_is_running = true;
+ } else {
+ TU_LOG_DRV(" NOTIFICATION_FINISHED\n");
+ }
+} // notification_xmit
- bool transferring;
+//-----------------------------------------------------------------------------
+//
+// everything about packet transmission (driver -> TinyUSB)
+//
-} ncm_interface_t;
+/**
+ * Put NTB into the transmitter free list.
+ */
+static void xmit_put_ntb_into_free_list(xmit_ntb_t *free_ntb) {
+ TU_LOG_DRV("xmit_put_ntb_into_free_list() - %p\n", ncm_interface.xmit_tinyusb_ntb);
-//--------------------------------------------------------------------+
-// INTERNAL OBJECT & FUNCTION DECLARATION
-//--------------------------------------------------------------------+
+ if (free_ntb == NULL) { // can happen due to ZLPs
+ return;
+ }
-CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static const ntb_parameters_t ntb_parameters = {
- .wLength = sizeof(ntb_parameters_t),
- .bmNtbFormatsSupported = 0x01,
- .dwNtbInMaxSize = CFG_TUD_NCM_IN_NTB_MAX_SIZE,
- .wNdbInDivisor = 4,
- .wNdbInPayloadRemainder = 0,
- .wNdbInAlignment = CFG_TUD_NCM_ALIGNMENT,
- .wReserved = 0,
- .dwNtbOutMaxSize = CFG_TUD_NCM_OUT_NTB_MAX_SIZE,
- .wNdbOutDivisor = 4,
- .wNdbOutPayloadRemainder = 0,
- .wNdbOutAlignment = CFG_TUD_NCM_ALIGNMENT,
- .wNtbOutMaxDatagrams = 0
-};
+ for (int i = 0; i < XMIT_NTB_N; ++i) {
+ if (ncm_interface.xmit_free_ntb[i] == NULL) {
+ ncm_interface.xmit_free_ntb[i] = free_ntb;
+ return;
+ }
+ }
+ TU_LOG_DRV("(EE) xmit_put_ntb_into_free_list - no entry in free list\n");// this should not happen
+} // xmit_put_ntb_into_free_list
-CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static transmit_ntb_t transmit_ntb[2];
+/**
+ * Get an NTB from the free list
+ */
+static xmit_ntb_t *xmit_get_free_ntb(void) {
+ TU_LOG_DRV("xmit_get_free_ntb()\n");
-CFG_TUD_MEM_SECTION CFG_TUSB_MEM_ALIGN tu_static uint8_t receive_ntb[CFG_TUD_NCM_OUT_NTB_MAX_SIZE];
+ for (int i = 0; i < XMIT_NTB_N; ++i) {
+ if (ncm_interface.xmit_free_ntb[i] != NULL) {
+ xmit_ntb_t *free = ncm_interface.xmit_free_ntb[i];
+ ncm_interface.xmit_free_ntb[i] = NULL;
+ return free;
+ }
+ }
+ return NULL;
+} // xmit_get_free_ntb
-tu_static ncm_interface_t ncm_interface;
+/**
+ * Put a filled NTB into the ready list
+ */
+static void xmit_put_ntb_into_ready_list(xmit_ntb_t *ready_ntb) {
+ TU_LOG_DRV("xmit_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength);
-/*
- * Set up the NTB state in ncm_interface to be ready to add datagrams.
+ for (int i = 0; i < XMIT_NTB_N; ++i) {
+ if (ncm_interface.xmit_ready_ntb[i] == NULL) {
+ ncm_interface.xmit_ready_ntb[i] = ready_ntb;
+ return;
+ }
+ }
+ TU_LOG_DRV("(EE) xmit_put_ntb_into_ready_list: ready list full\n");// this should not happen
+} // xmit_put_ntb_into_ready_list
+
+/**
+ * Get the next NTB from the ready list (and remove it from the list).
+ * If the ready list is empty, return NULL.
*/
-static void ncm_prepare_for_tx(void) {
- ncm_interface.datagram_count = 0;
- // datagrams start after all the headers
- ncm_interface.next_datagram_offset = sizeof(nth16_t) + sizeof(ndp16_t)
- + ((CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB + 1) * sizeof(ndp16_datagram_t));
-}
+static xmit_ntb_t *xmit_get_next_ready_ntb(void) {
+ xmit_ntb_t *r = NULL;
-/*
- * If not already transmitting, start sending the current NTB to the host and swap buffers
- * to start filling the other one with datagrams.
+ r = ncm_interface.xmit_ready_ntb[0];
+ memmove(ncm_interface.xmit_ready_ntb + 0, ncm_interface.xmit_ready_ntb + 1, sizeof(ncm_interface.xmit_ready_ntb) - sizeof(ncm_interface.xmit_ready_ntb[0]));
+ ncm_interface.xmit_ready_ntb[XMIT_NTB_N - 1] = NULL;
+
+ TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r);
+ return r;
+} // xmit_get_next_ready_ntb
+
+/**
+ * Transmit a ZLP if required
+ *
+ * \note
+ * Insertion of the ZLPs is a little bit different then described in the spec.
+ * But the below implementation actually works. Don't know if this is a spec
+ * or TinyUSB issue.
+ *
+ * \pre
+ * This must be called from netd_xfer_cb() so that ep_in is ready
*/
-static void ncm_start_tx(void) {
- if (ncm_interface.transferring) {
+static bool xmit_insert_required_zlp(uint8_t rhport, uint32_t xferred_bytes) {
+ TU_LOG_DRV("xmit_insert_required_zlp(%d,%ld)\n", rhport, xferred_bytes);
+
+ if (xferred_bytes == 0 || xferred_bytes % CFG_TUD_NET_ENDPOINT_SIZE != 0) {
+ return false;
+ }
+
+ TU_ASSERT(ncm_interface.itf_data_alt == 1, false);
+ TU_ASSERT(!usbd_edpt_busy(rhport, ncm_interface.ep_in), false);
+
+ TU_LOG_DRV("xmit_insert_required_zlp! (%u)\n", (unsigned) xferred_bytes);
+
+ // start transmission of the ZLP
+ usbd_edpt_xfer(rhport, ncm_interface.ep_in, NULL, 0);
+
+ return true;
+} // xmit_insert_required_zlp
+
+/**
+ * Start transmission if it there is a waiting packet and if can be done from interface side.
+ */
+static void xmit_start_if_possible(uint8_t rhport) {
+ TU_LOG_DRV("xmit_start_if_possible()\n");
+
+ if (ncm_interface.xmit_tinyusb_ntb != NULL) {
+ TU_LOG_DRV(" !xmit_start_if_possible 1\n");
+ return;
+ }
+ if (ncm_interface.itf_data_alt != 1) {
+ TU_LOG_DRV("(EE) !xmit_start_if_possible 2\n");
+ return;
+ }
+ if (usbd_edpt_busy(rhport, ncm_interface.ep_in)) {
+ TU_LOG_DRV(" !xmit_start_if_possible 3\n");
return;
}
- transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb];
- size_t ntb_length = ncm_interface.next_datagram_offset;
+ ncm_interface.xmit_tinyusb_ntb = xmit_get_next_ready_ntb();
+ if (ncm_interface.xmit_tinyusb_ntb == NULL) {
+ if (ncm_interface.xmit_glue_ntb == NULL || ncm_interface.xmit_glue_ntb_datagram_ndx == 0) {
+ // -> really nothing is waiting
+ return;
+ }
+ ncm_interface.xmit_tinyusb_ntb = ncm_interface.xmit_glue_ntb;
+ ncm_interface.xmit_glue_ntb = NULL;
+ }
+
+ #if CFG_TUD_NCM_LOG_LEVEL >= 3
+ {
+ uint16_t len = ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength;
+ TU_LOG_BUF(3, ncm_interface.xmit_tinyusb_ntb->data[i], len);
+ }
+ #endif
+
+ if (ncm_interface.xmit_glue_ntb_datagram_ndx != 1) {
+ TU_LOG_DRV(">> %d %d\n", ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength, ncm_interface.xmit_glue_ntb_datagram_ndx);
+ }
+
+ // Kick off an endpoint transfer
+ usbd_edpt_xfer(0, ncm_interface.ep_in, ncm_interface.xmit_tinyusb_ntb->data, ncm_interface.xmit_tinyusb_ntb->nth.wBlockLength);
+} // xmit_start_if_possible
+
+/**
+ * check if a new datagram fits into the current NTB
+ */
+static bool xmit_requested_datagram_fits_into_current_ntb(uint16_t datagram_size) {
+ TU_LOG_DRV("xmit_requested_datagram_fits_into_current_ntb(%d) - %p %p\n", datagram_size, ncm_interface.xmit_tinyusb_ntb, ncm_interface.xmit_glue_ntb);
+
+ if (ncm_interface.xmit_glue_ntb == NULL) {
+ return false;
+ }
+ if (ncm_interface.xmit_glue_ntb_datagram_ndx >= CFG_TUD_NCM_IN_MAX_DATAGRAMS_PER_NTB) {
+ return false;
+ }
+ if (ncm_interface.xmit_glue_ntb->nth.wBlockLength + datagram_size + XMIT_ALIGN_OFFSET(datagram_size) > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) {
+ return false;
+ }
+ return true;
+} // xmit_requested_datagram_fits_into_current_ntb
+
+/**
+ * Setup an NTB for the glue logic
+ */
+static bool xmit_setup_next_glue_ntb(void) {
+ TU_LOG_DRV("xmit_setup_next_glue_ntb - %p\n", ncm_interface.xmit_glue_ntb);
+
+ if (ncm_interface.xmit_glue_ntb != NULL) {
+ // put NTB into waiting list (the new datagram did not fit in)
+ xmit_put_ntb_into_ready_list(ncm_interface.xmit_glue_ntb);
+ }
+
+ ncm_interface.xmit_glue_ntb = xmit_get_free_ntb();// get next buffer (if any)
+ if (ncm_interface.xmit_glue_ntb == NULL) {
+ TU_LOG_DRV(" xmit_setup_next_glue_ntb - nothing free\n");// should happen rarely
+ return false;
+ }
+
+ ncm_interface.xmit_glue_ntb_datagram_ndx = 0;
+
+ xmit_ntb_t *ntb = ncm_interface.xmit_glue_ntb;
// Fill in NTB header
ntb->nth.dwSignature = NTH16_SIGNATURE;
- ntb->nth.wHeaderLength = sizeof(nth16_t);
- ntb->nth.wSequence = ncm_interface.nth_sequence++;
- ntb->nth.wBlockLength = ntb_length;
- ntb->nth.wNdpIndex = sizeof(nth16_t);
+ ntb->nth.wHeaderLength = sizeof(ntb->nth);
+ ntb->nth.wSequence = ncm_interface.xmit_sequence++;
+ ntb->nth.wBlockLength = sizeof(ntb->nth) + sizeof(ntb->ndp) + sizeof(ntb->ndp_datagram);
+ ntb->nth.wNdpIndex = sizeof(ntb->nth);
// Fill in NDP16 header and terminator
ntb->ndp.dwSignature = NDP16_SIGNATURE_NCM0;
- ntb->ndp.wLength = sizeof(ndp16_t) + (ncm_interface.datagram_count + 1) * sizeof(ndp16_datagram_t);
+ ntb->ndp.wLength = sizeof(ntb->ndp) + sizeof(ntb->ndp_datagram);
ntb->ndp.wNextNdpIndex = 0;
- ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = 0;
- ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = 0;
-
- // Kick off an endpoint transfer
- usbd_edpt_xfer(0, ncm_interface.ep_in, ntb->data, ntb_length);
- ncm_interface.transferring = true;
- // Swap to the other NTB and clear it out
- ncm_interface.current_ntb = 1 - ncm_interface.current_ntb;
- ncm_prepare_for_tx();
-}
+ memset(ntb->ndp_datagram, 0, sizeof(ntb->ndp_datagram));
+ return true;
+} // xmit_setup_next_glue_ntb
-tu_static struct ecm_notify_struct ncm_notify_connected =
-{
- .header = {
- .bmRequestType_bit = {
- .recipient = TUSB_REQ_RCPT_INTERFACE,
- .type = TUSB_REQ_TYPE_CLASS,
- .direction = TUSB_DIR_IN
- },
- .bRequest = CDC_NOTIF_NETWORK_CONNECTION,
- .wValue = 1 /* Connected */,
- .wLength = 0,
- },
-};
+//-----------------------------------------------------------------------------
+//
+// all the recv_*() stuff (TinyUSB -> driver -> glue logic)
+//
-tu_static struct ecm_notify_struct ncm_notify_speed_change =
-{
- .header = {
- .bmRequestType_bit = {
- .recipient = TUSB_REQ_RCPT_INTERFACE,
- .type = TUSB_REQ_TYPE_CLASS,
- .direction = TUSB_DIR_IN
- },
- .bRequest = CDC_NOTIF_CONNECTION_SPEED_CHANGE,
- .wLength = 8,
- },
- .downlink = 10000000,
- .uplink = 10000000,
-};
+/**
+ * Return pointer to an available receive buffer or NULL.
+ * Returned buffer (if any) has the size \a CFG_TUD_NCM_OUT_NTB_MAX_SIZE.
+ */
+static recv_ntb_t *recv_get_free_ntb(void) {
+ TU_LOG_DRV("recv_get_free_ntb()\n");
-void tud_network_recv_renew(void)
-{
- if (!ncm_interface.num_datagrams)
- {
- usbd_edpt_xfer(0, ncm_interface.ep_out, receive_ntb, sizeof(receive_ntb));
- return;
+ for (int i = 0; i < RECV_NTB_N; ++i) {
+ if (ncm_interface.recv_free_ntb[i] != NULL) {
+ recv_ntb_t *free = ncm_interface.recv_free_ntb[i];
+ ncm_interface.recv_free_ntb[i] = NULL;
+ return free;
+ }
}
+ return NULL;
+} // recv_get_free_ntb
- const ndp16_t *ndp = ncm_interface.ndp;
- const int i = ncm_interface.current_datagram_index;
- ncm_interface.current_datagram_index++;
- ncm_interface.num_datagrams--;
+/**
+ * Get the next NTB from the ready list (and remove it from the list).
+ * If the ready list is empty, return NULL.
+ */
+static recv_ntb_t *recv_get_next_ready_ntb(void) {
+ recv_ntb_t *r = NULL;
- tud_network_recv_cb(receive_ntb + ndp->datagram[i].wDatagramIndex, ndp->datagram[i].wDatagramLength);
-}
+ r = ncm_interface.recv_ready_ntb[0];
+ memmove(ncm_interface.recv_ready_ntb + 0, ncm_interface.recv_ready_ntb + 1, sizeof(ncm_interface.recv_ready_ntb) - sizeof(ncm_interface.recv_ready_ntb[0]));
+ ncm_interface.recv_ready_ntb[RECV_NTB_N - 1] = NULL;
-//--------------------------------------------------------------------+
-// USBD Driver API
-//--------------------------------------------------------------------+
+ TU_LOG_DRV("recv_get_next_ready_ntb: %p\n", r);
+ return r;
+} // recv_get_next_ready_ntb
-void netd_init(void)
-{
- tu_memclr(&ncm_interface, sizeof(ncm_interface));
- ncm_interface.ntb_in_size = CFG_TUD_NCM_IN_NTB_MAX_SIZE;
- ncm_interface.max_datagrams_per_ntb = CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB;
- ncm_prepare_for_tx();
-}
+/**
+ * Put NTB into the receiver free list.
+ */
+static void recv_put_ntb_into_free_list(recv_ntb_t *free_ntb) {
+ TU_LOG_DRV("recv_put_ntb_into_free_list(%p)\n", free_ntb);
-bool netd_deinit(void) {
- return true;
-}
+ for (int i = 0; i < RECV_NTB_N; ++i) {
+ if (ncm_interface.recv_free_ntb[i] == NULL) {
+ ncm_interface.recv_free_ntb[i] = free_ntb;
+ return;
+ }
+ }
+ TU_LOG_DRV("(EE) recv_put_ntb_into_free_list - no entry in free list\n");// this should not happen
+} // recv_put_ntb_into_free_list
-void netd_reset(uint8_t rhport)
-{
- (void) rhport;
+/**
+ * \a ready_ntb holds a validated NTB,
+ * put this buffer into the waiting list.
+ */
+static void recv_put_ntb_into_ready_list(recv_ntb_t *ready_ntb) {
+ TU_LOG_DRV("recv_put_ntb_into_ready_list(%p) %d\n", ready_ntb, ready_ntb->nth.wBlockLength);
- netd_init();
-}
+ for (int i = 0; i < RECV_NTB_N; ++i) {
+ if (ncm_interface.recv_ready_ntb[i] == NULL) {
+ ncm_interface.recv_ready_ntb[i] = ready_ntb;
+ return;
+ }
+ }
+ TU_LOG_DRV("(EE) recv_put_ntb_into_ready_list: ready list full\n");// this should not happen
+} // recv_put_ntb_into_ready_list
-uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const * itf_desc, uint16_t max_len)
-{
- // confirm interface hasn't already been allocated
- TU_ASSERT(0 == ncm_interface.ep_notif, 0);
+/**
+ * If possible, start a new reception TinyUSB -> driver.
+ */
+static void recv_try_to_start_new_reception(uint8_t rhport) {
+ TU_LOG_DRV("recv_try_to_start_new_reception(%d)\n", rhport);
- //------------- Management Interface -------------//
- ncm_interface.itf_num = itf_desc->bInterfaceNumber;
+ if (ncm_interface.itf_data_alt != 1) {
+ return;
+ }
+ if (ncm_interface.recv_tinyusb_ntb != NULL) {
+ return;
+ }
+ if (usbd_edpt_busy(rhport, ncm_interface.ep_out)) {
+ return;
+ }
- uint16_t drv_len = sizeof(tusb_desc_interface_t);
- uint8_t const * p_desc = tu_desc_next( itf_desc );
+ ncm_interface.recv_tinyusb_ntb = recv_get_free_ntb();
+ if (ncm_interface.recv_tinyusb_ntb == NULL) {
+ return;
+ }
- // Communication Functional Descriptors
- while ( TUSB_DESC_CS_INTERFACE == tu_desc_type(p_desc) && drv_len <= max_len )
- {
- drv_len += tu_desc_len(p_desc);
- p_desc = tu_desc_next(p_desc);
+ // initiate transfer
+ TU_LOG_DRV(" start reception\n");
+ bool r = usbd_edpt_xfer(rhport, ncm_interface.ep_out, ncm_interface.recv_tinyusb_ntb->data, CFG_TUD_NCM_OUT_NTB_MAX_SIZE);
+ if (!r) {
+ recv_put_ntb_into_free_list(ncm_interface.recv_tinyusb_ntb);
+ ncm_interface.recv_tinyusb_ntb = NULL;
}
+} // recv_try_to_start_new_reception
- // notification endpoint (if any)
- if ( TUSB_DESC_ENDPOINT == tu_desc_type(p_desc) )
- {
- TU_ASSERT( usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0 );
+/**
+ * Validate incoming datagram.
+ * \return true if valid
+ *
+ * \note
+ * \a ndp16->wNextNdpIndex != 0 is not supported
+ */
+static bool recv_validate_datagram(const recv_ntb_t *ntb, uint32_t len) {
+ const nth16_t *nth16 = &(ntb->nth);
- ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
+ TU_LOG_DRV("recv_validate_datagram(%p, %d)\n", ntb, (int) len);
- drv_len += tu_desc_len(p_desc);
- p_desc = tu_desc_next(p_desc);
+ // check header
+ if (nth16->wHeaderLength != sizeof(nth16_t)) {
+ TU_LOG_DRV("(EE) ill nth16 length: %d\n", nth16->wHeaderLength);
+ return false;
+ }
+ if (nth16->dwSignature != NTH16_SIGNATURE) {
+ TU_LOG_DRV("(EE) ill signature: 0x%08x\n", (unsigned) nth16->dwSignature);
+ return false;
+ }
+ if (len < sizeof(nth16_t) + sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t)) {
+ TU_LOG_DRV("(EE) ill min len: %lu\n", len);
+ return false;
+ }
+ if (nth16->wBlockLength > len) {
+ TU_LOG_DRV("(EE) ill block length: %d > %lu\n", nth16->wBlockLength, len);
+ return false;
+ }
+ if (nth16->wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) {
+ TU_LOG_DRV("(EE) ill block length2: %d > %d\n", nth16->wBlockLength, CFG_TUD_NCM_OUT_NTB_MAX_SIZE);
+ return false;
+ }
+ if (nth16->wNdpIndex < sizeof(nth16) || nth16->wNdpIndex > len - (sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t))) {
+ TU_LOG_DRV("(EE) ill position of first ndp: %d (%lu)\n", nth16->wNdpIndex, len);
+ return false;
}
- //------------- Data Interface -------------//
- // - CDC-NCM data interface has 2 alternate settings
- // - 0 : zero endpoints for inactive (default)
- // - 1 : IN & OUT endpoints for transfer of NTBs
- TU_ASSERT(TUSB_DESC_INTERFACE == tu_desc_type(p_desc), 0);
+ // check (first) NDP(16)
+ const ndp16_t *ndp16 = (const ndp16_t *) (ntb->data + nth16->wNdpIndex);
- do
- {
- tusb_desc_interface_t const * data_itf_desc = (tusb_desc_interface_t const *) p_desc;
- TU_ASSERT(TUSB_CLASS_CDC_DATA == data_itf_desc->bInterfaceClass, 0);
+ if (ndp16->wLength < sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t)) {
+ TU_LOG_DRV("(EE) ill ndp16 length: %d\n", ndp16->wLength);
+ return false;
+ }
+ if (ndp16->dwSignature != NDP16_SIGNATURE_NCM0 && ndp16->dwSignature != NDP16_SIGNATURE_NCM1) {
+ TU_LOG_DRV("(EE) ill signature: 0x%08x\n", (unsigned) ndp16->dwSignature);
+ return false;
+ }
+ if (ndp16->wNextNdpIndex != 0) {
+ TU_LOG_DRV("(EE) cannot handle wNextNdpIndex!=0 (%d)\n", ndp16->wNextNdpIndex);
+ return false;
+ }
- drv_len += tu_desc_len(p_desc);
- p_desc = tu_desc_next(p_desc);
- } while((TUSB_DESC_INTERFACE == tu_desc_type(p_desc)) && (drv_len <= max_len));
+ const ndp16_datagram_t *ndp16_datagram = (const ndp16_datagram_t *) (ntb->data + nth16->wNdpIndex + sizeof(ndp16_t));
+ int ndx = 0;
+ uint16_t max_ndx = (uint16_t) ((ndp16->wLength - sizeof(ndp16_t)) / sizeof(ndp16_datagram_t));
- // Pair of endpoints
- TU_ASSERT(TUSB_DESC_ENDPOINT == tu_desc_type(p_desc), 0);
+ if (max_ndx > 2) { // number of datagrams in NTB > 1
+ TU_LOG_DRV("<< %d (%d)\n", max_ndx - 1, ntb->nth.wBlockLength);
+ }
+ if (ndp16_datagram[max_ndx - 1].wDatagramIndex != 0 || ndp16_datagram[max_ndx - 1].wDatagramLength != 0) {
+ TU_LOG_DRV(" max_ndx != 0\n");
+ return false;
+ }
+ while (ndp16_datagram[ndx].wDatagramIndex != 0 && ndp16_datagram[ndx].wDatagramLength != 0) {
+ TU_LOG_DRV(" << %d %d\n", ndp16_datagram[ndx].wDatagramIndex, ndp16_datagram[ndx].wDatagramLength);
+ if (ndp16_datagram[ndx].wDatagramIndex > len) {
+ TU_LOG_DRV("(EE) ill start of datagram[%d]: %d (%lu)\n", ndx, ndp16_datagram[ndx].wDatagramIndex, len);
+ return false;
+ }
+ if (ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength > len) {
+ TU_LOG_DRV("(EE) ill end of datagram[%d]: %d (%lu)\n", ndx, ndp16_datagram[ndx].wDatagramIndex + ndp16_datagram[ndx].wDatagramLength, len);
+ return false;
+ }
+ ++ndx;
+ }
- TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in) );
+ #if CFG_TUD_NCM_LOG_LEVEL >= 3
+ TU_LOG_BUF(3, ntb->data[i], len);
+ #endif
- drv_len += 2*sizeof(tusb_desc_endpoint_t);
+ // -> ntb contains a valid packet structure
+ // ok... I did not check for garbage within the datagram indices...
+ return true;
+} // recv_validate_datagram
- return drv_len;
-}
+/**
+ * Transfer the next (pending) datagram to the glue logic and return receive buffer if empty.
+ */
+static void recv_transfer_datagram_to_glue_logic(void) {
+ TU_LOG_DRV("recv_transfer_datagram_to_glue_logic()\n");
-static void ncm_report(void)
-{
- uint8_t const rhport = 0;
- if (ncm_interface.report_state == REPORT_SPEED) {
- ncm_notify_speed_change.header.wIndex = ncm_interface.itf_num;
- usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_speed_change, sizeof(ncm_notify_speed_change));
- ncm_interface.report_state = REPORT_CONNECTED;
- ncm_interface.report_pending = true;
- } else if (ncm_interface.report_state == REPORT_CONNECTED) {
- ncm_notify_connected.header.wIndex = ncm_interface.itf_num;
- usbd_edpt_xfer(rhport, ncm_interface.ep_notif, (uint8_t *) &ncm_notify_connected, sizeof(ncm_notify_connected));
- ncm_interface.report_state = REPORT_DONE;
- ncm_interface.report_pending = true;
+ if (ncm_interface.recv_glue_ntb == NULL) {
+ ncm_interface.recv_glue_ntb = recv_get_next_ready_ntb();
+ TU_LOG_DRV(" new buffer for glue logic: %p\n", ncm_interface.recv_glue_ntb);
+ ncm_interface.recv_glue_ntb_datagram_ndx = 0;
}
-}
-TU_ATTR_WEAK void tud_network_link_state_cb(bool state)
-{
- (void)state;
-}
+ if (ncm_interface.recv_glue_ntb != NULL) {
+ const ndp16_datagram_t *ndp16_datagram = (ndp16_datagram_t *) (ncm_interface.recv_glue_ntb->data + ncm_interface.recv_glue_ntb->nth.wNdpIndex + sizeof(ndp16_t));
-// Handle class control request
-// return false to stall control endpoint (e.g unsupported request)
-bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
-{
- if ( stage != CONTROL_STAGE_SETUP ) return true;
+ if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex == 0) {
+ TU_LOG_DRV("(EE) SOMETHING WENT WRONG 1\n");
+ } else if (ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength == 0) {
+ TU_LOG_DRV("(EE) SOMETHING WENT WRONG 2\n");
+ } else {
+ uint16_t datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramIndex;
+ uint16_t datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx].wDatagramLength;
- switch ( request->bmRequestType_bit.type )
- {
- case TUSB_REQ_TYPE_STANDARD:
- switch ( request->bRequest )
- {
- case TUSB_REQ_GET_INTERFACE:
- {
- uint8_t const req_itfnum = (uint8_t) request->wIndex;
- TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum);
+ TU_LOG_DRV(" recv[%d] - %d %d\n", ncm_interface.recv_glue_ntb_datagram_ndx, datagramIndex, datagramLength);
+ if (tud_network_recv_cb(ncm_interface.recv_glue_ntb->data + datagramIndex, datagramLength)) {
+ // send datagram successfully to glue logic
+ TU_LOG_DRV(" OK\n");
+ datagramIndex = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramIndex;
+ datagramLength = ndp16_datagram[ncm_interface.recv_glue_ntb_datagram_ndx + 1].wDatagramLength;
- tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1);
+ if (datagramIndex != 0 && datagramLength != 0) {
+ // -> next datagram
+ ++ncm_interface.recv_glue_ntb_datagram_ndx;
+ } else {
+ // end of datagrams reached
+ recv_put_ntb_into_free_list(ncm_interface.recv_glue_ntb);
+ ncm_interface.recv_glue_ntb = NULL;
}
- break;
+ }
+ }
+ }
+} // recv_transfer_datagram_to_glue_logic
- case TUSB_REQ_SET_INTERFACE:
- {
- uint8_t const req_itfnum = (uint8_t) request->wIndex;
- uint8_t const req_alt = (uint8_t) request->wValue;
+//-----------------------------------------------------------------------------
+//
+// all the tud_network_*() stuff (glue logic -> driver)
+//
- // Only valid for Data Interface with Alternate is either 0 or 1
- TU_VERIFY(ncm_interface.itf_num + 1 == req_itfnum && req_alt < 2);
+/**
+ * Check if the glue logic is allowed to call tud_network_xmit().
+ * This function also fetches a next buffer if required, so that tud_network_xmit() is ready for copy
+ * and transmission operation.
+ */
+bool tud_network_can_xmit(uint16_t size) {
+ TU_LOG_DRV("tud_network_can_xmit(%d)\n", size);
- if (req_alt != ncm_interface.itf_data_alt) {
- ncm_interface.itf_data_alt = req_alt;
+ TU_ASSERT(size <= CFG_TUD_NCM_OUT_NTB_MAX_SIZE - (sizeof(nth16_t) + sizeof(ndp16_t) + 2 * sizeof(ndp16_datagram_t)), false);
- if (ncm_interface.itf_data_alt) {
- if (!usbd_edpt_busy(rhport, ncm_interface.ep_out)) {
- tud_network_recv_renew(); // prepare for incoming datagrams
- }
- if (!ncm_interface.report_pending) {
- ncm_report();
- }
- }
+ if (xmit_requested_datagram_fits_into_current_ntb(size) || xmit_setup_next_glue_ntb()) {
+ // -> everything is fine
+ return true;
+ }
+ xmit_start_if_possible(ncm_interface.rhport);
+ TU_LOG_DRV("(II) tud_network_can_xmit: request blocked\n");// could happen if all xmit buffers are full (but should happen rarely)
+ return false;
+} // tud_network_can_xmit
- tud_network_link_state_cb(ncm_interface.itf_data_alt);
- }
+/**
+ * Put a datagram into a waiting NTB.
+ * If currently no transmission is started, then initiate transmission.
+ */
+void tud_network_xmit(void *ref, uint16_t arg) {
+ TU_LOG_DRV("tud_network_xmit(%p, %d)\n", ref, arg);
- tud_control_status(rhport, request);
- }
- break;
+ if (ncm_interface.xmit_glue_ntb == NULL) {
+ TU_LOG_DRV("(EE) tud_network_xmit: no buffer\n");// must not happen (really)
+ return;
+ }
- // unsupported request
- default: return false;
- }
- break;
+ xmit_ntb_t *ntb = ncm_interface.xmit_glue_ntb;
- case TUSB_REQ_TYPE_CLASS:
- TU_VERIFY (ncm_interface.itf_num == request->wIndex);
+ // copy new datagram to the end of the current NTB
+ uint16_t size = tud_network_xmit_cb(ntb->data + ntb->nth.wBlockLength, ref, arg);
- if (NCM_GET_NTB_PARAMETERS == request->bRequest)
- {
- tud_control_xfer(rhport, request, (void*)(uintptr_t) &ntb_parameters, sizeof(ntb_parameters));
- }
+ // correct NTB internals
+ ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramIndex = ntb->nth.wBlockLength;
+ ntb->ndp_datagram[ncm_interface.xmit_glue_ntb_datagram_ndx].wDatagramLength = size;
+ ncm_interface.xmit_glue_ntb_datagram_ndx += 1;
- break;
+ ntb->nth.wBlockLength += (uint16_t) (size + XMIT_ALIGN_OFFSET(size));
- // unsupported request
- default: return false;
+ if (ntb->nth.wBlockLength > CFG_TUD_NCM_OUT_NTB_MAX_SIZE) {
+ TU_LOG_DRV("(EE) tud_network_xmit: buffer overflow\n"); // must not happen (really)
+ return;
}
- return true;
-}
+ xmit_start_if_possible(ncm_interface.rhport);
+} // tud_network_xmit
-static void handle_incoming_datagram(uint32_t len)
-{
- uint32_t size = len;
+/**
+ * Keep the receive logic busy and transfer pending packets to the glue logic.
+ */
+void tud_network_recv_renew(void) {
+ TU_LOG_DRV("tud_network_recv_renew()\n");
- if (len == 0) {
- return;
- }
+ recv_transfer_datagram_to_glue_logic();
+ recv_try_to_start_new_reception(ncm_interface.rhport);
+} // tud_network_recv_renew
- TU_ASSERT(size >= sizeof(nth16_t), );
+/**
+ * Same as tud_network_recv_renew() but knows \a rhport
+ */
+void tud_network_recv_renew_r(uint8_t rhport) {
+ TU_LOG_DRV("tud_network_recv_renew_r(%d)\n", rhport);
- const nth16_t *hdr = (const nth16_t *)receive_ntb;
- TU_ASSERT(hdr->dwSignature == NTH16_SIGNATURE, );
- TU_ASSERT(hdr->wNdpIndex >= sizeof(nth16_t) && (hdr->wNdpIndex + sizeof(ndp16_t)) <= len, );
+ ncm_interface.rhport = rhport;
+ tud_network_recv_renew();
+} // tud_network_recv_renew
- const ndp16_t *ndp = (const ndp16_t *)(receive_ntb + hdr->wNdpIndex);
- TU_ASSERT(ndp->dwSignature == NDP16_SIGNATURE_NCM0 || ndp->dwSignature == NDP16_SIGNATURE_NCM1, );
- TU_ASSERT(hdr->wNdpIndex + ndp->wLength <= len, );
+//-----------------------------------------------------------------------------
+//
+// all the netd_*() stuff (interface TinyUSB -> driver)
+//
+/**
+ * Initialize the driver data structures.
+ * Might be called several times.
+ */
+void netd_init(void) {
+ TU_LOG_DRV("netd_init()\n");
- int num_datagrams = (ndp->wLength - 12) / 4;
- ncm_interface.current_datagram_index = 0;
- ncm_interface.num_datagrams = 0;
- ncm_interface.ndp = ndp;
- for (int i = 0; i < num_datagrams && ndp->datagram[i].wDatagramIndex && ndp->datagram[i].wDatagramLength; i++)
- {
- ncm_interface.num_datagrams++;
+ memset(&ncm_interface, 0, sizeof(ncm_interface));
+
+ for (int i = 0; i < XMIT_NTB_N; ++i) {
+ ncm_interface.xmit_free_ntb[i] = ncm_interface.xmit_ntb + i;
}
+ for (int i = 0; i < RECV_NTB_N; ++i) {
+ ncm_interface.recv_free_ntb[i] = ncm_interface.recv_ntb + i;
+ }
+} // netd_init
- tud_network_recv_renew();
+/**
+ * Deinit driver
+ */
+bool netd_deinit(void) {
+ return true;
}
-bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
-{
+/**
+ * Resets the port.
+ * In this driver this is the same as netd_init()
+ */
+void netd_reset(uint8_t rhport) {
(void) rhport;
- (void) result;
- /* new datagram receive_ntb */
- if (ep_addr == ncm_interface.ep_out )
- {
- handle_incoming_datagram(xferred_bytes);
- }
+ netd_init();
+} // netd_reset
- /* data transmission finished */
- if (ep_addr == ncm_interface.ep_in )
- {
- if (ncm_interface.transferring) {
- ncm_interface.transferring = false;
- }
+/**
+ * Open the USB interface.
+ * - parse the USB descriptor \a TUD_CDC_NCM_DESCRIPTOR for itfnum and endpoints
+ * - a specific order of elements in the descriptor is tested.
+ *
+ * \note
+ * Actually all of the information could be read directly from \a itf_desc, because the
+ * structure and the values are well known. But we do it this way.
+ *
+ * \post
+ * - \a itf_num set
+ * - \a ep_notif, \a ep_in and \a ep_out are set
+ * - USB interface is open
+ */
+uint16_t netd_open(uint8_t rhport, tusb_desc_interface_t const *itf_desc, uint16_t max_len) {
+ TU_ASSERT(ncm_interface.ep_notif == 0, 0);// assure that the interface is only opened once
- // If there are datagrams queued up that we tried to send while this NTB was being emitted, send them now
- if (ncm_interface.datagram_count && ncm_interface.itf_data_alt == 1) {
- ncm_start_tx();
- }
- }
+ ncm_interface.itf_num = itf_desc->bInterfaceNumber;// management interface
- if (ep_addr == ncm_interface.ep_notif )
- {
- ncm_interface.report_pending = false;
- ncm_report();
+ // skip the two first entries and the following TUSB_DESC_CS_INTERFACE entries
+ uint16_t drv_len = sizeof(tusb_desc_interface_t);
+ uint8_t const *p_desc = tu_desc_next(itf_desc);
+ while (tu_desc_type(p_desc) == TUSB_DESC_CS_INTERFACE && drv_len <= max_len) {
+ drv_len += tu_desc_len(p_desc);
+ p_desc = tu_desc_next(p_desc);
}
- return true;
-}
+ // get notification endpoint
+ TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0);
+ TU_ASSERT(usbd_edpt_open(rhport, (tusb_desc_endpoint_t const *) p_desc), 0);
+ ncm_interface.ep_notif = ((tusb_desc_endpoint_t const *) p_desc)->bEndpointAddress;
+ drv_len += tu_desc_len(p_desc);
+ p_desc = tu_desc_next(p_desc);
-// poll network driver for its ability to accept another packet to transmit
-bool tud_network_can_xmit(uint16_t size)
-{
- TU_VERIFY(ncm_interface.itf_data_alt == 1);
+ // skip the following TUSB_DESC_INTERFACE entries (which must be TUSB_CLASS_CDC_DATA)
+ while (tu_desc_type(p_desc) == TUSB_DESC_INTERFACE && drv_len <= max_len) {
+ tusb_desc_interface_t const *data_itf_desc = (tusb_desc_interface_t const *) p_desc;
+ TU_ASSERT(data_itf_desc->bInterfaceClass == TUSB_CLASS_CDC_DATA, 0);
- if (ncm_interface.datagram_count >= ncm_interface.max_datagrams_per_ntb) {
- TU_LOG_DRV("NTB full [by count]\r\n");
- return false;
+ drv_len += tu_desc_len(p_desc);
+ p_desc = tu_desc_next(p_desc);
}
- size_t next_datagram_offset = ncm_interface.next_datagram_offset;
- if (next_datagram_offset + size > ncm_interface.ntb_in_size) {
- TU_LOG_DRV("ntb full [by size]\r\n");
- return false;
+ // a TUSB_DESC_ENDPOINT (actually two) must follow, open these endpoints
+ TU_ASSERT(tu_desc_type(p_desc) == TUSB_DESC_ENDPOINT, 0);
+ TU_ASSERT(usbd_open_edpt_pair(rhport, p_desc, 2, TUSB_XFER_BULK, &ncm_interface.ep_out, &ncm_interface.ep_in));
+ drv_len += 2 * sizeof(tusb_desc_endpoint_t);
+
+ return drv_len;
+} // netd_open
+
+/**
+ * Handle TinyUSB requests to process transfer events.
+ */
+bool netd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes) {
+ (void) result;
+
+ if (ep_addr == ncm_interface.ep_out) {
+ // new NTB received
+ // - make the NTB valid
+ // - if ready transfer datagrams to the glue logic for further processing
+ // - if there is a free receive buffer, initiate reception
+ if (!recv_validate_datagram(ncm_interface.recv_tinyusb_ntb, xferred_bytes)) {
+ // verification failed: ignore NTB and return it to free
+ TU_LOG_DRV("(EE) VALIDATION FAILED. WHAT CAN WE DO IN THIS CASE?\n");
+ } else {
+ // packet ok -> put it into ready list
+ recv_put_ntb_into_ready_list(ncm_interface.recv_tinyusb_ntb);
+ }
+ ncm_interface.recv_tinyusb_ntb = NULL;
+ tud_network_recv_renew_r(rhport);
+ } else if (ep_addr == ncm_interface.ep_in) {
+ // transmission of an NTB finished
+ // - free the transmitted NTB buffer
+ // - insert ZLPs when necessary
+ // - if there is another transmit NTB waiting, try to start transmission
+ xmit_put_ntb_into_free_list(ncm_interface.xmit_tinyusb_ntb);
+ ncm_interface.xmit_tinyusb_ntb = NULL;
+ if (!xmit_insert_required_zlp(rhport, xferred_bytes)) {
+ xmit_start_if_possible(rhport);
+ }
+ } else if (ep_addr == ncm_interface.ep_notif) {
+ // next transfer on notification channel
+ notification_xmit(rhport, true);
}
return true;
-}
+} // netd_xfer_cb
-void tud_network_xmit(void *ref, uint16_t arg)
-{
- transmit_ntb_t *ntb = &transmit_ntb[ncm_interface.current_ntb];
- size_t next_datagram_offset = ncm_interface.next_datagram_offset;
+/**
+ * Respond to TinyUSB control requests.
+ * At startup transmission of notification packets are done here.
+ */
+bool netd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const *request) {
+ if (stage != CONTROL_STAGE_SETUP) {
+ return true;
+ }
- uint16_t size = tud_network_xmit_cb(ntb->data + next_datagram_offset, ref, arg);
+ switch (request->bmRequestType_bit.type) {
+ case TUSB_REQ_TYPE_STANDARD:
- ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramIndex = ncm_interface.next_datagram_offset;
- ntb->ndp.datagram[ncm_interface.datagram_count].wDatagramLength = size;
+ switch (request->bRequest) {
+ case TUSB_REQ_GET_INTERFACE: {
+ TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex, false);
- ncm_interface.datagram_count++;
- next_datagram_offset += size;
+ tud_control_xfer(rhport, request, &ncm_interface.itf_data_alt, 1);
+ } break;
- // round up so the next datagram is aligned correctly
- next_datagram_offset += (CFG_TUD_NCM_ALIGNMENT - 1);
- next_datagram_offset -= (next_datagram_offset % CFG_TUD_NCM_ALIGNMENT);
+ case TUSB_REQ_SET_INTERFACE: {
+ TU_VERIFY(ncm_interface.itf_num + 1 == request->wIndex && request->wValue < 2, false);
- ncm_interface.next_datagram_offset = next_datagram_offset;
+ ncm_interface.itf_data_alt = (uint8_t) request->wValue;
- ncm_start_tx();
-}
+ if (ncm_interface.itf_data_alt == 1) {
+ tud_network_recv_renew_r(rhport);
+ notification_xmit(rhport, false);
+ }
+ tud_control_status(rhport, request);
+ } break;
-#endif
+ // unsupported request
+ default:
+ return false;
+ }
+ break;
+
+ case TUSB_REQ_TYPE_CLASS:
+ TU_VERIFY(ncm_interface.itf_num == request->wIndex, false);
+ switch (request->bRequest) {
+ case NCM_GET_NTB_PARAMETERS: {
+ // transfer NTB parameters to host.
+ tud_control_xfer(rhport, request, (void *) (uintptr_t) &ntb_parameters, sizeof(ntb_parameters));
+ } break;
+
+ // unsupported request
+ default:
+ return false;
+ }
+ break;
+ // unsupported request
+ default:
+ return false;
+ }
+
+ return true;
+} // netd_control_xfer_cb
+
+#endif // ( CFG_TUD_ENABLED && CFG_TUD_NCM )
diff --git a/src/class/net/net_device.h b/src/class/net/net_device.h
index da1a7b1e8..4c9a92f2d 100644
--- a/src/class/net/net_device.h
+++ b/src/class/net/net_device.h
@@ -28,14 +28,13 @@
#ifndef _TUSB_NET_DEVICE_H_
#define _TUSB_NET_DEVICE_H_
+#include <stdint.h>
#include "class/cdc/cdc.h"
#if CFG_TUD_ECM_RNDIS && CFG_TUD_NCM
#error "Cannot enable both ECM_RNDIS and NCM network drivers"
#endif
-#include "ncm.h"
-
/* declared here, NOT in usb_descriptors.c, so that the driver can intelligently ZLP as needed */
#define CFG_TUD_NET_ENDPOINT_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
@@ -44,21 +43,13 @@
#define CFG_TUD_NET_MTU 1514
#endif
-#ifndef CFG_TUD_NCM_IN_NTB_MAX_SIZE
-#define CFG_TUD_NCM_IN_NTB_MAX_SIZE 3200
-#endif
-
-#ifndef CFG_TUD_NCM_OUT_NTB_MAX_SIZE
-#define CFG_TUD_NCM_OUT_NTB_MAX_SIZE 3200
-#endif
-#ifndef CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB
-#define CFG_TUD_NCM_MAX_DATAGRAMS_PER_NTB 8
-#endif
+// Table 4.3 Data Class Interface Protocol Codes
+typedef enum
+{
+ NCM_DATA_PROTOCOL_NETWORK_TRANSFER_BLOCK = 0x01
+} ncm_data_interface_protocol_code_t;
-#ifndef CFG_TUD_NCM_ALIGNMENT
-#define CFG_TUD_NCM_ALIGNMENT 4
-#endif
#ifdef __cplusplus
extern "C" {
@@ -96,11 +87,6 @@ void tud_network_init_cb(void);
// TODO removed later since it is not part of tinyusb stack
extern uint8_t tud_network_mac_address[6];
-//------------- NCM -------------//
-
-// callback to client providing optional indication of internal state of network driver
-void tud_network_link_state_cb(bool state);
-
//--------------------------------------------------------------------+
// INTERNAL USBD-CLASS DRIVER API
//--------------------------------------------------------------------+
diff --git a/src/class/usbtmc/usbtmc.h b/src/class/usbtmc/usbtmc.h
index 090ab3c4a..327de087c 100644
--- a/src/class/usbtmc/usbtmc.h
+++ b/src/class/usbtmc/usbtmc.h
@@ -184,6 +184,23 @@ typedef enum {
} usmtmc_request_type_enum;
typedef enum {
+ // The last and first valid bNotify1 for use by the USBTMC class specification.
+ USBTMC_bNOTIFY1_USBTMC_FIRST = 0x00,
+ USBTMC_bNOTIFY1_USBTMC_LAST = 0x3F,
+
+ // The last and first valid bNotify1 for use by vendors.
+ USBTMC_bNOTIFY1_VENDOR_SPECIFIC_FIRST = 0x40,
+ USBTMC_bNOTIFY1_VENDOR_SPECIFIC_LAST = 0x7F,
+
+ // The last and first valid bNotify1 for use by USBTMC subclass specifications.
+ USBTMC_bNOTIFY1_SUBCLASS_FIRST = 0x80,
+ USBTMC_bNOTIFY1_SUBCLASS_LAST = 0xFF,
+
+ // From the USB488 Subclass Specification, Section 3.4.
+ USB488_bNOTIFY1_SRQ = 0x81,
+} usbtmc_int_in_payload_format;
+
+typedef enum {
USBTMC_STATUS_SUCCESS = 0x01,
USBTMC_STATUS_PENDING = 0x02,
USBTMC_STATUS_FAILED = 0x80,
@@ -305,6 +322,14 @@ TU_VERIFY_STATIC(sizeof(usbtmc_read_stb_rsp_488_t) == 3u, "struct wrong length")
typedef struct TU_ATTR_PACKED
{
+ uint8_t bNotify1; // Must be USB488_bNOTIFY1_SRQ
+ uint8_t StatusByte;
+} usbtmc_srq_interrupt_488_t;
+
+TU_VERIFY_STATIC(sizeof(usbtmc_srq_interrupt_488_t) == 2u, "struct wrong length");
+
+typedef struct TU_ATTR_PACKED
+{
struct TU_ATTR_PACKED
{
unsigned int bTag : 7;
diff --git a/src/class/usbtmc/usbtmc_device.c b/src/class/usbtmc/usbtmc_device.c
index f6cddfbd7..129ff465d 100644
--- a/src/class/usbtmc/usbtmc_device.c
+++ b/src/class/usbtmc/usbtmc_device.c
@@ -86,6 +86,11 @@ tu_static char logMsg[150];
// imposes a minimum buffer size of 32 bytes.
#define USBTMCD_BUFFER_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
+// Interrupt endpoint buffer size, default to 2 bytes as USB488 specification.
+#ifndef CFG_TUD_USBTMC_INT_EP_SIZE
+#define CFG_TUD_USBTMC_INT_EP_SIZE 2
+#endif
+
/*
* The state machine does not allow simultaneous reading and writing. This is
* consistent with USBTMC.
@@ -124,13 +129,15 @@ typedef struct
uint8_t ep_bulk_in;
uint8_t ep_bulk_out;
uint8_t ep_int_in;
+ uint32_t ep_bulk_in_wMaxPacketSize;
+ uint32_t ep_bulk_out_wMaxPacketSize;
// IN buffer is only used for first packet, not the remainder
// in order to deal with prepending header
CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_in_buf[USBTMCD_BUFFER_SIZE];
- uint32_t ep_bulk_in_wMaxPacketSize;
// OUT buffer receives one packet at a time
CFG_TUSB_MEM_ALIGN uint8_t ep_bulk_out_buf[USBTMCD_BUFFER_SIZE];
- uint32_t ep_bulk_out_wMaxPacketSize;
+ // Buffer int msg to ensure alignment and placement correctness
+ CFG_TUSB_MEM_ALIGN uint8_t ep_int_in_buf[CFG_TUD_USBTMC_INT_EP_SIZE];
uint32_t transfer_size_remaining; // also used for requested length for bulk IN.
uint32_t transfer_size_sent; // To keep track of data bytes that have been queued in FIFO (not header bytes)
@@ -240,6 +247,19 @@ bool tud_usbtmc_transmit_dev_msg_data(
return true;
}
+bool tud_usbtmc_transmit_notification_data(const void * data, size_t len)
+{
+#ifndef NDEBUG
+ TU_ASSERT(len > 0);
+ TU_ASSERT(usbtmc_state.ep_int_in != 0);
+#endif
+ TU_VERIFY(usbd_edpt_busy(usbtmc_state.rhport, usbtmc_state.ep_int_in));
+
+ TU_VERIFY(tu_memcpy_s(usbtmc_state.ep_int_in_buf, sizeof(usbtmc_state.ep_int_in_buf), data, len) == 0);
+ TU_VERIFY(usbd_edpt_xfer(usbtmc_state.rhport, usbtmc_state.ep_int_in, usbtmc_state.ep_int_in_buf, (uint16_t)len));
+ return true;
+}
+
void usbtmcd_init_cb(void)
{
usbtmc_state.capabilities = tud_usbtmc_get_capabilities_cb();
@@ -547,9 +567,10 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
case STATE_TX_INITIATED:
if(usbtmc_state.transfer_size_remaining >= sizeof(usbtmc_state.ep_bulk_in_buf))
{
- // FIXME! This removes const below!
+ // Copy buffer to ensure alignment correctness
+ memcpy(usbtmc_state.ep_bulk_in_buf, usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf));
TU_VERIFY( usbd_edpt_xfer(rhport, usbtmc_state.ep_bulk_in,
- (void*)(uintptr_t) usbtmc_state.devInBuffer, sizeof(usbtmc_state.ep_bulk_in_buf)));
+ usbtmc_state.ep_bulk_in_buf, sizeof(usbtmc_state.ep_bulk_in_buf)));
usbtmc_state.devInBuffer += sizeof(usbtmc_state.ep_bulk_in_buf);
usbtmc_state.transfer_size_remaining -= sizeof(usbtmc_state.ep_bulk_in_buf);
usbtmc_state.transfer_size_sent += sizeof(usbtmc_state.ep_bulk_in_buf);
@@ -585,7 +606,9 @@ bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
}
}
else if (ep_addr == usbtmc_state.ep_int_in) {
- // Good?
+ if (tud_usbtmc_notification_complete_cb) {
+ TU_VERIFY(tud_usbtmc_notification_complete_cb());
+ }
return true;
}
return false;
diff --git a/src/class/usbtmc/usbtmc_device.h b/src/class/usbtmc/usbtmc_device.h
index 3299a36eb..b85ef12b5 100644
--- a/src/class/usbtmc/usbtmc_device.h
+++ b/src/class/usbtmc/usbtmc_device.h
@@ -73,6 +73,10 @@ bool tud_usbtmc_check_abort_bulk_in_cb(usbtmc_check_abort_bulk_rsp_t *rsp);
bool tud_usbtmc_check_abort_bulk_out_cb(usbtmc_check_abort_bulk_rsp_t *rsp);
bool tud_usbtmc_check_clear_cb(usbtmc_get_clear_status_rsp_t *rsp);
+// The interrupt-IN endpoint buffer was transmitted to the host. Use
+// tud_usbtmc_transmit_notification_data to send another notification.
+TU_ATTR_WEAK bool tud_usbtmc_notification_complete_cb(void);
+
// Indicator pulse should be 0.5 to 1.0 seconds long
TU_ATTR_WEAK bool tud_usbtmc_indicator_pulse_cb(tusb_control_request_t const * msg, uint8_t *tmcResult);
@@ -82,17 +86,23 @@ TU_ATTR_WEAK bool tud_usbtmc_msg_trigger_cb(usbtmc_msg_generic_t* msg);
//TU_ATTR_WEAK bool tud_usbtmc_app_go_to_local_cb();
#endif
-/*******************************************
- * Called from app
- *
- * We keep a reference to the buffer, so it MUST not change until the app is
- * notified that the transfer is complete.
- ******************************************/
-
+// Called from app
+//
+// We keep a reference to the buffer, so it MUST not change until the app is
+// notified that the transfer is complete.
bool tud_usbtmc_transmit_dev_msg_data(
const void * data, size_t len,
bool endOfMessage, bool usingTermChar);
+// Buffers a notification to be sent to the host. The data starts
+// with the bNotify1 field, see the USBTMC Specification, Table 13.
+//
+// If the previous notification data has not yet been sent, this
+// returns false.
+//
+// Requires an interrupt endpoint in the interface.
+bool tud_usbtmc_transmit_notification_data(const void * data, size_t len);
+
bool tud_usbtmc_start_bus_read(void);
@@ -105,9 +115,4 @@ void usbtmcd_reset_cb(uint8_t rhport);
bool usbtmcd_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes);
bool usbtmcd_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
-/************************************************************
- * USBTMC Descriptor Templates
- *************************************************************/
-
-
#endif /* CLASS_USBTMC_USBTMC_DEVICE_H_ */
diff --git a/src/class/vendor/vendor_device.c b/src/class/vendor/vendor_device.c
index e87ce3997..56ef098c7 100644
--- a/src/class/vendor/vendor_device.c
+++ b/src/class/vendor/vendor_device.c
@@ -36,6 +36,8 @@
//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF
//--------------------------------------------------------------------+
+#define BULK_PACKET_SIZE (TUD_OPT_HIGH_SPEED ? 512 : 64)
+
typedef struct
{
uint8_t itf_num;
@@ -273,7 +275,6 @@ uint16_t vendord_open(uint8_t rhport, tusb_desc_interface_t const * desc_itf, ui
bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint32_t xferred_bytes)
{
- (void) rhport;
(void) result;
uint8_t itf = 0;
@@ -300,7 +301,18 @@ bool vendord_xfer_cb(uint8_t rhport, uint8_t ep_addr, xfer_result_t result, uint
{
if (tud_vendor_tx_cb) tud_vendor_tx_cb(itf, (uint16_t) xferred_bytes);
// Send complete, try to send more if possible
- tud_vendor_n_write_flush(itf);
+ if ( 0 == tud_vendor_n_write_flush(itf) )
+ {
+ // If there is no data left, a ZLP should be sent if
+ // xferred_bytes is multiple of EP Packet size and not zero
+ if ( !tu_fifo_count(&p_itf->tx_ff) && xferred_bytes && (0 == (xferred_bytes & (BULK_PACKET_SIZE-1))) )
+ {
+ if ( usbd_edpt_claim(rhport, p_itf->ep_in) )
+ {
+ usbd_edpt_xfer(rhport, p_itf->ep_in, NULL, 0);
+ }
+ }
+ }
}
return true;
diff --git a/src/common/tusb_compiler.h b/src/common/tusb_compiler.h
index 0d5570b1c..ce5566ffe 100644
--- a/src/common/tusb_compiler.h
+++ b/src/common/tusb_compiler.h
@@ -128,6 +128,7 @@
#define TU_ATTR_SECTION(sec_name) __attribute__ ((section(#sec_name)))
#define TU_ATTR_PACKED __attribute__ ((packed))
#define TU_ATTR_WEAK __attribute__ ((weak))
+ // #define TU_ATTR_WEAK_ALIAS(f) __attribute__ ((weak, alias(#f))
#ifndef TU_ATTR_ALWAYS_INLINE // allow to override for debug
#define TU_ATTR_ALWAYS_INLINE __attribute__ ((always_inline))
#endif
diff --git a/src/common/tusb_fifo.c b/src/common/tusb_fifo.c
index 76696396b..8a0fd4417 100644
--- a/src/common/tusb_fifo.c
+++ b/src/common/tusb_fifo.c
@@ -62,7 +62,9 @@ TU_ATTR_ALWAYS_INLINE static inline void _ff_unlock(osal_mutex_t mutex)
typedef enum
{
TU_FIFO_COPY_INC, ///< Copy from/to an increasing source/destination address - default mode
+#ifdef TUP_MEM_CONST_ADDR
TU_FIFO_COPY_CST_FULL_WORDS, ///< Copy from/to a constant source/destination address - required for e.g. STM32 to write into USB hardware FIFO
+#endif
} tu_fifo_copy_mode_t;
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable)
@@ -92,6 +94,7 @@ bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_si
// Pull & Push
//--------------------------------------------------------------------+
+#ifdef TUP_MEM_CONST_ADDR
// Intended to be used to read from hardware USB FIFO in e.g. STM32 where all data is read from a constant address
// Code adapted from dcd_synopsys.c
// TODO generalize with configurable 1 byte or 4 byte each read
@@ -140,6 +143,7 @@ static void _ff_pull_const_addr(void * app_buf, const uint8_t * ff_buf, uint16_t
*reg_tx = tmp32;
}
}
+#endif
// send one item to fifo WITHOUT updating write pointer
static inline void _ff_push(tu_fifo_t* f, void const * app_buf, uint16_t rel)
@@ -179,7 +183,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t
memcpy(f->buffer, ((uint8_t const*) app_buf) + lin_bytes, wrap_bytes);
}
break;
-
+#ifdef TUP_MEM_CONST_ADDR
case TU_FIFO_COPY_CST_FULL_WORDS:
// Intended for hardware buffers from which it can be read word by word only
if(n <= lin_count)
@@ -224,6 +228,7 @@ static void _ff_push_n(tu_fifo_t* f, void const * app_buf, uint16_t n, uint16_t
if (wrap_bytes > 0) _ff_push_const_addr(ff_buf, app_buf, wrap_bytes);
}
break;
+#endif
default: break;
}
}
@@ -265,7 +270,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr,
memcpy((uint8_t*) app_buf + lin_bytes, f->buffer, wrap_bytes);
}
break;
-
+#ifdef TUP_MEM_CONST_ADDR
case TU_FIFO_COPY_CST_FULL_WORDS:
if ( n <= lin_count )
{
@@ -310,6 +315,7 @@ static void _ff_pull_n(tu_fifo_t* f, void* app_buf, uint16_t n, uint16_t rd_ptr,
// Read data wrapped part
if (wrap_bytes > 0) _ff_pull_const_addr(app_buf, ff_buf, wrap_bytes);
}
+#endif
break;
default: break;
@@ -727,10 +733,29 @@ uint16_t tu_fifo_read_n(tu_fifo_t* f, void * buffer, uint16_t n)
return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_INC);
}
+#ifdef TUP_MEM_CONST_ADDR
+/******************************************************************************/
+/*!
+ @brief This function will read n elements from the array index specified by
+ the read pointer and increment the read index.
+ This function checks for an overflow and corrects read pointer if required.
+ The dest address will not be incremented which is useful for writing to registers.
+
+ @param[in] f
+ Pointer to the FIFO buffer to manipulate
+ @param[in] buffer
+ The pointer to data location
+ @param[in] n
+ Number of element that buffer can afford
+
+ @returns number of items read from the FIFO
+ */
+/******************************************************************************/
uint16_t tu_fifo_read_n_const_addr_full_words(tu_fifo_t* f, void * buffer, uint16_t n)
{
return _tu_fifo_read_n(f, buffer, n, TU_FIFO_COPY_CST_FULL_WORDS);
}
+#endif
/******************************************************************************/
/*!
@@ -839,6 +864,7 @@ uint16_t tu_fifo_write_n(tu_fifo_t* f, const void * data, uint16_t n)
return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_INC);
}
+#ifdef TUP_MEM_CONST_ADDR
/******************************************************************************/
/*!
@brief This function will write n elements into the array index specified by
@@ -858,6 +884,7 @@ uint16_t tu_fifo_write_n_const_addr_full_words(tu_fifo_t* f, const void * data,
{
return _tu_fifo_write_n(f, data, n, TU_FIFO_COPY_CST_FULL_WORDS);
}
+#endif
/******************************************************************************/
/*!
diff --git a/src/common/tusb_fifo.h b/src/common/tusb_fifo.h
index 2d9f5e667..6c0efb509 100644
--- a/src/common/tusb_fifo.h
+++ b/src/common/tusb_fifo.h
@@ -145,22 +145,26 @@ bool tu_fifo_clear(tu_fifo_t *f);
bool tu_fifo_config(tu_fifo_t *f, void* buffer, uint16_t depth, uint16_t item_size, bool overwritable);
#if OSAL_MUTEX_REQUIRED
- TU_ATTR_ALWAYS_INLINE static inline
- void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) {
- f->mutex_wr = wr_mutex;
- f->mutex_rd = rd_mutex;
- }
+TU_ATTR_ALWAYS_INLINE static inline
+void tu_fifo_config_mutex(tu_fifo_t *f, osal_mutex_t wr_mutex, osal_mutex_t rd_mutex) {
+ f->mutex_wr = wr_mutex;
+ f->mutex_rd = rd_mutex;
+}
#else
- #define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex)
+#define tu_fifo_config_mutex(_f, _wr_mutex, _rd_mutex)
#endif
bool tu_fifo_write (tu_fifo_t* f, void const * p_data);
uint16_t tu_fifo_write_n (tu_fifo_t* f, void const * p_data, uint16_t n);
+#ifdef TUP_MEM_CONST_ADDR
uint16_t tu_fifo_write_n_const_addr_full_words (tu_fifo_t* f, const void * data, uint16_t n);
+#endif
bool tu_fifo_read (tu_fifo_t* f, void * p_buffer);
uint16_t tu_fifo_read_n (tu_fifo_t* f, void * p_buffer, uint16_t n);
+#ifdef TUP_MEM_CONST_ADDR
uint16_t tu_fifo_read_n_const_addr_full_words (tu_fifo_t* f, void * buffer, uint16_t n);
+#endif
bool tu_fifo_peek (tu_fifo_t* f, void * p_buffer);
uint16_t tu_fifo_peek_n (tu_fifo_t* f, void * p_buffer, uint16_t n);
diff --git a/src/common/tusb_mcu.h b/src/common/tusb_mcu.h
index 0ae2573cd..80826c895 100644
--- a/src/common/tusb_mcu.h
+++ b/src/common/tusb_mcu.h
@@ -195,6 +195,7 @@
#elif TU_CHECK_MCU(OPT_MCU_STM32F4)
#define TUP_USBIP_DWC2
#define TUP_USBIP_DWC2_STM32
+ #define TUP_USBIP_DWC2_TEST_MODE
// For most mcu, FS has 4, HS has 6. TODO 446/469/479 HS has 9
#define TUP_DCD_ENDPOINT_MAX 6
@@ -209,6 +210,7 @@
// MCU with on-chip HS Phy
#if defined(STM32F723xx) || defined(STM32F730xx) || defined(STM32F733xx)
#define TUP_RHPORT_HIGHSPEED 1 // Port0: FS, Port1: HS
+ #define TUP_USBIP_DWC2_TEST_MODE
#endif
#elif TU_CHECK_MCU(OPT_MCU_STM32H7)
@@ -269,16 +271,24 @@
#define TUP_DCD_ENDPOINT_MAX 8
#elif TU_CHECK_MCU(OPT_MCU_STM32U5)
- #define TUP_USBIP_DWC2
- #define TUP_USBIP_DWC2_STM32
+ #if defined (STM32U535xx) || defined (STM32U545xx)
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_STM32
+ #define TUP_DCD_ENDPOINT_MAX 8
- // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY
- #if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \
- defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx)
- #define TUP_DCD_ENDPOINT_MAX 9
- #define TUP_RHPORT_HIGHSPEED 1
#else
- #define TUP_DCD_ENDPOINT_MAX 6
+ #define TUP_USBIP_DWC2
+ #define TUP_USBIP_DWC2_STM32
+
+ // U59x/5Ax/5Fx/5Gx are highspeed with built-in HS PHY
+ #if defined(STM32U595xx) || defined(STM32U599xx) || defined(STM32U5A5xx) || defined(STM32U5A9xx) || \
+ defined(STM32U5F7xx) || defined(STM32U5F9xx) || defined(STM32U5G7xx) || defined(STM32U5G9xx)
+ #define TUP_DCD_ENDPOINT_MAX 9
+ #define TUP_RHPORT_HIGHSPEED 1
+ #define TUP_USBIP_DWC2_TEST_MODE
+ #else
+ #define TUP_DCD_ENDPOINT_MAX 6
+ #endif
#endif
#elif TU_CHECK_MCU(OPT_MCU_STM32L5)
@@ -329,6 +339,9 @@
#define TUP_USBIP_DWC2
#define TUP_DCD_ENDPOINT_MAX 6
+#elif TU_CHECK_MCU(OPT_MCU_ESP32, OPT_MCU_ESP32C2, OPT_MCU_ESP32C3, OPT_MCU_ESP32C6, OPT_MCU_ESP32H2) && (CFG_TUD_ENABLED || !(defined(CFG_TUH_MAX3421) && CFG_TUH_MAX3421))
+ #error "MCUs are only supported with CFG_TUH_MAX3421 enabled"
+
//--------------------------------------------------------------------+
// Dialog
//--------------------------------------------------------------------+
@@ -396,16 +409,66 @@
#elif TU_CHECK_MCU(OPT_MCU_F1C100S)
#define TUP_DCD_ENDPOINT_MAX 4
-//------------- WCH -------------//
+//--------------------------------------------------------------------+
+// WCH
+//--------------------------------------------------------------------+
+#elif TU_CHECK_MCU(OPT_MCU_CH32F20X)
+ #define TUP_USBIP_WCH_USBHS
+ #define TUP_USBIP_WCH_USBFS
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBFS)
+ #define CFG_TUD_WCH_USBIP_USBFS 0
+ #endif
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBHS)
+ #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #endif
+
+ #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
+ #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
+
+#elif TU_CHECK_MCU(OPT_MCU_CH32V103)
+ #define TUP_USBIP_WCH_USBFS
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBFS)
+ #define CFG_TUD_WCH_USBIP_USBFS 1
+ #endif
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+
+#elif TU_CHECK_MCU(OPT_MCU_CH32V20X)
+ // v20x support both FSDEV (USBD) and USBFS, default to FSDEV
+ #define TUP_USBIP_WCH_USBFS
+ #define TUP_USBIP_FSDEV
+ #define TUP_USBIP_FSDEV_CH32
+
+ #if !defined(CFG_TUD_WCH_USBIP_USBFS)
+ #define CFG_TUD_WCH_USBIP_USBFS 0
+ #endif
+
+ #if !defined(CFG_TUD_WCH_USBIP_FSDEV)
+ #define CFG_TUD_WCH_USBIP_FSDEV (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #endif
+
+ #define TUP_DCD_ENDPOINT_MAX 8
+
#elif TU_CHECK_MCU(OPT_MCU_CH32V307)
- #define TUP_DCD_ENDPOINT_MAX 16
- #define TUP_RHPORT_HIGHSPEED 1
+ // v307 support both FS and HS, default to HS
+ #define TUP_USBIP_WCH_USBHS
+ #define TUP_USBIP_WCH_USBFS
-#elif TU_CHECK_MCU(OPT_MCU_CH32F20X)
- #define TUP_DCD_ENDPOINT_MAX 16
- #define TUP_RHPORT_HIGHSPEED 1
-#endif
+ #if !defined(CFG_TUD_WCH_USBIP_USBFS)
+ #define CFG_TUD_WCH_USBIP_USBFS 0
+ #endif
+ #if !defined(CFG_TUD_WCH_USBIP_USBHS)
+ #define CFG_TUD_WCH_USBIP_USBHS (CFG_TUD_WCH_USBIP_USBFS ? 0 : 1)
+ #endif
+
+ #define TUP_RHPORT_HIGHSPEED CFG_TUD_WCH_USBIP_USBHS
+ #define TUP_DCD_ENDPOINT_MAX (CFG_TUD_WCH_USBIP_USBHS ? 16 : 8)
+
+#endif
//--------------------------------------------------------------------+
// External USB controller
@@ -426,7 +489,7 @@
#define TUP_MCU_MULTIPLE_CORE 0
#endif
-#ifndef TUP_DCD_ENDPOINT_MAX
+#if !defined(TUP_DCD_ENDPOINT_MAX) && defined(CFG_TUD_ENABLED) && CFG_TUD_ENABLED
#warning "TUP_DCD_ENDPOINT_MAX is not defined for this MCU, default to 8"
#define TUP_DCD_ENDPOINT_MAX 8
#endif
@@ -445,4 +508,8 @@
#define TUP_DCD_EDPT_ISO_ALLOC
#endif
+#if defined(TUP_USBIP_DWC2)
+ #define TUP_MEM_CONST_ADDR
+#endif
+
#endif
diff --git a/src/common/tusb_verify.h b/src/common/tusb_verify.h
index 71406dacf..dde0550d3 100644
--- a/src/common/tusb_verify.h
+++ b/src/common/tusb_verify.h
@@ -78,13 +78,12 @@
// Halt CPU (breakpoint) when hitting error, only apply for Cortex M3, M4, M7, M33. M55
#if defined(__ARM_ARCH_7M__) || defined (__ARM_ARCH_7EM__) || defined(__ARM_ARCH_8M_MAIN__) || defined(__ARM_ARCH_8_1M_MAIN__) || \
defined(__ARM7M__) || defined (__ARM7EM__) || defined(__ARM8M_MAINLINE__) || defined(__ARM8EM_MAINLINE__)
- #define TU_BREAKPOINT() do \
- { \
+ #define TU_BREAKPOINT() do { \
volatile uint32_t* ARM_CM_DHCSR = ((volatile uint32_t*) 0xE000EDF0UL); /* Cortex M CoreDebug->DHCSR */ \
if ( (*ARM_CM_DHCSR) & 1UL ) __asm("BKPT #0\n"); /* Only halt mcu if debugger is attached */ \
} while(0)
-#elif defined(__riscv)
+#elif defined(__riscv) && !TUP_MCU_ESPRESSIF
#define TU_BREAKPOINT() do { __asm("ebreak\n"); } while(0)
#elif defined(_mips)
diff --git a/src/device/dcd.h b/src/device/dcd.h
index d4f105aa3..f6735b077 100644
--- a/src/device/dcd.h
+++ b/src/device/dcd.h
@@ -24,8 +24,8 @@
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_DCD_H_
-#define _TUSB_DCD_H_
+#ifndef TUSB_DCD_H_
+#define TUSB_DCD_H_
#include "common/tusb_common.h"
#include "osal/osal.h"
@@ -36,14 +36,6 @@
#endif
//--------------------------------------------------------------------+
-// Configuration
-//--------------------------------------------------------------------+
-
-#ifndef CFG_TUD_ENDPPOINT_MAX
- #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX
-#endif
-
-//--------------------------------------------------------------------+
// MACRO CONSTANT TYPEDEF PROTYPES
//--------------------------------------------------------------------+
@@ -97,6 +89,14 @@ typedef struct TU_ATTR_ALIGNED(4) {
};
} dcd_event_t;
+typedef enum {
+ TEST_J = 1,
+ TEST_K,
+ TEST_SE0_NAK,
+ TEST_PACKET,
+ TEST_FORCE_ENABLE,
+} test_mode_t;
+
//TU_VERIFY_STATIC(sizeof(dcd_event_t) <= 12, "size is not correct");
//--------------------------------------------------------------------+
@@ -141,14 +141,21 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr);
void dcd_remote_wakeup(uint8_t rhport);
// Connect by enabling internal pull-up resistor on D+/D-
-void dcd_connect(uint8_t rhport) TU_ATTR_WEAK;
+void dcd_connect(uint8_t rhport);
// Disconnect by disabling internal pull-up resistor on D+/D-
-void dcd_disconnect(uint8_t rhport) TU_ATTR_WEAK;
+void dcd_disconnect(uint8_t rhport);
// Enable/Disable Start-of-frame interrupt. Default is disabled
void dcd_sof_enable(uint8_t rhport, bool en);
+#if CFG_TUD_TEST_MODE
+// Check if the test mode is supported, returns true is test mode selector is supported
+bool dcd_check_test_mode_support(test_mode_t test_selector) TU_ATTR_WEAK;
+
+// Put device into a test mode (needs power cycle to quit)
+void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) TU_ATTR_WEAK;
+#endif
//--------------------------------------------------------------------+
// Endpoint API
//--------------------------------------------------------------------+
@@ -239,4 +246,4 @@ TU_ATTR_ALWAYS_INLINE static inline void dcd_event_sof(uint8_t rhport, uint32_t
}
#endif
-#endif /* _TUSB_DCD_H_ */
+#endif
diff --git a/src/device/usbd.c b/src/device/usbd.c
index e51aa0fc4..800d9c824 100644
--- a/src/device/usbd.c
+++ b/src/device/usbd.c
@@ -45,15 +45,27 @@
//--------------------------------------------------------------------+
// Weak stubs: invoked if no strong implementation is available
//--------------------------------------------------------------------+
+TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
+ (void)rhport;
+ (void)eventid;
+ (void)in_isr;
+}
+
+TU_ATTR_WEAK void tud_sof_cb(uint32_t frame_count) {
+ (void)frame_count;
+}
+
TU_ATTR_WEAK bool dcd_deinit(uint8_t rhport) {
(void) rhport;
return false;
}
-TU_ATTR_WEAK void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr) {
- (void)rhport;
- (void)eventid;
- (void)in_isr;
+TU_ATTR_WEAK void dcd_connect(uint8_t rhport) {
+ (void) rhport;
+}
+
+TU_ATTR_WEAK void dcd_disconnect(uint8_t rhport) {
+ (void) rhport;
}
//--------------------------------------------------------------------+
@@ -76,6 +88,7 @@ typedef struct {
volatile uint8_t cfg_num; // current active configuration (0x00 is not configured)
uint8_t speed;
volatile uint8_t setup_count;
+ volatile uint8_t sof_consumer;
uint8_t itf2drv[CFG_TUD_INTERFACE_MAX]; // map interface number to driver (0xff is invalid)
uint8_t ep2drv[CFG_TUD_ENDPPOINT_MAX][2]; // map endpoint to driver ( 0xff is invalid ), can use only 4-bit each
@@ -90,16 +103,16 @@ tu_static usbd_device_t _usbd_dev;
// Class Driver
//--------------------------------------------------------------------+
#if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
- #define DRIVER_NAME(_name) .name = _name,
+ #define DRIVER_NAME(_name) _name
#else
- #define DRIVER_NAME(_name)
+ #define DRIVER_NAME(_name) NULL
#endif
// Built-in class drivers
tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_CDC
{
- DRIVER_NAME("CDC")
+ .name = DRIVER_NAME("CDC"),
.init = cdcd_init,
.deinit = cdcd_deinit,
.reset = cdcd_reset,
@@ -112,7 +125,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_MSC
{
- DRIVER_NAME("MSC")
+ .name = DRIVER_NAME("MSC"),
.init = mscd_init,
.deinit = NULL,
.reset = mscd_reset,
@@ -125,7 +138,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_HID
{
- DRIVER_NAME("HID")
+ .name = DRIVER_NAME("HID"),
.init = hidd_init,
.deinit = hidd_deinit,
.reset = hidd_reset,
@@ -138,7 +151,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_AUDIO
{
- DRIVER_NAME("AUDIO")
+ .name = DRIVER_NAME("AUDIO"),
.init = audiod_init,
.deinit = audiod_deinit,
.reset = audiod_reset,
@@ -151,7 +164,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_VIDEO
{
- DRIVER_NAME("VIDEO")
+ .name = DRIVER_NAME("VIDEO"),
.init = videod_init,
.deinit = videod_deinit,
.reset = videod_reset,
@@ -164,7 +177,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_MIDI
{
- DRIVER_NAME("MIDI")
+ .name = DRIVER_NAME("MIDI"),
.init = midid_init,
.deinit = midid_deinit,
.open = midid_open,
@@ -177,7 +190,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_VENDOR
{
- DRIVER_NAME("VENDOR")
+ .name = DRIVER_NAME("VENDOR"),
.init = vendord_init,
.deinit = vendord_deinit,
.reset = vendord_reset,
@@ -190,7 +203,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_USBTMC
{
- DRIVER_NAME("TMC")
+ .name = DRIVER_NAME("TMC"),
.init = usbtmcd_init_cb,
.deinit = usbtmcd_deinit,
.reset = usbtmcd_reset_cb,
@@ -203,7 +216,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_DFU_RUNTIME
{
- DRIVER_NAME("DFU-RUNTIME")
+ .name = DRIVER_NAME("DFU-RUNTIME"),
.init = dfu_rtd_init,
.deinit = dfu_rtd_deinit,
.reset = dfu_rtd_reset,
@@ -216,7 +229,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_DFU
{
- DRIVER_NAME("DFU")
+ .name = DRIVER_NAME("DFU"),
.init = dfu_moded_init,
.deinit = dfu_moded_deinit,
.reset = dfu_moded_reset,
@@ -229,7 +242,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_ECM_RNDIS || CFG_TUD_NCM
{
- DRIVER_NAME("NET")
+ .name = DRIVER_NAME("NET"),
.init = netd_init,
.deinit = netd_deinit,
.reset = netd_reset,
@@ -242,7 +255,7 @@ tu_static usbd_class_driver_t const _usbd_driver[] = {
#if CFG_TUD_BTH
{
- DRIVER_NAME("BTH")
+ .name = DRIVER_NAME("BTH"),
.init = btd_init,
.deinit = btd_deinit,
.reset = btd_reset,
@@ -275,6 +288,7 @@ TU_ATTR_ALWAYS_INLINE static inline usbd_class_driver_t const * get_driver(uint8
return driver;
}
+
//--------------------------------------------------------------------+
// DCD Event
//--------------------------------------------------------------------+
@@ -307,7 +321,9 @@ TU_ATTR_ALWAYS_INLINE static inline bool queue_event(dcd_event_t const * event,
static bool process_control_request(uint8_t rhport, tusb_control_request_t const * p_request);
static bool process_set_config(uint8_t rhport, uint8_t cfg_num);
static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const * p_request);
-
+#if CFG_TUD_TEST_MODE
+static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
+#endif
// from usbd_control.c
void usbd_control_reset(void);
void usbd_control_set_request(tusb_control_request_t const *request);
@@ -371,17 +387,19 @@ bool tud_remote_wakeup(void) {
}
bool tud_disconnect(void) {
- TU_VERIFY(dcd_disconnect);
dcd_disconnect(_usbd_rhport);
return true;
}
bool tud_connect(void) {
- TU_VERIFY(dcd_connect);
dcd_connect(_usbd_rhport);
return true;
}
+void tud_sof_cb_enable(bool en) {
+ usbd_sof_enable(_usbd_rhport, SOF_CONSUMER_USER, en);
+}
+
//--------------------------------------------------------------------+
// USBD Task
//--------------------------------------------------------------------+
@@ -393,7 +411,7 @@ bool tud_init(uint8_t rhport) {
// skip if already initialized
if (tud_inited()) return true;
- TU_LOG_USBD("USBD init on controller %u\r\n", rhport);
+ TU_LOG_USBD("USBD init on controller %u, Highspeed = %u\r\n", rhport, TUD_OPT_HIGH_SPEED);
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(usbd_device_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(dcd_event_t));
TU_LOG_INT(CFG_TUD_LOG_LEVEL, sizeof(tu_fifo_t));
@@ -612,6 +630,12 @@ void tud_task_ext(uint32_t timeout_ms, bool in_isr) {
break;
case DCD_EVENT_SOF:
+ if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) {
+ TU_LOG_USBD("\r\n");
+ tud_sof_cb(event.sof.frame_count);
+ }
+ break;
+
default:
TU_BREAKPOINT();
break;
@@ -702,6 +726,9 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
// already configured: need to clear all endpoints and driver first
TU_LOG_USBD(" Clear current Configuration (%u) before switching\r\n", _usbd_dev.cfg_num);
+ // disable SOF
+ dcd_sof_enable(rhport, false);
+
// close all non-control endpoints, cancel all pending transfers if any
dcd_edpt_close_all(rhport);
@@ -732,14 +759,47 @@ static bool process_control_request(uint8_t rhport, tusb_control_request_t const
break;
case TUSB_REQ_SET_FEATURE:
- // Only support remote wakeup for device feature
- TU_VERIFY(TUSB_REQ_FEATURE_REMOTE_WAKEUP == p_request->wValue);
+ // Handle the feature selector
+ switch(p_request->wValue)
+ {
+ // Support for remote wakeup
+ case TUSB_REQ_FEATURE_REMOTE_WAKEUP:
+ TU_LOG_USBD(" Enable Remote Wakeup\r\n");
- TU_LOG_USBD(" Enable Remote Wakeup\r\n");
+ // Host may enable remote wake up before suspending especially HID device
+ _usbd_dev.remote_wakeup_en = true;
+ tud_control_status(rhport, p_request);
+ break;
- // Host may enable remote wake up before suspending especially HID device
- _usbd_dev.remote_wakeup_en = true;
- tud_control_status(rhport, p_request);
+#if CFG_TUD_TEST_MODE
+ // Support for TEST_MODE
+ case TUSB_REQ_FEATURE_TEST_MODE: {
+ // Only handle the test mode if supported and valid
+ TU_VERIFY(dcd_enter_test_mode && dcd_check_test_mode_support && 0 == tu_u16_low(p_request->wIndex));
+
+ uint8_t selector = tu_u16_high(p_request->wIndex);
+
+ // Stall request if the selected test mode isn't supported
+ if (!dcd_check_test_mode_support((test_mode_t)selector))
+ {
+ TU_LOG_USBD(" Unsupported Test Mode (test selector index: %d)\r\n", selector);
+
+ return false;
+ }
+
+ // Acknowledge request
+ tud_control_status(rhport, p_request);
+
+ TU_LOG_USBD(" Enter Test Mode (test selector index: %d)\r\n", selector);
+
+ usbd_control_set_complete_callback(process_test_mode_cb);
+ break;
+ }
+#endif /* CFG_TUD_TEST_MODE */
+
+ // Stall unsupported feature selector
+ default: return false;
+ }
break;
case TUSB_REQ_CLEAR_FEATURE:
@@ -1067,6 +1127,20 @@ static bool process_get_descriptor(uint8_t rhport, tusb_control_request_t const
}
}
+#if CFG_TUD_TEST_MODE
+static bool process_test_mode_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request)
+{
+ // At this point it should already be ensured that dcd_enter_test_mode() is defined
+
+ // Only enter the test mode after the request for it has completed
+ TU_VERIFY(CONTROL_STAGE_ACK == stage);
+
+ dcd_enter_test_mode(rhport, (test_mode_t)tu_u16_high(request->wIndex));
+
+ return true;
+}
+#endif /* CFG_TUD_TEST_MODE */
+
//--------------------------------------------------------------------+
// DCD Event Handler
//--------------------------------------------------------------------+
@@ -1101,6 +1175,14 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr)
break;
case DCD_EVENT_SOF:
+ // SOF driver handler in ISR context
+ for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
+ usbd_class_driver_t const* driver = get_driver(i);
+ if (driver && driver->sof) {
+ driver->sof(event->rhport, event->sof.frame_count);
+ }
+ }
+
// Some MCUs after running dcd_remote_wakeup() does not have way to detect the end of remote wakeup
// which last 1-15 ms. DCD can use SOF as a clear indicator that bus is back to operational
if (_usbd_dev.suspended) {
@@ -1110,15 +1192,10 @@ TU_ATTR_FAST_FUNC void dcd_event_handler(dcd_event_t const* event, bool in_isr)
queue_event(&event_resume, in_isr);
}
- // SOF driver handler in ISR context
- for (uint8_t i = 0; i < TOTAL_DRIVER_COUNT; i++) {
- usbd_class_driver_t const* driver = get_driver(i);
- if (driver && driver->sof) {
- driver->sof(event->rhport, event->sof.frame_count);
- }
+ if (tu_bit_test(_usbd_dev.sof_consumer, SOF_CONSUMER_USER)) {
+ dcd_event_t const event_sof = {.rhport = event->rhport, .event_id = DCD_EVENT_SOF, .sof.frame_count = event->sof.frame_count};
+ queue_event(&event_sof, in_isr);
}
-
- // skip osal queue for SOF in usbd task
break;
case DCD_EVENT_SETUP_RECEIVED:
@@ -1355,12 +1432,21 @@ void usbd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
return;
}
-void usbd_sof_enable(uint8_t rhport, bool en) {
+void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en) {
rhport = _usbd_rhport;
- // TODO: Check needed if all drivers including the user sof_cb does not need an active SOF ISR any more.
- // Only if all drivers switched off SOF calls the SOF interrupt may be disabled
- dcd_sof_enable(rhport, en);
+ uint8_t consumer_old = _usbd_dev.sof_consumer;
+ // Keep track how many class instances need the SOF interrupt
+ if (en) {
+ _usbd_dev.sof_consumer |= (uint8_t)(1 << consumer);
+ } else {
+ _usbd_dev.sof_consumer &= (uint8_t)(~(1 << consumer));
+ }
+
+ // Test logically unequal
+ if(!_usbd_dev.sof_consumer != !consumer_old) {
+ dcd_sof_enable(rhport, _usbd_dev.sof_consumer);
+ }
}
bool usbd_edpt_iso_alloc(uint8_t rhport, uint8_t ep_addr, uint16_t largest_packet_size) {
diff --git a/src/device/usbd.h b/src/device/usbd.h
index 0197628e2..e47f674ea 100644
--- a/src/device/usbd.h
+++ b/src/device/usbd.h
@@ -60,7 +60,7 @@ void tud_task (void) {
// Check if there is pending events need processing by tud_task()
bool tud_task_event_ready(void);
-#ifndef _TUSB_DCD_H_
+#ifndef TUSB_DCD_H_
extern void dcd_int_handler(uint8_t rhport);
#endif
@@ -97,6 +97,9 @@ bool tud_disconnect(void);
// Return false on unsupported MCUs
bool tud_connect(void);
+// Enable or disable the Start Of Frame callback support
+void tud_sof_cb_enable(bool en);
+
// Carry out Data and Status stage of control transfer
// - If len = 0, it is equivalent to sending status only
// - If len > wLength : it will be truncated
@@ -152,6 +155,9 @@ TU_ATTR_WEAK void tud_resume_cb(void);
// Invoked when there is a new usb event, which need to be processed by tud_task()/tud_task_ext()
void tud_event_hook_cb(uint8_t rhport, uint32_t eventid, bool in_isr);
+// Invoked when a new (micro) frame started
+void tud_sof_cb(uint32_t frame_count);
+
// Invoked when received control request with VENDOR TYPE
TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb_control_request_t const * request);
@@ -221,8 +227,8 @@ TU_ATTR_WEAK bool tud_vendor_control_xfer_cb(uint8_t rhport, uint8_t stage, tusb
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_HEADER, U16_TO_U8S_LE(0x0120),\
/* CDC Call */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_CALL_MANAGEMENT, 0, (uint8_t)((_itfnum) + 1),\
- /* CDC ACM: support line request */\
- 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 2,\
+ /* CDC ACM: support line request + send break */\
+ 4, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_ABSTRACT_CONTROL_MANAGEMENT, 6,\
/* CDC Union */\
5, TUSB_DESC_CS_INTERFACE, CDC_FUNC_DESC_UNION, _itfnum, (uint8_t)((_itfnum) + 1),\
/* Endpoint Notification */\
diff --git a/src/device/usbd_pvt.h b/src/device/usbd_pvt.h
index 47752f32c..335d46cd8 100644
--- a/src/device/usbd_pvt.h
+++ b/src/device/usbd_pvt.h
@@ -23,8 +23,8 @@
*
* This file is part of the TinyUSB stack.
*/
-#ifndef _TUSB_USBD_PVT_H_
-#define _TUSB_USBD_PVT_H_
+#ifndef TUSB_USBD_PVT_H_
+#define TUSB_USBD_PVT_H_
#include "osal/osal.h"
#include "common/tusb_fifo.h"
@@ -36,14 +36,20 @@
#define TU_LOG_USBD(...) TU_LOG(CFG_TUD_LOG_LEVEL, __VA_ARGS__)
//--------------------------------------------------------------------+
+// MACRO CONSTANT TYPEDEF PROTYPES
+//--------------------------------------------------------------------+
+
+typedef enum {
+ SOF_CONSUMER_USER = 0,
+ SOF_CONSUMER_AUDIO,
+} sof_consumer_t;
+
+//--------------------------------------------------------------------+
// Class Driver API
//--------------------------------------------------------------------+
typedef struct {
- #if CFG_TUSB_DEBUG >= CFG_TUD_LOG_LEVEL
char const* name;
- #endif
-
void (* init ) (void);
bool (* deinit ) (void);
void (* reset ) (uint8_t rhport);
@@ -111,7 +117,7 @@ bool usbd_edpt_ready(uint8_t rhport, uint8_t ep_addr) {
}
// Enable SOF interrupt
-void usbd_sof_enable(uint8_t rhport, bool en);
+void usbd_sof_enable(uint8_t rhport, sof_consumer_t consumer, bool en);
/*------------------------------------------------------------------*/
/* Helper
diff --git a/src/host/usbh.c b/src/host/usbh.c
index 7a47f5056..a94c22c4c 100644
--- a/src/host/usbh.c
+++ b/src/host/usbh.c
@@ -1113,7 +1113,7 @@ bool tuh_interface_set(uint8_t daddr, uint8_t itf_num, uint8_t itf_alt,
TU_LOG_USBH("Set Interface %u Alternate %u\r\n", itf_num, itf_alt);
tusb_control_request_t const request = {
.bmRequestType_bit = {
- .recipient = TUSB_REQ_RCPT_DEVICE,
+ .recipient = TUSB_REQ_RCPT_INTERFACE,
.type = TUSB_REQ_TYPE_STANDARD,
.direction = TUSB_DIR_OUT
},
diff --git a/src/portable/analog/max3421/hcd_max3421.c b/src/portable/analog/max3421/hcd_max3421.c
index 39afb7505..d9b8e1fc3 100644
--- a/src/portable/analog/max3421/hcd_max3421.c
+++ b/src/portable/analog/max3421/hcd_max3421.c
@@ -174,7 +174,8 @@ enum {
enum {
EP_STATE_IDLE = 0,
EP_STATE_COMPLETE = 1,
- EP_STATE_ATTEMPT_1 = 2, // pending 1st attempt
+ EP_STATE_ABORTING = 2,
+ EP_STATE_ATTEMPT_1 = 3, // pending 1st attempt
EP_STATE_ATTEMPT_MAX = 15
};
@@ -459,6 +460,7 @@ bool hcd_configure(uint8_t rhport, uint32_t cfg_id, const void* cfg_param) {
tuh_configure_param_t const* cfg = (tuh_configure_param_t const*) cfg_param;
_tuh_cfg = cfg->max3421;
+ _tuh_cfg.max_nak = tu_min8(_tuh_cfg.max_nak, EP_STATE_ATTEMPT_MAX-EP_STATE_ATTEMPT_1);
return true;
}
@@ -479,13 +481,15 @@ bool hcd_init(uint8_t rhport) {
_hcd_data.spi_mutex = osal_mutex_create(&_hcd_data.spi_mutexdef);
#endif
+ // NOTE: driver does not seem to work without nRST pin signal
+
// full duplex, interrupt negative edge
reg_write(rhport, PINCTL_ADDR, _tuh_cfg.pinctl | PINCTL_FDUPSPI, false);
// v1 is 0x01, v2 is 0x12, v3 is 0x13
uint8_t const revision = reg_read(rhport, REVISION_ADDR, false);
- TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
TU_LOG2_HEX(revision);
+ TU_ASSERT(revision == 0x01 || revision == 0x12 || revision == 0x13, false);
// reset
reg_write(rhport, USBCTL_ADDR, USBCTL_CHIPRES, false);
@@ -676,7 +680,6 @@ static void xact_generic(uint8_t rhport, max3421_ep_t *ep, bool switch_ep, bool
bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buffer, uint16_t buflen) {
uint8_t const ep_num = tu_edpt_number(ep_addr);
uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr);
-
max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
TU_VERIFY(ep);
@@ -700,14 +703,19 @@ bool hcd_edpt_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr, uint8_t * buf
return true;
}
-// Abort a queued transfer. Note: it can only abort transfer that has not been started
-// Return true if a queued transfer is aborted, false if there is no transfer to abort
-bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t dev_addr, uint8_t ep_addr) {
- (void) rhport;
- (void) dev_addr;
- (void) ep_addr;
+bool hcd_edpt_abort_xfer(uint8_t rhport, uint8_t daddr, uint8_t ep_addr) {
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ uint8_t const ep_dir = (uint8_t) tu_edpt_dir(ep_addr);
+ max3421_ep_t* ep = find_opened_ep(daddr, ep_num, ep_dir);
+ TU_VERIFY(ep);
- return false;
+ if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) {
+ hcd_int_disable(rhport);
+ ep->state = EP_STATE_ABORTING;
+ hcd_int_enable(rhport);
+ }
+
+ return true;
}
// Submit a special transfer to send 8-byte Setup Packet, when complete hcd_event_xfer_complete() must be invoked
@@ -817,7 +825,6 @@ static void xfer_complete_isr(uint8_t rhport, max3421_ep_t *ep, xfer_result_t re
static void handle_xfer_done(uint8_t rhport, bool in_isr) {
uint8_t const hrsl = reg_read(rhport, HRSL_ADDR, in_isr);
uint8_t const hresult = hrsl & HRSL_RESULT_MASK;
-
uint8_t const ep_num = _hcd_data.hxfr & HXFR_EPNUM_MASK;
uint8_t const hxfr_type = _hcd_data.hxfr & 0xf0;
uint8_t const ep_dir = ((hxfr_type & HXFR_SETUP) || (hxfr_type & HXFR_OUT_NIN)) ? 0 : 1;
@@ -827,34 +834,30 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
xfer_result_t xfer_result;
switch(hresult) {
- case HRSL_SUCCESS:
- xfer_result = XFER_RESULT_SUCCESS;
- break;
-
- case HRSL_STALL:
- xfer_result = XFER_RESULT_STALLED;
- break;
-
case HRSL_NAK:
- if (ep_num == 0) {
- // control endpoint -> retry immediately
- hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ if (ep->state == EP_STATE_ABORTING) {
+ ep->state = EP_STATE_IDLE;
} else {
- if (ep->state < EP_STATE_ATTEMPT_MAX) {
+ if (ep_num == 0) {
+ // control endpoint -> retry immediately and return
+ hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ return;
+ } else if (EP_STATE_ATTEMPT_1 <= ep->state && ep->state < EP_STATE_ATTEMPT_MAX) {
ep->state++;
}
+ }
- max3421_ep_t * next_ep = find_next_pending_ep(ep);
- if (ep == next_ep) {
- // this endpoint is only one pending -> retry immediately
- hxfr_write(rhport, _hcd_data.hxfr, in_isr);
- } else if (next_ep) {
- // switch to next pending endpoint TODO could have issue with double buffered if not clear previously out data
- xact_generic(rhport, next_ep, true, in_isr);
- } else {
- // no more pending in this frame -> clear busy
- atomic_flag_clear(&_hcd_data.busy);
- }
+ max3421_ep_t * next_ep = find_next_pending_ep(ep);
+ if (ep == next_ep) {
+ // this endpoint is only one pending -> retry immediately
+ hxfr_write(rhport, _hcd_data.hxfr, in_isr);
+ } else if (next_ep) {
+ // switch to next pending endpoint
+ // TODO could have issue with double buffered if not clear previously out data
+ xact_generic(rhport, next_ep, true, in_isr);
+ } else {
+ // no more pending in this frame -> clear busy
+ atomic_flag_clear(&_hcd_data.busy);
}
return;
@@ -862,6 +865,14 @@ static void handle_xfer_done(uint8_t rhport, bool in_isr) {
// occurred when initialized without any pending transfer. Skip for now
return;
+ case HRSL_SUCCESS:
+ xfer_result = XFER_RESULT_SUCCESS;
+ break;
+
+ case HRSL_STALL:
+ xfer_result = XFER_RESULT_STALLED;
+ break;
+
default:
TU_LOG3("HRSL: %02X\r\n", hrsl);
xfer_result = XFER_RESULT_FAILED;
@@ -940,9 +951,8 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
if (hirq & HIRQ_FRAME_IRQ) {
_hcd_data.frame_count++;
+ // reset all endpoints nak counter, retry with 1st pending ep.
max3421_ep_t* ep_retry = NULL;
-
- // reset all endpoints attempt counter
for (size_t i = 0; i < CFG_TUH_MAX3421_ENDPOINT_TOTAL; i++) {
max3421_ep_t* ep = &_hcd_data.ep[i];
if (ep->packet_size && ep->state > EP_STATE_ATTEMPT_1) {
@@ -1002,7 +1012,7 @@ void hcd_int_handler(uint8_t rhport, bool in_isr) {
// clear all interrupt except SNDBAV_IRQ (never clear by us). Note RCVDAV_IRQ, HXFRDN_IRQ already clear while processing
hirq &= (uint8_t) ~HIRQ_SNDBAV_IRQ;
- if ( hirq ) {
+ if (hirq) {
hirq_write(rhport, hirq, in_isr);
}
}
diff --git a/src/portable/chipidea/ci_hs/dcd_ci_hs.c b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
index f9ec666e5..93e1d78dd 100644
--- a/src/portable/chipidea/ci_hs/dcd_ci_hs.c
+++ b/src/portable/chipidea/ci_hs/dcd_ci_hs.c
@@ -309,10 +309,12 @@ void dcd_disconnect(uint8_t rhport)
void dcd_sof_enable(uint8_t rhport, bool en)
{
- (void) rhport;
- (void) en;
-
- // TODO implement later
+ ci_hs_regs_t* dcd_reg = CI_HS_REG(rhport);
+ if (en) {
+ dcd_reg->USBINTR |= INTR_SOF;
+ } else {
+ dcd_reg->USBINTR &= ~INTR_SOF;
+ }
}
//--------------------------------------------------------------------+
@@ -679,7 +681,8 @@ void dcd_int_handler(uint8_t rhport)
if (int_status & INTR_SOF)
{
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
+ const uint32_t frame = dcd_reg->FRINDEX;
+ dcd_event_sof(rhport, frame, true);
}
}
diff --git a/src/portable/espressif/esp32sx/dcd_esp32sx.c b/src/portable/espressif/esp32sx/dcd_esp32sx.c
index bfc0baa56..f912bef89 100644
--- a/src/portable/espressif/esp32sx/dcd_esp32sx.c
+++ b/src/portable/espressif/esp32sx/dcd_esp32sx.c
@@ -31,7 +31,8 @@
#if (((CFG_TUSB_MCU == OPT_MCU_ESP32S2) || (CFG_TUSB_MCU == OPT_MCU_ESP32S3)) && CFG_TUD_ENABLED)
// Espressif
-#include "xtensa_api.h"
+#include "xtensa/xtensa_api.h"
+
#include "esp_intr_alloc.h"
#include "esp_log.h"
#include "soc/dport_reg.h"
diff --git a/src/portable/microchip/samd/dcd_samd.c b/src/portable/microchip/samd/dcd_samd.c
index 976d3dfd0..005b63faf 100644
--- a/src/portable/microchip/samd/dcd_samd.c
+++ b/src/portable/microchip/samd/dcd_samd.c
@@ -183,9 +183,12 @@ void dcd_connect(uint8_t rhport)
void dcd_sof_enable(uint8_t rhport, bool en)
{
(void) rhport;
- (void) en;
- // TODO implement later
+ if (en) {
+ USB->DEVICE.INTENSET.bit.SOF = 1;
+ } else {
+ USB->DEVICE.INTENCLR.bit.SOF = 1;
+ }
}
/*------------------------------------------------------------------*/
@@ -374,7 +377,9 @@ void dcd_int_handler (uint8_t rhport)
if ( int_status & USB_DEVICE_INTFLAG_SOF )
{
USB->DEVICE.INTFLAG.reg = USB_DEVICE_INTFLAG_SOF;
- dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ const uint32_t frame = USB->DEVICE.FNUM.bit.FNUM;
+ dcd_event_sof(0, frame, true);
+ //dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
// SAMD doesn't distinguish between Suspend and Disconnect state.
diff --git a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
index c3d0c7297..d5c0daaeb 100644
--- a/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
+++ b/src/portable/mindmotion/mm32/dcd_mm32f327x_otg.c
@@ -283,7 +283,18 @@ void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
/* Response with status first before changing device address */
dcd_edpt_xfer(rhport, tu_edpt_addr(0, TUSB_DIR_IN), NULL, 0);
}
+
+#ifdef __GNUC__ // caused by extra declaration of SystemCoreClock in freeRTOSConfig.h
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wredundant-decls"
+#endif
+
extern u32 SystemCoreClock;
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
void dcd_remote_wakeup(uint8_t rhport)
{
(void) rhport;
diff --git a/src/portable/nordic/nrf5x/dcd_nrf5x.c b/src/portable/nordic/nrf5x/dcd_nrf5x.c
index 2fe721d6b..1cc5c1836 100644
--- a/src/portable/nordic/nrf5x/dcd_nrf5x.c
+++ b/src/portable/nordic/nrf5x/dcd_nrf5x.c
@@ -120,6 +120,9 @@ static struct {
// nRF can only carry one DMA at a time, this is used to guard the access to EasyDMA
atomic_flag dma_running;
+
+ // Track whether sof has been manually enabled
+ bool sof_enabled;
} _dcd;
/*------------------------------------------------------------------*/
@@ -147,7 +150,7 @@ static void start_dma(volatile uint32_t* reg_startep) {
static void edpt_dma_start(volatile uint32_t* reg_startep) {
if (atomic_flag_test_and_set(&_dcd.dma_running)) {
- usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, true);
+ usbd_defer_func((osal_task_func_t)(uintptr_t ) edpt_dma_start, (void*) (uintptr_t) reg_startep, is_in_isr());
} else {
start_dma(reg_startep);
}
@@ -283,9 +286,13 @@ void dcd_connect(uint8_t rhport) {
void dcd_sof_enable(uint8_t rhport, bool en) {
(void) rhport;
- (void) en;
-
- // TODO implement later
+ if (en) {
+ _dcd.sof_enabled = true;
+ NRF_USBD->INTENSET = USBD_INTENSET_SOF_Msk;
+ } else {
+ _dcd.sof_enabled = false;
+ NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
+ }
}
//--------------------------------------------------------------------+
@@ -607,13 +614,16 @@ void dcd_int_handler(uint8_t rhport) {
}
}
- if (!iso_enabled) {
- // ISO endpoint is not used, SOF is only enabled one-time for remote wakeup
- // so we disable it now
- NRF_USBD->INTENCLR = USBD_INTENSET_SOF_Msk;
+ if (!iso_enabled && !_dcd.sof_enabled) {
+ // SOF interrupt not manually enabled and ISO endpoint is not used,
+ // SOF is only enabled one-time for remote wakeup so we disable it now
+
+ NRF_USBD->INTENCLR = USBD_INTENCLR_SOF_Msk;
}
- dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
+ const uint32_t frame = NRF_USBD->FRAMECNTR;
+ dcd_event_sof(0, frame, true);
+ //dcd_event_bus_signal(0, DCD_EVENT_SOF, true);
}
if (int_status & USBD_INTEN_USBEVENT_Msk) {
@@ -897,9 +907,9 @@ void tusb_hal_nrf_power_event(uint32_t event) {
USB_EVT_READY = 2
};
-#if CFG_TUSB_DEBUG >= 2
+#if CFG_TUSB_DEBUG >= 3
const char* const power_evt_str[] = {"Detected", "Removed", "Ready"};
- TU_LOG(2, "Power USB event: %s\r\n", power_evt_str[event]);
+ TU_LOG(3, "Power USB event: %s\r\n", power_evt_str[event]);
#endif
switch (event) {
diff --git a/src/portable/nxp/khci/dcd_khci.c b/src/portable/nxp/khci/dcd_khci.c
index dc71117b3..ef61146aa 100644
--- a/src/portable/nxp/khci/dcd_khci.c
+++ b/src/portable/nxp/khci/dcd_khci.c
@@ -540,7 +540,7 @@ void dcd_int_handler(uint8_t rhport)
}
if (is & USB_ISTAT_SLEEP_MASK) {
- // TU_LOG2("Suspend: "); TU_LOG2_HEX(is);
+ // TU_LOG3("Suspend: "); TU_LOG2_HEX(is);
// Note Host usually has extra delay after bus reset (without SOF), which could falsely
// detected as Sleep event. Though usbd has debouncing logic so we are good
diff --git a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
index 022904a3a..cc18cf59b 100644
--- a/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
+++ b/src/portable/nxp/lpc_ip3511/dcd_lpc_ip3511.c
@@ -42,7 +42,18 @@
#if TU_CHECK_MCU(OPT_MCU_LPC11UXX, OPT_MCU_LPC13XX, OPT_MCU_LPC15XX)
// LPCOpen
+ #ifdef __GNUC__
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wunused-parameter"
+ #pragma GCC diagnostic ignored "-Wstrict-prototypes"
+ #endif
+
#include "chip.h"
+
+ #ifdef __GNUC__
+ #pragma GCC diagnostic pop
+ #endif
+
#else
// SDK
#include "fsl_device_registers.h"
diff --git a/src/portable/renesas/rusb2/dcd_rusb2.c b/src/portable/renesas/rusb2/dcd_rusb2.c
index 50400d1f5..7c6044ca0 100644
--- a/src/portable/renesas/rusb2/dcd_rusb2.c
+++ b/src/portable/renesas/rusb2/dcd_rusb2.c
@@ -29,10 +29,6 @@
#if CFG_TUD_ENABLED && defined(TUP_USBIP_RUSB2)
-// 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
-
#include "device/dcd.h"
#include "rusb2_type.h"
@@ -74,6 +70,8 @@ typedef struct
{
pipe_state_t pipe[PIPE_COUNT];
uint8_t ep[2][16]; /* a lookup table for a pipe index from an endpoint address */
+ // Track whether sof has been manually enabled
+ bool sof_enabled;
} dcd_data_t;
static dcd_data_t _dcd;
@@ -664,6 +662,10 @@ void dcd_init(uint8_t rhport)
rusb2_reg_t* rusb = RUSB2_REG(rhport);
rusb2_module_start(rhport, true);
+// We disable SOF for now until needed later on.
+// Since TinyUSB doesn't use SOF for now, and this interrupt often (1ms interval)
+_dcd.sof_enabled = false;
+
#ifdef RUSB2_SUPPORT_HIGHSPEED
if ( rusb2_is_highspeed_rhport(rhport) ) {
rusb->SYSCFG_b.HSE = 1;
@@ -708,7 +710,7 @@ void dcd_init(uint8_t rhport)
rusb->INTSTS0 = 0;
rusb->INTENB0 = RUSB2_INTSTS0_VBINT_Msk | RUSB2_INTSTS0_BRDY_Msk | RUSB2_INTSTS0_BEMP_Msk |
- RUSB2_INTSTS0_DVST_Msk | RUSB2_INTSTS0_CTRT_Msk | (USE_SOF ? RUSB2_INTSTS0_SOFR_Msk : 0) |
+ RUSB2_INTSTS0_DVST_Msk | RUSB2_INTSTS0_CTRT_Msk | (_dcd.sof_enabled ? RUSB2_INTSTS0_SOFR_Msk : 0) |
RUSB2_INTSTS0_RESM_Msk;
rusb->BEMPENB = 1;
rusb->BRDYENB = 1;
@@ -756,10 +758,9 @@ void dcd_disconnect(uint8_t rhport)
void dcd_sof_enable(uint8_t rhport, bool en)
{
- (void) rhport;
- (void) en;
-
- // TODO implement later
+ rusb2_reg_t* rusb = RUSB2_REG(rhport);
+ _dcd.sof_enabled = en;
+ rusb->INTENB0_b.SOFE = en ? 1: 0;
}
//--------------------------------------------------------------------+
@@ -949,18 +950,19 @@ void dcd_int_handler(uint8_t rhport)
// Resumed
if ( is0 & RUSB2_INTSTS0_RESM_Msk ) {
dcd_event_bus_signal(rhport, DCD_EVENT_RESUME, true);
-#if (0 == USE_SOF)
- rusb->INTENB0_b.SOFE = 0;
-#endif
+ if (!_dcd.sof_enabled) {
+ rusb->INTENB0_b.SOFE = 0;
+ }
}
// SOF received
if ( (is0 & RUSB2_INTSTS0_SOFR_Msk) && rusb->INTENB0_b.SOFE ) {
// USBD will exit suspended mode when SOF event is received
- dcd_event_bus_signal(rhport, DCD_EVENT_SOF, true);
-#if (0 == USE_SOF)
- rusb->INTENB0_b.SOFE = 0;
-#endif
+ const uint32_t frame = rusb->FRMNUM_b.FRNM;
+ dcd_event_sof(rhport, frame, true);
+ if (!_dcd.sof_enabled) {
+ rusb->INTENB0_b.SOFE = 0;
+ }
}
// Device state changes
@@ -979,9 +981,9 @@ void dcd_int_handler(uint8_t rhport)
case RUSB2_INTSTS0_DVSQ_STATE_SUSP2:
case RUSB2_INTSTS0_DVSQ_STATE_SUSP3:
dcd_event_bus_signal(rhport, DCD_EVENT_SUSPEND, true);
-#if (0 == USE_SOF)
- rusb->INTENB0_b.SOFE = 1;
-#endif
+ if (!_dcd.sof_enabled) {
+ rusb->INTENB0_b.SOFE = 1;
+ }
default: break;
}
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
index a26c66892..8bfb899ca 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
+++ b/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.c
@@ -37,14 +37,20 @@
* It also should work with minimal changes for any ST MCU with an "USB A"/"PCD"/"HCD" peripheral. This
* covers:
*
- * F04x, F072, F078, 070x6/B 1024 byte buffer
+ * F04x, F072, F078, F070x6/B 1024 byte buffer
* F102, F103 512 byte buffer; no internal D+ pull-up (maybe many more changes?)
* F302xB/C, F303xB/C, F373 512 byte buffer; no internal D+ pull-up
* F302x6/8, F302xD/E2, F303xD/E 1024 byte buffer; no internal D+ pull-up
+ * G0 2048 byte buffer; 32-bit bus; host mode
+ * G4 1024 byte buffer
+ * H5 2048 byte buffer; 32-bit bus; host mode
* L0x2, L0x3 1024 byte buffer
* L1 512 byte buffer
* L4x2, L4x3 1024 byte buffer
- * G0 2048 byte buffer
+ * L5 1024 byte buffer
+ * U0 1024 byte buffer; 32-bit bus
+ * U535, U545 2048 byte buffer; 32-bit bus; host mode
+ * WB35, WB55 1024 byte buffer
*
* To use this driver, you must:
* - If you are using a device with crystal-less USB, set up the clock recovery system (CRS)
@@ -102,25 +108,29 @@
#include "tusb_option.h"
-#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV)
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_FSDEV) && \
+ !(defined(TUP_USBIP_FSDEV_CH32) && CFG_TUD_WCH_USBIP_FSDEV == 0)
#include "device/dcd.h"
-#ifdef TUP_USBIP_FSDEV_STM32
-// Undefine to reduce the dependence on HAL
-#undef USE_HAL_DRIVER
-#include "portable/st/stm32_fsdev/dcd_stm32_fsdev.h"
+#if defined(TUP_USBIP_FSDEV_STM32)
+ // Undefine to reduce the dependence on HAL
+ #undef USE_HAL_DRIVER
+ #include "fsdev_stm32.h"
+#elif defined(TUP_USBIP_FSDEV_CH32)
+ #include "fsdev_ch32.h"
+#else
+ #error "Unknown USB IP"
#endif
-/*****************************************************
- * Configuration
- *****************************************************/
+#include "fsdev_common.h"
-// HW supports max of 8 bidirectional endpoints, but this can be reduced to save RAM
-// (8u here would mean 8 IN and 8 OUT)
-#ifndef MAX_EP_COUNT
-#define MAX_EP_COUNT 8U
-#endif
+//--------------------------------------------------------------------+
+// Configuration
+//--------------------------------------------------------------------+
+
+// hardware limit endpoint
+#define FSDEV_EP_COUNT 8
// If sharing with CAN, one can set this to be non-zero to give CAN space where it wants it
// Both of these MUST be a multiple of 2, and are in byte units.
@@ -132,11 +142,6 @@
#define DCD_STM32_BTABLE_SIZE (FSDEV_PMA_SIZE - DCD_STM32_BTABLE_BASE)
#endif
-/***************************************************
- * Checks, structs, defines, function definitions, etc.
- */
-
-TU_VERIFY_STATIC((MAX_EP_COUNT) <= STFSDEV_EP_COUNT, "Only 8 endpoints supported on the hardware");
TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) + (DCD_STM32_BTABLE_SIZE)) <= (FSDEV_PMA_SIZE), "BTABLE does not fit in PMA RAM");
TU_VERIFY_STATIC(((DCD_STM32_BTABLE_BASE) % 8) == 0, "BTABLE base must be aligned to 8 bytes");
@@ -162,9 +167,9 @@ typedef struct {
bool allocated[2];
} ep_alloc_t;
-static xfer_ctl_t xfer_status[MAX_EP_COUNT][2];
+static xfer_ctl_t xfer_status[CFG_TUD_ENDPPOINT_MAX][2];
-static ep_alloc_t ep_alloc_status[STFSDEV_EP_COUNT];
+static ep_alloc_t ep_alloc_status[FSDEV_EP_COUNT];
static TU_ATTR_ALIGNED(4) uint32_t _setup_packet[6];
@@ -199,7 +204,7 @@ TU_ATTR_ALWAYS_INLINE static inline xfer_ctl_t *xfer_ctl_ptr(uint32_t ep_addr)
uint8_t epnum = tu_edpt_number(ep_addr);
uint8_t dir = tu_edpt_dir(ep_addr);
// Fix -Werror=null-dereference
- TU_ASSERT(epnum < MAX_EP_COUNT, &xfer_status[0][0]);
+ TU_ASSERT(epnum < CFG_TUD_ENDPPOINT_MAX, &xfer_status[0][0]);
return &xfer_status[epnum][dir];
}
@@ -216,30 +221,30 @@ void dcd_init(uint8_t rhport)
/* The RM mentions to use a special ordering of PDWN and FRES, but this isn't done in HAL.
* Here, the RM is followed. */
- for (uint32_t i = 0; i < 200; i++) { // should be a few us
+ for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
// Perform USB peripheral reset
USB->CNTR = USB_CNTR_FRES | USB_CNTR_PDWN;
- for (uint32_t i = 0; i < 200; i++) { // should be a few us
+ for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
USB->CNTR &= ~USB_CNTR_PDWN;
// Wait startup time, for F042 and F070, this is <= 1 us.
- for (uint32_t i = 0; i < 200; i++) { // should be a few us
+ for (volatile uint32_t i = 0; i < 200; i++) { // should be a few us
asm("NOP");
}
USB->CNTR = 0; // Enable USB
-#if !defined(STM32G0) && !defined(STM32H5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address
+#if !defined(STM32G0) && !defined(STM32H5) && !defined(STM32U5) // BTABLE register does not exist any more on STM32G0, it is fixed to USB SRAM base address
USB->BTABLE = DCD_STM32_BTABLE_BASE;
#endif
USB->ISTR = 0; // Clear pending interrupts
// Reset endpoints to disabled
- for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) {
+ for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) {
// This doesn't clear all bits since some bits are "toggle", but does set the type to DISABLED.
pcd_set_endpoint(USB, i, 0u);
}
@@ -248,43 +253,9 @@ void dcd_init(uint8_t rhport)
dcd_handle_bus_reset();
// Enable pull-up if supported
- if (dcd_connect) {
- dcd_connect(rhport);
- }
+ dcd_connect(rhport);
}
-// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU.
-#if defined(USB_BCDR_DPPU)
-
-// Disable internal D+ PU
-void dcd_disconnect(uint8_t rhport)
-{
- (void)rhport;
- USB->BCDR &= ~(USB_BCDR_DPPU);
-}
-
-// Enable internal D+ PU
-void dcd_connect(uint8_t rhport)
-{
- (void)rhport;
- USB->BCDR |= USB_BCDR_DPPU;
-}
-
-#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151
-// Disable internal D+ PU
-void dcd_disconnect(uint8_t rhport)
-{
- (void)rhport;
- SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
-}
-
-// Enable internal D+ PU
-void dcd_connect(uint8_t rhport)
-{
- (void)rhport;
- SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
-}
-#endif
void dcd_sof_enable(uint8_t rhport, bool en)
{
@@ -298,126 +269,6 @@ void dcd_sof_enable(uint8_t rhport, bool en)
}
}
-// Enable device interrupt
-void dcd_int_enable(uint8_t rhport)
-{
- (void)rhport;
- // Member here forces write to RAM before allowing ISR to execute
- __DSB();
- __ISB();
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4
- NVIC_EnableIRQ(USB_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
- NVIC_EnableIRQ(USB_LP_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
-// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
-// shared USB/CAN IRQs to separate CAN and USB IRQs.
-// This dynamically checks if this remap is active to enable the right IRQs.
-#ifdef SYSCFG_CFGR1_USB_IT_RMP
- if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
- NVIC_EnableIRQ(USB_HP_IRQn);
- NVIC_EnableIRQ(USB_LP_IRQn);
- NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
- } else
-#endif
- {
- NVIC_EnableIRQ(USB_HP_CAN_TX_IRQn);
- NVIC_EnableIRQ(USB_LP_CAN_RX0_IRQn);
- NVIC_EnableIRQ(USBWakeUp_IRQn);
- }
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
- NVIC_EnableIRQ(USB_HP_CAN1_TX_IRQn);
- NVIC_EnableIRQ(USB_LP_CAN1_RX0_IRQn);
- NVIC_EnableIRQ(USBWakeUp_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
- NVIC_EnableIRQ(USB_HP_IRQn);
- NVIC_EnableIRQ(USB_LP_IRQn);
- NVIC_EnableIRQ(USBWakeUp_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
-#ifdef STM32G0B0xx
- NVIC_EnableIRQ(USB_IRQn);
-#else
- NVIC_EnableIRQ(USB_UCPD1_2_IRQn);
-#endif
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
- NVIC_EnableIRQ(USB_DRD_FS_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
- NVIC_EnableIRQ(USB_HP_IRQn);
- NVIC_EnableIRQ(USB_LP_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
- NVIC_EnableIRQ(USB_FS_IRQn);
-
-#else
-#error Unknown arch in USB driver
-#endif
-}
-
-// Disable device interrupt
-void dcd_int_disable(uint8_t rhport)
-{
- (void)rhport;
-
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0 || CFG_TUSB_MCU == OPT_MCU_STM32L0 || CFG_TUSB_MCU == OPT_MCU_STM32L4
- NVIC_DisableIRQ(USB_IRQn);
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
- NVIC_DisableIRQ(USB_LP_IRQn);
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F3
-// Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
-// shared USB/CAN IRQs to separate CAN and USB IRQs.
-// This dynamically checks if this remap is active to disable the right IRQs.
-#ifdef SYSCFG_CFGR1_USB_IT_RMP
- if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
- NVIC_DisableIRQ(USB_HP_IRQn);
- NVIC_DisableIRQ(USB_LP_IRQn);
- NVIC_DisableIRQ(USBWakeUp_RMP_IRQn);
- } else
-#endif
- {
- NVIC_DisableIRQ(USB_HP_CAN_TX_IRQn);
- NVIC_DisableIRQ(USB_LP_CAN_RX0_IRQn);
- NVIC_DisableIRQ(USBWakeUp_IRQn);
- }
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
- NVIC_DisableIRQ(USB_HP_CAN1_TX_IRQn);
- NVIC_DisableIRQ(USB_LP_CAN1_RX0_IRQn);
- NVIC_DisableIRQ(USBWakeUp_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
- NVIC_DisableIRQ(USB_HP_IRQn);
- NVIC_DisableIRQ(USB_LP_IRQn);
- NVIC_DisableIRQ(USBWakeUp_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
-#ifdef STM32G0B0xx
- NVIC_DisableIRQ(USB_IRQn);
-#else
- NVIC_DisableIRQ(USB_UCPD1_2_IRQn);
-#endif
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
- NVIC_DisableIRQ(USB_DRD_FS_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
- NVIC_DisableIRQ(USB_HP_IRQn);
- NVIC_DisableIRQ(USB_LP_IRQn);
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
- NVIC_DisableIRQ(USB_FS_IRQn);
-
-#else
-#error Unknown arch in USB driver
-#endif
-
- // CMSIS has a membar after disabling interrupts
-}
-
// Receive Set Address request, mcu port must also include status IN response
void dcd_set_address(uint8_t rhport, uint8_t dev_addr)
{
@@ -461,7 +312,7 @@ static void dcd_handle_bus_reset(void)
{
USB->DADDR = 0u; // disable USB peripheral by clearing the EF flag
- for (uint32_t i = 0; i < STFSDEV_EP_COUNT; i++) {
+ for (uint32_t i = 0; i < FSDEV_EP_COUNT; i++) {
// Clear EP allocation status
ep_alloc_status[i].ep_num = 0xFF;
ep_alloc_status[i].ep_type = 0xFF;
@@ -470,7 +321,7 @@ static void dcd_handle_bus_reset(void)
}
// Reset PMA allocation
- ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT;
+ ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX;
dcd_edpt_open(0, &ep0OUT_desc);
dcd_edpt_open(0, &ep0IN_desc);
@@ -653,7 +504,6 @@ static void dcd_ep_ctr_handler(void)
void dcd_int_handler(uint8_t rhport)
{
-
(void)rhport;
uint32_t int_status = USB->ISTR;
@@ -774,7 +624,7 @@ static uint8_t dcd_ep_alloc(uint8_t ep_addr, uint8_t ep_type)
uint8_t const epnum = tu_edpt_number(ep_addr);
uint8_t const dir = tu_edpt_dir(ep_addr);
- for (uint8_t i = 0; i < STFSDEV_EP_COUNT; i++) {
+ for (uint8_t i = 0; i < FSDEV_EP_COUNT; i++) {
// Check if already allocated
if (ep_alloc_status[i].allocated[dir] &&
ep_alloc_status[i].ep_type == ep_type &&
@@ -818,7 +668,7 @@ bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *p_endpoint_desc)
uint16_t pma_addr;
uint32_t wType;
- TU_ASSERT(ep_idx < STFSDEV_EP_COUNT);
+ TU_ASSERT(ep_idx < FSDEV_EP_COUNT);
TU_ASSERT(buffer_size <= 64);
// Set type
@@ -865,7 +715,7 @@ void dcd_edpt_close_all(uint8_t rhport)
{
(void)rhport;
- for (uint32_t i = 1; i < STFSDEV_EP_COUNT; i++) {
+ for (uint32_t i = 1; i < FSDEV_EP_COUNT; i++) {
// Reset endpoint
pcd_set_endpoint(USB, i, 0);
// Clear EP allocation status
@@ -876,7 +726,7 @@ void dcd_edpt_close_all(uint8_t rhport)
}
// Reset PMA allocation
- ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * MAX_EP_COUNT + 2 * CFG_TUD_ENDPOINT0_SIZE;
+ ep_buf_ptr = DCD_STM32_BTABLE_BASE + 8 * CFG_TUD_ENDPPOINT_MAX + 2 * CFG_TUD_ENDPOINT0_SIZE;
}
/**
@@ -1155,7 +1005,7 @@ static bool dcd_write_packet_memory(uint16_t dst, const void *__restrict src, ui
}
if (wNBytes) {
- temp1 = *srcVal;
+ temp1 = (uint16_t) *srcVal;
*pdwVal = temp1;
}
diff --git a/src/portable/st/stm32_fsdev/fsdev_ch32.h b/src/portable/st/stm32_fsdev/fsdev_ch32.h
new file mode 100644
index 000000000..f63a80d56
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/fsdev_ch32.h
@@ -0,0 +1,242 @@
+/*
+* The MIT License (MIT)
+ *
+ * Copyright (c) 2024, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+/** <h2><center>&copy; Copyright (c) 2016 STMicroelectronics.
+ * All rights reserved.</center></h2>
+ *
+ * This software component is licensed by ST under BSD 3-Clause license,
+ * the "License"; You may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at:
+ * opensource.org/licenses/BSD-3-Clause
+ */
+
+#ifndef TUSB_FSDEV_CH32_H
+#define TUSB_FSDEV_CH32_H
+
+#include "common/tusb_compiler.h"
+
+// https://github.com/openwch/ch32v307/pull/90
+// https://github.com/openwch/ch32v20x/pull/12
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_CH32F20X
+ #include <ch32f20x.h>
+#elif CFG_TUSB_MCU == OPT_MCU_CH32V20X
+ #include <ch32v20x.h>
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#define FSDEV_PMA_SIZE (512u)
+
+// volatile 32-bit aligned
+#define _va32 volatile TU_ATTR_ALIGNED(4)
+
+typedef struct {
+ _va32 uint16_t EP0R; // 00: USB Endpoint 0 register
+ _va32 uint16_t EP1R; // 04: USB Endpoint 1 register
+ _va32 uint16_t EP2R; // 08: USB Endpoint 2 register
+ _va32 uint16_t EP3R; // 0C: USB Endpoint 3 register
+ _va32 uint16_t EP4R; // 10: USB Endpoint 4 register
+ _va32 uint16_t EP5R; // 14: USB Endpoint 5 register
+ _va32 uint16_t EP6R; // 18: USB Endpoint 6 register
+ _va32 uint16_t EP7R; // 1C: USB Endpoint 7 register
+ _va32 uint16_t RESERVED7[16]; // Reserved
+ _va32 uint16_t CNTR; // 40: Control register
+ _va32 uint16_t ISTR; // 44: Interrupt status register
+ _va32 uint16_t FNR; // 48: Frame number register
+ _va32 uint16_t DADDR; // 4C: Device address register
+ _va32 uint16_t BTABLE; // 50: Buffer Table address register
+} USB_TypeDef;
+
+TU_VERIFY_STATIC(sizeof(USB_TypeDef) == 0x54, "Size is not correct");
+TU_VERIFY_STATIC(offsetof(USB_TypeDef, CNTR) == 0x40, "Wrong offset");
+
+#define USB_BASE (APB1PERIPH_BASE + 0x00005C00UL) /*!< USB_IP Peripheral Registers base address */
+#define USB_PMAADDR (APB1PERIPH_BASE + 0x00006000UL) /*!< USB_IP Packet Memory Area base address */
+#define USB ((USB_TypeDef *)USB_BASE)
+
+/******************************************************************************/
+/* */
+/* USB Device General registers */
+/* */
+/******************************************************************************/
+#define USB_CNTR (USB_BASE + 0x40U) /*!< Control register */
+#define USB_ISTR (USB_BASE + 0x44U) /*!< Interrupt status register */
+#define USB_FNR (USB_BASE + 0x48U) /*!< Frame number register */
+#define USB_DADDR (USB_BASE + 0x4CU) /*!< Device address register */
+#define USB_BTABLE (USB_BASE + 0x50U) /*!< Buffer Table address register */
+
+/**************************** ISTR interrupt events *************************/
+#define USB_ISTR_CTR ((uint16_t)0x8000U) /*!< Correct TRansfer (clear-only bit) */
+#define USB_ISTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun (clear-only bit) */
+#define USB_ISTR_ERR ((uint16_t)0x2000U) /*!< ERRor (clear-only bit) */
+#define USB_ISTR_WKUP ((uint16_t)0x1000U) /*!< WaKe UP (clear-only bit) */
+#define USB_ISTR_SUSP ((uint16_t)0x0800U) /*!< SUSPend (clear-only bit) */
+#define USB_ISTR_RESET ((uint16_t)0x0400U) /*!< RESET (clear-only bit) */
+#define USB_ISTR_SOF ((uint16_t)0x0200U) /*!< Start Of Frame (clear-only bit) */
+#define USB_ISTR_ESOF ((uint16_t)0x0100U) /*!< Expected Start Of Frame (clear-only bit) */
+#define USB_ISTR_DIR ((uint16_t)0x0010U) /*!< DIRection of transaction (read-only bit) */
+#define USB_ISTR_EP_ID ((uint16_t)0x000FU) /*!< EndPoint IDentifier (read-only bit) */
+
+/* Legacy defines */
+#define USB_ISTR_PMAOVRM USB_ISTR_PMAOVR
+
+#define USB_CLR_CTR (~USB_ISTR_CTR) /*!< clear Correct TRansfer bit */
+#define USB_CLR_PMAOVR (~USB_ISTR_PMAOVR) /*!< clear DMA OVeR/underrun bit*/
+#define USB_CLR_ERR (~USB_ISTR_ERR) /*!< clear ERRor bit */
+#define USB_CLR_WKUP (~USB_ISTR_WKUP) /*!< clear WaKe UP bit */
+#define USB_CLR_SUSP (~USB_ISTR_SUSP) /*!< clear SUSPend bit */
+#define USB_CLR_RESET (~USB_ISTR_RESET) /*!< clear RESET bit */
+#define USB_CLR_SOF (~USB_ISTR_SOF) /*!< clear Start Of Frame bit */
+#define USB_CLR_ESOF (~USB_ISTR_ESOF) /*!< clear Expected Start Of Frame bit */
+
+/* Legacy defines */
+#define USB_CLR_PMAOVRM USB_CLR_PMAOVR
+
+/************************* CNTR control register bits definitions ***********/
+#define USB_CNTR_CTRM ((uint16_t)0x8000U) /*!< Correct TRansfer Mask */
+#define USB_CNTR_PMAOVR ((uint16_t)0x4000U) /*!< DMA OVeR/underrun Mask */
+#define USB_CNTR_ERRM ((uint16_t)0x2000U) /*!< ERRor Mask */
+#define USB_CNTR_WKUPM ((uint16_t)0x1000U) /*!< WaKe UP Mask */
+#define USB_CNTR_SUSPM ((uint16_t)0x0800U) /*!< SUSPend Mask */
+#define USB_CNTR_RESETM ((uint16_t)0x0400U) /*!< RESET Mask */
+#define USB_CNTR_SOFM ((uint16_t)0x0200U) /*!< Start Of Frame Mask */
+#define USB_CNTR_ESOFM ((uint16_t)0x0100U) /*!< Expected Start Of Frame Mask */
+#define USB_CNTR_RESUME ((uint16_t)0x0010U) /*!< RESUME request */
+#define USB_CNTR_FSUSP ((uint16_t)0x0008U) /*!< Force SUSPend */
+#define USB_CNTR_LPMODE ((uint16_t)0x0004U) /*!< Low-power MODE */
+#define USB_CNTR_PDWN ((uint16_t)0x0002U) /*!< Power DoWN */
+#define USB_CNTR_FRES ((uint16_t)0x0001U) /*!< Force USB RESet */
+
+/* Legacy defines */
+#define USB_CNTR_PMAOVRM USB_CNTR_PMAOVR
+#define USB_CNTR_LP_MODE USB_CNTR_LPMODE
+
+/******************** FNR Frame Number Register bit definitions ************/
+#define USB_FNR_RXDP ((uint16_t)0x8000U) /*!< status of D+ data line */
+#define USB_FNR_RXDM ((uint16_t)0x4000U) /*!< status of D- data line */
+#define USB_FNR_LCK ((uint16_t)0x2000U) /*!< LoCKed */
+#define USB_FNR_LSOF ((uint16_t)0x1800U) /*!< Lost SOF */
+#define USB_FNR_FN ((uint16_t)0x07FFU) /*!< Frame Number */
+
+/******************** DADDR Device ADDRess bit definitions ****************/
+#define USB_DADDR_EF ((uint8_t)0x80U) /*!< USB device address Enable Function */
+#define USB_DADDR_ADD ((uint8_t)0x7FU) /*!< USB device address */
+
+/****************************** Endpoint register *************************/
+#define USB_EP0R USB_BASE /*!< endpoint 0 register address */
+#define USB_EP1R (USB_BASE + 0x04U) /*!< endpoint 1 register address */
+#define USB_EP2R (USB_BASE + 0x08U) /*!< endpoint 2 register address */
+#define USB_EP3R (USB_BASE + 0x0CU) /*!< endpoint 3 register address */
+#define USB_EP4R (USB_BASE + 0x10U) /*!< endpoint 4 register address */
+#define USB_EP5R (USB_BASE + 0x14U) /*!< endpoint 5 register address */
+#define USB_EP6R (USB_BASE + 0x18U) /*!< endpoint 6 register address */
+#define USB_EP7R (USB_BASE + 0x1CU) /*!< endpoint 7 register address */
+/* bit positions */
+#define USB_EP_CTR_RX ((uint16_t)0x8000U) /*!< EndPoint Correct TRansfer RX */
+#define USB_EP_DTOG_RX ((uint16_t)0x4000U) /*!< EndPoint Data TOGGLE RX */
+#define USB_EPRX_STAT ((uint16_t)0x3000U) /*!< EndPoint RX STATus bit field */
+#define USB_EP_SETUP ((uint16_t)0x0800U) /*!< EndPoint SETUP */
+#define USB_EP_T_FIELD ((uint16_t)0x0600U) /*!< EndPoint TYPE */
+#define USB_EP_KIND ((uint16_t)0x0100U) /*!< EndPoint KIND */
+#define USB_EP_CTR_TX ((uint16_t)0x0080U) /*!< EndPoint Correct TRansfer TX */
+#define USB_EP_DTOG_TX ((uint16_t)0x0040U) /*!< EndPoint Data TOGGLE TX */
+#define USB_EPTX_STAT ((uint16_t)0x0030U) /*!< EndPoint TX STATus bit field */
+#define USB_EPADDR_FIELD ((uint16_t)0x000FU) /*!< EndPoint ADDRess FIELD */
+
+/* EndPoint REGister MASK (no toggle fields) */
+#define USB_EPREG_MASK (USB_EP_CTR_RX|USB_EP_SETUP|USB_EP_T_FIELD|USB_EP_KIND|USB_EP_CTR_TX|USB_EPADDR_FIELD)
+ /*!< EP_TYPE[1:0] EndPoint TYPE */
+#define USB_EP_TYPE_MASK ((uint16_t)0x0600U) /*!< EndPoint TYPE Mask */
+#define USB_EP_BULK ((uint16_t)0x0000U) /*!< EndPoint BULK */
+#define USB_EP_CONTROL ((uint16_t)0x0200U) /*!< EndPoint CONTROL */
+#define USB_EP_ISOCHRONOUS ((uint16_t)0x0400U) /*!< EndPoint ISOCHRONOUS */
+#define USB_EP_INTERRUPT ((uint16_t)0x0600U) /*!< EndPoint INTERRUPT */
+#define USB_EP_T_MASK ((uint16_t) ~USB_EP_T_FIELD & USB_EPREG_MASK)
+
+#define USB_EPKIND_MASK ((uint16_t) ~USB_EP_KIND & USB_EPREG_MASK) /*!< EP_KIND EndPoint KIND */
+ /*!< STAT_TX[1:0] STATus for TX transfer */
+#define USB_EP_TX_DIS ((uint16_t)0x0000U) /*!< EndPoint TX DISabled */
+#define USB_EP_TX_STALL ((uint16_t)0x0010U) /*!< EndPoint TX STALLed */
+#define USB_EP_TX_NAK ((uint16_t)0x0020U) /*!< EndPoint TX NAKed */
+#define USB_EP_TX_VALID ((uint16_t)0x0030U) /*!< EndPoint TX VALID */
+#define USB_EPTX_DTOG1 ((uint16_t)0x0010U) /*!< EndPoint TX Data TOGgle bit1 */
+#define USB_EPTX_DTOG2 ((uint16_t)0x0020U) /*!< EndPoint TX Data TOGgle bit2 */
+#define USB_EPTX_DTOGMASK (USB_EPTX_STAT|USB_EPREG_MASK)
+ /*!< STAT_RX[1:0] STATus for RX transfer */
+#define USB_EP_RX_DIS ((uint16_t)0x0000U) /*!< EndPoint RX DISabled */
+#define USB_EP_RX_STALL ((uint16_t)0x1000U) /*!< EndPoint RX STALLed */
+#define USB_EP_RX_NAK ((uint16_t)0x2000U) /*!< EndPoint RX NAKed */
+#define USB_EP_RX_VALID ((uint16_t)0x3000U) /*!< EndPoint RX VALID */
+#define USB_EPRX_DTOG1 ((uint16_t)0x1000U) /*!< EndPoint RX Data TOGgle bit1 */
+#define USB_EPRX_DTOG2 ((uint16_t)0x2000U) /*!< EndPoint RX Data TOGgle bit1 */
+#define USB_EPRX_DTOGMASK (USB_EPRX_STAT|USB_EPREG_MASK)
+
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+#if CFG_TUSB_MCU == OPT_MCU_CH32V20X
+static const IRQn_Type fsdev_irq[] = {
+ USB_HP_CAN1_TX_IRQn,
+ USB_LP_CAN1_RX0_IRQn,
+ USBWakeUp_IRQn
+};
+enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) };
+#else
+ #error "Unsupported MCU"
+#endif
+
+void dcd_int_enable(uint8_t rhport) {
+ (void)rhport;
+ for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) {
+ NVIC_EnableIRQ(fsdev_irq[i]);
+ }
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void)rhport;
+ for(uint8_t i=0; i < FSDEV_IRQ_NUM; i++) {
+ NVIC_DisableIRQ(fsdev_irq[i]);
+ }
+}
+
+void dcd_disconnect(uint8_t rhport) {
+ (void) rhport;
+ EXTEN->EXTEN_CTR &= ~EXTEN_USBD_PU_EN;
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void) rhport;
+ EXTEN->EXTEN_CTR |= EXTEN_USBD_PU_EN;
+}
+
+#endif
diff --git a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h b/src/portable/st/stm32_fsdev/fsdev_common.h
index 7992f34a1..e8a6af8cb 100644
--- a/src/portable/st/stm32_fsdev/dcd_stm32_fsdev.h
+++ b/src/portable/st/stm32_fsdev/fsdev_common.h
@@ -1,174 +1,43 @@
/*
+ * The MIT License (MIT)
+ *
* Copyright(c) 2016 STMicroelectronics
* Copyright(c) N Conrad
- * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ * Copyright (c) 2024, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
*
- * Redistribution and use in source and binary forms, with or without modification,
- * are permitted provided that the following conditions are met:
- * 1. Redistributions of source code must retain the above copyright notice,
- * this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- * 3. Neither the name of STMicroelectronics nor the names of its contributors
- * may be used to endorse or promote products derived from this software
- * without specific prior written permission.
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
*
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
- * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
*
- * This file is part of the TinyUSB stack.
*/
-// This file contains source copied from ST's HAL, and thus should have their copyright statement.
+#ifndef TUSB_FSDEV_COMMON_H
+#define TUSB_FSDEV_COMMON_H
+
+#ifdef __cplusplus
+ extern "C" {
+#endif
+
+#include "stdint.h"
// FSDEV_PMA_SIZE is PMA buffer size in bytes.
// On 512-byte devices, access with a stride of two words (use every other 16-bit address)
// On 1024-byte devices, access with a stride of one word (use every 16-bit address)
-#ifndef PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
-#define PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_
-
-#if CFG_TUSB_MCU == OPT_MCU_STM32F0
- #include "stm32f0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- // F0x2 models are crystal-less
- // All have internal D+ pull-up
- // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support
- // PMA dedicated to USB (no sharing with CAN)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
- #include "stm32f1xx.h"
- #define FSDEV_PMA_SIZE (512u)
- // NO internal Pull-ups
- // *B, and *C: 2 x 16 bits/word
-
- // F1 names this differently from the rest
- #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
-
-#elif defined(STM32F302xB) || defined(STM32F302xC) || \
- defined(STM32F303xB) || defined(STM32F303xC) || \
- defined(STM32F373xC)
- #include "stm32f3xx.h"
- #define FSDEV_PMA_SIZE (512u)
- // NO internal Pull-ups
- // *B, and *C: 1 x 16 bits/word
- // PMA dedicated to USB (no sharing with CAN)
-
-#elif defined(STM32F302x6) || defined(STM32F302x8) || \
- defined(STM32F302xD) || defined(STM32F302xE) || \
- defined(STM32F303xD) || defined(STM32F303xE)
- #include "stm32f3xx.h"
- #define FSDEV_PMA_SIZE (1024u)
- // NO internal Pull-ups
- // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
- // When CAN clock is enabled, USB can use first 768 bytes ONLY.
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
- #include "stm32l0xx.h"
- #define FSDEV_PMA_SIZE (1024u)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
- #include "stm32l1xx.h"
- #define FSDEV_PMA_SIZE (512u)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
- #include "stm32g4xx.h"
- #define FSDEV_PMA_SIZE (1024u)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
- #include "stm32g0xx.h"
- #define FSDEV_BUS_32BIT
- #define FSDEV_PMA_SIZE (2048u)
- #undef USB_PMAADDR
- #define USB_PMAADDR USB_DRD_PMAADDR
- #define USB_TypeDef USB_DRD_TypeDef
- #define EP0R CHEP0R
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
- #define USB_EPREG_MASK USB_CHEP_REG_MASK
- #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
- #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
- #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
- #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
- #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
- #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
- #define USB_EPRX_STAT USB_CH_RX_VALID
- #define USB_EPKIND_MASK USB_EP_KIND_MASK
- #define USB USB_DRD_FS
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
- #include "stm32h5xx.h"
- #define FSDEV_BUS_32BIT
-
- #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE)
- #define USB_DRD_BASE USB_DRD_FS_BASE
- #endif
-
- #define FSDEV_PMA_SIZE (2048u)
- #undef USB_PMAADDR
- #define USB_PMAADDR USB_DRD_PMAADDR
- #define USB_TypeDef USB_DRD_TypeDef
- #define EP0R CHEP0R
- #define USB_EP_CTR_RX USB_EP_VTRX
- #define USB_EP_CTR_TX USB_EP_VTTX
- #define USB_EP_T_FIELD USB_CHEP_UTYPE
- #define USB_EPREG_MASK USB_CHEP_REG_MASK
- #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
- #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
- #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
- #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
- #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
- #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
- #define USB_EPRX_STAT USB_CH_RX_VALID
- #define USB_EPKIND_MASK USB_EP_KIND_MASK
- #define USB USB_DRD_FS
- #define USB_CNTR_FRES USB_CNTR_USBRST
- #define USB_CNTR_RESUME USB_CNTR_L2RES
- #define USB_ISTR_EP_ID USB_ISTR_IDN
- #define USB_EPADDR_FIELD USB_CHEP_ADDR
- #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
- #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
- #include "stm32wbxx.h"
- #define FSDEV_PMA_SIZE (1024u)
- /* ST provided header has incorrect value */
- #undef USB_PMAADDR
- #define USB_PMAADDR USB1_PMAADDR
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
- #include "stm32l4xx.h"
- #define FSDEV_PMA_SIZE (1024u)
-
-#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
- #include "stm32l5xx.h"
- #define FSDEV_PMA_SIZE (1024u)
-
- #ifndef USB_PMAADDR
- #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
- #endif
-
-#else
- #error You are using an untested or unimplemented STM32 variant. Please update the driver.
- // This includes L1x0, L1x1, L1x2, L4x2 and L4x3, G1x1, G1x3, and G1x4
-#endif
-
// For purposes of accessing the packet
#if ((FSDEV_PMA_SIZE) == 512u)
#define FSDEV_PMA_STRIDE (2u)
@@ -181,24 +50,24 @@
// The compiler should warn us if we cast it to a non-volatile type?
#ifdef FSDEV_BUS_32BIT
typedef uint32_t fsdev_bus_t;
-static __IO uint32_t * const pma32 = (__IO uint32_t*)USB_PMAADDR;
+static volatile uint32_t * const pma32 = (volatile uint32_t*)USB_PMAADDR;
#else
typedef uint16_t fsdev_bus_t;
// Volatile is also needed to prevent the optimizer from changing access to 32-bit (as 32-bit access is forbidden)
-static __IO uint16_t * const pma = (__IO uint16_t*)USB_PMAADDR;
+static volatile uint16_t * const pma = (volatile uint16_t*)USB_PMAADDR;
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) {
+TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t * pcd_btable_word_ptr(USB_TypeDef * USBx, size_t x) {
size_t total_word_offset = (((USBx)->BTABLE)>>1) + x;
total_word_offset *= FSDEV_PMA_STRIDE;
return &(pma[total_word_offset]);
}
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
+TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t* pcd_ep_tx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 1u);
}
-TU_ATTR_ALWAYS_INLINE static inline __IO uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
+TU_ATTR_ALWAYS_INLINE static inline volatile uint16_t* pcd_ep_rx_cnt_ptr(USB_TypeDef * USBx, uint32_t bEpIdx) {
return pcd_btable_word_ptr(USBx,(bEpIdx)*4u + 3u);
}
#endif
@@ -218,10 +87,10 @@ TU_ATTR_ALWAYS_INLINE static inline uint16_t pcd_aligned_buffer_size(uint16_t si
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wRegValue) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
- __O uint32_t *reg = (__O uint32_t *)(USB_DRD_BASE + bEpIdx*4);
+ volatile uint32_t *reg = (volatile uint32_t *)(USB_DRD_BASE + bEpIdx*4);
*reg = wRegValue;
#else
- __O uint16_t *reg = (__O uint16_t *)((&USBx->EP0R) + bEpIdx*2u);
+ volatile uint16_t *reg = (volatile uint16_t *)((&USBx->EP0R) + bEpIdx*2u);
*reg = (uint16_t)wRegValue;
#endif
}
@@ -229,9 +98,9 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_endpoint(USB_TypeDef * USBx, ui
TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_endpoint(USB_TypeDef * USBx, uint32_t bEpIdx) {
#ifdef FSDEV_BUS_32BIT
(void) USBx;
- __I uint32_t *reg = (__I uint32_t *)(USB_DRD_BASE + bEpIdx*4);
+ volatile const uint32_t *reg = (volatile const uint32_t *)(USB_DRD_BASE + bEpIdx*4);
#else
- __I uint16_t *reg = (__I uint16_t *)((&USBx->EP0R) + bEpIdx*2u);
+ volatile const uint16_t *reg = (volatile const uint16_t *)((&USBx->EP0R) + bEpIdx*2u);
#endif
return *reg;
}
@@ -283,7 +152,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_tx_cnt(USB_TypeDef * USB
(void) USBx;
return (pma32[2*bEpIdx] & 0x03FF0000) >> 16;
#else
- __I uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx);
+ volatile const uint16_t *regPtr = pcd_ep_tx_cnt_ptr(USBx, bEpIdx);
return *regPtr & 0x3ffU;
#endif
}
@@ -293,7 +162,7 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_cnt(USB_TypeDef * USB
(void) USBx;
return (pma32[2*bEpIdx + 1] & 0x03FF0000) >> 16;
#else
- __I uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
+ volatile const uint16_t *regPtr = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
return *regPtr & 0x3ffU;
#endif
}
@@ -363,7 +232,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_cnt(USB_TypeDef * USBx, u
(void) USBx;
pma32[2*bEpIdx] = (pma32[2*bEpIdx] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
#else
- __IO uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx);
+ volatile uint16_t * reg = pcd_ep_tx_cnt_ptr(USBx, bEpIdx);
*reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU);
#endif
}
@@ -375,7 +244,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_dbuf1_cnt(USB_TypeDef * U
(void) USBx;
pma32[2*bEpIdx + 1] = (pma32[2*bEpIdx + 1] & ~0x03FF0000u) | ((wCount & 0x3FFu) << 16);
#else
- __IO uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
+ volatile uint16_t * reg = pcd_ep_rx_cnt_ptr(USBx, bEpIdx);
*reg = (uint16_t) (*reg & (uint16_t) ~0x3FFU) | (wCount & 0x3FFU);
#endif
}
@@ -387,7 +256,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_blsize_num_blocks(USB_TypeDe
(void) USBx;
pma32[rxtx_idx] = (pma32[rxtx_idx] & 0x0000FFFFu) | (blocksize << 31) | ((numblocks - blocksize) << 26);
#else
- __IO uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u);
+ volatile uint16_t *pdwReg = pcd_btable_word_ptr(USBx, rxtx_idx*2u + 1u);
*pdwReg = (blocksize << 15) | ((numblocks - blocksize) << 10);
#endif
}
@@ -426,18 +295,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_cnt(USB_TypeDef * USBx, u
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPTX_DTOGMASK;
-
- /* toggle first bit ? */
- if((USB_EPTX_DTOG1 & (wState))!= 0U)
- {
- regVal ^= USB_EPTX_DTOG1;
- }
- /* toggle second bit ? */
- if((USB_EPTX_DTOG2 & ((uint32_t)(wState)))!= 0U)
- {
- regVal ^= USB_EPTX_DTOG2;
- }
-
+ regVal ^= wState;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
@@ -453,16 +311,7 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_tx_status(USB_TypeDef * USBx
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_rx_status(USB_TypeDef * USBx, uint32_t bEpIdx, uint32_t wState) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPRX_DTOGMASK;
-
- /* toggle first bit ? */
- if((USB_EPRX_DTOG1 & wState)!= 0U) {
- regVal ^= USB_EPRX_DTOG1;
- }
- /* toggle second bit ? */
- if((USB_EPRX_DTOG2 & wState)!= 0U) {
- regVal ^= USB_EPRX_DTOG2;
- }
-
+ regVal ^= wState;
regVal |= USB_EP_CTR_RX|USB_EP_CTR_TX;
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
@@ -472,13 +321,6 @@ TU_ATTR_ALWAYS_INLINE static inline uint32_t pcd_get_ep_rx_status(USB_TypeDef *
return (regVal & USB_EPRX_STAT) >> (12u);
}
-
-/**
- * @brief Toggles DTOG_RX / DTOG_TX bit in the endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @retval None
- */
TU_ATTR_ALWAYS_INLINE static inline void pcd_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal &= USB_EPREG_MASK;
@@ -493,12 +335,6 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_tx_dtog(USB_TypeDef * USBx, uint32
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-/**
- * @brief Clears DTOG_RX / DTOG_TX bit in the endpoint register.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @retval None
- */
TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_rx_dtog(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
if((regVal & USB_EP_DTOG_RX) != 0) {
@@ -513,12 +349,6 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_tx_dtog(USB_TypeDef * USBx,
}
}
-/**
- * @brief set & clear EP_KIND bit.
- * @param USBx USB peripheral instance register address.
- * @param bEpIdx Endpoint Number.
- * @retval None
- */
TU_ATTR_ALWAYS_INLINE static inline void pcd_set_ep_kind(USB_TypeDef * USBx, uint32_t bEpIdx) {
uint32_t regVal = pcd_get_endpoint(USBx, bEpIdx);
regVal |= USB_EP_KIND;
@@ -534,18 +364,8 @@ TU_ATTR_ALWAYS_INLINE static inline void pcd_clear_ep_kind(USB_TypeDef * USBx, u
pcd_set_endpoint(USBx, bEpIdx, regVal);
}
-// This checks if the device has "LPM"
-#if defined(USB_ISTR_L1REQ)
-#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ)
-#else
-#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U)
+#ifdef __cplusplus
+ }
#endif
-#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
- USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
-
-// Number of endpoints in hardware
-// TODO should use TUP_DCD_ENDPOINT_MAX
-#define STFSDEV_EP_COUNT (8u)
-
-#endif /* PORTABLE_ST_STM32F0_DCD_STM32F0_FSDEV_PVT_ST_H_ */
+#endif
diff --git a/src/portable/st/stm32_fsdev/fsdev_stm32.h b/src/portable/st/stm32_fsdev/fsdev_stm32.h
new file mode 100644
index 000000000..a8f61a35f
--- /dev/null
+++ b/src/portable/st/stm32_fsdev/fsdev_stm32.h
@@ -0,0 +1,323 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright(c) N Conrad
+ * Copyright (c) 2019 Ha Thach (tinyusb.org)
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ * 3. Neither the name of STMicroelectronics nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef TUSB_FSDEV_STM32_H
+#define TUSB_FSDEV_STM32_H
+
+#if CFG_TUSB_MCU == OPT_MCU_STM32F0
+ #include "stm32f0xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ // F0x2 models are crystal-less
+ // All have internal D+ pull-up
+ // 070RB: 2 x 16 bits/word memory LPM Support, BCD Support
+ // PMA dedicated to USB (no sharing with CAN)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32F1
+ #include "stm32f1xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+ // NO internal Pull-ups
+ // *B, and *C: 2 x 16 bits/word
+
+ // F1 names this differently from the rest
+ #define USB_CNTR_LPMODE USB_CNTR_LP_MODE
+
+#elif defined(STM32F302xB) || defined(STM32F302xC) || \
+ defined(STM32F303xB) || defined(STM32F303xC) || \
+ defined(STM32F373xC)
+ #include "stm32f3xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+ // NO internal Pull-ups
+ // *B, and *C: 1 x 16 bits/word
+ // PMA dedicated to USB (no sharing with CAN)
+
+#elif defined(STM32F302x6) || defined(STM32F302x8) || \
+ defined(STM32F302xD) || defined(STM32F302xE) || \
+ defined(STM32F303xD) || defined(STM32F303xE)
+ #include "stm32f3xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ // NO internal Pull-ups
+ // *6, *8, *D, and *E: 2 x 16 bits/word LPM Support
+ // When CAN clock is enabled, USB can use first 768 bytes ONLY.
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L0
+ #include "stm32l0xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L1
+ #include "stm32l1xx.h"
+ #define FSDEV_PMA_SIZE (512u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G4
+ #include "stm32g4xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+ #include "stm32g0xx.h"
+ #define FSDEV_BUS_32BIT
+ #define FSDEV_PMA_SIZE (2048u)
+ #undef USB_PMAADDR
+ #define USB_PMAADDR USB_DRD_PMAADDR
+ #define USB_TypeDef USB_DRD_TypeDef
+ #define EP0R CHEP0R
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
+ #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
+ #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
+ #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
+ #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB USB_DRD_FS
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32H5
+ #include "stm32h5xx.h"
+ #define FSDEV_BUS_32BIT
+
+ #if !defined(USB_DRD_BASE) && defined(USB_DRD_FS_BASE)
+ #define USB_DRD_BASE USB_DRD_FS_BASE
+ #endif
+
+ #define FSDEV_PMA_SIZE (2048u)
+ #undef USB_PMAADDR
+ #define USB_PMAADDR USB_DRD_PMAADDR
+ #define USB_TypeDef USB_DRD_TypeDef
+ #define EP0R CHEP0R
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
+ #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
+ #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
+ #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
+ #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB USB_DRD_FS
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ #include "stm32wbxx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+ /* ST provided header has incorrect value */
+ #undef USB_PMAADDR
+ #define USB_PMAADDR USB1_PMAADDR
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L4
+ #include "stm32l4xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ #include "stm32l5xx.h"
+ #define FSDEV_PMA_SIZE (1024u)
+
+ #ifndef USB_PMAADDR
+ #define USB_PMAADDR (USB_BASE + (USB_PMAADDR_NS - USB_BASE_NS))
+ #endif
+
+#elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ #include "stm32u5xx.h"
+ #define FSDEV_BUS_32BIT
+
+ #define FSDEV_PMA_SIZE (2048u)
+ #undef USB_PMAADDR
+ #define USB_PMAADDR USB_DRD_PMAADDR
+ #define USB_TypeDef USB_DRD_TypeDef
+ #define EP0R CHEP0R
+ #define USB_EP_CTR_RX USB_EP_VTRX
+ #define USB_EP_CTR_TX USB_EP_VTTX
+ #define USB_EP_T_FIELD USB_CHEP_UTYPE
+ #define USB_EPREG_MASK USB_CHEP_REG_MASK
+ #define USB_EPTX_DTOGMASK USB_CHEP_TX_DTOGMASK
+ #define USB_EPRX_DTOGMASK USB_CHEP_RX_DTOGMASK
+ #define USB_EPTX_DTOG1 USB_CHEP_TX_DTOG1
+ #define USB_EPTX_DTOG2 USB_CHEP_TX_DTOG2
+ #define USB_EPRX_DTOG1 USB_CHEP_RX_DTOG1
+ #define USB_EPRX_DTOG2 USB_CHEP_RX_DTOG2
+ #define USB_EPRX_STAT USB_CH_RX_VALID
+ #define USB_EPKIND_MASK USB_EP_KIND_MASK
+ #define USB USB_DRD_FS
+ #define USB_CNTR_FRES USB_CNTR_USBRST
+ #define USB_CNTR_RESUME USB_CNTR_L2RES
+ #define USB_ISTR_EP_ID USB_ISTR_IDN
+ #define USB_EPADDR_FIELD USB_CHEP_ADDR
+ #define USB_CNTR_LPMODE USB_CNTR_SUSPRDY
+ #define USB_CNTR_FSUSP USB_CNTR_SUSPEN
+
+#else
+ #error You are using an untested or unimplemented STM32 variant. Please update the driver.
+ // This includes U0
+#endif
+
+// This checks if the device has "LPM"
+#if defined(USB_ISTR_L1REQ)
+#define USB_ISTR_L1REQ_FORCED (USB_ISTR_L1REQ)
+#else
+#define USB_ISTR_L1REQ_FORCED ((uint16_t)0x0000U)
+#endif
+
+#define USB_ISTR_ALL_EVENTS (USB_ISTR_PMAOVR | USB_ISTR_ERR | USB_ISTR_WKUP | USB_ISTR_SUSP | \
+ USB_ISTR_RESET | USB_ISTR_SOF | USB_ISTR_ESOF | USB_ISTR_L1REQ_FORCED )
+
+//--------------------------------------------------------------------+
+//
+//--------------------------------------------------------------------+
+
+#if TU_CHECK_MCU(OPT_MCU_STM32L1) && !defined(USBWakeUp_IRQn)
+ #define USBWakeUp_IRQn USB_FS_WKUP_IRQn
+#endif
+
+static const IRQn_Type fsdev_irq[] = {
+ #if TU_CHECK_MCU(OPT_MCU_STM32F0, OPT_MCU_STM32L0, OPT_MCU_STM32L4)
+ USB_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32F1
+ USB_HP_CAN1_TX_IRQn,
+ USB_LP_CAN1_RX0_IRQn,
+ USBWakeUp_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32F3
+ // USB remap handles dcd functions
+ USB_HP_CAN_TX_IRQn,
+ USB_LP_CAN_RX0_IRQn,
+ USBWakeUp_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32G0
+ #ifdef STM32G0B0xx
+ USB_IRQn,
+ #else
+ USB_UCPD1_2_IRQn,
+ #endif
+ #elif TU_CHECK_MCU(OPT_MCU_STM32G4, OPT_MCU_STM32L1)
+ USB_HP_IRQn,
+ USB_LP_IRQn,
+ USBWakeUp_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32H5
+ USB_DRD_FS_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32L5
+ USB_FS_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32WB
+ USB_HP_IRQn,
+ USB_LP_IRQn,
+ #elif CFG_TUSB_MCU == OPT_MCU_STM32U5
+ USB_IRQn,
+ #else
+ #error Unknown arch in USB driver
+ #endif
+};
+enum { FSDEV_IRQ_NUM = TU_ARRAY_SIZE(fsdev_irq) };
+
+void dcd_int_enable(uint8_t rhport) {
+ (void)rhport;
+
+ // forces write to RAM before allowing ISR to execute
+ __DSB(); __ISB();
+
+ #if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP)
+ // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+ // shared USB/CAN IRQs to separate CAN and USB IRQs.
+ // This dynamically checks if this remap is active to enable the right IRQs.
+ if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
+ NVIC_EnableIRQ(USB_HP_IRQn);
+ NVIC_EnableIRQ(USB_LP_IRQn);
+ NVIC_EnableIRQ(USBWakeUp_RMP_IRQn);
+ } else
+ #endif
+ {
+ for (uint8_t i = 0; i < FSDEV_IRQ_NUM; i++) {
+ NVIC_EnableIRQ(fsdev_irq[i]);
+ }
+ }
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void)rhport;
+
+ #if CFG_TUSB_MCU == OPT_MCU_STM32F3 && defined(SYSCFG_CFGR1_USB_IT_RMP)
+ // Some STM32F302/F303 devices allow to remap the USB interrupt vectors from
+ // shared USB/CAN IRQs to separate CAN and USB IRQs.
+ // This dynamically checks if this remap is active to enable the right IRQs.
+ if (SYSCFG->CFGR1 & SYSCFG_CFGR1_USB_IT_RMP) {
+ NVIC_DisableIRQ(USB_HP_IRQn);
+ NVIC_DisableIRQ(USB_LP_IRQn);
+ NVIC_DisableIRQ(USBWakeUp_RMP_IRQn);
+ } else
+ #endif
+ {
+ for (uint8_t i = 0; i < FSDEV_IRQ_NUM; i++) {
+ NVIC_DisableIRQ(fsdev_irq[i]);
+ }
+ }
+
+ // CMSIS has a membar after disabling interrupts
+}
+
+// Define only on MCU with internal pull-up. BSP can define on MCU without internal PU.
+#if defined(USB_BCDR_DPPU)
+
+void dcd_disconnect(uint8_t rhport) {
+ (void)rhport;
+ USB->BCDR &= ~(USB_BCDR_DPPU);
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void)rhport;
+ USB->BCDR |= USB_BCDR_DPPU;
+}
+
+#elif defined(SYSCFG_PMC_USB_PU) // works e.g. on STM32L151
+
+void dcd_disconnect(uint8_t rhport) {
+ (void)rhport;
+ SYSCFG->PMC &= ~(SYSCFG_PMC_USB_PU);
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void)rhport;
+ SYSCFG->PMC |= SYSCFG_PMC_USB_PU;
+}
+#endif
+
+
+#endif /* TUSB_FSDEV_STM32_H */
diff --git a/src/portable/sunxi/dcd_sunxi_musb.c b/src/portable/sunxi/dcd_sunxi_musb.c
index 6cc1975a8..6f36ad441 100644
--- a/src/portable/sunxi/dcd_sunxi_musb.c
+++ b/src/portable/sunxi/dcd_sunxi_musb.c
@@ -35,7 +35,9 @@
#include <f1c100s-irq.h>
#include <device/dcd.h>
#include "musb_def.h"
-#include "bsp/board.h"
+
+//#include "bsp/board_api.h"
+extern uint32_t board_millis(void); // TODO remove
typedef uint32_t u32;
typedef uint16_t u16;
@@ -58,7 +60,7 @@ typedef struct TU_ATTR_PACKED
typedef struct
{
- tusb_control_request_t setup_packet;
+ CFG_TUD_MEM_ALIGN tusb_control_request_t setup_packet;
uint16_t remaining_ctrl; /* The number of bytes remaining in data stage of control transfer. */
int8_t status_out;
pipe_state_t pipe0;
@@ -350,7 +352,7 @@ static void USBC_INT_DisableRxEp(u8 ep_index)
* INTERNAL FUNCTION DECLARATION
*------------------------------------------------------------------*/
-static dcd_data_t _dcd;
+CFG_TUD_MEM_ALIGN static dcd_data_t _dcd;
static inline free_block_t *find_containing_block(free_block_t *beg, free_block_t *end, uint_fast16_t addr)
{
@@ -560,7 +562,7 @@ static void pipe_read_write_packet_ff(tu_fifo_t *f, volatile void *fifo, unsigne
static void process_setup_packet(uint8_t rhport)
{
- uint32_t *p = (uint32_t*)&_dcd.setup_packet;
+ uint32_t *p = (uint32_t*)(uintptr_t) &_dcd.setup_packet;
p[0] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
p[1] = USBC_Readl(USBC_REG_EPFIFO0(USBC0_BASE));
@@ -594,7 +596,7 @@ static bool handle_xfer_in(uint_fast8_t ep_addr)
if (len) {
volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_IN] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_IN);
+ pipe_read_write_packet_ff((tu_fifo_t *)(uintptr_t) buf, addr, len, TUSB_DIR_IN);
} else {
pipe_write_packet(buf, addr, len);
pipe->buf = buf + len;
@@ -622,7 +624,7 @@ static bool handle_xfer_out(uint_fast8_t ep_addr)
if (len) {
volatile void* addr = (volatile void*)(USBC_REG_EPFIFO1(USBC0_BASE) + (epnum_minus1 << 2));
if (_dcd.pipe_buf_is_fifo[TUSB_DIR_OUT] & TU_BIT(epnum_minus1)) {
- pipe_read_write_packet_ff((tu_fifo_t *)buf, addr, len, TUSB_DIR_OUT);
+ pipe_read_write_packet_ff((tu_fifo_t *)(uintptr_t )buf, addr, len, TUSB_DIR_OUT);
} else {
pipe_read_packet(buf, addr, len);
pipe->buf = buf + len;
diff --git a/src/portable/synopsys/dwc2/dcd_dwc2.c b/src/portable/synopsys/dwc2/dcd_dwc2.c
index 8c3a6ec61..ffcb52f40 100644
--- a/src/portable/synopsys/dwc2/dcd_dwc2.c
+++ b/src/portable/synopsys/dwc2/dcd_dwc2.c
@@ -1297,4 +1297,25 @@ void dcd_int_handler(uint8_t rhport) {
// }
}
+#if defined(TUP_USBIP_DWC2_TEST_MODE) && CFG_TUD_TEST_MODE
+
+bool dcd_check_test_mode_support(test_mode_t test_selector) {
+ // Check if test mode selector is unsupported
+ if (TEST_FORCE_ENABLE < test_selector || TEST_J > test_selector) {
+ return false;
+ }
+
+ return true;
+}
+
+void dcd_enter_test_mode(uint8_t rhport, test_mode_t test_selector) {
+ // Get port address...
+ dwc2_regs_t* dwc2 = DWC2_REG(rhport);
+
+ // Enable the test mode
+ dwc2->dctl = (dwc2->dctl & ~DCTL_TCTL_Msk) | (test_selector << DCTL_TCTL_Pos);
+}
+
+#endif /* TUP_USBIP_DWC2_TEST_MODE && CFG_TUD_TEST_MODE */
+
#endif
diff --git a/src/portable/synopsys/dwc2/dwc2_esp32.h b/src/portable/synopsys/dwc2/dwc2_esp32.h
index fc12d7551..74b10aa9a 100644
--- a/src/portable/synopsys/dwc2/dwc2_esp32.h
+++ b/src/portable/synopsys/dwc2/dwc2_esp32.h
@@ -35,6 +35,7 @@
#include "esp_intr_alloc.h"
#include "soc/periph_defs.h"
//#include "soc/usb_periph.h"
+#include "freertos/task.h"
#define DWC2_REG_BASE 0x60080000UL
#define DWC2_EP_MAX 7
diff --git a/src/portable/synopsys/dwc2/dwc2_type.h b/src/portable/synopsys/dwc2/dwc2_type.h
index 08c9b8b1b..244323b51 100644
--- a/src/portable/synopsys/dwc2/dwc2_type.h
+++ b/src/portable/synopsys/dwc2/dwc2_type.h
@@ -1,17 +1,34 @@
-/**
- * @author MCD Application Team
- * Ha Thach (tinyusb.org)
- *
- * @attention
- *
- * <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024, hathach (tinyusb.org)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ */
+/** <h2><center>&copy; Copyright (c) 2019 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
- *
*/
#ifndef _TUSB_DWC2_TYPES_H_
diff --git a/src/portable/wch/ch32_usbfs_reg.h b/src/portable/wch/ch32_usbfs_reg.h
new file mode 100644
index 000000000..68be64f5e
--- /dev/null
+++ b/src/portable/wch/ch32_usbfs_reg.h
@@ -0,0 +1,175 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Matthew Tran
+ * Copyright (c) 2024 hathach
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#ifndef USB_CH32_USBFS_REG_H
+#define USB_CH32_USBFS_REG_H
+
+// https://github.com/openwch/ch32v307/pull/90
+// https://github.com/openwch/ch32v20x/pull/12
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_CH32F20X
+ #include <ch32f20x.h>
+#elif CFG_TUSB_MCU == OPT_MCU_CH32V103
+ #include <ch32v10x.h>
+ typedef struct
+ {
+ __IO uint8_t BASE_CTRL;
+ __IO uint8_t UDEV_CTRL;
+ __IO uint8_t INT_EN;
+ __IO uint8_t DEV_ADDR;
+ __IO uint8_t Reserve0;
+ __IO uint8_t MIS_ST;
+ __IO uint8_t INT_FG;
+ __IO uint8_t INT_ST;
+ __IO uint32_t RX_LEN;
+ __IO uint8_t UEP4_1_MOD;
+ __IO uint8_t UEP2_3_MOD;
+ __IO uint8_t UEP5_6_MOD;
+ __IO uint8_t UEP7_MOD;
+ __IO uint32_t UEP0_DMA;
+ __IO uint32_t UEP1_DMA;
+ __IO uint32_t UEP2_DMA;
+ __IO uint32_t UEP3_DMA;
+ __IO uint32_t UEP4_DMA;
+ __IO uint32_t UEP5_DMA;
+ __IO uint32_t UEP6_DMA;
+ __IO uint32_t UEP7_DMA;
+ __IO uint16_t UEP0_TX_LEN;
+ __IO uint8_t UEP0_TX_CTRL;
+ __IO uint8_t UEP0_RX_CTRL;
+ __IO uint16_t UEP1_TX_LEN;
+ __IO uint8_t UEP1_TX_CTRL;
+ __IO uint8_t UEP1_RX_CTRL;
+ __IO uint16_t UEP2_TX_LEN;
+ __IO uint8_t UEP2_TX_CTRL;
+ __IO uint8_t UEP2_RX_CTRL;
+ __IO uint16_t UEP3_TX_LEN;
+ __IO uint8_t UEP3_TX_CTRL;
+ __IO uint8_t UEP3_RX_CTRL;
+ __IO uint16_t UEP4_TX_LEN;
+ __IO uint8_t UEP4_TX_CTRL;
+ __IO uint8_t UEP4_RX_CTRL;
+ __IO uint16_t UEP5_TX_LEN;
+ __IO uint8_t UEP5_TX_CTRL;
+ __IO uint8_t UEP5_RX_CTRL;
+ __IO uint16_t UEP6_TX_LEN;
+ __IO uint8_t UEP6_TX_CTRL;
+ __IO uint8_t UEP6_RX_CTRL;
+ __IO uint16_t UEP7_TX_LEN;
+ __IO uint8_t UEP7_TX_CTRL;
+ __IO uint8_t UEP7_RX_CTRL;
+ __IO uint32_t Reserve1;
+ __IO uint32_t OTG_CR;
+ __IO uint32_t OTG_SR;
+ } USBOTG_FS_TypeDef;
+
+ #define USBOTG_FS ((USBOTG_FS_TypeDef *) 0x40023400)
+#elif CFG_TUSB_MCU == OPT_MCU_CH32V20X
+ #include <ch32v20x.h>
+#elif CFG_TUSB_MCU == OPT_MCU_CH32V307
+ #include <ch32v30x.h>
+ #define USBHD_IRQn OTG_FS_IRQn
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+// CTRL
+#define USBFS_CTRL_DMA_EN (1 << 0)
+#define USBFS_CTRL_CLR_ALL (1 << 1)
+#define USBFS_CTRL_RESET_SIE (1 << 2)
+#define USBFS_CTRL_INT_BUSY (1 << 3)
+#define USBFS_CTRL_SYS_CTRL (1 << 4)
+#define USBFS_CTRL_DEV_PUEN (1 << 5)
+#define USBFS_CTRL_LOW_SPEED (1 << 6)
+#define USBFS_CTRL_HOST_MODE (1 << 7)
+
+// INT_EN
+#define USBFS_INT_EN_BUS_RST (1 << 0)
+#define USBFS_INT_EN_DETECT (1 << 0)
+#define USBFS_INT_EN_TRANSFER (1 << 1)
+#define USBFS_INT_EN_SUSPEND (1 << 2)
+#define USBFS_INT_EN_HST_SOF (1 << 3)
+#define USBFS_INT_EN_FIFO_OV (1 << 4)
+#define USBFS_INT_EN_DEV_NAK (1 << 6)
+#define USBFS_INT_EN_DEV_SOF (1 << 7)
+
+// INT_FG
+#define USBFS_INT_FG_BUS_RST (1 << 0)
+#define USBFS_INT_FG_DETECT (1 << 0)
+#define USBFS_INT_FG_TRANSFER (1 << 1)
+#define USBFS_INT_FG_SUSPEND (1 << 2)
+#define USBFS_INT_FG_HST_SOF (1 << 3)
+#define USBFS_INT_FG_FIFO_OV (1 << 4)
+#define USBFS_INT_FG_SIE_FREE (1 << 5)
+#define USBFS_INT_FG_TOG_OK (1 << 6)
+#define USBFS_INT_FG_IS_NAK (1 << 7)
+
+// INT_ST
+#define USBFS_INT_ST_MASK_UIS_ENDP(x) (((x) >> 0) & 0x0F)
+#define USBFS_INT_ST_MASK_UIS_TOKEN(x) (((x) >> 4) & 0x03)
+
+// UDEV_CTRL
+#define USBFS_UDEV_CTRL_PORT_EN (1 << 0)
+#define USBFS_UDEV_CTRL_GP_BIT (1 << 1)
+#define USBFS_UDEV_CTRL_LOW_SPEED (1 << 2)
+#define USBFS_UDEV_CTRL_DM_PIN (1 << 4)
+#define USBFS_UDEV_CTRL_DP_PIN (1 << 5)
+#define USBFS_UDEV_CTRL_PD_DIS (1 << 7)
+
+// TX_CTRL
+#define USBFS_EP_T_RES_MASK (3 << 0)
+#define USBFS_EP_T_TOG (1 << 2)
+#define USBFS_EP_T_AUTO_TOG (1 << 3)
+
+#define USBFS_EP_T_RES_ACK (0 << 0)
+#define USBFS_EP_T_RES_NYET (1 << 0)
+#define USBFS_EP_T_RES_NAK (2 << 0)
+#define USBFS_EP_T_RES_STALL (3 << 0)
+
+// RX_CTRL
+#define USBFS_EP_R_RES_MASK (3 << 0)
+#define USBFS_EP_R_TOG (1 << 2)
+#define USBFS_EP_R_AUTO_TOG (1 << 3)
+
+#define USBFS_EP_R_RES_ACK (0 << 0)
+#define USBFS_EP_R_RES_NYET (1 << 0)
+#define USBFS_EP_R_RES_NAK (2 << 0)
+#define USBFS_EP_R_RES_STALL (3 << 0)
+
+// token PID
+#define PID_OUT 0
+#define PID_SOF 1
+#define PID_IN 2
+#define PID_SETUP 3
+
+#endif // USB_CH32_USBFS_REG_H
diff --git a/src/portable/wch/ch32_usbhs_reg.h b/src/portable/wch/ch32_usbhs_reg.h
index 9b956231f..87300b497 100644
--- a/src/portable/wch/ch32_usbhs_reg.h
+++ b/src/portable/wch/ch32_usbhs_reg.h
@@ -1,12 +1,51 @@
-#ifndef _USB_CH32_USBHS_REG_H
-#define _USB_CH32_USBHS_REG_H
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Matthew Tran
+ * Copyright (c) 2024 hathach
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
-#if (CFG_TUSB_MCU == OPT_MCU_CH32V307)
-#include <ch32v30x.h>
-#elif (CFG_TUSB_MCU == OPT_MCU_CH32F20X)
-#include <ch32f20x.h>
+#ifndef USB_CH32_USBHS_REG_H
+#define USB_CH32_USBHS_REG_H
+
+// https://github.com/openwch/ch32v307/pull/90
+// https://github.com/openwch/ch32v20x/pull/12
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wstrict-prototypes"
+#endif
+
+#if CFG_TUSB_MCU == OPT_MCU_CH32V307
+ #include <ch32v30x.h>
+#elif CFG_TUSB_MCU == OPT_MCU_CH32F20X
+ #include <ch32f20x.h>
+#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
#endif
+
/******************* GLOBAL ******************/
// USB CONTROL
@@ -36,8 +75,13 @@
// USB DEV AD
#define USBHS_DEV_AD_OFFSET 0x03
+
// USB FRAME_NO
#define USBHS_FRAME_NO_OFFSET 0x04
+#define USBHS_FRAME_NO_NUM_MASK (0x7FF)
+#define USBHS_FRAME_NO_MICROFRAME_SHIFT (11)
+#define USBHS_FRAME_NO_MICROFRAME_MASK (0x7 << USBHS_FRAME_NO_MICROFRAME_SHIFT)
+
// USB SUSPEND
#define USBHS_SUSPEND_OFFSET 0x06
#define USBHS_DEV_REMOTE_WAKEUP (1 << 2)
@@ -47,7 +91,10 @@
// USB SPEED TYPE
#define USBHS_SPEED_TYPE_OFFSET 0x08
-#define USBSPEED_MASK (0x03)
+#define USBHS_SPEED_TYPE_MASK 0x03
+#define USBHS_SPEED_TYPE_FULL 0
+#define USBHS_SPEED_TYPE_HIGH 1
+#define USBHS_SPEED_TYPE_LOW 2
// USB_MIS_ST
#define USBHS_MIS_ST_OFFSET 0x09
@@ -72,12 +119,16 @@
#define USBHS_ISO_ACT_FLAG (1 << 6)
// INT_ST
-#define USBHS_INT_ST_OFFSET 0x0B
-#define USBHS_DEV_UIS_IS_NAK (1 << 7)
-#define USBHS_DEV_UIS_TOG_OK (1 << 6)
-#define MASK_UIS_TOKEN (3 << 4)
-#define MASK_UIS_ENDP (0x0F)
-#define MASK_UIS_H_RES (0x0F)
+#define USBHS_INT_ST_OFFSET 0x0B
+#define USBHS_DEV_UIS_IS_NAK (1 << 7)
+#define USBHS_DEV_UIS_TOG_OK (1 << 6)
+#define MASK_UIS_TOKEN (3 << 4)
+#define USBHS_TOKEN_PID_OUT (0 << 4)
+#define USBHS_TOKEN_PID_SOF (1 << 4)
+#define USBHS_TOKEN_PID_IN (2 << 4)
+#define USBHS_TOKEN_PID_SETUP (3 << 4)
+#define MASK_UIS_ENDP (0x0F)
+#define MASK_UIS_H_RES (0x0F)
#define USBHS_TOGGLE_OK (0x40)
#define USBHS_HOST_RES (0x0f)
@@ -340,10 +391,5 @@
#define USBHS_UH_T_TOG_AUTO (1 << 5)
#define USBHS_UH_T_DATA_NO (1 << 6)
-// 00: OUT, 01:SOF, 10:IN, 11:SETUP
-#define PID_OUT 0
-#define PID_SOF 1
-#define PID_IN 2
-#define PID_SETUP 3
#endif
diff --git a/src/portable/wch/dcd_ch32_usbfs.c b/src/portable/wch/dcd_ch32_usbfs.c
new file mode 100644
index 000000000..9ed370b40
--- /dev/null
+++ b/src/portable/wch/dcd_ch32_usbfs.c
@@ -0,0 +1,344 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2024 Matthew Tran
+ * Copyright (c) 2024 hathach
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * This file is part of the TinyUSB stack.
+ */
+
+#include "tusb_option.h"
+
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBFS) && CFG_TUD_WCH_USBIP_USBFS
+
+#include "device/dcd.h"
+#include "ch32_usbfs_reg.h"
+
+/* private defines */
+#define EP_MAX (8)
+
+#define EP_DMA(ep) ((&USBOTG_FS->UEP0_DMA)[ep])
+#define EP_TX_LEN(ep) ((&USBOTG_FS->UEP0_TX_LEN)[2 * ep])
+#define EP_TX_CTRL(ep) ((&USBOTG_FS->UEP0_TX_CTRL)[4 * ep])
+#define EP_RX_CTRL(ep) ((&USBOTG_FS->UEP0_RX_CTRL)[4 * ep])
+
+/* private data */
+struct usb_xfer {
+ bool valid;
+ uint8_t* buffer;
+ size_t len;
+ size_t processed_len;
+ size_t max_size;
+};
+
+static struct {
+ bool ep0_tog;
+ bool isochronous[EP_MAX];
+ struct usb_xfer xfer[EP_MAX][2];
+ TU_ATTR_ALIGNED(4) uint8_t buffer[EP_MAX][2][64];
+ TU_ATTR_ALIGNED(4) struct {
+ // OUT transfers >64 bytes will overwrite queued IN data!
+ uint8_t out[64];
+ uint8_t in[1023];
+ uint8_t pad;
+ } ep3_buffer;
+} data;
+
+/* private helpers */
+static void update_in(uint8_t rhport, uint8_t ep, bool force) {
+ struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_IN];
+ if (xfer->valid) {
+ if (force || xfer->len) {
+ size_t len = TU_MIN(xfer->max_size, xfer->len);
+ if (ep == 0) {
+ memcpy(data.buffer[ep][TUSB_DIR_OUT], xfer->buffer, len); // ep0 uses same chunk
+ } else if (ep == 3) {
+ memcpy(data.ep3_buffer.in, xfer->buffer, len);
+ } else {
+ memcpy(data.buffer[ep][TUSB_DIR_IN], xfer->buffer, len);
+ }
+ xfer->buffer += len;
+ xfer->len -= len;
+ xfer->processed_len += len;
+
+ EP_TX_LEN(ep) = len;
+ if (ep == 0) {
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_ACK | (data.ep0_tog ? USBFS_EP_T_TOG : 0);
+ data.ep0_tog = !data.ep0_tog;
+ } else if (data.isochronous[ep]) {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NYET;
+ } else {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_ACK;
+ }
+ } else {
+ xfer->valid = false;
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK)) | USBFS_EP_T_RES_NAK;
+ dcd_event_xfer_complete(
+ rhport, ep | TUSB_DIR_IN_MASK, xfer->processed_len,
+ XFER_RESULT_SUCCESS, true);
+ }
+ }
+}
+
+static void update_out(uint8_t rhport, uint8_t ep, size_t rx_len) {
+ struct usb_xfer* xfer = &data.xfer[ep][TUSB_DIR_OUT];
+ if (xfer->valid) {
+ size_t len = TU_MIN(xfer->max_size, TU_MIN(xfer->len, rx_len));
+ if (ep == 3) {
+ memcpy(xfer->buffer, data.ep3_buffer.out, len);
+ } else {
+ memcpy(xfer->buffer, data.buffer[ep][TUSB_DIR_OUT], len);
+ }
+ xfer->buffer += len;
+ xfer->len -= len;
+ xfer->processed_len += len;
+
+ if (xfer->len == 0 || len < xfer->max_size) {
+ xfer->valid = false;
+ dcd_event_xfer_complete(rhport, ep, xfer->processed_len, XFER_RESULT_SUCCESS, true);
+ }
+
+ if (ep == 0) {
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+ }
+ }
+}
+
+/* public functions */
+void dcd_init(uint8_t rhport) {
+ // init registers
+ USBOTG_FS->BASE_CTRL = USBFS_CTRL_SYS_CTRL | USBFS_CTRL_INT_BUSY | USBFS_CTRL_DMA_EN;
+ USBOTG_FS->UDEV_CTRL = USBFS_UDEV_CTRL_PD_DIS | USBFS_UDEV_CTRL_PORT_EN;
+ USBOTG_FS->DEV_ADDR = 0x00;
+
+ USBOTG_FS->INT_FG = 0xFF;
+ USBOTG_FS->INT_EN = USBFS_INT_EN_BUS_RST | USBFS_INT_EN_TRANSFER | USBFS_INT_EN_SUSPEND;
+
+ // setup endpoint 0
+ EP_DMA(0) = (uint32_t) &data.buffer[0][0];
+ EP_TX_LEN(0) = 0;
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+
+ // enable other endpoints but NAK everything
+ USBOTG_FS->UEP4_1_MOD = 0xCC;
+ USBOTG_FS->UEP2_3_MOD = 0xCC;
+ USBOTG_FS->UEP5_6_MOD = 0xCC;
+ USBOTG_FS->UEP7_MOD = 0x0C;
+
+ for (uint8_t ep = 1; ep < EP_MAX; ep++) {
+ EP_DMA(ep) = (uint32_t) &data.buffer[ep][0];
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NAK;
+ }
+ EP_DMA(3) = (uint32_t) &data.ep3_buffer.out[0];
+
+ dcd_connect(rhport);
+}
+
+void dcd_int_handler(uint8_t rhport) {
+ (void) rhport;
+ uint8_t status = USBOTG_FS->INT_FG;
+ if (status & USBFS_INT_FG_TRANSFER) {
+ uint8_t ep = USBFS_INT_ST_MASK_UIS_ENDP(USBOTG_FS->INT_ST);
+ uint8_t token = USBFS_INT_ST_MASK_UIS_TOKEN(USBOTG_FS->INT_ST);
+
+ switch (token) {
+ case PID_OUT: {
+ uint16_t rx_len = USBOTG_FS->RX_LEN;
+ update_out(rhport, ep, rx_len);
+ break;
+ }
+
+ case PID_IN:
+ update_in(rhport, ep, false);
+ break;
+
+ case PID_SETUP:
+ // setup clears stall
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+
+ data.ep0_tog = true;
+ dcd_event_setup_received(rhport, &data.buffer[0][TUSB_DIR_OUT][0], true);
+ break;
+ }
+
+ USBOTG_FS->INT_FG = USBFS_INT_FG_TRANSFER;
+ } else if (status & USBFS_INT_FG_BUS_RST) {
+ data.ep0_tog = true;
+ data.xfer[0][TUSB_DIR_OUT].max_size = 64;
+ data.xfer[0][TUSB_DIR_IN].max_size = 64;
+
+ dcd_event_bus_signal(rhport, DCD_EVENT_BUS_RESET, true);
+
+ USBOTG_FS->DEV_ADDR = 0x00;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+
+ USBOTG_FS->INT_FG = USBFS_INT_FG_BUS_RST;
+ } else if (status & USBFS_INT_FG_SUSPEND) {
+ dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND};
+ dcd_event_handler(&event, true);
+ USBOTG_FS->INT_FG = USBFS_INT_FG_SUSPEND;
+ }
+}
+
+void dcd_int_enable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_EnableIRQ(USBHD_IRQn);
+}
+
+void dcd_int_disable(uint8_t rhport) {
+ (void) rhport;
+ NVIC_DisableIRQ(USBHD_IRQn);
+}
+
+void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
+ (void) dev_addr;
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0); // zlp status response
+}
+
+void dcd_remote_wakeup(uint8_t rhport) {
+ (void) rhport;
+ // TODO optional
+}
+
+void dcd_connect(uint8_t rhport) {
+ (void) rhport;
+ USBOTG_FS->BASE_CTRL |= USBFS_CTRL_DEV_PUEN;
+}
+
+void dcd_disconnect(uint8_t rhport) {
+ (void) rhport;
+ USBOTG_FS->BASE_CTRL &= ~USBFS_CTRL_DEV_PUEN;
+}
+
+void dcd_sof_enable(uint8_t rhport, bool en) {
+ (void) rhport;
+ (void) en;
+
+ // TODO implement later
+}
+
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
+ (void) rhport;
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ USBOTG_FS->DEV_ADDR = (uint8_t) request->wValue;
+ }
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_NAK;
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+}
+
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_ep) {
+ (void) rhport;
+ uint8_t ep = tu_edpt_number(desc_ep->bEndpointAddress);
+ uint8_t dir = tu_edpt_dir(desc_ep->bEndpointAddress);
+ TU_ASSERT(ep < EP_MAX);
+
+ data.isochronous[ep] = desc_ep->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS;
+ data.xfer[ep][dir].max_size = tu_edpt_packet_size(desc_ep);
+
+ if (ep != 0) {
+ if (dir == TUSB_DIR_OUT) {
+ if (data.isochronous[ep]) {
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_NYET;
+ } else {
+ EP_RX_CTRL(ep) = USBFS_EP_R_AUTO_TOG | USBFS_EP_R_RES_ACK;
+ }
+ } else {
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBFS_EP_T_AUTO_TOG | USBFS_EP_T_RES_NAK;
+ }
+ }
+ return true;
+}
+
+void dcd_edpt_close_all(uint8_t rhport) {
+ (void) rhport;
+ // TODO optional
+}
+
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ (void) ep_addr;
+ // TODO optional
+}
+
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ (void) rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+
+ struct usb_xfer* xfer = &data.xfer[ep][dir];
+ dcd_int_disable(rhport);
+ xfer->valid = true;
+ xfer->buffer = buffer;
+ xfer->len = total_bytes;
+ xfer->processed_len = 0;
+ dcd_int_enable(rhport);
+
+ if (dir == TUSB_DIR_IN) {
+ update_in(rhport, ep, true);
+ }
+ return true;
+}
+
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+ if (ep == 0) {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_STALL;
+ } else {
+ EP_TX_LEN(0) = 0;
+ EP_TX_CTRL(0) = USBFS_EP_T_RES_STALL;
+ }
+ } else {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~USBFS_EP_R_RES_MASK) | USBFS_EP_R_RES_STALL;
+ } else {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~USBFS_EP_T_RES_MASK) | USBFS_EP_T_RES_STALL;
+ }
+ }
+}
+
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
+ uint8_t ep = tu_edpt_number(ep_addr);
+ uint8_t dir = tu_edpt_dir(ep_addr);
+ if (ep == 0) {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(0) = USBFS_EP_R_RES_ACK;
+ }
+ } else {
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep) = (EP_RX_CTRL(ep) & ~(USBFS_EP_R_RES_MASK | USBFS_EP_R_TOG)) | USBFS_EP_R_RES_ACK;
+ } else {
+ EP_TX_CTRL(ep) = (EP_TX_CTRL(ep) & ~(USBFS_EP_T_RES_MASK | USBFS_EP_T_TOG)) | USBFS_EP_T_RES_NAK;
+ }
+ }
+}
+
+#endif
diff --git a/src/portable/wch/dcd_ch32_usbhs.c b/src/portable/wch/dcd_ch32_usbhs.c
index 1f1c0b876..622f9c508 100644
--- a/src/portable/wch/dcd_ch32_usbhs.c
+++ b/src/portable/wch/dcd_ch32_usbhs.c
@@ -2,6 +2,7 @@
* The MIT License (MIT)
*
* Copyright (c) 2022 Greg Davill
+ * Copyright (c) 2023 Denis Krasutski
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -26,366 +27,394 @@
#include "tusb_option.h"
-#if CFG_TUD_ENABLED && ((CFG_TUSB_MCU == OPT_MCU_CH32V307) || (CFG_TUSB_MCU == OPT_MCU_CH32F20X))
-#include "device/dcd.h"
-
+#if CFG_TUD_ENABLED && defined(TUP_USBIP_WCH_USBHS) && CFG_TUD_WCH_USBIP_USBHS
#include "ch32_usbhs_reg.h"
+#include "device/dcd.h"
// Max number of bi-directional endpoints including EP0
-#define EP_MAX 16
+#define EP_MAX 16
typedef struct {
- uint8_t *buffer;
- // tu_fifo_t * ff; // TODO support dcd_edpt_xfer_fifo API
- uint16_t total_len;
- uint16_t queued_len;
- uint16_t max_size;
- bool short_packet;
+ uint8_t* buffer;
+ uint16_t total_len;
+ uint16_t queued_len;
+ uint16_t max_size;
+ bool is_last_packet;
+ bool is_iso;
} xfer_ctl_t;
+typedef enum {
+ EP_RESPONSE_ACK,
+ EP_RESPONSE_NAK,
+} ep_response_list_t;
+
#define XFER_CTL_BASE(_ep, _dir) &xfer_status[_ep][_dir]
static xfer_ctl_t xfer_status[EP_MAX][2];
-#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep)*2)
-#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep)*4)
-#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep)*4)
-#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep)*2)
+#define EP_TX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_TX_LEN) + (ep) * 2)
+#define EP_TX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_TX_CTRL) + (ep) * 4)
+#define EP_RX_CTRL(ep) *(volatile uint8_t *)((volatile uint8_t *)&(USBHSD->UEP0_RX_CTRL) + (ep) * 4)
+#define EP_RX_MAX_LEN(ep) *(volatile uint16_t *)((volatile uint16_t *)&(USBHSD->UEP0_MAX_LEN) + (ep) * 2)
#define EP_TX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_TX_DMA) + (ep - 1))
#define EP_RX_DMA_ADDR(ep) *(volatile uint32_t *)((volatile uint32_t *)&(USBHSD->UEP1_RX_DMA) + (ep - 1))
/* Endpoint Buffer */
-TU_ATTR_ALIGNED(4) uint8_t EP0_DatabufHD[64]; // ep0(64)
+TU_ATTR_ALIGNED(4) static uint8_t ep0_buffer[CFG_TUD_ENDPOINT0_SIZE];
+
+static void ep_set_response_and_toggle(uint8_t ep_num, tusb_dir_t ep_dir, ep_response_list_t response_type) {
+ if (ep_dir == TUSB_DIR_IN) {
+ uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_T_RES_ACK : USBHS_EP_T_RES_NAK;
+ if (ep_num == 0) {
+ if (response_type == EP_RESPONSE_ACK) {
+ if (EP_TX_LEN(ep_num) == 0) {
+ EP_TX_CTRL(ep_num) |= USBHS_EP_T_TOG_1;
+ } else {
+ EP_TX_CTRL(ep_num) ^= USBHS_EP_T_TOG_1;
+ }
+ }
+ }
+ if (xfer_status[ep_num][TUSB_DIR_IN].is_iso == true) {
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG;
+ } else {
+ EP_TX_CTRL(ep_num) = (EP_TX_CTRL(ep_num) & ~(USBHS_EP_T_RES_MASK)) | response;
+ }
+ } else {
+ uint8_t response = (response_type == EP_RESPONSE_ACK) ? USBHS_EP_R_RES_ACK : USBHS_EP_R_RES_NAK;
+ if (ep_num == 0) {
+ if (response_type == EP_RESPONSE_ACK) {
+ if (xfer_status[ep_num][TUSB_DIR_OUT].queued_len == 0) {
+ EP_RX_CTRL(ep_num) |= USBHS_EP_R_TOG_1;
+ }
+ } else {
+ EP_RX_CTRL(ep_num) ^= USBHS_EP_R_TOG_1;
+ }
+ }
+ EP_RX_CTRL(ep_num) = (EP_RX_CTRL(ep_num) & ~(USBHS_EP_R_RES_MASK)) | response;
+ }
+}
+
+static void xfer_data_packet(uint8_t ep_num, tusb_dir_t ep_dir, xfer_ctl_t* xfer) {
+ if (ep_dir == TUSB_DIR_IN) {
+ uint16_t remaining = xfer->total_len - xfer->queued_len;
+ uint16_t next_tx_size = TU_MIN(remaining, xfer->max_size);
+
+ if (ep_num == 0) {
+ memcpy(ep0_buffer, &xfer->buffer[xfer->queued_len], next_tx_size);
+ } else {
+ EP_TX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
+ }
+
+ EP_TX_LEN(ep_num) = next_tx_size;
+ xfer->queued_len += next_tx_size;
+ if (xfer->queued_len == xfer->total_len) {
+ xfer->is_last_packet = true;
+ }
+ if (xfer->is_iso == true) {
+ /* Enable EP to generate ISA_ACT interrupt */
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
+ }
+ } else { /* TUSB_DIR_OUT */
+ uint16_t left_to_receive = xfer->total_len - xfer->queued_len;
+ uint16_t max_possible_rx_size = TU_MIN(xfer->max_size, left_to_receive);
-volatile uint8_t USBHS_Dev_Endp0_Tog = 0x01;
+ if (max_possible_rx_size == left_to_receive) {
+ xfer->is_last_packet = true;
+ }
+
+ if (ep_num > 0) {
+ EP_RX_DMA_ADDR(ep_num) = (uint32_t) &xfer->buffer[xfer->queued_len];
+ EP_RX_MAX_LEN(ep_num) = max_possible_rx_size;
+ }
+ }
+ ep_set_response_and_toggle(ep_num, ep_dir, USBHS_EP_R_RES_ACK);
+}
void dcd_init(uint8_t rhport) {
- (void)rhport;
+ (void) rhport;
- memset(&xfer_status, 0, sizeof(xfer_status));
+ memset(&xfer_status, 0, sizeof(xfer_status));
- USBHSD->HOST_CTRL = 0x00;
- USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
+ USBHSD->HOST_CTRL = 0x00;
+ USBHSD->HOST_CTRL = USBHS_PHY_SUSPENDM;
- USBHSD->CONTROL = 0;
+ USBHSD->CONTROL = 0;
#if TUD_OPT_HIGH_SPEED
- USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
+ USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_HIGH_SPEED;
#else
- #error OPT_MODE_FULL_SPEED not currently supported on CH32
- USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
+ #error OPT_MODE_FULL_SPEED not currently supported on CH32
+ USBHSD->CONTROL = USBHS_DMA_EN | USBHS_INT_BUSY_EN | USBHS_FULL_SPEED;
#endif
- USBHSD->INT_EN = 0;
- USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_DETECT_EN | USBHS_SUSPEND_EN;
-
- /* ALL endpoint enable */
- USBHSD->ENDP_CONFIG = 0xffffffff;
-
- USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
- USBHSD->ENDP_TYPE = 0x00;
- USBHSD->BUF_MODE = 0x00;
+ USBHSD->INT_EN = 0;
+ USBHSD->INT_EN = USBHS_SETUP_ACT_EN | USBHS_TRANSFER_EN | USBHS_BUS_RST_EN | USBHS_SUSPEND_EN | USBHS_ISO_ACT_EN;
- USBHSD->UEP0_MAX_LEN = 64;
+ USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
+ USBHSD->ENDP_TYPE = 0x00;
+ USBHSD->BUF_MODE = 0x00;
- USBHSD->UEP0_DMA = (uint32_t)EP0_DatabufHD;
+ for (int ep = 0; ep < EP_MAX; ep++) {
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
+ EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
- USBHSD->UEP0_TX_LEN = 0;
- USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_NAK;
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
+ EP_RX_MAX_LEN(ep) = 0;
+ }
- for (int ep = 1; ep < EP_MAX; ep++) {
- EP_TX_LEN(ep) = 0;
- EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
- EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ USBHSD->UEP0_DMA = (uint32_t) ep0_buffer;
+ USBHSD->UEP0_MAX_LEN = CFG_TUD_ENDPOINT0_SIZE;
+ xfer_status[0][TUSB_DIR_OUT].max_size = CFG_TUD_ENDPOINT0_SIZE;
+ xfer_status[0][TUSB_DIR_IN].max_size = CFG_TUD_ENDPOINT0_SIZE;
- EP_RX_MAX_LEN(ep) = 512;
- }
-
- USBHSD->DEV_AD = 0;
- USBHSD->CONTROL |= USBHS_DEV_PU_EN;
+ USBHSD->DEV_AD = 0;
+ USBHSD->CONTROL |= USBHS_DEV_PU_EN;
}
void dcd_int_enable(uint8_t rhport) {
- (void)rhport;
-
- NVIC_EnableIRQ(USBHS_IRQn);
+ (void) rhport;
+ NVIC_EnableIRQ(USBHS_IRQn);
}
void dcd_int_disable(uint8_t rhport) {
- (void)rhport;
-
- NVIC_DisableIRQ(USBHS_IRQn);
+ (void) rhport;
+ NVIC_DisableIRQ(USBHS_IRQn);
}
void dcd_edpt_close_all(uint8_t rhport) {
- (void)rhport;
+ (void) rhport;
+
+ for (size_t ep = 1; ep < EP_MAX; ep++) {
+ EP_TX_LEN(ep) = 0;
+ EP_TX_CTRL(ep) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK;
+ EP_RX_CTRL(ep) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+
+ EP_RX_MAX_LEN(ep) = 0;
+ }
+
+ USBHSD->ENDP_CONFIG = USBHS_EP0_T_EN | USBHS_EP0_R_EN;
}
void dcd_set_address(uint8_t rhport, uint8_t dev_addr) {
- (void)dev_addr;
+ (void) dev_addr;
- // Response with zlp status
- dcd_edpt_xfer(rhport, 0x80, NULL, 0);
+ // Response with zlp status
+ dcd_edpt_xfer(rhport, 0x80, NULL, 0);
}
-void dcd_remote_wakeup(uint8_t rhport)
-{
+void dcd_remote_wakeup(uint8_t rhport) {
(void) rhport;
}
-void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const *request) {
- (void)rhport;
-
- if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
- request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
- request->bRequest == TUSB_REQ_SET_ADDRESS) {
- USBHSD->DEV_AD = (uint8_t)request->wValue;
- }
-
- EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK;
- EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK;
+void dcd_sof_enable(uint8_t rhport, bool en) {
+ (void) rhport;
+ if (en) {
+ USBHSD->INT_EN |= USBHS_SOF_ACT_EN;
+ } else {
+ USBHSD->INT_EN &= ~(USBHS_SOF_ACT_EN);
+ }
}
-bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const *desc_edpt) {
- (void)rhport;
-
- uint8_t const epnum = tu_edpt_number(desc_edpt->bEndpointAddress);
- uint8_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
-
- TU_ASSERT(epnum < EP_MAX);
-
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
- xfer->max_size = tu_edpt_packet_size(desc_edpt);
-
- if (epnum != 0) {
- if (tu_edpt_dir(desc_edpt->bEndpointAddress) == TUSB_DIR_OUT) {
- EP_RX_CTRL(epnum) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_ACK;
- } else {
- EP_TX_LEN(epnum) = 0;
- EP_TX_CTRL(epnum) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
- }
- }
-
- return true;
-}
+void dcd_edpt0_status_complete(uint8_t rhport, tusb_control_request_t const* request) {
+ (void) rhport;
-int usbd_ep_close(const uint8_t ep) {
- (void)ep;
+ if (request->bmRequestType_bit.recipient == TUSB_REQ_RCPT_DEVICE &&
+ request->bmRequestType_bit.type == TUSB_REQ_TYPE_STANDARD &&
+ request->bRequest == TUSB_REQ_SET_ADDRESS) {
+ USBHSD->DEV_AD = (uint8_t) request->wValue;
+ }
- return 0;
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ EP_RX_CTRL(0) = USBHS_EP_R_RES_NAK | USBHS_EP_R_TOG_0;
}
-void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
- (void)rhport;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+bool dcd_edpt_open(uint8_t rhport, tusb_desc_endpoint_t const* desc_edpt) {
+ (void) rhport;
- if (epnum == 0) {
- if (dir == TUSB_DIR_OUT) {
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_STALL;
- } else {
- USBHSD->UEP0_TX_LEN = 0;
- USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_STALL;
- }
- } else {
- if (dir == TUSB_DIR_OUT) {
- EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~USBHS_EP_R_RES_MASK) | USBHS_EP_R_RES_STALL;
+ uint8_t const ep_num = tu_edpt_number(desc_edpt->bEndpointAddress);
+ tusb_dir_t const dir = tu_edpt_dir(desc_edpt->bEndpointAddress);
- } else {
- EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~USBHS_EP_T_RES_MASK) | USBHS_EP_T_RES_STALL;
- }
- }
-}
+ TU_ASSERT(ep_num < EP_MAX);
-void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
- (void)rhport;
+ if (ep_num == 0) {
+ return true;
+ }
- 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(ep_num, dir);
+ xfer->max_size = tu_edpt_packet_size(desc_edpt);
- if (epnum == 0) {
- if (dir == TUSB_DIR_OUT) {
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK;
- } else {
- }
+ xfer->is_iso = (desc_edpt->bmAttributes.xfer == TUSB_XFER_ISOCHRONOUS);
+ if (dir == TUSB_DIR_OUT) {
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << ep_num);
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ if (xfer->is_iso == true) {
+ USBHSD->ENDP_TYPE |= (USBHS_EP0_R_TYP << ep_num);
+ }
+ EP_RX_MAX_LEN(ep_num) = xfer->max_size;
+ } else {
+ if (xfer->is_iso == true) {
+ USBHSD->ENDP_TYPE |= (USBHS_EP0_T_TYP << ep_num);
} else {
- if (dir == TUSB_DIR_OUT) {
- EP_RX_CTRL(epnum) = (EP_RX_CTRL(epnum) & ~(USBHS_EP_R_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_ACK;
-
- } else {
- EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK | USBHS_EP_T_TOG_MASK)) | USBHS_EP_T_RES_NAK;
- }
+ /* Enable all types except Isochronous to avoid ISO_ACT interrupt generation */
+ USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << ep_num);
}
-}
-
-bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t *buffer, uint16_t total_bytes) {
- (void)rhport;
- uint8_t const epnum = tu_edpt_number(ep_addr);
- uint8_t const dir = tu_edpt_dir(ep_addr);
+ EP_TX_LEN(ep_num) = 0;
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ }
- xfer_ctl_t *xfer = XFER_CTL_BASE(epnum, dir);
- xfer->buffer = buffer;
- // xfer->ff = NULL; // TODO support dcd_edpt_xfer_fifo API
- xfer->total_len = total_bytes;
- xfer->queued_len = 0;
- xfer->short_packet = false;
-
- // uint16_t num_packets = (total_bytes / xfer->max_size);
- uint16_t short_packet_size = total_bytes % (xfer->max_size + 1);
+ return true;
+}
- // Zero-size packet is special case.
- if (short_packet_size == 0 || (total_bytes == 0)) {
- xfer->short_packet = true;
- }
+void dcd_edpt_close(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
- if (tu_edpt_dir(ep_addr) == TUSB_DIR_IN) {
- if (!total_bytes) {
- xfer->short_packet = true;
- if (epnum == 0) {
- USBHSD->UEP0_TX_LEN = 0;
- USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
- USBHS_Dev_Endp0_Tog ^= 1;
- } else {
- EP_TX_LEN(epnum) = 0;
- EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
- }
- } else {
- if (epnum == 0) {
- xfer->queued_len += short_packet_size;
- memcpy(&EP0_DatabufHD[0], buffer, short_packet_size);
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- USBHSD->UEP0_TX_LEN = short_packet_size;
- USBHSD->UEP0_TX_CTRL = USBHS_EP_T_RES_ACK | (USBHS_Dev_Endp0_Tog ? USBHS_EP_T_TOG_1 : USBHS_EP_T_TOG_0);
- USBHS_Dev_Endp0_Tog ^= 1;
- } else {
- xfer->queued_len += short_packet_size;
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ EP_RX_MAX_LEN(ep_num) = 0;
+ USBHSD->ENDP_TYPE &= ~(USBHS_EP0_R_TYP << ep_num);
+ USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_R_EN << ep_num);
+ } else { // TUSB_DIR_IN
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
+ EP_TX_LEN(ep_num) = 0;
+ USBHSD->ENDP_TYPE &= ~(USBHS_EP0_T_TYP << ep_num);
+ USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num);
+ }
+}
- EP_TX_DMA_ADDR(epnum) = (uint32_t)buffer;
- USBHSD->ENDP_CONFIG |= (USBHS_EP0_T_EN << epnum);
- EP_TX_LEN(epnum) = short_packet_size;
- EP_TX_CTRL(epnum) = (EP_TX_CTRL(epnum) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_ACK;
- }
- }
- } else { /* TUSB_DIR_OUT */
- if (epnum == 0) {
- uint32_t read_count = USBHSD->RX_LEN;
- read_count = TU_MIN(read_count, total_bytes);
+void dcd_edpt_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
- if ((total_bytes == 8)) {
- read_count = 8;
- memcpy(buffer, &EP0_DatabufHD[0], 8);
- } else {
- memcpy(buffer, &EP0_DatabufHD[0], read_count);
- }
- } else {
- EP_RX_DMA_ADDR(epnum) = (uint32_t)xfer->buffer;
- USBHSD->ENDP_CONFIG |= (USBHS_EP0_R_EN << epnum);
- }
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- // usbd_ep_read(ep_addr, buffer, total_bytes, &ret_bytes);
- }
- return true;
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_RES_STALL;
+ } else {
+ EP_TX_LEN(0) = 0;
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_RES_STALL;
+ }
}
+void dcd_edpt_clear_stall(uint8_t rhport, uint8_t ep_addr) {
+ (void) rhport;
-static void receive_packet(xfer_ctl_t *xfer, uint16_t xfer_size) {
- // xfer->queued_len = xfer->total_len - remaining;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- uint16_t remaining = xfer->total_len - xfer->queued_len;
- uint16_t to_recv_size;
+ if (dir == TUSB_DIR_OUT) {
+ EP_RX_CTRL(ep_num) = USBHS_EP_R_AUTOTOG | USBHS_EP_R_RES_NAK;
+ } else {
+ EP_TX_CTRL(ep_num) = USBHS_EP_T_AUTOTOG | USBHS_EP_R_RES_NAK;
+ }
+}
- if (remaining <= xfer->max_size) {
- // Avoid buffer overflow.
- to_recv_size = (xfer_size > remaining) ? remaining : xfer_size;
- } else {
- // Room for full packet, choose recv_size based on what the microcontroller
- // claims.
- to_recv_size = (xfer_size > xfer->max_size) ? xfer->max_size : xfer_size;
- }
+bool dcd_edpt_xfer(uint8_t rhport, uint8_t ep_addr, uint8_t* buffer, uint16_t total_bytes) {
+ (void) rhport;
+ uint8_t const ep_num = tu_edpt_number(ep_addr);
+ tusb_dir_t const dir = tu_edpt_dir(ep_addr);
- if (to_recv_size) {
- }
+ xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, dir);
+ xfer->buffer = buffer;
+ xfer->total_len = total_bytes;
+ xfer->queued_len = 0;
+ xfer->is_last_packet = false;
- xfer->queued_len += xfer_size;
+ xfer_data_packet(ep_num, dir, xfer);
- // Per USB spec, a short OUT packet (including length 0) is always
- // indicative of the end of a transfer (at least for ctl, bulk, int).
- xfer->short_packet = (xfer_size < xfer->max_size);
+ return true;
}
void dcd_int_handler(uint8_t rhport) {
- (void)rhport;
-
- uint32_t end_num, rx_token;
- uint8_t intflag = 0;
-
- intflag = USBHSD->INT_FG;
-
- if (intflag & USBHS_TRANSFER_FLAG) {
-
- end_num = (USBHSD->INT_ST) & MASK_UIS_ENDP;
- rx_token = (((USBHSD->INT_ST) & MASK_UIS_TOKEN) >> 4) & 0x03;
-
- uint8_t endp = end_num | (rx_token == PID_IN ? TUSB_DIR_IN_MASK : 0);
-
- xfer_ctl_t *xfer = XFER_CTL_BASE(end_num, tu_edpt_dir(endp));
-
- if (rx_token == PID_OUT) {
- uint16_t rx_len = USBHSD->RX_LEN;
-
- receive_packet(xfer, rx_len);
+ (void) rhport;
- if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
- xfer->short_packet = false;
+ uint8_t int_flag = USBHSD->INT_FG;
+ uint8_t int_status = USBHSD->INT_ST;
- dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
- }
+ if (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)) {
+ uint8_t const token = int_status & MASK_UIS_TOKEN;
- if (end_num == 0) {
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
- }
+ if (token == USBHS_TOKEN_PID_SOF) {
+ uint32_t frame_count = USBHSD->FRAME_NO & USBHS_FRAME_NO_NUM_MASK;
+ dcd_event_sof(rhport, frame_count, true);
+ }else {
+ uint8_t const ep_num = int_status & MASK_UIS_ENDP;
+ tusb_dir_t const ep_dir = (token == USBHS_TOKEN_PID_IN) ? TUSB_DIR_IN : TUSB_DIR_OUT;
+ uint8_t const ep_addr = tu_edpt_addr(ep_num, ep_dir);
+ xfer_ctl_t* xfer = XFER_CTL_BASE(ep_num, ep_dir);
- } else if (rx_token == PID_IN) {
- if (xfer->short_packet || (xfer->queued_len == xfer->total_len)) {
- xfer->short_packet = false;
- xfer->total_len = 0;
- dcd_event_xfer_complete(0, endp, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ if (token == USBHS_TOKEN_PID_OUT) {
+ uint16_t rx_len = USBHSD->RX_LEN;
- EP_TX_CTRL(end_num) = (EP_TX_CTRL(end_num) & ~(USBHS_EP_T_RES_MASK)) | USBHS_EP_T_RES_NAK;
+ if (ep_num == 0) {
+ memcpy(&xfer->buffer[xfer->queued_len], ep0_buffer, rx_len);
+ }
- if (end_num == 0) {
- }
- } else {
- dcd_edpt_xfer(0, endp, xfer->buffer + xfer->queued_len, xfer->total_len - xfer->queued_len);
- }
+ xfer->queued_len += rx_len;
+ if (rx_len < xfer->max_size) {
+ xfer->is_last_packet = true;
+ }
+ } else if (token == USBHS_TOKEN_PID_IN) {
+ if (xfer->is_iso && xfer->is_last_packet) {
+ /* Disable EP to avoid ISO_ACT interrupt generation */
+ USBHSD->ENDP_CONFIG &= ~(USBHS_EP0_T_EN << ep_num);
+ } else {
+ // Do nothing, no need to update xfer->is_last_packet, it is already updated in xfer_data_packet
}
+ }
- USBHSD->INT_FG = USBHS_TRANSFER_FLAG; /* Clear flag */
- } else if (intflag & USBHS_SETUP_FLAG) {
- USBHS_Dev_Endp0_Tog = 1;
- dcd_event_setup_received(0, EP0_DatabufHD, true);
+ if (xfer->is_last_packet == true) {
+ ep_set_response_and_toggle(ep_num, ep_dir, EP_RESPONSE_NAK);
+ dcd_event_xfer_complete(0, ep_addr, xfer->queued_len, XFER_RESULT_SUCCESS, true);
+ } else {
+ /* prepare next part of packet to xref */
+ xfer_data_packet(ep_num, ep_dir, xfer);
+ }
+ }
- USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
- } else if (intflag & USBHS_DETECT_FLAG) {
- USBHS_Dev_Endp0_Tog = 1;
+ USBHSD->INT_FG = (int_flag & (USBHS_ISO_ACT_FLAG | USBHS_TRANSFER_FLAG)); /* Clear flag */
+ } else if (int_flag & USBHS_SETUP_FLAG) {
+ ep_set_response_and_toggle(0, TUSB_DIR_IN, EP_RESPONSE_NAK);
+ ep_set_response_and_toggle(0, TUSB_DIR_OUT, EP_RESPONSE_NAK);
+ dcd_event_setup_received(0, ep0_buffer, true);
- xfer_status[0][TUSB_DIR_OUT].max_size = 64;
- xfer_status[0][TUSB_DIR_IN].max_size = 64;
+ USBHSD->INT_FG = USBHS_SETUP_FLAG; /* Clear flag */
+ } else if (int_flag & USBHS_BUS_RST_FLAG) {
+ // TODO CH32 does not detect actual speed at this time (should be known at end of reset)
+ // This interrupt probably triggered at start of bus reset
+// tusb_speed_t actual_speed;
+// switch(USBHSD->SPEED_TYPE & USBHS_SPEED_TYPE_MASK){
+// case USBHS_SPEED_TYPE_HIGH:
+// actual_speed = TUSB_SPEED_HIGH;
+// break;
+// case USBHS_SPEED_TYPE_FULL:
+// actual_speed = TUSB_SPEED_FULL;
+// break;
+// case USBHS_SPEED_TYPE_LOW:
+// actual_speed = TUSB_SPEED_LOW;
+// break;
+// default:
+// TU_ASSERT(0,);
+// break;
+// }
+// dcd_event_bus_reset(0, actual_speed, true);
- dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
+ dcd_event_bus_reset(0, TUSB_SPEED_HIGH, true);
- USBHSD->DEV_AD = 0;
- USBHSD->UEP0_RX_CTRL = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+ USBHSD->DEV_AD = 0;
+ EP_RX_CTRL(0) = USBHS_EP_R_RES_ACK | USBHS_EP_R_TOG_0;
+ EP_TX_CTRL(0) = USBHS_EP_T_RES_NAK | USBHS_EP_T_TOG_0;
- USBHSD->INT_FG = USBHS_DETECT_FLAG; /* Clear flag */
- } else if (intflag & USBHS_SUSPEND_FLAG) {
- dcd_event_t event = { .rhport = rhport, .event_id = DCD_EVENT_SUSPEND };
- dcd_event_handler(&event, true);
+ USBHSD->INT_FG = USBHS_BUS_RST_FLAG; /* Clear flag */
+ } else if (int_flag & USBHS_SUSPEND_FLAG) {
+ dcd_event_t event = {.rhport = rhport, .event_id = DCD_EVENT_SUSPEND};
+ dcd_event_handler(&event, true);
- USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
- }
+ USBHSD->INT_FG = USBHS_SUSPEND_FLAG; /* Clear flag */
+ }
}
#endif
diff --git a/src/tusb.h b/src/tusb.h
index c9d56d3c3..4f69a1414 100644
--- a/src/tusb.h
+++ b/src/tusb.h
@@ -38,8 +38,6 @@
#include "osal/osal.h"
#include "common/tusb_fifo.h"
-#include "class/hid/hid.h"
-
//------------- TypeC -------------//
#if CFG_TUC_ENABLED
#include "typec/usbc.h"
diff --git a/src/tusb_option.h b/src/tusb_option.h
index cbcb69edd..8990cf92b 100644
--- a/src/tusb_option.h
+++ b/src/tusb_option.h
@@ -29,14 +29,12 @@
#include "common/tusb_compiler.h"
-// Version is release as major.minor.revision eg 1.0.0. though there could be notable APIs before a new release.
-// For notable API changes within a release, we increase the build number.
+// Version is release as major.minor.revision eg 1.0.0
#define TUSB_VERSION_MAJOR 0
-#define TUSB_VERSION_MINOR 16
+#define TUSB_VERSION_MINOR 17
#define TUSB_VERSION_REVISION 0
-#define TUSB_VERSION_BUILD 3
-#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR << 24 | TUSB_VERSION_MINOR << 16 | TUSB_VERSION_REVISION << 8 | TUSB_VERSION_BUILD)
+#define TUSB_VERSION_NUMBER (TUSB_VERSION_MAJOR * 10000 + TUSB_VERSION_MINOR * 100 + TUSB_VERSION_REVISION)
#define TUSB_VERSION_STRING TU_STRING(TUSB_VERSION_MAJOR) "." TU_STRING(TUSB_VERSION_MINOR) "." TU_STRING(TUSB_VERSION_REVISION)
//--------------------------------------------------------------------+
@@ -55,7 +53,8 @@
#define OPT_MCU_LPC18XX 6 ///< NXP LPC18xx
#define OPT_MCU_LPC40XX 7 ///< NXP LPC40xx
#define OPT_MCU_LPC43XX 8 ///< NXP LPC43xx
-#define OPT_MCU_LPC51UXX 9 ///< NXP LPC51U6x
+#define OPT_MCU_LPC51 9 ///< NXP LPC51
+#define OPT_MCU_LPC51UXX OPT_MCU_LPC51 ///< NXP LPC51
#define OPT_MCU_LPC54 10 ///< NXP LPC54
#define OPT_MCU_LPC55 11 ///< NXP LPC55
// legacy naming
@@ -119,6 +118,12 @@
// Espressif
#define OPT_MCU_ESP32S2 900 ///< Espressif ESP32-S2
#define OPT_MCU_ESP32S3 901 ///< Espressif ESP32-S3
+#define OPT_MCU_ESP32 902 ///< Espressif ESP32 (for host max3421e)
+#define OPT_MCU_ESP32C3 903 ///< Espressif ESP32-C3
+#define OPT_MCU_ESP32C6 904 ///< Espressif ESP32-C6
+#define OPT_MCU_ESP32C2 905 ///< Espressif ESP32-C2
+#define OPT_MCU_ESP32H2 906 ///< Espressif ESP32-H2
+#define TUP_MCU_ESPRESSIF (CFG_TUSB_MCU >= 900 && CFG_TUSB_MCU < 1000) // check if Espressif MCU
// Dialog
#define OPT_MCU_DA1469X 1000 ///< Dialog Semiconductor DA1469x
@@ -176,7 +181,8 @@
// WCH
#define OPT_MCU_CH32V307 2200 ///< WCH CH32V307
#define OPT_MCU_CH32F20X 2210 ///< WCH CH32F20x
-
+#define OPT_MCU_CH32V20X 2220 ///< WCH CH32V20X
+#define OPT_MCU_CH32V103 2230 ///< WCH CH32V103
// NXP LPC MCX
#define OPT_MCU_MCXN9 2300 ///< NXP MCX N9 Series
@@ -199,19 +205,9 @@
#define OPT_OS_RTTHREAD 6 ///< RT-Thread
#define OPT_OS_RTX4 7 ///< Keil RTX 4
-// Allow to use command line to change the config name/location
-#ifdef CFG_TUSB_CONFIG_FILE
- #include CFG_TUSB_CONFIG_FILE
-#else
- #include "tusb_config.h"
-#endif
-
-#include "common/tusb_mcu.h"
-
-//--------------------------------------------------------------------
-// RootHub Mode Configuration
-// CFG_TUSB_RHPORTx_MODE contains operation mode and speed for that port
-//--------------------------------------------------------------------
+//--------------------------------------------------------------------+
+// Mode and Speed
+//--------------------------------------------------------------------+
// Low byte is operational mode
#define OPT_MODE_NONE 0x0000 ///< Disabled
@@ -225,7 +221,24 @@
#define OPT_MODE_HIGH_SPEED 0x0400 ///< High Speed
#define OPT_MODE_SPEED_MASK 0xff00
-//------------- Roothub as Device -------------//
+//--------------------------------------------------------------------+
+// Include tusb_config.h and tusb_mcu.h
+//--------------------------------------------------------------------+
+
+// Allow to use command line to change the config name/location
+#ifdef CFG_TUSB_CONFIG_FILE
+ #include CFG_TUSB_CONFIG_FILE
+#else
+ #include "tusb_config.h"
+#endif
+
+#include "common/tusb_mcu.h"
+
+//--------------------------------------------------------------------
+// RootHub Mode detection
+//--------------------------------------------------------------------
+
+//------------- Root hub as Device -------------//
#if defined(CFG_TUSB_RHPORT0_MODE) && ((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_DEVICE)
#define TUD_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE)
@@ -253,7 +266,7 @@
// highspeed support indicator
#define TUD_OPT_HIGH_SPEED (CFG_TUD_MAX_SPEED ? (CFG_TUD_MAX_SPEED & OPT_MODE_HIGH_SPEED) : TUP_RHPORT_HIGHSPEED)
-//------------- Roothub as Host -------------//
+//------------- Root hub as Host -------------//
#if defined(CFG_TUSB_RHPORT0_MODE) && ((CFG_TUSB_RHPORT0_MODE) & OPT_MODE_HOST)
#define TUH_RHPORT_MODE (CFG_TUSB_RHPORT0_MODE)
@@ -359,6 +372,20 @@
#define CFG_TUD_INTERFACE_MAX 16
#endif
+// default to max hardware endpoint, but can be smaller to save RAM
+#ifndef CFG_TUD_ENDPPOINT_MAX
+ #define CFG_TUD_ENDPPOINT_MAX TUP_DCD_ENDPOINT_MAX
+#endif
+
+#if CFG_TUD_ENDPPOINT_MAX > TUP_DCD_ENDPOINT_MAX
+ #error "CFG_TUD_ENDPPOINT_MAX must be less than or equal to TUP_DCD_ENDPOINT_MAX"
+#endif
+
+// USB 2.0 compliance test mode support
+#ifndef CFG_TUD_TEST_MODE
+ #define CFG_TUD_TEST_MODE 0
+#endif
+
//------------- Device Class Driver -------------//
#ifndef CFG_TUD_BTH
#define CFG_TUD_BTH 0
@@ -454,26 +481,26 @@
#define CFG_TUH_CDC 0
#endif
+// FTDI is not part of CDC class, only to re-use CDC driver API
#ifndef CFG_TUH_CDC_FTDI
- // FTDI is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_FTDI 0
#endif
+// List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID
#ifndef CFG_TUH_CDC_FTDI_VID_PID_LIST
- // List of product IDs that can use the FTDI CDC driver. 0x0403 is FTDI's VID
#define CFG_TUH_CDC_FTDI_VID_PID_LIST \
{0x0403, 0x6001}, {0x0403, 0x6006}, {0x0403, 0x6010}, {0x0403, 0x6011}, \
{0x0403, 0x6014}, {0x0403, 0x6015}, {0x0403, 0x8372}, {0x0403, 0xFBFA}, \
{0x0403, 0xCD18}
#endif
+// CP210X is not part of CDC class, only to re-use CDC driver API
#ifndef CFG_TUH_CDC_CP210X
- // CP210X is not part of CDC class, only to re-use CDC driver API
#define CFG_TUH_CDC_CP210X 0
#endif
+// List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID
#ifndef CFG_TUH_CDC_CP210X_VID_PID_LIST
- // List of product IDs that can use the CP210X CDC driver. 0x10C4 is Silicon Labs' VID
#define CFG_TUH_CDC_CP210X_VID_PID_LIST \
{0x10C4, 0xEA60}, {0x10C4, 0xEA70}
#endif
@@ -483,8 +510,8 @@
#define CFG_TUH_CDC_CH34X 0
#endif
+// List of product IDs that can use the CH34X CDC driver
#ifndef CFG_TUH_CDC_CH34X_VID_PID_LIST
- // List of product IDs that can use the CH34X CDC driver
#define CFG_TUH_CDC_CH34X_VID_PID_LIST \
{ 0x1a86, 0x5523 }, /* ch341 chip */ \
{ 0x1a86, 0x7522 }, /* ch340k chip */ \