1- #ifdef ARDUINO_USB_MODE
21
32#include " massStorage.h"
43#include " display.h"
54#include " sd_functions.h"
6- #include < USB.h>
5+ #ifdef SOC_USB_OTG_SUPPORTED
6+ #include " esp_private/usb_phy.h"
7+ #include " tusb.h"
8+ #include < cstring>
9+ #include < algorithm>
10+ #if CONFIG_IDF_TARGET_ESP32P4
11+ #include " esp_private/periph_ctrl.h"
12+ #include " soc/lp_system_struct.h"
13+ #include " soc/usb_wrap_struct.h"
14+ #include " hal/usb_serial_jtag_ll.h"
15+ #include " hal/usb_wrap_ll.h"
16+ #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
17+ #include " soc/periph_defs.h"
18+ #include " soc/rtc_cntl_reg.h"
19+ #include " soc/usb_wrap_struct.h"
20+ #include " hal/clk_gate_ll.h"
21+ #endif
722
823bool MassStorage::shouldStop = false ;
924
10- MassStorage::MassStorage () { setup (); }
25+ namespace {
26+ usb_phy_handle_t s_usbPhy = nullptr ;
27+ TaskHandle_t s_usbDeviceTask = nullptr ;
28+ bool s_usbStarted = false ;
29+ bool s_usbMounted = false ;
30+
31+ constexpr uint8_t kUsbItfMsc = 0 ;
32+ constexpr uint8_t kUsbEpOut = 0x01 ;
33+ constexpr uint8_t kUsbEpIn = 0x81 ;
34+ constexpr uint16_t kUsbEpSize = 64 ;
35+
36+ constexpr tusb_desc_device_t kDeviceDescriptor = {
37+ sizeof (tusb_desc_device_t ),
38+ TUSB_DESC_DEVICE,
39+ 0x0200 ,
40+ TUSB_CLASS_MSC,
41+ MSC_SUBCLASS_SCSI,
42+ MSC_PROTOCOL_BOT,
43+ CFG_TUD_ENDOINT0_SIZE,
44+ 0x303A ,
45+ 0x1001 ,
46+ 0x0100 ,
47+ 0x01 ,
48+ 0x02 ,
49+ 0x03 ,
50+ 0x01 ,
51+ };
52+
53+ constexpr uint8_t kConfigDescriptor [] = {
54+ TUD_CONFIG_DESCRIPTOR (1 , 1 , 0 , TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN, TUSB_DESC_CONFIG_ATT_SELF_POWERED, 500 ),
55+ TUD_MSC_DESCRIPTOR (kUsbItfMsc , 4 , kUsbEpOut , kUsbEpIn , kUsbEpSize ),
56+ };
57+
58+ const char *kUsbStrings [] = {
59+ " " ,
60+ " M5Stack" ,
61+ " Launcher SD" ,
62+ " TAB5-SD" ,
63+ " MSC" ,
64+ };
65+
66+ void resetUsbDevicePeripheral () {
67+ #if CONFIG_IDF_TARGET_ESP32P4
68+ PERIPH_RCC_ATOMIC () {
69+ _usb_wrap_ll_reset_register ();
70+ }
71+ #elif CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
72+ REG_CLR_BIT (RTC_CNTL_USB_CONF_REG, RTC_CNTL_IO_MUX_RESET_DISABLE);
73+ REG_CLR_BIT (RTC_CNTL_USB_CONF_REG, RTC_CNTL_USB_RESET_DISABLE);
74+ periph_ll_reset (PERIPH_USB_MODULE);
75+ periph_ll_enable_clk_clear_rst (PERIPH_USB_MODULE);
76+ #endif
77+ }
78+
79+ void usbDeviceTask (void *param) {
80+ (void )param;
81+ while (true ) {
82+ tud_task ();
83+ bool mounted = tud_mounted ();
84+ if (mounted != s_usbMounted) {
85+ s_usbMounted = mounted;
86+ drawUSBStickIcon (mounted);
87+ }
88+ vTaskDelay (1 );
89+ }
90+ }
91+
92+ void restoreUsbSerial () {
93+ #if CONFIG_IDF_TARGET_ESP32P4
94+ PERIPH_RCC_ATOMIC () {
95+ _usb_wrap_ll_enable_bus_clock (false );
96+ }
97+ usb_wrap_ll_phy_enable_pad (&USB_WRAP, false );
98+ PERIPH_RCC_ATOMIC () {
99+ _usb_serial_jtag_ll_enable_bus_clock (true );
100+ (usb_serial_jtag_ll_reset_register)();
101+ }
102+ usb_serial_jtag_ll_phy_set_defaults ();
103+ LP_SYS.usb_ctrl .sw_hw_usb_phy_sel = 1 ;
104+ LP_SYS.usb_ctrl .sw_usb_phy_sel = 0 ; // USB_SERIAL_JTAG -> FSLS PHY0 (Tab5 USB-C)
105+ usb_serial_jtag_ll_phy_enable_pad (true );
106+ vTaskDelay (pdMS_TO_TICKS (50 ));
107+ #endif
108+ #if ARDUINO_USB_CDC_ON_BOOT
109+ Serial.begin (115200 );
110+ #endif
111+ }
11112
12- MassStorage::~MassStorage () {
13- msc.end ();
14- USB.~ESPUSB ();
113+ bool beginUsbRaw () {
114+ if (s_usbStarted) return true ;
15115
16- // Hack to make USB back to flash mode
17- USB.enableDFU ();
116+ #if CONFIG_IDF_TARGET_ESP32P4
117+ PERIPH_RCC_ATOMIC () {
118+ _usb_serial_jtag_ll_enable_bus_clock (false );
119+ _usb_wrap_ll_enable_bus_clock (true );
120+ }
121+ #endif
122+ resetUsbDevicePeripheral ();
123+ vTaskDelay (pdMS_TO_TICKS (20 ));
124+
125+ static const usb_phy_otg_io_conf_t otgIoConf = USB_PHY_SELF_POWERED_DEVICE (-1 );
126+ usb_phy_config_t phyConfig = {
127+ .controller = USB_PHY_CTRL_OTG,
128+ .target = USB_PHY_TARGET_INT,
129+ .otg_mode = USB_OTG_MODE_DEVICE,
130+ .otg_speed = USB_PHY_SPEED_FULL,
131+ .ext_io_conf = nullptr ,
132+ .otg_io_conf = &otgIoConf,
133+ };
134+ if (usb_new_phy (&phyConfig, &s_usbPhy) != ESP_OK) return false ;
135+
136+ tusb_rhport_init_t tinit = {};
137+ tinit.role = TUSB_ROLE_DEVICE;
138+ tinit.speed = TUSB_SPEED_FULL;
139+ if (!tusb_init (0 , &tinit)) return false ;
140+ tud_connect ();
141+
142+ xTaskCreate (usbDeviceTask, " usb_msc" , 4096 , nullptr , configMAX_PRIORITIES - 1 , &s_usbDeviceTask);
143+ s_usbStarted = true ;
144+ return true ;
145+ }
146+
147+ void endUsbRaw () {
148+ s_usbMounted = false ;
149+ if (s_usbStarted) {
150+ tud_disconnect ();
151+ vTaskDelay (pdMS_TO_TICKS (30 ));
152+ tusb_deinit (0 );
153+ }
154+ if (s_usbDeviceTask) {
155+ vTaskDelete (s_usbDeviceTask);
156+ s_usbDeviceTask = nullptr ;
157+ }
158+ if (s_usbPhy) {
159+ usb_del_phy (s_usbPhy);
160+ s_usbPhy = nullptr ;
161+ }
162+ resetUsbDevicePeripheral ();
163+ s_usbStarted = false ;
164+ restoreUsbSerial ();
18165}
166+ } // namespace
167+
168+ extern " C" uint8_t const *tud_descriptor_device_cb (void ) {
169+ return reinterpret_cast <uint8_t const *>(&kDeviceDescriptor );
170+ }
171+
172+ extern " C" uint8_t const *tud_descriptor_configuration_cb (uint8_t index) {
173+ (void )index;
174+ return kConfigDescriptor ;
175+ }
176+
177+ extern " C" uint16_t const *tud_descriptor_string_cb (uint8_t index, uint16_t langid) {
178+ (void )langid;
179+ static uint16_t desc[32 ];
180+ uint8_t chrCount = 0 ;
181+
182+ if (index == 0 ) {
183+ desc[1 ] = 0x0409 ;
184+ chrCount = 1 ;
185+ } else {
186+ if (index >= (sizeof (kUsbStrings ) / sizeof (kUsbStrings [0 ]))) return nullptr ;
187+ const char *str = kUsbStrings [index];
188+ chrCount = static_cast <uint8_t >(std::min<size_t >(std::strlen (str), 31 ));
189+ for (uint8_t i = 0 ; i < chrCount; ++i) desc[1 + i] = str[i];
190+ }
191+
192+ desc[0 ] = static_cast <uint16_t >((TUSB_DESC_STRING << 8 ) | (2 * chrCount + 2 ));
193+ return desc;
194+ }
195+
196+ extern " C" uint8_t tud_msc_get_maxlun_cb (void ) {
197+ return 0 ;
198+ }
199+
200+ extern " C" void tud_msc_inquiry_cb (uint8_t lun, uint8_t vendor_id[8 ], uint8_t product_id[16 ], uint8_t product_rev[4 ]) {
201+ (void )lun;
202+ std::memset (vendor_id, ' ' , 8 );
203+ std::memset (product_id, ' ' , 16 );
204+ std::memset (product_rev, ' ' , 4 );
205+ std::memcpy (vendor_id, " M5Stack" , 7 );
206+ std::memcpy (product_id, " Launcher SD" , 11 );
207+ std::memcpy (product_rev, " 1.0" , 3 );
208+ }
209+
210+ extern " C" bool tud_msc_test_unit_ready_cb (uint8_t lun) {
211+ (void )lun;
212+ return true ;
213+ }
214+
215+ extern " C" void tud_msc_capacity_cb (uint8_t lun, uint32_t *block_count, uint16_t *block_size) {
216+ (void )lun;
217+ *block_count = SDM.numSectors ();
218+ *block_size = static_cast <uint16_t >(SDM.sectorSize ());
219+ }
220+
221+ extern " C" bool tud_msc_start_stop_cb (uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
222+ (void )lun;
223+ return usbStartStopCallback (power_condition, start, load_eject);
224+ }
225+
226+ extern " C" int32_t tud_msc_read10_cb (uint8_t lun, uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
227+ (void )lun;
228+ return usbReadCallback (lba, offset, buffer, bufsize);
229+ }
230+
231+ extern " C" int32_t tud_msc_write10_cb (uint8_t lun, uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
232+ (void )lun;
233+ return usbWriteCallback (lba, offset, buffer, bufsize);
234+ }
235+
236+ extern " C" bool tud_msc_is_writable_cb (uint8_t lun) {
237+ (void )lun;
238+ return true ;
239+ }
240+
241+ extern " C" int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16 ], void *buffer, uint16_t bufsize) {
242+ (void )lun;
243+ (void )buffer;
244+ (void )bufsize;
245+ switch (scsi_cmd[0 ]) {
246+ case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL: return 0 ;
247+ case 0x35 : return 0 ; // SYNCHRONIZE CACHE (10)
248+ default :
249+ tud_msc_set_sense (lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20 , 0x00 );
250+ return -1 ;
251+ }
252+ }
253+
254+
255+ MassStorage::MassStorage () { setup (); }
256+
257+ MassStorage::~MassStorage () { endUsbRaw (); }
19258
20259void MassStorage::setup () {
21260 displayMessage (" Mounting..." );
@@ -40,42 +279,18 @@ void MassStorage::loop() {
40279
41280void MassStorage::beginUsb () {
42281 drawUSBStickIcon (false );
43- setupUsbCallback ();
44- setupUsbEvent ();
45- USB.begin ();
46- }
47-
48- void MassStorage::setupUsbCallback () {
49- uint32_t secSize = SDM.sectorSize ();
50- uint32_t numSectors = SDM.numSectors ();
51-
52- msc.vendorID (" ESP32" );
53- msc.productID (" Launcher" );
54- msc.productRevision (" 1.0" );
55-
56- msc.onRead (usbReadCallback);
57- msc.onWrite (usbWriteCallback);
58- msc.onStartStop (usbStartStopCallback);
59-
60- msc.mediaPresent (true );
61- msc.begin (numSectors, secSize);
62- }
63-
64- void MassStorage::setupUsbEvent () {
65- #ifndef E_PAPER_DISPLAY
66- USB.onEvent ([](void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data) {
67- if (event_base == ARDUINO_USB_EVENTS) {
68- auto *data = reinterpret_cast <arduino_usb_event_data_t *>(event_data);
69- switch (event_id) {
70- case ARDUINO_USB_STARTED_EVENT: drawUSBStickIcon (true ); break ;
71- case ARDUINO_USB_STOPPED_EVENT: drawUSBStickIcon (false ); break ;
72- case ARDUINO_USB_SUSPEND_EVENT: MassStorage::displayMessage (" USB suspend" ); break ;
73- case ARDUINO_USB_RESUME_EVENT: MassStorage::displayMessage (" USB resume" ); break ;
74- default : break ;
75- }
76- }
77- });
282+ Serial.flush ();
283+ Serial.end ();
284+ #if CONFIG_IDF_TARGET_ESP32P4
285+ usb_serial_jtag_ll_phy_enable_pad (false );
286+ LP_SYS.usb_ctrl .sw_hw_usb_phy_sel = 1 ;
287+ LP_SYS.usb_ctrl .sw_usb_phy_sel = 1 ; // USB_WRAP -> FSLS PHY0 (GPIO24/25 on Tab5 USB-C)
288+ usb_wrap_ll_phy_set_defaults (&USB_WRAP);
289+ usb_wrap_ll_phy_enable_pad (&USB_WRAP, true );
290+ usb_wrap_ll_phy_set_pullup_strength (&USB_WRAP, true );
78291#endif
292+ s_usbMounted = false ;
293+ beginUsbRaw ();
79294}
80295
81296void MassStorage::displayMessage (String message) {
@@ -88,34 +303,24 @@ void MassStorage::displayMessage(String message) {
88303}
89304
90305int32_t usbWriteCallback (uint32_t lba, uint32_t offset, uint8_t *buffer, uint32_t bufsize) {
91- // Verify freespace
92- uint64_t freeSpace = SDM.totalBytes () - SDM.usedBytes ();
93- if (bufsize > freeSpace) {
94- return -1 ; // no space available
95- }
96-
97- // Verify sector size
98306 const uint32_t secSize = SDM.sectorSize ();
99- if (secSize == 0 ) return -1 ; // disk error
307+ if (secSize == 0 || offset != 0 || (bufsize % secSize) != 0 ) return -1 ;
100308
101- // Write blocs
102- for (uint32_t x = 0 ; x < bufsize / secSize; ++x) {
103- uint8_t blkBuffer[secSize];
104- memcpy (blkBuffer, buffer + secSize * x, secSize);
105- if (!SDM.writeRAW (blkBuffer, lba + x)) {
309+ const uint32_t blocks = bufsize / secSize;
310+ for (uint32_t x = 0 ; x < blocks; ++x) {
311+ if (!SDM.writeRAW (buffer + (secSize * x), lba + x)) {
106312 return -1 ; // write error
107313 }
108314 }
109315 return bufsize;
110316}
111317
112318int32_t usbReadCallback (uint32_t lba, uint32_t offset, void *buffer, uint32_t bufsize) {
113- // Verify sector size
114319 const uint32_t secSize = SDM.sectorSize ();
115- if (secSize == 0 ) return -1 ; // disk error
320+ if (secSize == 0 || offset != 0 || (bufsize % secSize) != 0 ) return -1 ;
116321
117- // Read blocs
118- for (uint32_t x = 0 ; x < bufsize / secSize ; ++x) {
322+ const uint32_t blocks = bufsize / secSize;
323+ for (uint32_t x = 0 ; x < blocks ; ++x) {
119324 if (!SDM.readRAW (reinterpret_cast <uint8_t *>(buffer) + (x * secSize), lba + x)) {
120325 return -1 ; // read error
121326 }
@@ -124,9 +329,10 @@ int32_t usbReadCallback(uint32_t lba, uint32_t offset, void *buffer, uint32_t bu
124329}
125330
126331bool usbStartStopCallback (uint8_t power_condition, bool start, bool load_eject) {
332+ (void )power_condition;
127333 if (!start && load_eject) {
128334 MassStorage::setShouldStop (true );
129- return false ;
335+ return true ;
130336 }
131337
132338 return true ;
0 commit comments