1
0

mass.c 17 KB

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