mass_storage_usb.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. #include "mass_storage_usb.h"
  2. #include <furi_hal.h>
  3. #define TAG "MassStorageUsb"
  4. #define USB_MSC_RX_EP (0x01)
  5. #define USB_MSC_TX_EP (0x82)
  6. #define USB_MSC_RX_EP_SIZE (64UL)
  7. #define USB_MSC_TX_EP_SIZE (64UL)
  8. #define USB_MSC_BOT_GET_MAX_LUN (0xFE)
  9. #define USB_MSC_BOT_RESET (0xFF)
  10. #define CBW_SIG (0x43425355)
  11. #define CBW_FLAGS_DEVICE_TO_HOST (0x80)
  12. #define CSW_SIG (0x53425355)
  13. #define CSW_STATUS_OK (0)
  14. #define CSW_STATUS_NOK (1)
  15. #define CSW_STATUS_PHASE_ERROR (2)
  16. // must be SCSI_BLOCK_SIZE aligned
  17. // larger than 0x10000 exceeds size_t, storage_file_* ops fail
  18. #define USB_MSC_BUF_MAX (0x10000UL - SCSI_BLOCK_SIZE)
  19. static usbd_respond usb_ep_config(usbd_device* dev, uint8_t cfg);
  20. static usbd_respond usb_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback);
  21. typedef enum {
  22. EventExit = 1 << 0,
  23. EventReset = 1 << 1,
  24. EventRxTx = 1 << 2,
  25. EventAll = EventExit | EventReset | EventRxTx,
  26. } MassStorageEvent;
  27. typedef struct {
  28. uint32_t sig;
  29. uint32_t tag;
  30. uint32_t len;
  31. uint8_t flags;
  32. uint8_t lun;
  33. uint8_t cmd_len;
  34. uint8_t cmd[16];
  35. } __attribute__((packed)) CBW;
  36. typedef struct {
  37. uint32_t sig;
  38. uint32_t tag;
  39. uint32_t residue;
  40. uint8_t status;
  41. } __attribute__((packed)) CSW;
  42. struct MassStorageUsb {
  43. FuriHalUsbInterface usb;
  44. FuriHalUsbInterface* usb_prev;
  45. FuriThread* thread;
  46. usbd_device* dev;
  47. SCSIDeviceFunc fn;
  48. };
  49. static int32_t mass_thread_worker(void* context) {
  50. MassStorageUsb* mass = context;
  51. usbd_device* dev = mass->dev;
  52. SCSISession scsi = {
  53. .fn = mass->fn,
  54. };
  55. CBW cbw = {0};
  56. CSW csw = {0};
  57. uint8_t* buf = NULL;
  58. uint32_t buf_len = 0, buf_cap = 0, buf_sent = 0;
  59. enum {
  60. StateReadCBW,
  61. StateReadData,
  62. StateWriteData,
  63. StateBuildCSW,
  64. StateWriteCSW,
  65. } state = StateReadCBW;
  66. while(true) {
  67. uint32_t flags = furi_thread_flags_wait(EventAll, FuriFlagWaitAny, FuriWaitForever);
  68. if(flags & EventExit) {
  69. FURI_LOG_D(TAG, "exit");
  70. break;
  71. }
  72. if(flags & EventReset) {
  73. FURI_LOG_D(TAG, "reset");
  74. scsi.sk = 0;
  75. scsi.asc = 0;
  76. memset(&cbw, 0, sizeof(cbw));
  77. memset(&csw, 0, sizeof(csw));
  78. if(buf) {
  79. free(buf);
  80. buf = NULL;
  81. }
  82. buf_len = buf_cap = buf_sent = 0;
  83. state = StateReadCBW;
  84. }
  85. if(flags & EventRxTx) do {
  86. switch(state) {
  87. case StateReadCBW: {
  88. FURI_LOG_T(TAG, "StateReadCBW");
  89. int32_t len = usbd_ep_read(dev, USB_MSC_RX_EP, &cbw, sizeof(cbw));
  90. if(len <= 0) {
  91. FURI_LOG_T(TAG, "cbw not ready");
  92. break;
  93. }
  94. if(len != sizeof(cbw) || cbw.sig != CBW_SIG) {
  95. FURI_LOG_W(TAG, "bad cbw sig=%08lx", cbw.sig);
  96. usbd_ep_stall(dev, USB_MSC_TX_EP);
  97. usbd_ep_stall(dev, USB_MSC_RX_EP);
  98. continue;
  99. }
  100. if(!scsi_cmd_start(&scsi, cbw.cmd, cbw.cmd_len)) {
  101. FURI_LOG_W(TAG, "bad cmd");
  102. usbd_ep_stall(dev, USB_MSC_RX_EP);
  103. csw.sig = CSW_SIG;
  104. csw.tag = cbw.tag;
  105. csw.status = CSW_STATUS_NOK;
  106. state = StateWriteCSW;
  107. continue;
  108. }
  109. if(cbw.flags & CBW_FLAGS_DEVICE_TO_HOST) {
  110. buf_len = 0;
  111. buf_sent = 0;
  112. state = StateWriteData;
  113. } else {
  114. buf_len = 0;
  115. state = StateReadData;
  116. }
  117. continue;
  118. }; break;
  119. case StateReadData: {
  120. FURI_LOG_T(TAG, "StateReadData %lu/%lu", buf_len, cbw.len);
  121. if(!cbw.len) {
  122. state = StateBuildCSW;
  123. continue;
  124. }
  125. uint32_t buf_clamp = MIN(cbw.len, USB_MSC_BUF_MAX);
  126. if(buf_clamp > buf_cap) {
  127. FURI_LOG_T(TAG, "growing buf %lu -> %lu", buf_cap, buf_clamp);
  128. if(buf) {
  129. free(buf);
  130. }
  131. buf_cap = buf_clamp;
  132. buf = malloc(buf_cap);
  133. }
  134. if(buf_len < buf_clamp) {
  135. int32_t len =
  136. usbd_ep_read(dev, USB_MSC_RX_EP, buf + buf_len, buf_clamp - buf_len);
  137. if(len < 0) {
  138. FURI_LOG_T(TAG, "rx not ready %ld", len);
  139. break;
  140. }
  141. FURI_LOG_T(TAG, "clamp %lu len %ld", buf_clamp, len);
  142. buf_len += len;
  143. }
  144. if(buf_len == buf_clamp) {
  145. if(!scsi_cmd_rx_data(&scsi, buf, buf_len)) {
  146. FURI_LOG_W(TAG, "short rx");
  147. usbd_ep_stall(dev, USB_MSC_RX_EP);
  148. csw.sig = CSW_SIG;
  149. csw.tag = cbw.tag;
  150. csw.status = CSW_STATUS_NOK;
  151. csw.residue = cbw.len;
  152. state = StateWriteCSW;
  153. continue;
  154. }
  155. cbw.len -= buf_len;
  156. buf_len = 0;
  157. }
  158. continue;
  159. }; break;
  160. case StateWriteData: {
  161. FURI_LOG_T(TAG, "StateWriteData %lu", cbw.len);
  162. if(!cbw.len) {
  163. state = StateBuildCSW;
  164. continue;
  165. }
  166. uint32_t buf_clamp = MIN(cbw.len, USB_MSC_BUF_MAX);
  167. if(buf_clamp > buf_cap) {
  168. FURI_LOG_T(TAG, "growing buf %lu -> %lu", buf_cap, buf_clamp);
  169. if(buf) {
  170. free(buf);
  171. }
  172. buf_cap = buf_clamp;
  173. buf = malloc(buf_cap);
  174. }
  175. if(!buf_len && !scsi_cmd_tx_data(&scsi, buf, &buf_len, buf_clamp)) {
  176. FURI_LOG_W(TAG, "short tx");
  177. // usbd_ep_stall(dev, USB_MSC_TX_EP);
  178. state = StateBuildCSW;
  179. continue;
  180. }
  181. int32_t len = usbd_ep_write(
  182. dev,
  183. USB_MSC_TX_EP,
  184. buf + buf_sent,
  185. MIN(USB_MSC_TX_EP_SIZE, buf_len - buf_sent));
  186. if(len < 0) {
  187. FURI_LOG_T(TAG, "tx not ready %ld", len);
  188. break;
  189. }
  190. buf_sent += len;
  191. if(buf_sent == buf_len) {
  192. cbw.len -= buf_len;
  193. buf_len = 0;
  194. buf_sent = 0;
  195. }
  196. continue;
  197. }; break;
  198. case StateBuildCSW: {
  199. FURI_LOG_T(TAG, "StateBuildCSW");
  200. csw.sig = CSW_SIG;
  201. csw.tag = cbw.tag;
  202. if(scsi_cmd_end(&scsi)) {
  203. csw.status = CSW_STATUS_OK;
  204. } else {
  205. csw.status = CSW_STATUS_NOK;
  206. }
  207. csw.residue = cbw.len;
  208. state = StateWriteCSW;
  209. continue;
  210. }; break;
  211. case StateWriteCSW: {
  212. FURI_LOG_T(TAG, "StateWriteCSW");
  213. if(csw.status) {
  214. FURI_LOG_W(
  215. TAG,
  216. "csw sig=%08lx tag=%08lx residue=%08lx status=%02x",
  217. csw.sig,
  218. csw.tag,
  219. csw.residue,
  220. csw.status);
  221. }
  222. int32_t len = usbd_ep_write(dev, USB_MSC_TX_EP, &csw, sizeof(csw));
  223. if(len < 0) {
  224. FURI_LOG_T(TAG, "csw not ready");
  225. break;
  226. }
  227. if(len != sizeof(csw)) {
  228. FURI_LOG_W(TAG, "bad csw write %ld", len);
  229. usbd_ep_stall(dev, USB_MSC_TX_EP);
  230. break;
  231. }
  232. memset(&cbw, 0, sizeof(cbw));
  233. memset(&csw, 0, sizeof(csw));
  234. state = StateReadCBW;
  235. continue;
  236. }; break;
  237. }
  238. break;
  239. } while(true);
  240. }
  241. if(buf) {
  242. free(buf);
  243. }
  244. return 0;
  245. }
  246. // needed in usb_deinit, usb_suspend, usb_rxtx_ep_callback, usb_control,
  247. // where if_ctx isn't passed
  248. static MassStorageUsb* mass_cur = NULL;
  249. static void usb_init(usbd_device* dev, FuriHalUsbInterface* intf, void* ctx) {
  250. UNUSED(intf);
  251. MassStorageUsb* mass = ctx;
  252. mass_cur = mass;
  253. mass->dev = dev;
  254. usbd_reg_config(dev, usb_ep_config);
  255. usbd_reg_control(dev, usb_control);
  256. usbd_connect(dev, true);
  257. mass->thread = furi_thread_alloc();
  258. furi_thread_set_name(mass->thread, "MassStorageUsb");
  259. furi_thread_set_stack_size(mass->thread, 1024);
  260. furi_thread_set_context(mass->thread, ctx);
  261. furi_thread_set_callback(mass->thread, mass_thread_worker);
  262. furi_thread_start(mass->thread);
  263. }
  264. static void usb_deinit(usbd_device* dev) {
  265. usbd_reg_config(dev, NULL);
  266. usbd_reg_control(dev, NULL);
  267. MassStorageUsb* mass = mass_cur;
  268. if(!mass || mass->dev != dev) {
  269. FURI_LOG_E(TAG, "deinit mass_cur leak");
  270. return;
  271. }
  272. mass_cur = NULL;
  273. furi_assert(mass->thread);
  274. furi_thread_flags_set(furi_thread_get_id(mass->thread), EventExit);
  275. furi_thread_join(mass->thread);
  276. furi_thread_free(mass->thread);
  277. mass->thread = NULL;
  278. free(mass->usb.str_prod_descr);
  279. mass->usb.str_prod_descr = NULL;
  280. free(mass->usb.str_serial_descr);
  281. mass->usb.str_serial_descr = NULL;
  282. free(mass);
  283. }
  284. static void usb_wakeup(usbd_device* dev) {
  285. UNUSED(dev);
  286. }
  287. static void usb_suspend(usbd_device* dev) {
  288. MassStorageUsb* mass = mass_cur;
  289. if(!mass || mass->dev != dev) return;
  290. furi_thread_flags_set(furi_thread_get_id(mass->thread), EventReset);
  291. }
  292. static void usb_rxtx_ep_callback(usbd_device* dev, uint8_t event, uint8_t ep) {
  293. UNUSED(ep);
  294. UNUSED(event);
  295. MassStorageUsb* mass = mass_cur;
  296. if(!mass || mass->dev != dev) return;
  297. furi_thread_flags_set(furi_thread_get_id(mass->thread), EventRxTx);
  298. }
  299. static usbd_respond usb_ep_config(usbd_device* dev, uint8_t cfg) {
  300. switch(cfg) {
  301. case 0: // deconfig
  302. usbd_ep_deconfig(dev, USB_MSC_RX_EP);
  303. usbd_ep_deconfig(dev, USB_MSC_TX_EP);
  304. usbd_reg_endpoint(dev, USB_MSC_RX_EP, NULL);
  305. usbd_reg_endpoint(dev, USB_MSC_TX_EP, NULL);
  306. return usbd_ack;
  307. case 1: // config
  308. usbd_ep_config(
  309. dev, USB_MSC_RX_EP, USB_EPTYPE_BULK /* | USB_EPTYPE_DBLBUF*/, USB_MSC_RX_EP_SIZE);
  310. usbd_ep_config(
  311. dev, USB_MSC_TX_EP, USB_EPTYPE_BULK /* | USB_EPTYPE_DBLBUF*/, USB_MSC_TX_EP_SIZE);
  312. usbd_reg_endpoint(dev, USB_MSC_RX_EP, usb_rxtx_ep_callback);
  313. usbd_reg_endpoint(dev, USB_MSC_TX_EP, usb_rxtx_ep_callback);
  314. return usbd_ack;
  315. }
  316. return usbd_fail;
  317. }
  318. static usbd_respond usb_control(usbd_device* dev, usbd_ctlreq* req, usbd_rqc_callback* callback) {
  319. UNUSED(callback);
  320. if(((USB_REQ_RECIPIENT | USB_REQ_TYPE) & req->bmRequestType) !=
  321. (USB_REQ_INTERFACE | USB_REQ_CLASS)) {
  322. return usbd_fail;
  323. }
  324. switch(req->bRequest) {
  325. case USB_MSC_BOT_GET_MAX_LUN: {
  326. static uint8_t max_lun = 0;
  327. dev->status.data_ptr = &max_lun;
  328. dev->status.data_count = 1;
  329. return usbd_ack;
  330. }; break;
  331. case USB_MSC_BOT_RESET: {
  332. MassStorageUsb* mass = mass_cur;
  333. if(!mass || mass->dev != dev) return usbd_fail;
  334. furi_thread_flags_set(furi_thread_get_id(mass->thread), EventReset);
  335. return usbd_ack;
  336. }; break;
  337. }
  338. return usbd_fail;
  339. }
  340. static const struct usb_string_descriptor dev_manuf_desc = USB_STRING_DESC("Flipper Devices Inc.");
  341. struct MassStorageDescriptor {
  342. struct usb_config_descriptor config;
  343. struct usb_interface_descriptor intf;
  344. struct usb_endpoint_descriptor ep_rx;
  345. struct usb_endpoint_descriptor ep_tx;
  346. } __attribute__((packed));
  347. static const struct usb_device_descriptor usb_mass_dev_descr = {
  348. .bLength = sizeof(struct usb_device_descriptor),
  349. .bDescriptorType = USB_DTYPE_DEVICE,
  350. .bcdUSB = VERSION_BCD(2, 0, 0),
  351. .bDeviceClass = USB_CLASS_PER_INTERFACE,
  352. .bDeviceSubClass = USB_SUBCLASS_NONE,
  353. .bDeviceProtocol = USB_PROTO_NONE,
  354. .bMaxPacketSize0 = 8, // USB_EP0_SIZE
  355. .idVendor = 0x0483,
  356. .idProduct = 0x5720,
  357. .bcdDevice = VERSION_BCD(1, 0, 0),
  358. .iManufacturer = 1, // UsbDevManuf
  359. .iProduct = 2, // UsbDevProduct
  360. .iSerialNumber = 3, // UsbDevSerial
  361. .bNumConfigurations = 1,
  362. };
  363. static const struct MassStorageDescriptor usb_mass_cfg_descr = {
  364. .config =
  365. {
  366. .bLength = sizeof(struct usb_config_descriptor),
  367. .bDescriptorType = USB_DTYPE_CONFIGURATION,
  368. .wTotalLength = sizeof(struct MassStorageDescriptor),
  369. .bNumInterfaces = 1,
  370. .bConfigurationValue = 1,
  371. .iConfiguration = NO_DESCRIPTOR,
  372. .bmAttributes = USB_CFG_ATTR_RESERVED | USB_CFG_ATTR_SELFPOWERED,
  373. .bMaxPower = USB_CFG_POWER_MA(100),
  374. },
  375. .intf =
  376. {
  377. .bLength = sizeof(struct usb_interface_descriptor),
  378. .bDescriptorType = USB_DTYPE_INTERFACE,
  379. .bInterfaceNumber = 0,
  380. .bAlternateSetting = 0,
  381. .bNumEndpoints = 2,
  382. .bInterfaceClass = USB_CLASS_MASS_STORAGE,
  383. .bInterfaceSubClass = 0x06, // scsi transparent
  384. .bInterfaceProtocol = 0x50, // bulk only
  385. .iInterface = NO_DESCRIPTOR,
  386. },
  387. .ep_rx =
  388. {
  389. .bLength = sizeof(struct usb_endpoint_descriptor),
  390. .bDescriptorType = USB_DTYPE_ENDPOINT,
  391. .bEndpointAddress = USB_MSC_RX_EP,
  392. .bmAttributes = USB_EPTYPE_BULK,
  393. .wMaxPacketSize = USB_MSC_RX_EP_SIZE,
  394. .bInterval = 0,
  395. },
  396. .ep_tx =
  397. {
  398. .bLength = sizeof(struct usb_endpoint_descriptor),
  399. .bDescriptorType = USB_DTYPE_ENDPOINT,
  400. .bEndpointAddress = USB_MSC_TX_EP,
  401. .bmAttributes = USB_EPTYPE_BULK,
  402. .wMaxPacketSize = USB_MSC_TX_EP_SIZE,
  403. .bInterval = 0,
  404. },
  405. };
  406. MassStorageUsb* mass_storage_usb_start(const char* filename, SCSIDeviceFunc fn) {
  407. MassStorageUsb* mass = malloc(sizeof(MassStorageUsb));
  408. mass->usb_prev = furi_hal_usb_get_config();
  409. mass->usb.init = usb_init;
  410. mass->usb.deinit = usb_deinit;
  411. mass->usb.wakeup = usb_wakeup;
  412. mass->usb.suspend = usb_suspend;
  413. mass->usb.dev_descr = (struct usb_device_descriptor*)&usb_mass_dev_descr;
  414. mass->usb.str_manuf_descr = (void*)&dev_manuf_desc;
  415. mass->usb.str_prod_descr = NULL;
  416. mass->usb.str_serial_descr = NULL;
  417. mass->usb.cfg_descr = (void*)&usb_mass_cfg_descr;
  418. const char* name = furi_hal_version_get_device_name_ptr();
  419. if(!name) name = "Flipper Zero";
  420. size_t len = strlen(name);
  421. struct usb_string_descriptor* str_prod_descr = malloc(len * 2 + 2);
  422. str_prod_descr->bLength = len * 2 + 2;
  423. str_prod_descr->bDescriptorType = USB_DTYPE_STRING;
  424. for(uint8_t i = 0; i < len; i++)
  425. str_prod_descr->wString[i] = name[i];
  426. mass->usb.str_prod_descr = str_prod_descr;
  427. len = strlen(filename);
  428. struct usb_string_descriptor* str_serial_descr = malloc(len * 2 + 2);
  429. str_serial_descr->bLength = len * 2 + 2;
  430. str_serial_descr->bDescriptorType = USB_DTYPE_STRING;
  431. for(uint8_t i = 0; i < len; i++)
  432. str_serial_descr->wString[i] = filename[i];
  433. mass->usb.str_serial_descr = str_serial_descr;
  434. mass->fn = fn;
  435. if(!furi_hal_usb_set_config(&mass->usb, mass)) {
  436. FURI_LOG_E(TAG, "USB locked, cannot start Mass Storage");
  437. free(mass->usb.str_prod_descr);
  438. free(mass->usb.str_serial_descr);
  439. free(mass);
  440. return NULL;
  441. }
  442. return mass;
  443. }
  444. void mass_storage_usb_stop(MassStorageUsb* mass) {
  445. furi_hal_usb_set_config(mass->usb_prev, NULL);
  446. }