mstorage.c 15 KB

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