mstorage.c 17 KB

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