mstorage.c 15 KB

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