mass.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. /*
  2. * File : mass.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2011, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://www.rt-thread.org/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2011-12-12 Yi Qiu first version
  13. */
  14. #include <rtthread.h>
  15. #include <drivers/usb_host.h>
  16. #include "mass.h"
  17. #ifdef RT_USBH_MSTORAGE
  18. extern rt_err_t rt_udisk_run(struct uintf* intf);
  19. extern rt_err_t rt_udisk_stop(struct uintf* intf);
  20. static struct uclass_driver storage_driver;
  21. /**
  22. * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
  23. *
  24. * @param intf the interface instance.
  25. * @param max_lun the buffer to save max_lun.
  26. *
  27. * @return the error code, RT_EOK on successfully.
  28. */
  29. static rt_err_t _pipe_check(struct uintf* intf, upipe_t pipe)
  30. {
  31. struct uinstance* device;
  32. rt_err_t ret;
  33. ustor_t stor;
  34. int size = 0;
  35. struct ustorage_csw csw;
  36. if(intf == RT_NULL || pipe == RT_NULL)
  37. {
  38. rt_kprintf("the interface is not available\n");
  39. return -RT_EIO;
  40. }
  41. /* get usb device instance from the interface instance */
  42. device = intf->device;
  43. /* get storage instance from the interface instance */
  44. stor = (ustor_t)intf->user_data;
  45. /* check pipe status */
  46. if(pipe->status == UPIPE_STATUS_OK) return RT_EOK;
  47. if(pipe->status == UPIPE_STATUS_ERROR)
  48. {
  49. rt_kprintf("pipe status error\n");
  50. return -RT_EIO;
  51. }
  52. /* clear the pipe stall status */
  53. ret = rt_usbh_clear_feature(device, pipe->ep.bEndpointAddress,
  54. USB_FEATURE_ENDPOINT_HALT);
  55. if(ret != RT_EOK) return ret;
  56. rt_thread_delay(50);
  57. rt_kprintf("pipes1 0x%x, 0x%x\n", stor->pipe_in, stor->pipe_out);
  58. stor->pipe_in->status = UPIPE_STATUS_OK;
  59. RT_DEBUG_LOG(RT_DEBUG_USB, ("clean storage in pipe stall\n"));
  60. /* it should receive csw after clear the stall feature */
  61. size = rt_usb_hcd_bulk_xfer(stor->pipe_in->intf->device->hcd,
  62. stor->pipe_in, &csw, SIZEOF_CSW, 100);
  63. if(size != SIZEOF_CSW)
  64. {
  65. rt_kprintf("receive the csw after stall failed\n");
  66. return -RT_EIO;
  67. }
  68. return -RT_ERROR;
  69. }
  70. /**
  71. * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
  72. *
  73. * @param intf the interface instance.
  74. * @param max_lun the buffer to save max_lun.
  75. *
  76. * @return the error code, RT_EOK on successfully.
  77. */
  78. static rt_err_t rt_usb_bulk_only_xfer(struct uintf* intf,
  79. ustorage_cbw_t cmd, rt_uint8_t* buffer, int timeout)
  80. {
  81. rt_size_t size;
  82. rt_err_t ret;
  83. upipe_t pipe;
  84. struct ustorage_csw csw;
  85. ustor_t stor;
  86. RT_ASSERT(cmd != RT_NULL);
  87. if(intf == RT_NULL)
  88. {
  89. rt_kprintf("the interface is not available\n");
  90. return -RT_EIO;
  91. }
  92. /* get storage instance from the interface instance */
  93. stor = (ustor_t)intf->user_data;
  94. do
  95. {
  96. /* send the cbw */
  97. size = rt_usb_hcd_bulk_xfer(intf->device->hcd, stor->pipe_out,
  98. cmd, SIZEOF_CBW, timeout);
  99. if(size != SIZEOF_CBW)
  100. {
  101. rt_kprintf("CBW size error\n");
  102. return -RT_EIO;
  103. }
  104. if(cmd->xfer_len != 0)
  105. {
  106. pipe = (cmd->dflags == CBWFLAGS_DIR_IN) ? stor->pipe_in :
  107. stor->pipe_out;
  108. size = rt_usb_hcd_bulk_xfer(intf->device->hcd, pipe, (void*)buffer,
  109. cmd->xfer_len, timeout);
  110. if(size != cmd->xfer_len)
  111. {
  112. rt_kprintf("request size %d, transfer size %d\n",
  113. cmd->xfer_len, size);
  114. break;
  115. }
  116. }
  117. /* receive the csw */
  118. size = rt_usb_hcd_bulk_xfer(intf->device->hcd, stor->pipe_in,
  119. &csw, SIZEOF_CSW, timeout);
  120. if(size != SIZEOF_CSW)
  121. {
  122. rt_kprintf("csw size error\n");
  123. return -RT_EIO;
  124. }
  125. }while(0);
  126. /* check in pipes status */
  127. ret = _pipe_check(intf, stor->pipe_in);
  128. if(ret != RT_EOK)
  129. {
  130. rt_kprintf("in pipe error\n");
  131. return ret;
  132. }
  133. /* check out pipes status */
  134. ret = _pipe_check(intf, stor->pipe_out);
  135. if(ret != RT_EOK)
  136. {
  137. rt_kprintf("out pipe error\n");
  138. return ret;
  139. }
  140. /* check csw status */
  141. if(csw.signature != CSW_SIGNATURE || csw.tag != CBW_TAG_VALUE)
  142. {
  143. rt_kprintf("csw signature error\n");
  144. return -RT_EIO;
  145. }
  146. if(csw.status != 0)
  147. {
  148. rt_kprintf("csw status error\n");
  149. return -RT_ERROR;
  150. }
  151. return RT_EOK;
  152. }
  153. /**
  154. * This function will do USBREQ_GET_MAX_LUN request for the usb interface instance.
  155. *
  156. * @param intf the interface instance.
  157. * @param max_lun the buffer to save max_lun.
  158. *
  159. * @return the error code, RT_EOK on successfully.
  160. */
  161. rt_err_t rt_usbh_storage_get_max_lun(struct uintf* intf, rt_uint8_t* max_lun)
  162. {
  163. struct uinstance* device;
  164. struct urequest setup;
  165. int timeout = 100;
  166. if(intf == RT_NULL)
  167. {
  168. rt_kprintf("the interface is not available\n");
  169. return -RT_EIO;
  170. }
  171. /* parameter check */
  172. RT_ASSERT(intf->device != RT_NULL);
  173. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_get_max_lun\n"));
  174. /* get usb device instance from the interface instance */
  175. device = intf->device;
  176. /* construct the request */
  177. setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS |
  178. USB_REQ_TYPE_INTERFACE;
  179. setup.request = USBREQ_GET_MAX_LUN;
  180. setup.index = intf->intf_desc->bInterfaceNumber;
  181. setup.length = 1;
  182. setup.value = 0;
  183. /* do control transfer request */
  184. if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, max_lun, 1,
  185. timeout) != 1) return -RT_EIO;
  186. return RT_EOK;
  187. }
  188. /**
  189. * This function will do USBREQ_MASS_STORAGE_RESET request for the usb interface instance.
  190. *
  191. * @param intf the interface instance.
  192. *
  193. * @return the error code, RT_EOK on successfully.
  194. */
  195. rt_err_t rt_usbh_storage_reset(struct uintf* intf)
  196. {
  197. struct urequest setup;
  198. struct uinstance* device;
  199. int timeout = 100;
  200. /* parameter check */
  201. if(intf == RT_NULL)
  202. {
  203. rt_kprintf("the interface is not available\n");
  204. return -RT_EIO;
  205. }
  206. RT_ASSERT(intf->device != RT_NULL);
  207. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_reset\n"));
  208. /* get usb device instance from the interface instance */
  209. device = intf->device;
  210. /* construct the request */
  211. setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS |
  212. USB_REQ_TYPE_INTERFACE;
  213. setup.request = USBREQ_MASS_STORAGE_RESET;
  214. setup.index = intf->intf_desc->bInterfaceNumber;
  215. setup.length = 0;
  216. setup.value = 0;
  217. if(rt_usb_hcd_control_xfer(device->hcd, device, &setup, RT_NULL, 0,
  218. timeout) != 0) return -RT_EIO;
  219. return RT_EOK;
  220. }
  221. /**
  222. * This function will execute SCSI_READ_10 command to read data from the usb device.
  223. *
  224. * @param intf the interface instance.
  225. * @param buffer the data buffer to save read data
  226. * @param sector the start sector address to read.
  227. * @param sector the sector count to read.
  228. *
  229. * @return the error code, RT_EOK on successfully.
  230. */
  231. rt_err_t rt_usbh_storage_read10(struct uintf* intf, rt_uint8_t *buffer,
  232. rt_uint32_t sector, rt_size_t count, int timeout)
  233. {
  234. struct ustorage_cbw cmd;
  235. /* parameter check */
  236. if(intf == RT_NULL)
  237. {
  238. rt_kprintf("interface is not available\n");
  239. return -RT_EIO;
  240. }
  241. RT_ASSERT(intf->device != RT_NULL);
  242. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_read10\n"));
  243. /* construct the command block wrapper */
  244. rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
  245. cmd.signature = CBW_SIGNATURE;
  246. cmd.tag = CBW_TAG_VALUE;
  247. cmd.xfer_len = SECTOR_SIZE * count;
  248. cmd.dflags = CBWFLAGS_DIR_IN;
  249. cmd.lun = 0;
  250. cmd.cb_len = 10;
  251. cmd.cb[0] = SCSI_READ_10;
  252. cmd.cb[1] = 0;
  253. cmd.cb[2] = (rt_uint8_t)(sector >> 24);
  254. cmd.cb[3] = (rt_uint8_t)(sector >> 16);
  255. cmd.cb[4] = (rt_uint8_t)(sector >> 8);
  256. cmd.cb[5] = (rt_uint8_t)sector;
  257. cmd.cb[6] = 0;
  258. cmd.cb[7] = (count & 0xff00) >> 8;
  259. cmd.cb[8] = (rt_uint8_t) count & 0xff;
  260. return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
  261. }
  262. /**
  263. * This function will execute SCSI_WRITE_10 command to write data to the usb device.
  264. *
  265. * @param intf the interface instance.
  266. * @param buffer the data buffer to save write data
  267. * @param sector the start sector address to write.
  268. * @param sector the sector count to write.
  269. *
  270. * @return the error code, RT_EOK on successfully.
  271. */
  272. rt_err_t rt_usbh_storage_write10(struct uintf* intf, rt_uint8_t *buffer,
  273. rt_uint32_t sector, rt_size_t count, int timeout)
  274. {
  275. struct ustorage_cbw cmd;
  276. /* parameter check */
  277. if(intf == RT_NULL)
  278. {
  279. rt_kprintf("the interface is not available\n");
  280. return -RT_EIO;
  281. }
  282. RT_ASSERT(intf->device != RT_NULL);
  283. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_write10\n"));
  284. /* construct the command block wrapper */
  285. rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
  286. cmd.signature = CBW_SIGNATURE;
  287. cmd.tag = CBW_TAG_VALUE;
  288. cmd.xfer_len = SECTOR_SIZE * count;
  289. cmd.dflags = CBWFLAGS_DIR_OUT;
  290. cmd.lun = 0;
  291. cmd.cb_len = 10;
  292. cmd.cb[0] = SCSI_WRITE_10;
  293. cmd.cb[1] = 0;
  294. cmd.cb[2] = (rt_uint8_t)(sector >> 24);
  295. cmd.cb[3] = (rt_uint8_t)(sector >> 16);
  296. cmd.cb[4] = (rt_uint8_t)(sector >> 8);
  297. cmd.cb[5] = (rt_uint8_t)sector;
  298. cmd.cb[6] = 0;
  299. cmd.cb[7] = (count & 0xff00) >> 8;
  300. cmd.cb[8] = (rt_uint8_t) count & 0xff;
  301. return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
  302. }
  303. /**
  304. * This function will execute SCSI_REQUEST_SENSE command to get sense data.
  305. *
  306. * @param intf the interface instance.
  307. * @param buffer the data buffer to save sense data
  308. *
  309. * @return the error code, RT_EOK on successfully.
  310. */
  311. rt_err_t rt_usbh_storage_request_sense(struct uintf* intf, rt_uint8_t* buffer)
  312. {
  313. struct ustorage_cbw cmd;
  314. int timeout = 200;
  315. /* parameter check */
  316. if(intf == RT_NULL)
  317. {
  318. rt_kprintf("the interface is not available\n");
  319. return -RT_EIO;
  320. }
  321. RT_ASSERT(intf->device != RT_NULL);
  322. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_request_sense\n"));
  323. /* construct the command block wrapper */
  324. rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
  325. cmd.signature = CBW_SIGNATURE;
  326. cmd.tag = CBW_TAG_VALUE;
  327. cmd.xfer_len = 18;
  328. cmd.dflags = CBWFLAGS_DIR_IN;
  329. cmd.lun = 0;
  330. cmd.cb_len = 6;
  331. cmd.cb[0] = SCSI_REQUEST_SENSE;
  332. cmd.cb[4] = 18;
  333. return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
  334. }
  335. /**
  336. * This function will execute SCSI_TEST_UNIT_READY command to get unit ready status.
  337. *
  338. * @param intf the interface instance.
  339. *
  340. * @return the error code, RT_EOK on successfully.
  341. */
  342. rt_err_t rt_usbh_storage_test_unit_ready(struct uintf* intf)
  343. {
  344. struct ustorage_cbw cmd;
  345. int timeout = 200;
  346. /* parameter check */
  347. if(intf == RT_NULL)
  348. {
  349. rt_kprintf("the interface is not available\n");
  350. return -RT_EIO;
  351. }
  352. RT_ASSERT(intf->device != RT_NULL);
  353. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_test_unit_ready\n"));
  354. /* construct the command block wrapper */
  355. rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
  356. cmd.signature = CBW_SIGNATURE;
  357. cmd.tag = CBW_TAG_VALUE;
  358. cmd.xfer_len = 0;
  359. cmd.dflags = CBWFLAGS_DIR_OUT;
  360. cmd.lun = 0;
  361. cmd.cb_len = 12;
  362. cmd.cb[0] = SCSI_TEST_UNIT_READY;
  363. return rt_usb_bulk_only_xfer(intf, &cmd, RT_NULL, timeout);
  364. }
  365. /**
  366. * This function will execute SCSI_INQUIRY_CMD command to get inquiry data.
  367. *
  368. * @param intf the interface instance.
  369. * @param buffer the data buffer to save inquiry data
  370. *
  371. * @return the error code, RT_EOK on successfully.
  372. */
  373. rt_err_t rt_usbh_storage_inquiry(struct uintf* intf, rt_uint8_t* buffer)
  374. {
  375. struct ustorage_cbw cmd;
  376. int timeout = 200;
  377. /* parameter check */
  378. if(intf == RT_NULL)
  379. {
  380. rt_kprintf("the interface is not available\n");
  381. return -RT_EIO;
  382. }
  383. RT_ASSERT(intf->device != RT_NULL);
  384. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_inquiry\n"));
  385. /* construct the command block wrapper */
  386. rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
  387. cmd.signature = CBW_SIGNATURE;
  388. cmd.tag = CBW_TAG_VALUE;
  389. cmd.xfer_len = 36;
  390. cmd.dflags = CBWFLAGS_DIR_IN;
  391. cmd.lun = 0;
  392. cmd.cb_len = 12;
  393. cmd.cb[0] = SCSI_INQUIRY_CMD;
  394. cmd.cb[4] = 36;
  395. return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
  396. }
  397. /**
  398. * This function will execute SCSI_READ_CAPACITY command to get capacity data.
  399. *
  400. * @param intf the interface instance.
  401. * @param buffer the data buffer to save capacity data
  402. *
  403. * @return the error code, RT_EOK on successfully.
  404. */
  405. rt_err_t rt_usbh_storage_get_capacity(struct uintf* intf, rt_uint8_t* buffer)
  406. {
  407. struct ustorage_cbw cmd;
  408. int timeout = 200;
  409. /* parameter check */
  410. if(intf == RT_NULL)
  411. {
  412. rt_kprintf("the interface is not available\n");
  413. return -RT_EIO;
  414. }
  415. RT_ASSERT(intf->device != RT_NULL);
  416. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_get_capacity\n"));
  417. /* construct the command block wrapper */
  418. rt_memset(&cmd, 0, sizeof(struct ustorage_cbw));
  419. cmd.signature = CBW_SIGNATURE;
  420. cmd.tag = CBW_TAG_VALUE;
  421. cmd.xfer_len = 8;
  422. cmd.dflags = CBWFLAGS_DIR_IN;
  423. cmd.lun = 0;
  424. cmd.cb_len = 12;
  425. cmd.cb[0] = SCSI_READ_CAPACITY;
  426. return rt_usb_bulk_only_xfer(intf, &cmd, buffer, timeout);
  427. }
  428. /**
  429. * This function will run mass storage class driver when usb device is detected
  430. * and identified as a mass storage class device, it will continue to do the enumulate
  431. * process.
  432. *
  433. * @param arg the argument.
  434. *
  435. * @return the error code, RT_EOK on successfully.
  436. */
  437. static rt_err_t rt_usbh_storage_enable(void* arg)
  438. {
  439. int i = 0;
  440. rt_err_t ret;
  441. ustor_t stor;
  442. struct uintf* intf = (struct uintf*)arg;
  443. /* parameter check */
  444. if(intf == RT_NULL)
  445. {
  446. rt_kprintf("the interface is not available\n");
  447. return -RT_EIO;
  448. }
  449. RT_DEBUG_LOG(RT_DEBUG_USB, ("subclass %d, protocal %d\n",
  450. intf->intf_desc->bInterfaceSubClass,
  451. intf->intf_desc->bInterfaceProtocol));
  452. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_run\n"));
  453. /* only support SCSI subclass and bulk only protocal */
  454. stor = rt_malloc(sizeof(struct ustor));
  455. RT_ASSERT(stor != RT_NULL);
  456. /* initilize the data structure */
  457. rt_memset(stor, 0, sizeof(struct ustor));
  458. intf->user_data = (void*)stor;
  459. for(i=0; i<intf->intf_desc->bNumEndpoints; i++)
  460. {
  461. uep_desc_t ep_desc;
  462. /* get endpoint descriptor from interface descriptor */
  463. rt_usbh_get_endpoint_descriptor(intf->intf_desc, i, &ep_desc);
  464. if(ep_desc == RT_NULL)
  465. {
  466. rt_kprintf("rt_usb_get_endpoint_descriptor error\n");
  467. return -RT_ERROR;
  468. }
  469. /* the endpoint type of mass storage class should be BULK */
  470. if((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) != USB_EP_ATTR_BULK)
  471. continue;
  472. /* allocate pipes according to the endpoint type */
  473. if(ep_desc->bEndpointAddress & USB_DIR_IN)
  474. {
  475. /* alloc an in pipe for the storage instance */
  476. ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &stor->pipe_in,
  477. intf, ep_desc, RT_NULL);
  478. if(ret != RT_EOK) return ret;
  479. }
  480. else
  481. {
  482. /* alloc an output pipe for the storage instance */
  483. ret = rt_usb_hcd_alloc_pipe(intf->device->hcd, &stor->pipe_out,
  484. intf, ep_desc, RT_NULL);
  485. if(ret != RT_EOK) return ret;
  486. }
  487. }
  488. /* check pipes infomation */
  489. if(stor->pipe_in == RT_NULL || stor->pipe_out == RT_NULL)
  490. {
  491. rt_kprintf("pipe error, unsupported device\n");
  492. return -RT_ERROR;
  493. }
  494. /* should implement as callback */
  495. ret = rt_udisk_run(intf);
  496. if(ret != RT_EOK) return ret;
  497. return RT_EOK;
  498. }
  499. /**
  500. * This function will be invoked when usb device plug out is detected and it would clean
  501. * and release all mass storage class related resources.
  502. *
  503. * @param arg the argument.
  504. *
  505. * @return the error code, RT_EOK on successfully.
  506. */
  507. static rt_err_t rt_usbh_storage_disable(void* arg)
  508. {
  509. ustor_t stor;
  510. struct uintf* intf = (struct uintf*)arg;
  511. /* parameter check */
  512. RT_ASSERT(intf != RT_NULL);
  513. RT_ASSERT(intf->user_data != RT_NULL);
  514. RT_ASSERT(intf->device != RT_NULL);
  515. RT_DEBUG_LOG(RT_DEBUG_USB, ("rt_usbh_storage_stop\n"));
  516. /* get storage instance from interface instance */
  517. stor = (ustor_t)intf->user_data;
  518. rt_udisk_stop(intf);
  519. rt_kprintf("in 0x%x, out 0x%x\n", stor->pipe_in,
  520. stor->pipe_out);
  521. /* free in pipe */
  522. if(stor->pipe_in != RT_NULL)
  523. rt_usb_hcd_free_pipe(intf->device->hcd, stor->pipe_in);
  524. /* free out pipe */
  525. if(stor->pipe_out != RT_NULL)
  526. rt_usb_hcd_free_pipe(intf->device->hcd, stor->pipe_out);
  527. /* free storage instance */
  528. if(stor != RT_NULL) rt_free(stor);
  529. /* free interface instance */
  530. if(intf != RT_NULL) rt_free(intf);
  531. return RT_EOK;
  532. }
  533. /**
  534. * This function will register mass storage class driver to the usb class driver manager.
  535. * and it should be invoked in the usb system initialization.
  536. *
  537. * @return the error code, RT_EOK on successfully.
  538. */
  539. ucd_t rt_usbh_class_driver_storage(void)
  540. {
  541. storage_driver.class_code = USB_CLASS_MASS_STORAGE;
  542. storage_driver.enable = rt_usbh_storage_enable;
  543. storage_driver.disable = rt_usbh_storage_disable;
  544. return &storage_driver;
  545. }
  546. #endif