mass.c 18 KB

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