usbh_msc.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. /**
  2. * @file usbh_msc.c
  3. * @brief
  4. *
  5. * Copyright (c) 2022 sakumisu
  6. *
  7. * Licensed to the Apache Software Foundation (ASF) under one or more
  8. * contributor license agreements. See the NOTICE file distributed with
  9. * this work for additional information regarding copyright ownership. The
  10. * ASF licenses this file to you under the Apache License, Version 2.0 (the
  11. * "License"); you may not use this file except in compliance with the
  12. * License. You may obtain a copy of the License at
  13. *
  14. * http://www.apache.org/licenses/LICENSE-2.0
  15. *
  16. * Unless required by applicable law or agreed to in writing, software
  17. * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  18. * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  19. * License for the specific language governing permissions and limitations
  20. * under the License.
  21. *
  22. */
  23. #include "usbh_core.h"
  24. #include "usbh_msc.h"
  25. #include "usb_scsi.h"
  26. #define DEV_FORMAT "/dev/sd%c"
  27. static uint32_t g_devinuse = 0;
  28. /****************************************************************************
  29. * Name: usbh_msc_devno_alloc
  30. *
  31. * Description:
  32. * Allocate a unique /dev/sd[n] minor number in the range 0-31.
  33. *
  34. ****************************************************************************/
  35. static int usbh_msc_devno_alloc(struct usbh_msc *msc_class)
  36. {
  37. size_t flags;
  38. int devno;
  39. flags = usb_osal_enter_critical_section();
  40. for (devno = 0; devno < 26; devno++) {
  41. uint32_t bitno = 1 << devno;
  42. if ((g_devinuse & bitno) == 0) {
  43. g_devinuse |= bitno;
  44. msc_class->sdchar = 'a' + devno;
  45. usb_osal_leave_critical_section(flags);
  46. return 0;
  47. }
  48. }
  49. usb_osal_leave_critical_section(flags);
  50. return -EMFILE;
  51. }
  52. /****************************************************************************
  53. * Name: usbh_msc_devno_free
  54. *
  55. * Description:
  56. * Free a /dev/sd[n] minor number so that it can be used.
  57. *
  58. ****************************************************************************/
  59. static void usbh_msc_devno_free(struct usbh_msc *msc_class)
  60. {
  61. int devno = msc_class->sdchar - 'a';
  62. if (devno >= 0 && devno < 26) {
  63. size_t flags = usb_osal_enter_critical_section();
  64. g_devinuse &= ~(1 << devno);
  65. usb_osal_leave_critical_section(flags);
  66. }
  67. }
  68. static int usbh_msc_get_maxlun(struct usbh_msc *msc_class, uint8_t *buffer)
  69. {
  70. struct usb_setup_packet *setup = msc_class->hport->setup;
  71. setup->bmRequestType = USB_REQUEST_DIR_IN | USB_REQUEST_CLASS | USB_REQUEST_RECIPIENT_INTERFACE;
  72. setup->bRequest = MSC_REQUEST_GET_MAX_LUN;
  73. setup->wValue = 0;
  74. setup->wIndex = msc_class->intf;
  75. setup->wLength = 1;
  76. return usbh_control_transfer(msc_class->hport->ep0, setup, buffer);
  77. }
  78. static void usbh_msc_cbw_dump(struct CBW *cbw)
  79. {
  80. #if 0
  81. int i;
  82. USB_LOG_INFO("CBW:\r\n");
  83. USB_LOG_INFO(" signature: 0x%08x\r\n", (unsigned int)cbw->dSignature);
  84. USB_LOG_INFO(" tag: 0x%08x\r\n", (unsigned int)cbw->dTag);
  85. USB_LOG_INFO(" datlen: 0x%08x\r\n", (unsigned int)cbw->dDataLength);
  86. USB_LOG_INFO(" flags: 0x%02x\r\n", cbw->bmFlags);
  87. USB_LOG_INFO(" lun: 0x%02x\r\n", cbw->bLUN);
  88. USB_LOG_INFO(" cblen: 0x%02x\r\n", cbw->bCBLength);
  89. USB_LOG_INFO("CB:\r\n");
  90. for (i = 0; i < cbw->bCBLength; i += 8) {
  91. USB_LOG_INFO(" 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\r\n",
  92. cbw->CB[i], cbw->CB[i + 1], cbw->CB[i + 2],
  93. cbw->CB[i + 3], cbw->CB[i + 4], cbw->CB[i + 5],
  94. cbw->CB[i + 6], cbw->CB[i + 7]);
  95. }
  96. #endif
  97. }
  98. static void usbh_msc_csw_dump(struct CSW *csw)
  99. {
  100. #if 0
  101. USB_LOG_INFO("CSW:\r\n");
  102. USB_LOG_INFO(" signature: 0x%08x\r\n", (unsigned int)csw->dSignature);
  103. USB_LOG_INFO(" tag: 0x%08x\r\n", (unsigned int)csw->dTag);
  104. USB_LOG_INFO(" residue: 0x%08x\r\n", (unsigned int)csw->dDataResidue);
  105. USB_LOG_INFO(" status: 0x%02x\r\n", csw->bStatus);
  106. #endif
  107. }
  108. static inline int usbh_msc_scsi_testunitready(struct usbh_msc *msc_class)
  109. {
  110. int nbytes;
  111. struct CBW *cbw;
  112. /* Construct the CBW */
  113. cbw = (struct CBW *)msc_class->tx_buffer;
  114. memset(cbw, 0, USB_SIZEOF_MSC_CBW);
  115. cbw->dSignature = MSC_CBW_Signature;
  116. cbw->bCBLength = SCSICMD_TESTUNITREADY_SIZEOF;
  117. cbw->CB[0] = SCSI_CMD_TESTUNITREADY;
  118. usbh_msc_cbw_dump(cbw);
  119. /* Send the CBW */
  120. nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
  121. if (nbytes >= 0) {
  122. /* Receive the CSW */
  123. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
  124. if (nbytes >= 0) {
  125. usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
  126. }
  127. }
  128. return nbytes < 0 ? (int)nbytes : 0;
  129. }
  130. static inline int usbh_msc_scsi_requestsense(struct usbh_msc *msc_class)
  131. {
  132. int nbytes;
  133. struct CBW *cbw;
  134. /* Construct the CBW */
  135. cbw = (struct CBW *)msc_class->tx_buffer;
  136. memset(cbw, 0, USB_SIZEOF_MSC_CBW);
  137. cbw->dSignature = MSC_CBW_Signature;
  138. cbw->bmFlags = 0x80;
  139. cbw->bCBLength = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
  140. cbw->dDataLength = SCSICMD_REQUESTSENSE_SIZEOF;
  141. cbw->CB[0] = SCSI_CMD_REQUESTSENSE;
  142. cbw->CB[4] = SCSIRESP_FIXEDSENSEDATA_SIZEOF;
  143. usbh_msc_cbw_dump(cbw);
  144. /* Send the CBW */
  145. nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
  146. if (nbytes >= 0) {
  147. /* Receive the sense data response */
  148. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_FIXEDSENSEDATA_SIZEOF, CONFIG_USBHOST_MSC_TIMEOUT);
  149. if (nbytes >= 0) {
  150. /* Receive the CSW */
  151. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
  152. if (nbytes >= 0) {
  153. usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
  154. }
  155. }
  156. }
  157. return nbytes < 0 ? (int)nbytes : 0;
  158. }
  159. static inline int usbh_msc_scsi_inquiry(struct usbh_msc *msc_class)
  160. {
  161. int nbytes;
  162. struct CBW *cbw;
  163. /* Construct the CBW */
  164. cbw = (struct CBW *)msc_class->tx_buffer;
  165. memset(cbw, 0, USB_SIZEOF_MSC_CBW);
  166. cbw->dSignature = MSC_CBW_Signature;
  167. cbw->dDataLength = SCSIRESP_INQUIRY_SIZEOF;
  168. cbw->bmFlags = 0x80;
  169. cbw->bCBLength = SCSICMD_INQUIRY_SIZEOF;
  170. cbw->CB[0] = SCSI_CMD_INQUIRY;
  171. cbw->CB[4] = SCSIRESP_INQUIRY_SIZEOF;
  172. usbh_msc_cbw_dump(cbw);
  173. /* Send the CBW */
  174. nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
  175. if (nbytes >= 0) {
  176. /* Receive the sense data response */
  177. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_INQUIRY_SIZEOF, CONFIG_USBHOST_MSC_TIMEOUT);
  178. if (nbytes >= 0) {
  179. /* Receive the CSW */
  180. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
  181. if (nbytes >= 0) {
  182. usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
  183. }
  184. }
  185. }
  186. return nbytes < 0 ? (int)nbytes : 0;
  187. }
  188. static inline int usbh_msc_scsi_readcapacity10(struct usbh_msc *msc_class)
  189. {
  190. int nbytes;
  191. struct CBW *cbw;
  192. /* Construct the CBW */
  193. cbw = (struct CBW *)msc_class->tx_buffer;
  194. memset(cbw, 0, USB_SIZEOF_MSC_CBW);
  195. cbw->dSignature = MSC_CBW_Signature;
  196. cbw->dDataLength = SCSIRESP_READCAPACITY10_SIZEOF;
  197. cbw->bmFlags = 0x80;
  198. cbw->bCBLength = SCSICMD_READCAPACITY10_SIZEOF;
  199. cbw->CB[0] = SCSI_CMD_READCAPACITY10;
  200. usbh_msc_cbw_dump(cbw);
  201. /* Send the CBW */
  202. nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
  203. if (nbytes >= 0) {
  204. /* Receive the sense data response */
  205. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, SCSIRESP_READCAPACITY10_SIZEOF, CONFIG_USBHOST_MSC_TIMEOUT);
  206. if (nbytes >= 0) {
  207. /* Save the capacity information */
  208. msc_class->blocknum = GET_BE32(&msc_class->tx_buffer[0]) + 1;
  209. msc_class->blocksize = GET_BE32(&msc_class->tx_buffer[4]);
  210. /* Receive the CSW */
  211. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
  212. if (nbytes >= 0) {
  213. usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
  214. }
  215. }
  216. }
  217. return nbytes < 0 ? (int)nbytes : 0;
  218. }
  219. int usbh_msc_scsi_write10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
  220. {
  221. int nbytes;
  222. struct CBW *cbw;
  223. /* Construct the CBW */
  224. cbw = (struct CBW *)msc_class->tx_buffer;
  225. memset(cbw, 0, USB_SIZEOF_MSC_CBW);
  226. cbw->dSignature = MSC_CBW_Signature;
  227. cbw->dDataLength = (msc_class->blocksize * nsectors);
  228. cbw->bCBLength = SCSICMD_WRITE10_SIZEOF;
  229. cbw->CB[0] = SCSI_CMD_WRITE10;
  230. SET_BE32(&cbw->CB[2], start_sector);
  231. SET_BE16(&cbw->CB[7], nsectors);
  232. usbh_msc_cbw_dump(cbw);
  233. /* Send the CBW */
  234. nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
  235. if (nbytes >= 0) {
  236. /* Send the user data */
  237. nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)buffer, msc_class->blocksize * nsectors, CONFIG_USBHOST_MSC_TIMEOUT);
  238. if (nbytes >= 0) {
  239. /* Receive the CSW */
  240. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
  241. if (nbytes >= 0) {
  242. usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
  243. }
  244. }
  245. }
  246. return nbytes < 0 ? (int)nbytes : 0;
  247. }
  248. int usbh_msc_scsi_read10(struct usbh_msc *msc_class, uint32_t start_sector, const uint8_t *buffer, uint32_t nsectors)
  249. {
  250. int nbytes;
  251. struct CBW *cbw;
  252. /* Construct the CBW */
  253. cbw = (struct CBW *)msc_class->tx_buffer;
  254. memset(cbw, 0, USB_SIZEOF_MSC_CBW);
  255. cbw->dSignature = MSC_CBW_Signature;
  256. cbw->dDataLength = (msc_class->blocksize * nsectors);
  257. cbw->bmFlags = 0x80;
  258. cbw->bCBLength = SCSICMD_READ10_SIZEOF;
  259. cbw->CB[0] = SCSI_CMD_READ10;
  260. SET_BE32(&cbw->CB[2], start_sector);
  261. SET_BE16(&cbw->CB[7], nsectors);
  262. usbh_msc_cbw_dump(cbw);
  263. /* Send the CBW */
  264. nbytes = usbh_ep_bulk_transfer(msc_class->bulkout, (uint8_t *)cbw, USB_SIZEOF_MSC_CBW, CONFIG_USBHOST_MSC_TIMEOUT);
  265. if (nbytes >= 0) {
  266. /* Receive the user data */
  267. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, (uint8_t *)buffer, msc_class->blocksize * nsectors, CONFIG_USBHOST_MSC_TIMEOUT);
  268. if (nbytes >= 0) {
  269. /* Receive the CSW */
  270. nbytes = usbh_ep_bulk_transfer(msc_class->bulkin, msc_class->tx_buffer, USB_SIZEOF_MSC_CSW, CONFIG_USBHOST_MSC_TIMEOUT);
  271. if (nbytes >= 0) {
  272. usbh_msc_csw_dump((struct CSW *)msc_class->tx_buffer);
  273. }
  274. }
  275. }
  276. return nbytes < 0 ? (int)nbytes : 0;
  277. }
  278. static int usbh_msc_connect(struct usbh_hubport *hport, uint8_t intf)
  279. {
  280. struct usbh_endpoint_cfg ep_cfg = { 0 };
  281. struct usb_endpoint_descriptor *ep_desc;
  282. int ret;
  283. struct usbh_msc *msc_class = usb_malloc(sizeof(struct usbh_msc));
  284. if (msc_class == NULL) {
  285. USB_LOG_ERR("Fail to alloc msc_class\r\n");
  286. return -ENOMEM;
  287. }
  288. memset(msc_class, 0, sizeof(struct usbh_msc));
  289. usbh_msc_devno_alloc(msc_class);
  290. msc_class->hport = hport;
  291. msc_class->intf = intf;
  292. hport->config.intf[intf].priv = msc_class;
  293. msc_class->tx_buffer = usb_iomalloc(64);
  294. if (msc_class->tx_buffer == NULL) {
  295. USB_LOG_ERR("Fail to alloc tx_buffer\r\n");
  296. return -ENOMEM;
  297. }
  298. ret = usbh_msc_get_maxlun(msc_class, msc_class->tx_buffer);
  299. if (ret < 0) {
  300. return ret;
  301. }
  302. USB_LOG_INFO("Get max LUN:%u\r\n", msc_class->tx_buffer[0] + 1);
  303. for (uint8_t i = 0; i < hport->config.intf[intf].intf_desc.bNumEndpoints; i++) {
  304. ep_desc = &hport->config.intf[intf].ep[i].ep_desc;
  305. ep_cfg.ep_addr = ep_desc->bEndpointAddress;
  306. ep_cfg.ep_type = ep_desc->bmAttributes & USB_ENDPOINT_TYPE_MASK;
  307. ep_cfg.ep_mps = ep_desc->wMaxPacketSize;
  308. ep_cfg.ep_interval = ep_desc->bInterval;
  309. ep_cfg.hport = hport;
  310. if (ep_desc->bEndpointAddress & 0x80) {
  311. usbh_ep_alloc(&msc_class->bulkin, &ep_cfg);
  312. } else {
  313. usbh_ep_alloc(&msc_class->bulkout, &ep_cfg);
  314. }
  315. }
  316. ret = usbh_msc_scsi_testunitready(msc_class);
  317. if (ret < 0) {
  318. USB_LOG_ERR("Fail to scsi_testunitready\r\n");
  319. return ret;
  320. }
  321. ret = usbh_msc_scsi_inquiry(msc_class);
  322. if (ret < 0) {
  323. USB_LOG_ERR("Fail to scsi_inquiry\r\n");
  324. return ret;
  325. }
  326. ret = usbh_msc_scsi_readcapacity10(msc_class);
  327. if (ret < 0) {
  328. USB_LOG_ERR("Fail to scsi_readcapacity10\r\n");
  329. return ret;
  330. }
  331. if (msc_class->blocksize) {
  332. USB_LOG_INFO("Capacity info:\r\n");
  333. USB_LOG_INFO("Block num:%d,block size:%d\r\n", (unsigned int)msc_class->blocknum, (unsigned int)msc_class->blocksize);
  334. } else {
  335. USB_LOG_ERR("Fail to read capacity10\r\n");
  336. return -ERANGE;
  337. }
  338. snprintf(hport->config.intf[intf].devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, msc_class->sdchar);
  339. USB_LOG_INFO("Register MSC Class:%s\r\n", hport->config.intf[intf].devname);
  340. extern int msc_test();
  341. msc_test();
  342. return ret;
  343. }
  344. static int usbh_msc_disconnect(struct usbh_hubport *hport, uint8_t intf)
  345. {
  346. int ret = 0;
  347. struct usbh_msc *msc_class = (struct usbh_msc *)hport->config.intf[intf].priv;
  348. if (msc_class) {
  349. usbh_msc_devno_free(msc_class);
  350. if (msc_class->bulkin) {
  351. ret = usb_ep_cancel(msc_class->bulkin);
  352. if (ret < 0) {
  353. }
  354. usbh_ep_free(msc_class->bulkin);
  355. }
  356. if (msc_class->bulkout) {
  357. ret = usb_ep_cancel(msc_class->bulkout);
  358. if (ret < 0) {
  359. }
  360. usbh_ep_free(msc_class->bulkout);
  361. }
  362. if (msc_class->tx_buffer)
  363. usb_iofree(msc_class->tx_buffer);
  364. usb_free(msc_class);
  365. if (hport->config.intf[intf].devname[0] != '\0')
  366. USB_LOG_INFO("Unregister MSC Class:%s\r\n", hport->config.intf[intf].devname);
  367. memset(hport->config.intf[intf].devname, 0, CONFIG_USBHOST_DEV_NAMELEN);
  368. hport->config.intf[intf].priv = NULL;
  369. }
  370. return ret;
  371. }
  372. const struct usbh_class_driver msc_class_driver = {
  373. .driver_name = "msc",
  374. .connect = usbh_msc_connect,
  375. .disconnect = usbh_msc_disconnect
  376. };
  377. CLASS_INFO_DEFINE const struct usbh_class_info msc_class_info = {
  378. .match_flags = USB_CLASS_MATCH_INTF_CLASS | USB_CLASS_MATCH_INTF_SUBCLASS | USB_CLASS_MATCH_INTF_PROTOCOL,
  379. .class = USB_DEVICE_CLASS_MASS_STORAGE,
  380. .subclass = MSC_SUBCLASS_SCSI,
  381. .protocol = MSC_PROTOCOL_BULK_ONLY,
  382. .vid = 0x00,
  383. .pid = 0x00,
  384. .class_driver = &msc_class_driver
  385. };