mstorage.c 16 KB

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