1 /*
2  * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <stdbool.h>
8 #include <stdint.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/queue.h>
13 #include <sys/param.h>
14 #include "esp_log.h"
15 #include "freertos/FreeRTOS.h"
16 #include "freertos/task.h"
17 #include "freertos/semphr.h"
18 #include "usb/usb_host.h"
19 #include "diskio_usb.h"
20 #include "msc_common.h"
21 #include "msc_host.h"
22 #include "msc_scsi_bot.h"
23 #include "usb/usb_types_ch9.h"
24 #include "usb/usb_helpers.h"
25 
26 static portMUX_TYPE msc_lock = portMUX_INITIALIZER_UNLOCKED;
27 
28 #define MSC_ENTER_CRITICAL()    portENTER_CRITICAL(&msc_lock)
29 #define MSC_EXIT_CRITICAL()     portEXIT_CRITICAL(&msc_lock)
30 
31 #define MSC_GOTO_ON_FALSE_CRITICAL(exp, err)    \
32     do {                                        \
33         if(!(exp)) {                            \
34             MSC_EXIT_CRITICAL();                \
35             ret = err;                          \
36             goto fail;                          \
37         }                                       \
38     } while(0)
39 
40 #define MSC_RETURN_ON_FALSE_CRITICAL(exp, err)  \
41     do {                                        \
42         if(!(exp)) {                            \
43             MSC_EXIT_CRITICAL();                \
44             return err;                         \
45         }                                       \
46     } while(0)
47 
48 #define WAIT_FOR_READY_TIMEOUT_MS 3000
49 #define TAG "USB_MSC"
50 
51 #define SCSI_COMMAND_SET    0x06
52 #define BULK_ONLY_TRANSFER  0x50
53 #define MSC_NO_SENSE        0x00
54 #define MSC_NOT_READY       0x02
55 #define MSC_UNIT_ATTENTION  0x06
56 
57 typedef struct {
58     usb_host_client_handle_t client_handle;
59     msc_host_event_cb_t user_cb;
60     void *user_arg;
61     SemaphoreHandle_t all_events_handled;
62     volatile bool end_client_event_handling;
63 } msc_driver_t;
64 
65 static msc_driver_t *s_msc_driver;
66 
67 STAILQ_HEAD(devices, msc_host_device) devices_tailq;
68 
next_interface_desc(const usb_standard_desc_t * desc,size_t len,size_t * offset)69 static const usb_standard_desc_t *next_interface_desc(const usb_standard_desc_t *desc, size_t len, size_t *offset)
70 {
71     return usb_parse_next_descriptor_of_type(desc, len, USB_W_VALUE_DT_INTERFACE, (int *)offset);
72 }
73 
next_endpoint_desc(const usb_standard_desc_t * desc,size_t len,size_t * offset)74 static const usb_standard_desc_t *next_endpoint_desc(const usb_standard_desc_t *desc, size_t len, size_t *offset)
75 {
76     return usb_parse_next_descriptor_of_type(desc, len, USB_B_DESCRIPTOR_TYPE_ENDPOINT, (int *)offset);
77 }
78 
find_msc_interface(const usb_config_desc_t * config_desc,size_t * offset)79 static const usb_intf_desc_t *find_msc_interface(const usb_config_desc_t *config_desc, size_t *offset)
80 {
81     size_t total_length = config_desc->wTotalLength;
82     const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)config_desc;
83 
84     next_desc = next_interface_desc(next_desc, total_length, offset);
85 
86     while ( next_desc ) {
87 
88         const usb_intf_desc_t *ifc_desc = (const usb_intf_desc_t *)next_desc;
89 
90         if ( ifc_desc->bInterfaceClass == USB_CLASS_MASS_STORAGE &&
91                 ifc_desc->bInterfaceSubClass == SCSI_COMMAND_SET &&
92                 ifc_desc->bInterfaceProtocol == BULK_ONLY_TRANSFER ) {
93             return ifc_desc;
94         }
95 
96         next_desc = next_interface_desc(next_desc, total_length, offset);
97     };
98     return NULL;
99 }
100 
101 /**
102  * @brief Extracts configuration from configuration descriptor.
103  *
104  * @note  Passes interface and endpoint descriptors to obtain:
105 
106  *        - interface number, IN endpoint, OUT endpoint, max. packet size
107  *
108  * @param[in]  cfg_desc  Configuration descriptor
109  * @param[out] cfg       Obtained configuration
110  * @return esp_err_t
111  */
extract_config_from_descriptor(const usb_config_desc_t * cfg_desc,msc_config_t * cfg)112 static esp_err_t extract_config_from_descriptor(const usb_config_desc_t *cfg_desc, msc_config_t *cfg)
113 {
114     size_t offset = 0;
115     size_t total_len = cfg_desc->wTotalLength;
116     const usb_intf_desc_t *ifc_desc = find_msc_interface(cfg_desc, &offset);
117     assert(ifc_desc);
118     const usb_standard_desc_t *next_desc = (const usb_standard_desc_t *)ifc_desc;
119     const usb_ep_desc_t *ep_desc = NULL;
120 
121     cfg->iface_num = ifc_desc->bInterfaceNumber;
122 
123     next_desc = next_endpoint_desc(next_desc, total_len, &offset);
124     MSC_RETURN_ON_FALSE(next_desc, ESP_ERR_NOT_SUPPORTED);
125     ep_desc = (const usb_ep_desc_t *)next_desc;
126 
127     if (ep_desc->bEndpointAddress & 0x80) {
128         cfg->bulk_in_ep = ep_desc->bEndpointAddress;
129         cfg->bulk_in_mps = ep_desc->wMaxPacketSize;
130     } else {
131         cfg->bulk_out_ep = ep_desc->bEndpointAddress;
132     }
133 
134     next_desc = next_endpoint_desc(next_desc, total_len, &offset);
135     MSC_RETURN_ON_FALSE(next_desc, ESP_ERR_NOT_SUPPORTED);
136     ep_desc = (const usb_ep_desc_t *)next_desc;
137 
138     if (ep_desc->bEndpointAddress & 0x80) {
139         cfg->bulk_in_ep = ep_desc->bEndpointAddress;
140         cfg->bulk_in_mps = ep_desc->wMaxPacketSize;
141     } else {
142         cfg->bulk_out_ep = ep_desc->bEndpointAddress;
143     }
144 
145     return ESP_OK;
146 }
147 
msc_deinit_device(msc_device_t * dev,bool install_failed)148 static esp_err_t msc_deinit_device(msc_device_t *dev, bool install_failed)
149 {
150     MSC_ENTER_CRITICAL();
151     MSC_RETURN_ON_FALSE_CRITICAL( dev, ESP_ERR_INVALID_STATE );
152     STAILQ_REMOVE(&devices_tailq, dev, msc_host_device, tailq_entry);
153     MSC_EXIT_CRITICAL();
154 
155     if (dev->transfer_done) {
156         vSemaphoreDelete(dev->transfer_done);
157     }
158     if (install_failed) {
159         // Error code is unchecked, as it's unknown at what point installation failed.
160         usb_host_interface_release(s_msc_driver->client_handle, dev->handle, dev->config.iface_num);
161         usb_host_device_close(s_msc_driver->client_handle, dev->handle);
162         usb_host_transfer_free(dev->xfer);
163     } else {
164         MSC_RETURN_ON_ERROR( usb_host_interface_release(s_msc_driver->client_handle, dev->handle, dev->config.iface_num) );
165         MSC_RETURN_ON_ERROR( usb_host_device_close(s_msc_driver->client_handle, dev->handle) );
166         MSC_RETURN_ON_ERROR( usb_host_transfer_free(dev->xfer) );
167     }
168 
169     free(dev);
170     return ESP_OK;
171 }
172 
173 // Some MSC devices requires to change its internal state from non-ready to ready
msc_wait_for_ready_state(msc_device_t * dev,size_t timeout_ms)174 static esp_err_t msc_wait_for_ready_state(msc_device_t *dev, size_t timeout_ms)
175 {
176     esp_err_t err;
177     scsi_sense_data_t sense;
178     uint32_t trials = MAX(1, timeout_ms / 100);
179 
180     do {
181         err = scsi_cmd_unit_ready(dev);
182         if (err != ESP_OK) {
183             MSC_RETURN_ON_ERROR( scsi_cmd_sense(dev, &sense) );
184             if (sense.key != MSC_NOT_READY &&
185                     sense.key != MSC_UNIT_ATTENTION &&
186                     sense.key != MSC_NO_SENSE) {
187                 return ESP_ERR_MSC_INTERNAL;
188             }
189         }
190         vTaskDelay( pdMS_TO_TICKS(100) );
191     } while (trials-- && err);
192 
193     return err;
194 }
195 
is_mass_storage_device(uint8_t dev_addr)196 static bool is_mass_storage_device(uint8_t dev_addr)
197 {
198     size_t dummy = 0;
199     bool is_msc_device = false;
200     usb_device_handle_t device;
201     const usb_config_desc_t *config_desc;
202 
203     if ( usb_host_device_open(s_msc_driver->client_handle, dev_addr, &device) == ESP_OK) {
204         if ( usb_host_get_active_config_descriptor(device, &config_desc) == ESP_OK ) {
205             if ( find_msc_interface(config_desc, &dummy) ) {
206                 is_msc_device = true;
207             } else {
208                 ESP_LOGD(TAG, "Connected USB device is not MSC");
209             }
210         }
211         usb_host_device_close(s_msc_driver->client_handle, device);
212     }
213 
214     return is_msc_device;
215 }
216 
event_handler_task(void * arg)217 static void event_handler_task(void *arg)
218 {
219     while (1) {
220         usb_host_client_handle_events(s_msc_driver->client_handle, pdMS_TO_TICKS(50));
221 
222         if (s_msc_driver->end_client_event_handling) {
223             break;
224         }
225     }
226     usb_host_client_unblock(s_msc_driver->client_handle);
227     ESP_ERROR_CHECK( usb_host_client_deregister(s_msc_driver->client_handle) );
228     xSemaphoreGive(s_msc_driver->all_events_handled);
229     vTaskDelete(NULL);
230 }
231 
find_msc_device(usb_device_handle_t device_handle)232 static msc_device_t *find_msc_device(usb_device_handle_t device_handle)
233 {
234     msc_host_device_handle_t device;
235 
236     STAILQ_FOREACH(device, &devices_tailq, tailq_entry) {
237         if (device_handle == device->handle) {
238             return device;
239         }
240     }
241 
242     return NULL;
243 }
244 
client_event_cb(const usb_host_client_event_msg_t * event,void * arg)245 static void client_event_cb(const usb_host_client_event_msg_t *event, void *arg)
246 {
247     if (event->event == USB_HOST_CLIENT_EVENT_NEW_DEV) {
248         if (is_mass_storage_device(event->new_dev.address)) {
249             const msc_host_event_t msc_event = {
250                 .event = MSC_DEVICE_CONNECTED,
251                 .device.address = event->new_dev.address,
252             };
253             s_msc_driver->user_cb(&msc_event, s_msc_driver->user_arg);
254         }
255     } else if (event->event == USB_HOST_CLIENT_EVENT_DEV_GONE) {
256         msc_device_t *msc_device = find_msc_device(event->dev_gone.dev_hdl);
257         if (msc_device) {
258             const msc_host_event_t msc_event = {
259                 .event = MSC_DEVICE_DISCONNECTED,
260                 .device.handle = msc_device,
261             };
262             s_msc_driver->user_cb(&msc_event, s_msc_driver->user_arg);
263         }
264     }
265 }
266 
msc_host_install(const msc_host_driver_config_t * config)267 esp_err_t msc_host_install(const msc_host_driver_config_t *config)
268 {
269     esp_err_t ret;
270 
271     MSC_RETURN_ON_INVALID_ARG(config);
272     MSC_RETURN_ON_INVALID_ARG(config->callback);
273     if ( config->create_backround_task ) {
274         MSC_RETURN_ON_FALSE(config->stack_size != 0, ESP_ERR_INVALID_ARG);
275         MSC_RETURN_ON_FALSE(config->task_priority != 0, ESP_ERR_INVALID_ARG);
276     }
277     MSC_RETURN_ON_FALSE(!s_msc_driver, ESP_ERR_INVALID_STATE);
278 
279     msc_driver_t *driver = calloc(1, sizeof(msc_driver_t));
280     MSC_RETURN_ON_FALSE(driver, ESP_ERR_NO_MEM);
281     driver->user_cb = config->callback;
282     driver->user_arg = config->callback_arg;
283 
284     usb_host_client_config_t client_config = {
285         .async.client_event_callback = client_event_cb,
286         .async.callback_arg = NULL,
287         .max_num_event_msg = 10,
288     };
289 
290     driver->end_client_event_handling = false;
291     driver->all_events_handled = xSemaphoreCreateBinary();
292     MSC_GOTO_ON_FALSE(driver->all_events_handled, ESP_ERR_NO_MEM);
293 
294     MSC_GOTO_ON_ERROR( usb_host_client_register(&client_config, &driver->client_handle) );
295 
296     MSC_ENTER_CRITICAL();
297     MSC_GOTO_ON_FALSE_CRITICAL(!s_msc_driver, ESP_ERR_INVALID_STATE);
298     s_msc_driver = driver;
299     STAILQ_INIT(&devices_tailq);
300     MSC_EXIT_CRITICAL();
301 
302     if (config->create_backround_task) {
303         BaseType_t task_created = xTaskCreatePinnedToCore(
304             event_handler_task, "USB MSC", config->stack_size,
305             NULL, config->task_priority, NULL, config->core_id);
306         MSC_GOTO_ON_FALSE(task_created, ESP_ERR_NO_MEM);
307     }
308 
309     return ESP_OK;
310 
311 fail:
312     s_msc_driver = NULL;
313     usb_host_client_deregister(driver->client_handle);
314     if (driver->all_events_handled) {
315         vSemaphoreDelete(driver->all_events_handled);
316     }
317     free(driver);
318     return ret;
319 }
320 
msc_host_uninstall(void)321 esp_err_t msc_host_uninstall(void)
322 {
323     // Make sure msc driver is installed,
324     // not being uninstalled from other task
325     // and no msc device is registered
326     MSC_ENTER_CRITICAL();
327     MSC_RETURN_ON_FALSE_CRITICAL( s_msc_driver != NULL, ESP_ERR_INVALID_STATE );
328     MSC_RETURN_ON_FALSE_CRITICAL( !s_msc_driver->end_client_event_handling, ESP_ERR_INVALID_STATE );
329     MSC_RETURN_ON_FALSE_CRITICAL( STAILQ_EMPTY(&devices_tailq), ESP_ERR_INVALID_STATE );
330     s_msc_driver->end_client_event_handling = true;
331     MSC_EXIT_CRITICAL();
332 
333     xSemaphoreTake(s_msc_driver->all_events_handled, portMAX_DELAY);
334     vSemaphoreDelete(s_msc_driver->all_events_handled);
335     free(s_msc_driver);
336     s_msc_driver = NULL;
337     return ESP_OK;
338 }
339 
msc_host_install_device(uint8_t device_address,msc_host_device_handle_t * msc_device_handle)340 esp_err_t msc_host_install_device(uint8_t device_address, msc_host_device_handle_t *msc_device_handle)
341 {
342     esp_err_t ret;
343     uint32_t block_size, block_count;
344     const usb_config_desc_t *config_desc;
345     msc_device_t *msc_device;
346     uint8_t lun;
347     size_t transfer_size = 512; // Normally the smallest block size
348 
349     MSC_GOTO_ON_FALSE( msc_device = calloc(1, sizeof(msc_device_t)), ESP_ERR_NO_MEM );
350 
351     MSC_ENTER_CRITICAL();
352     MSC_GOTO_ON_FALSE_CRITICAL( s_msc_driver, ESP_ERR_INVALID_STATE );
353     MSC_GOTO_ON_FALSE_CRITICAL( s_msc_driver->client_handle, ESP_ERR_INVALID_STATE );
354     STAILQ_INSERT_TAIL(&devices_tailq, msc_device, tailq_entry);
355     MSC_EXIT_CRITICAL();
356 
357     MSC_GOTO_ON_FALSE( msc_device->transfer_done = xSemaphoreCreateBinary(), ESP_ERR_NO_MEM);
358     MSC_GOTO_ON_ERROR( usb_host_device_open(s_msc_driver->client_handle, device_address, &msc_device->handle) );
359     MSC_GOTO_ON_ERROR( usb_host_get_active_config_descriptor(msc_device->handle, &config_desc) );
360     MSC_GOTO_ON_ERROR( extract_config_from_descriptor(config_desc, &msc_device->config) );
361     MSC_GOTO_ON_ERROR( usb_host_transfer_alloc(transfer_size, 0, &msc_device->xfer) );
362     MSC_GOTO_ON_ERROR( usb_host_interface_claim(s_msc_driver->client_handle,
363                                                 msc_device->handle,
364                                                 msc_device->config.iface_num, 0) );
365 
366     MSC_GOTO_ON_ERROR( msc_get_max_lun(msc_device, &lun) );
367     MSC_GOTO_ON_ERROR( scsi_cmd_inquiry(msc_device) );
368     MSC_GOTO_ON_ERROR( msc_wait_for_ready_state(msc_device, WAIT_FOR_READY_TIMEOUT_MS) );
369     MSC_GOTO_ON_ERROR( scsi_cmd_read_capacity(msc_device, &block_size, &block_count) );
370 
371     // Configuration descriptor size of simple MSC device is 32 bytes.
372     if (config_desc->wTotalLength != 32) {
373         ESP_LOGE(TAG, "COMPOSITE DEVICES UNSUPPORTED");
374     }
375 
376     msc_device->disk.block_size = block_size;
377     msc_device->disk.block_count = block_count;
378 
379     if (block_size > transfer_size) {
380         usb_transfer_t *larger_xfer;
381         MSC_GOTO_ON_ERROR( usb_host_transfer_alloc(block_size, 0, &larger_xfer) );
382         usb_host_transfer_free(msc_device->xfer);
383         msc_device->xfer = larger_xfer;
384     }
385 
386     *msc_device_handle = msc_device;
387 
388     return ESP_OK;
389 
390 fail:
391     msc_deinit_device(msc_device, true);
392     return ret;
393 }
394 
msc_host_uninstall_device(msc_host_device_handle_t device)395 esp_err_t msc_host_uninstall_device(msc_host_device_handle_t device)
396 {
397     MSC_RETURN_ON_INVALID_ARG(device);
398     return msc_deinit_device((msc_device_t *)device, false);
399 }
400 
401 
msc_host_read_sector(msc_host_device_handle_t device,size_t sector,void * data,size_t size)402 esp_err_t msc_host_read_sector(msc_host_device_handle_t device, size_t sector, void *data, size_t size)
403 {
404     MSC_RETURN_ON_INVALID_ARG(device);
405     msc_device_t *dev = (msc_device_t *)device;
406 
407     return scsi_cmd_read10(dev, data, sector, 1, dev->disk.block_size);
408 }
409 
msc_host_write_sector(msc_host_device_handle_t device,size_t sector,const void * data,size_t size)410 esp_err_t msc_host_write_sector(msc_host_device_handle_t device, size_t sector, const void *data, size_t size)
411 {
412     MSC_RETURN_ON_INVALID_ARG(device);
413     msc_device_t *dev = (msc_device_t *)device;
414 
415     return scsi_cmd_write10(dev, data, sector, 1, dev->disk.block_size);
416 }
417 
msc_host_handle_events(uint32_t timeout_ms)418 esp_err_t msc_host_handle_events(uint32_t timeout_ms)
419 {
420     MSC_RETURN_ON_FALSE(s_msc_driver != NULL, ESP_ERR_INVALID_STATE);
421 
422     return usb_host_client_handle_events(s_msc_driver->client_handle, timeout_ms);
423 }
424 
msc_read_string_desc(msc_device_t * dev,uint8_t index,wchar_t * str)425 static esp_err_t msc_read_string_desc(msc_device_t *dev, uint8_t index, wchar_t *str)
426 {
427     if (index == 0) {
428         // String descriptor not available
429         str[0] = 0;
430         return ESP_OK;
431     }
432 
433     usb_transfer_t *xfer = dev->xfer;
434     USB_SETUP_PACKET_INIT_GET_STR_DESC((usb_setup_packet_t *)xfer->data_buffer, index, 0x409, 64);
435     MSC_RETURN_ON_ERROR( msc_control_transfer(dev, xfer, USB_SETUP_PACKET_SIZE + 64) );
436 
437     usb_standard_desc_t *desc = (usb_standard_desc_t *)(xfer->data_buffer + USB_SETUP_PACKET_SIZE);
438     wchar_t *data = (wchar_t *)(xfer->data_buffer + USB_SETUP_PACKET_SIZE + 2);
439     size_t len = MIN((desc->bLength - USB_STANDARD_DESC_SIZE) / 2, MSC_STR_DESC_SIZE - 1);
440 
441     wcsncpy(str, data, len);
442     str[len] = 0;
443 
444     return ESP_OK;
445 }
446 
msc_host_get_device_info(msc_host_device_handle_t device,msc_host_device_info_t * info)447 esp_err_t msc_host_get_device_info(msc_host_device_handle_t device, msc_host_device_info_t *info)
448 {
449     MSC_RETURN_ON_INVALID_ARG(device);
450     MSC_RETURN_ON_INVALID_ARG(info);
451 
452     msc_device_t *dev = (msc_device_t *)device;
453     const usb_device_desc_t *desc;
454 
455     MSC_RETURN_ON_ERROR( usb_host_get_device_descriptor(dev->handle, &desc) );
456 
457     info->idProduct = desc->idProduct;
458     info->idVendor = desc->idVendor;
459     info->sector_size = dev->disk.block_size;
460     info->sector_count = dev->disk.block_count;
461 
462     MSC_RETURN_ON_ERROR( msc_read_string_desc(dev, desc->iManufacturer, info->iManufacturer) );
463     MSC_RETURN_ON_ERROR( msc_read_string_desc(dev, desc->iProduct, info->iProduct) );
464     MSC_RETURN_ON_ERROR( msc_read_string_desc(dev, desc->iSerialNumber, info->iSerialNumber) );
465 
466     return ESP_OK;
467 }
468 
msc_host_print_descriptors(msc_host_device_handle_t device)469 esp_err_t msc_host_print_descriptors(msc_host_device_handle_t device)
470 {
471     msc_device_t *dev = (msc_device_t *)device;
472     const usb_device_desc_t *device_desc;
473     const usb_config_desc_t *config_desc;
474     MSC_RETURN_ON_ERROR( usb_host_get_device_descriptor(dev->handle, &device_desc) );
475     MSC_RETURN_ON_ERROR( usb_host_get_active_config_descriptor(dev->handle, &config_desc) );
476     usb_print_device_descriptor(device_desc);
477     usb_print_config_descriptor(config_desc, NULL);
478     return ESP_OK;
479 }
480 
transfer_callback(usb_transfer_t * transfer)481 static void transfer_callback(usb_transfer_t *transfer)
482 {
483     msc_device_t *device = (msc_device_t *)transfer->context;
484 
485     if (transfer->status != USB_TRANSFER_STATUS_COMPLETED) {
486         ESP_LOGE("Transfer failed", "Status %d", transfer->status);
487     }
488 
489     device->transfer_status = transfer->status;
490     xSemaphoreGive(device->transfer_done);
491 }
492 
wait_for_transfer_done(usb_transfer_t * xfer)493 static esp_err_t wait_for_transfer_done(usb_transfer_t *xfer)
494 {
495     msc_device_t *device = (msc_device_t *)xfer->context;
496     BaseType_t received = xSemaphoreTake(device->transfer_done, pdMS_TO_TICKS(xfer->timeout_ms));
497 
498     if (received != pdTRUE) {
499         usb_host_endpoint_halt(xfer->device_handle, xfer->bEndpointAddress);
500         usb_host_endpoint_flush(xfer->device_handle, xfer->bEndpointAddress);
501         xSemaphoreTake(device->transfer_done, portMAX_DELAY);
502         return ESP_ERR_TIMEOUT;
503     }
504 
505     return (device->transfer_status == USB_TRANSFER_STATUS_COMPLETED) ? ESP_OK : ESP_FAIL;
506 }
507 
is_in_endpoint(uint8_t endpoint)508 static inline bool is_in_endpoint(uint8_t endpoint)
509 {
510     return endpoint & USB_B_ENDPOINT_ADDRESS_EP_DIR_MASK ? true : false;
511 }
512 
msc_bulk_transfer(msc_device_t * device,uint8_t * data,size_t size,msc_endpoint_t ep)513 esp_err_t msc_bulk_transfer(msc_device_t *device, uint8_t *data, size_t size, msc_endpoint_t ep)
514 {
515     usb_transfer_t *xfer = device->xfer;
516     MSC_RETURN_ON_FALSE(size <= xfer->data_buffer_size, ESP_ERR_INVALID_SIZE);
517     uint8_t endpoint = (ep == MSC_EP_IN) ? device->config.bulk_in_ep : device->config.bulk_out_ep;
518 
519     if (is_in_endpoint(endpoint)) {
520         xfer->num_bytes = usb_round_up_to_mps(size, device->config.bulk_in_mps);
521     } else {
522         memcpy(xfer->data_buffer, data, size);
523         xfer->num_bytes = size;
524     }
525 
526     xfer->device_handle = device->handle;
527     xfer->bEndpointAddress = endpoint;
528     xfer->callback = transfer_callback;
529     xfer->timeout_ms = 1000;
530     xfer->context = device;
531 
532     MSC_RETURN_ON_ERROR( usb_host_transfer_submit(xfer) );
533     MSC_RETURN_ON_ERROR( wait_for_transfer_done(xfer) );
534 
535     if (is_in_endpoint(endpoint)) {
536         memcpy(data, xfer->data_buffer, size);
537     }
538 
539     return ESP_OK;
540 }
541 
msc_control_transfer(msc_device_t * device,usb_transfer_t * xfer,size_t len)542 esp_err_t msc_control_transfer(msc_device_t *device, usb_transfer_t *xfer, size_t len)
543 {
544     xfer->device_handle = device->handle;
545     xfer->bEndpointAddress = 0;
546     xfer->callback = transfer_callback;
547     xfer->timeout_ms = 1000;
548     xfer->num_bytes = len;
549     xfer->context = device;
550 
551     MSC_RETURN_ON_ERROR( usb_host_transfer_submit_control(s_msc_driver->client_handle, xfer));
552     return wait_for_transfer_done(xfer);
553 }
554