mstorage.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544
  1. /*
  2. * File : mstorage.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2012, 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. * 2012-10-01 Yi Qiu first version
  13. */
  14. #include <rtthread.h>
  15. #include <rtservice.h>
  16. #include <rtdevice.h>
  17. #include "mstorage.h"
  18. #ifdef RT_USB_DEVICE_MSTORAGE
  19. #define STATUS_CBW 0x00
  20. #define STATUS_CSW 0x01
  21. #define STATUS_RECEIVE 0x02
  22. static uclass_t mstorage;
  23. static uep_t ep_in, ep_out;
  24. static rt_uint8_t *buffer;
  25. static rt_uint8_t *write_ptr;
  26. static int status = STATUS_CBW;
  27. static struct ustorage_csw csw;
  28. static rt_device_t disk;
  29. static struct rt_device_blk_geometry geometry;
  30. static struct udevice_descriptor dev_desc =
  31. {
  32. USB_DESC_LENGTH_DEVICE, //bLength;
  33. USB_DESC_TYPE_DEVICE, //type;
  34. USB_BCD_VERSION, //bcdUSB;
  35. USB_CLASS_MASS_STORAGE, //bDeviceClass;
  36. 0x00, //bDeviceSubClass;
  37. 0x00, //bDeviceProtocol;
  38. 0x40, //bMaxPacketSize0;
  39. USB_VENDOR_ID, //idVendor;
  40. USB_MASS_STORAGE_PRODUCT_ID,//idProduct;
  41. USB_BCD_DEVICE, //bcdDevice;
  42. USB_STRING_MANU_INDEX, //iManufacturer;
  43. USB_STRING_PRODUCT_INDEX, //iProduct;
  44. USB_STRING_SERIAL_INDEX, //iSerialNumber;
  45. USB_DYNAMIC, //bNumConfigurations;
  46. };
  47. static struct umass_descriptor mass_desc =
  48. {
  49. USB_DESC_LENGTH_INTERFACE, //bLength;
  50. USB_DESC_TYPE_INTERFACE, //type;
  51. USB_DYNAMIC, //bInterfaceNumber;
  52. 0x00, //bAlternateSetting;
  53. 0x02, //bNumEndpoints
  54. USB_CLASS_MASS_STORAGE, //bInterfaceClass;
  55. 0x06, //bInterfaceSubClass;
  56. 0x50, //bInterfaceProtocol;
  57. 0x00, //iInterface;
  58. USB_DESC_LENGTH_ENDPOINT, //bLength;
  59. USB_DESC_TYPE_ENDPOINT, //type;
  60. USB_DYNAMIC | USB_DIR_OUT, //bEndpointAddress;
  61. USB_EP_ATTR_BULK, //bmAttributes;
  62. 0x40, //wMaxPacketSize;
  63. 0x00, //bInterval;
  64. USB_DESC_LENGTH_ENDPOINT, //bLength;
  65. USB_DESC_TYPE_ENDPOINT, //type;
  66. USB_DYNAMIC | USB_DIR_IN, //bEndpointAddress;
  67. USB_EP_ATTR_BULK, //bmAttributes;
  68. 0x40, //wMaxPacketSize;
  69. 0x00, //bInterval;
  70. };
  71. /**
  72. * This function will allocate an usb device instance from system.
  73. *
  74. * @param parent the hub instance to which the new allocated device attached.
  75. * @param port the hub port.
  76. *
  77. * @return the allocate instance on successful, or RT_NULL on failure.
  78. */
  79. static rt_err_t _inquiry_cmd(udevice_t device)
  80. {
  81. rt_uint8_t data[36];
  82. *(rt_uint32_t*)&data[0] = 0x0 | (0x80 << 8);
  83. *(rt_uint32_t*)&data[4] = 31;
  84. rt_memset(&data[8], 0x20, 28);
  85. rt_memcpy(&data[8], "RTT", 3);
  86. rt_memcpy(&data[16], "USB Disk", 8);
  87. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 36);
  88. return RT_EOK;
  89. }
  90. /**
  91. * This function will handle sense request.
  92. *
  93. * @param device the usb device object.
  94. *
  95. * @return RT_EOK on successful.
  96. */
  97. static rt_err_t _request_sense(udevice_t device)
  98. {
  99. struct request_sense_data data;
  100. data.ErrorCode = 0x70;
  101. data.Valid = 0;
  102. data.SenseKey = 5;
  103. data.Information[0] = 0;
  104. data.Information[1] = 0;
  105. data.Information[2] = 0;
  106. data.Information[3] = 0;
  107. data.AdditionalSenseLength = 0x0b;
  108. data.AdditionalSenseCode = 0x20;
  109. data.AdditionalSenseCodeQualifier =0;
  110. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, sizeof(struct request_sense_data));
  111. return RT_EOK;
  112. }
  113. /**
  114. * This function will handle mode_sense_6 request.
  115. *
  116. * @param device the usb device object.
  117. *
  118. * @return RT_EOK on successful.
  119. */
  120. static rt_err_t _mode_sense_6(udevice_t device)
  121. {
  122. rt_uint8_t data[4];
  123. data[0]=3;
  124. data[1]=0;
  125. data[2]=0;
  126. data[3]=0;
  127. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 4);
  128. return RT_EOK;
  129. }
  130. /**
  131. * This function will handle read_capacities request.
  132. *
  133. * @param device the usb device object.
  134. *
  135. * @return RT_EOK on successful.
  136. */
  137. static rt_err_t _read_capacities(udevice_t device)
  138. {
  139. rt_uint8_t data[12];
  140. rt_uint32_t sector_count, sector_size;
  141. RT_ASSERT(device != RT_NULL);
  142. sector_count = geometry.sector_count;
  143. sector_size = geometry.bytes_per_sector;
  144. *(rt_uint32_t*)&data[0] = 0x08000000;
  145. data[4] = sector_count >> 24;
  146. data[5] = 0xff & (sector_count >> 16);
  147. data[6] = 0xff & (sector_count >> 8);
  148. data[7] = 0xff & (sector_count);
  149. data[8] = 0x02;
  150. data[9] = 0xff & (sector_size >> 16);
  151. data[10] = 0xff & (sector_size >> 8);
  152. data[11] = 0xff & sector_size;
  153. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 12);
  154. return RT_EOK;
  155. }
  156. /**
  157. * This function will handle read_capacity request.
  158. *
  159. * @param device the usb device object.
  160. *
  161. * @return RT_EOK on successful.
  162. */
  163. static rt_err_t _read_capacity(udevice_t device)
  164. {
  165. rt_uint8_t data[8];
  166. rt_uint32_t sector_count, sector_size;
  167. RT_ASSERT(device != RT_NULL);
  168. sector_count = geometry.sector_count;
  169. sector_size = geometry.bytes_per_sector;
  170. data[0] = sector_count >> 24;
  171. data[1] = 0xff & (sector_count >> 16);
  172. data[2] = 0xff & (sector_count >> 8);
  173. data[3] = 0xff & (sector_count);
  174. data[4] = 0x0;
  175. data[5] = 0xff & (sector_size >> 16);
  176. data[6] = 0xff & (sector_size >> 8);
  177. data[7] = 0xff & sector_size;
  178. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&data, 8);
  179. return RT_EOK;
  180. }
  181. /**
  182. * This function will handle read_10 request.
  183. *
  184. * @param device the usb device object.
  185. * @param cbw the command block wrapper.
  186. *
  187. * @return RT_EOK on successful.
  188. */
  189. static rt_err_t _read_10(udevice_t device, ustorage_cbw_t cbw)
  190. {
  191. rt_uint32_t block;
  192. rt_uint32_t count;
  193. RT_ASSERT(device != RT_NULL);
  194. RT_ASSERT(cbw != RT_NULL);
  195. block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 |
  196. cbw->cb[5]<<0 ;
  197. count = cbw->cb[7]<<8 | cbw->cb[8]<<0 ;
  198. RT_ASSERT(count < geometry.sector_count);
  199. rt_device_read(disk, block, buffer, count);
  200. dcd_ep_write(device->dcd, ep_in, buffer, count * geometry.bytes_per_sector);
  201. return RT_EOK;
  202. }
  203. static rt_uint32_t _block;
  204. static rt_uint32_t _count, _size;
  205. /**
  206. * This function will handle write_10 request.
  207. *
  208. * @param device the usb device object.
  209. * @param cbw the command block wrapper.
  210. *
  211. * @return RT_EOK on successful.
  212. */
  213. static rt_err_t _write_10(udevice_t device, ustorage_cbw_t cbw)
  214. {
  215. RT_ASSERT(device != RT_NULL);
  216. RT_ASSERT(cbw != RT_NULL);
  217. _block = cbw->cb[2]<<24 | cbw->cb[3]<<16 | cbw->cb[4]<<8 |
  218. cbw->cb[5]<<0 ;
  219. _count = cbw->cb[7]<<8 | cbw->cb[8]<<0;
  220. csw.data_reside = cbw->xfer_len;
  221. _size = _count * geometry.bytes_per_sector;
  222. write_ptr = buffer;
  223. RT_DEBUG_LOG(RT_DEBUG_USB, ("_write_10 count 0x%x 0x%x\n",
  224. _count, geometry.sector_count));
  225. dcd_ep_read(device->dcd, ep_out, buffer, MIN(_size, 4096));
  226. return RT_EOK;
  227. }
  228. /**
  229. * This function will handle verify_10 request.
  230. *
  231. * @param device the usb device object.
  232. *
  233. * @return RT_EOK on successful.
  234. */
  235. static rt_err_t _verify_10(udevice_t device)
  236. {
  237. return RT_EOK;
  238. }
  239. /**
  240. * This function will handle mass storage bulk in endpoint request.
  241. *
  242. * @param device the usb device object.
  243. * @param size request size.
  244. *
  245. * @return RT_EOK.
  246. */
  247. static rt_err_t _ep_in_handler(udevice_t device, rt_size_t size)
  248. {
  249. RT_ASSERT(device != RT_NULL);
  250. if(status == STATUS_CSW)
  251. {
  252. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&csw, SIZEOF_CSW);
  253. status = STATUS_CBW;
  254. dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW);
  255. }
  256. return RT_EOK;
  257. }
  258. static void cbw_dump(struct ustorage_cbw* cbw)
  259. {
  260. RT_ASSERT(cbw != RT_NULL);
  261. RT_DEBUG_LOG(RT_DEBUG_USB, ("signature 0x%x\n", cbw->signature));
  262. RT_DEBUG_LOG(RT_DEBUG_USB, ("tag 0x%x\n", cbw->tag));
  263. RT_DEBUG_LOG(RT_DEBUG_USB, ("xfer_len 0x%x\n", cbw->xfer_len));
  264. RT_DEBUG_LOG(RT_DEBUG_USB, ("dflags 0x%x\n", cbw->dflags));
  265. RT_DEBUG_LOG(RT_DEBUG_USB, ("lun 0x%x\n", cbw->lun));
  266. RT_DEBUG_LOG(RT_DEBUG_USB, ("cb_len 0x%x\n", cbw->cb_len));
  267. RT_DEBUG_LOG(RT_DEBUG_USB, ("cb[0] 0x%x\n", cbw->cb[0]));
  268. }
  269. /**
  270. * This function will handle mass storage bulk out endpoint request.
  271. *
  272. * @param device the usb device object.
  273. * @param size request size.
  274. *
  275. * @return RT_EOK.
  276. */
  277. static rt_err_t _ep_out_handler(udevice_t device, rt_size_t size)
  278. {
  279. RT_ASSERT(device != RT_NULL);
  280. if(status == STATUS_CBW)
  281. {
  282. struct ustorage_cbw* cbw;
  283. /* dump cbw information */
  284. cbw = (struct ustorage_cbw*)ep_out->buffer;
  285. if(cbw->signature == CBW_SIGNATURE)
  286. {
  287. csw.signature = CSW_SIGNATURE;
  288. csw.tag = cbw->tag;
  289. csw.data_reside = 0;
  290. csw.status = 0;
  291. }
  292. switch(cbw->cb[0])
  293. {
  294. case SCSI_TEST_UNIT_READY:
  295. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&csw, SIZEOF_CSW);
  296. dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW);
  297. break;
  298. case SCSI_REQUEST_SENSE:
  299. _request_sense(device);
  300. status = STATUS_CSW;
  301. break;
  302. case SCSI_INQUIRY_CMD:
  303. _inquiry_cmd(device);
  304. status = STATUS_CSW;
  305. break;
  306. case SCSI_MODE_SENSE_6:
  307. _mode_sense_6(device);
  308. status = STATUS_CSW;
  309. break;
  310. case SCSI_ALLOW_MEDIUM_REMOVAL:
  311. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&csw, SIZEOF_CSW);
  312. dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW);
  313. break;
  314. case SCSI_READ_CAPACITIES:
  315. _read_capacities(device);
  316. status = STATUS_CSW;
  317. break;
  318. case SCSI_READ_CAPACITY:
  319. _read_capacity(device);
  320. status = STATUS_CSW;
  321. break;
  322. case SCSI_READ_10:
  323. _read_10(device, cbw);
  324. status = STATUS_CSW;
  325. break;
  326. case SCSI_WRITE_10:
  327. _write_10(device, cbw);
  328. status = STATUS_RECEIVE;
  329. break;
  330. case SCSI_VERIFY_10:
  331. _verify_10(device);
  332. break;
  333. }
  334. }
  335. else if(status == STATUS_RECEIVE)
  336. {
  337. RT_DEBUG_LOG(RT_DEBUG_USB, ("write size 0x%x block 0x%x oount 0x%x\n",
  338. size, _block, _size));
  339. _size -= size;
  340. write_ptr += size;
  341. csw.data_reside -= size;
  342. if(_size == 0)
  343. {
  344. rt_device_write(disk, _block, buffer, _count);
  345. dcd_ep_write(device->dcd, ep_in, (rt_uint8_t*)&csw, SIZEOF_CSW);
  346. dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW);
  347. status = STATUS_CBW;
  348. }
  349. else
  350. {
  351. dcd_ep_read(device->dcd, ep_out, write_ptr, MIN(_size, 4096));
  352. }
  353. }
  354. else
  355. {
  356. rt_kprintf("none cbw status\n");
  357. }
  358. return RT_EOK;
  359. }
  360. /**
  361. * This function will handle mass storage interface request.
  362. *
  363. * @param device the usb device object.
  364. * @param setup the setup request.
  365. *
  366. * @return RT_EOK on successful.
  367. */
  368. static rt_err_t _interface_handler(udevice_t device, ureq_t setup)
  369. {
  370. rt_uint8_t lun = 0;
  371. RT_ASSERT(device != RT_NULL);
  372. RT_ASSERT(setup != RT_NULL);
  373. RT_DEBUG_LOG(RT_DEBUG_USB, ("_interface_handler\n"));
  374. switch(setup->request)
  375. {
  376. case USBREQ_GET_MAX_LUN:
  377. dcd_ep_write(device->dcd, 0, &lun, 1);
  378. break;
  379. case USBREQ_MASS_STORAGE_RESET:
  380. break;
  381. default:
  382. rt_kprintf("unknown interface request\n");
  383. break;
  384. }
  385. return RT_EOK;
  386. }
  387. /**
  388. * This function will run mass storage class, it will be called on handle set configuration request.
  389. *
  390. * @param device the usb device object.
  391. *
  392. * @return RT_EOK on successful.
  393. */
  394. static rt_err_t _class_run(udevice_t device)
  395. {
  396. RT_ASSERT(device != RT_NULL);
  397. RT_DEBUG_LOG(RT_DEBUG_USB, ("mass storage run\n"));
  398. disk = rt_device_find(RT_USB_MSTORAGE_DISK_NAME);
  399. RT_ASSERT(disk != RT_NULL);
  400. buffer = (rt_uint8_t*)rt_malloc(RT_USB_MSTORAGE_BUFFER_SIZE);
  401. rt_device_control(disk, RT_DEVICE_CTRL_BLK_GETGEOME, (void*)&geometry);
  402. dcd_ep_read(device->dcd, ep_out, ep_out->buffer, SIZEOF_CBW);
  403. return RT_EOK;
  404. }
  405. /**
  406. * This function will stop mass storage class, it will be called on handle set configuration request.
  407. *
  408. * @param device the usb device object.
  409. *
  410. * @return RT_EOK on successful.
  411. */
  412. static rt_err_t _class_stop(udevice_t device)
  413. {
  414. RT_ASSERT(device != RT_NULL);
  415. RT_DEBUG_LOG(RT_DEBUG_USB, ("mass storage stop\n"));
  416. rt_free(buffer);
  417. return RT_EOK;
  418. }
  419. static struct uclass_ops ops =
  420. {
  421. _class_run,
  422. _class_stop,
  423. RT_NULL,
  424. };
  425. /**
  426. * This function will create a mass storage class instance.
  427. *
  428. * @param device the usb device object.
  429. *
  430. * @return RT_EOK on successful.
  431. */
  432. uclass_t rt_usbd_class_mstorage_create(udevice_t device)
  433. {
  434. uintf_t intf;
  435. ualtsetting_t setting;
  436. /* parameter check */
  437. RT_ASSERT(device != RT_NULL);
  438. /* create a mass storage class */
  439. mstorage = rt_usbd_class_create(device, &dev_desc, &ops);
  440. /* create an interface */
  441. intf = rt_usbd_interface_create(device, _interface_handler);
  442. /* create a bulk out and a bulk in endpoint */
  443. ep_in = rt_usbd_endpoint_create(&mass_desc.ep_in_desc, _ep_in_handler);
  444. ep_out = rt_usbd_endpoint_create(&mass_desc.ep_out_desc, _ep_out_handler);
  445. /* create an alternate setting */
  446. setting = rt_usbd_altsetting_create(&mass_desc.intf_desc,
  447. sizeof(struct umass_descriptor));
  448. /* add the bulk out and bulk in endpoint to the alternate setting */
  449. rt_usbd_altsetting_add_endpoint(setting, ep_out);
  450. rt_usbd_altsetting_add_endpoint(setting, ep_in);
  451. /* add the alternate setting to the interface, then set default setting */
  452. rt_usbd_interface_add_altsetting(intf, setting);
  453. rt_usbd_set_altsetting(intf, 0);
  454. /* add the interface to the mass storage class */
  455. rt_usbd_class_add_interface(mstorage, intf);
  456. return mstorage;
  457. }
  458. #endif