usbh_enum.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*!
  2. \file usbh_enum.c
  3. \brief USB host mode enumberation driver
  4. \version 2019-6-5, V1.0.0, firmware for GD32 USBFS&USBHS
  5. */
  6. /*
  7. Copyright (c) 2019, GigaDevice Semiconductor Inc.
  8. Redistribution and use in source and binary forms, with or without modification,
  9. are permitted provided that the following conditions are met:
  10. 1. Redistributions of source code must retain the above copyright notice, this
  11. list of conditions and the following disclaimer.
  12. 2. Redistributions in binary form must reproduce the above copyright notice,
  13. this list of conditions and the following disclaimer in the documentation
  14. and/or other materials provided with the distribution.
  15. 3. Neither the name of the copyright holder nor the names of its contributors
  16. may be used to endorse or promote products derived from this software without
  17. specific prior written permission.
  18. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  21. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
  22. INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  23. NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  24. PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  25. WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  26. ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
  27. OF SUCH DAMAGE.
  28. */
  29. #include "usbh_transc.h"
  30. #include "usbh_enum.h"
  31. static void usbh_devdesc_parse(usb_desc_dev* cfg_desc, uint8_t* buf, uint16_t len);
  32. static void usbh_cfgset_parse(usb_dev_prop* udev, uint8_t* buf);
  33. static void usbh_cfgdesc_parse(usb_desc_config* cfg_desc, uint8_t* buf);
  34. static void usbh_itfdesc_parse(usb_desc_itf* itf_desc, uint8_t* buf);
  35. static void usbh_epdesc_parse(usb_desc_ep* ep_desc, uint8_t* buf);
  36. static void usbh_strdesc_parse(uint8_t* psrc, uint8_t* pdest, uint16_t len);
  37. /*!
  38. \brief configure USB control status parameters
  39. \param[in] puhost: pointer to usb host
  40. \param[in] buf: control transfer data buffer pointer
  41. \param[in] len: length of the data buffer
  42. \param[out] none
  43. \retval none
  44. */
  45. void usbh_ctlstate_config(usbh_host* puhost, uint8_t* buf, uint16_t len)
  46. {
  47. /* prepare the transactions */
  48. puhost->control.buf = buf;
  49. puhost->control.ctl_len = len;
  50. puhost->control.ctl_state = CTL_SETUP;
  51. }
  52. /*!
  53. \brief get device descriptor from the USB device
  54. \param[in] pudev: pointer to usb core instance
  55. \param[in] puhost: pointer to usb host
  56. \param[in] len: length of the descriptor
  57. \param[out] none
  58. \retval operation status
  59. */
  60. usbh_status usbh_devdesc_get(usb_core_driver* pudev, usbh_host* puhost, uint8_t len)
  61. {
  62. usbh_status status = USBH_BUSY;
  63. usbh_control* usb_ctl = &puhost->control;
  64. if (CTL_IDLE == usb_ctl->ctl_state) {
  65. usb_ctl->setup.req = (usb_req) {
  66. .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
  67. .bRequest = USB_GET_DESCRIPTOR,
  68. .wValue = USBH_DESC(USB_DESCTYPE_DEV),
  69. .wIndex = 0U,
  70. .wLength = len
  71. };
  72. usbh_ctlstate_config(puhost, pudev->host.rx_buf, len);
  73. }
  74. status = usbh_ctl_handler(pudev, puhost);
  75. if (USBH_OK == status) {
  76. /* commands successfully sent and response received */
  77. usbh_devdesc_parse(&puhost->dev_prop.dev_desc, pudev->host.rx_buf, len);
  78. }
  79. return status;
  80. }
  81. /*!
  82. \brief get configuration descriptor from the USB device
  83. \param[in] pudev: pointer to usb core instance
  84. \param[in] puhost: pointer to usb host
  85. \param[in] len: length of the descriptor
  86. \param[out] none
  87. \retval operation status
  88. */
  89. usbh_status usbh_cfgdesc_get(usb_core_driver* pudev, usbh_host* puhost, uint16_t len)
  90. {
  91. usbh_status status = USBH_BUSY;
  92. usbh_control* usb_ctl = &puhost->control;
  93. if (CTL_IDLE == usb_ctl->ctl_state) {
  94. usb_ctl->setup.req = (usb_req) {
  95. .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
  96. .bRequest = USB_GET_DESCRIPTOR,
  97. .wValue = USBH_DESC(USB_DESCTYPE_CONFIG),
  98. .wIndex = 0U,
  99. .wLength = len
  100. };
  101. usbh_ctlstate_config(puhost, pudev->host.rx_buf, len);
  102. }
  103. status = usbh_ctl_handler(pudev, puhost);
  104. if (USBH_OK == status) {
  105. if (len <= USB_CFG_DESC_LEN) {
  106. usbh_cfgdesc_parse(&puhost->dev_prop.cfg_desc, pudev->host.rx_buf);
  107. } else {
  108. usbh_cfgset_parse(&puhost->dev_prop, pudev->host.rx_buf);
  109. }
  110. }
  111. return status;
  112. }
  113. /*!
  114. \brief get string descriptor from the USB device
  115. \param[in] pudev: pointer to usb core instance
  116. \param[in] puhost: pointer to usb host
  117. \param[in] str_index: index for the string descriptor
  118. \param[in] buf: buffer pointer to the string descriptor
  119. \param[in] len: length of the descriptor
  120. \param[out] none
  121. \retval operation status
  122. */
  123. usbh_status usbh_strdesc_get(usb_core_driver* pudev,
  124. usbh_host* puhost,
  125. uint8_t str_index,
  126. uint8_t* buf,
  127. uint16_t len)
  128. {
  129. usbh_status status = USBH_BUSY;
  130. usbh_control* usb_ctl = &puhost->control;
  131. if (CTL_IDLE == usb_ctl->ctl_state) {
  132. usb_ctl->setup.req = (usb_req) {
  133. .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
  134. .bRequest = USB_GET_DESCRIPTOR,
  135. .wValue = USBH_DESC(USB_DESCTYPE_STR) | str_index,
  136. .wIndex = 0x0409U,
  137. .wLength = len
  138. };
  139. usbh_ctlstate_config(puhost, pudev->host.rx_buf, len);
  140. }
  141. status = usbh_ctl_handler(pudev, puhost);
  142. if (USBH_OK == status) {
  143. /* commands successfully sent and response received */
  144. usbh_strdesc_parse(pudev->host.rx_buf, buf, len);
  145. }
  146. return status;
  147. }
  148. /*!
  149. \brief set the address to the connected device
  150. \param[in] pudev: pointer to usb core instance
  151. \param[in] puhost: pointer to usb host
  152. \param[in] dev_addr: device address to assign
  153. \param[out] none
  154. \retval operation status
  155. */
  156. usbh_status usbh_setaddress(usb_core_driver* pudev, usbh_host* puhost, uint8_t dev_addr)
  157. {
  158. usbh_status status = USBH_BUSY;
  159. usbh_control* usb_ctl = &puhost->control;
  160. if (CTL_IDLE == usb_ctl->ctl_state) {
  161. usb_ctl->setup.req = (usb_req) {
  162. .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
  163. .bRequest = USB_SET_ADDRESS,
  164. .wValue = (uint16_t)dev_addr,
  165. .wIndex = 0U,
  166. .wLength = 0U
  167. };
  168. usbh_ctlstate_config(puhost, NULL, 0U);
  169. }
  170. status = usbh_ctl_handler(pudev, puhost);
  171. return status;
  172. }
  173. /*!
  174. \brief set the configuration value to the connected device
  175. \param[in] pudev: pointer to usb core instance
  176. \param[in] puhost: pointer to usb host
  177. \param[in] config_index: configuration value
  178. \param[out] none
  179. \retval operation status
  180. */
  181. usbh_status usbh_setcfg(usb_core_driver* pudev, usbh_host* puhost, uint16_t config_index)
  182. {
  183. usbh_status status = USBH_BUSY;
  184. usbh_control* usb_ctl = &puhost->control;
  185. if (CTL_IDLE == usb_ctl->ctl_state) {
  186. usb_ctl->setup.req = (usb_req) {
  187. .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
  188. .bRequest = USB_SET_CONFIGURATION,
  189. .wValue = config_index,
  190. .wIndex = 0U,
  191. .wLength = 0U
  192. };
  193. usbh_ctlstate_config(puhost, NULL, 0U);
  194. }
  195. status = usbh_ctl_handler(pudev, puhost);
  196. return status;
  197. }
  198. /*!
  199. \brief set the interface value to the connected device
  200. \param[in] pudev: pointer to usb core instance
  201. \param[in] puhost: pointer to usb host
  202. \param[in] ep_num: endpoint number
  203. \param[in] alter_setting: altnated setting value
  204. \param[out] none
  205. \retval operation status
  206. */
  207. usbh_status usbh_setinterface(usb_core_driver* pudev,
  208. usbh_host* puhost,
  209. uint8_t ep_num,
  210. uint8_t set)
  211. {
  212. usbh_status status = USBH_BUSY;
  213. usbh_control* usb_ctl = &puhost->control;
  214. if (CTL_IDLE == usb_ctl->ctl_state) {
  215. usb_ctl->setup.req = (usb_req) {
  216. .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_ITF | USB_REQTYPE_STRD,
  217. .bRequest = USB_SET_INTERFACE,
  218. .wValue = set,
  219. .wIndex = ep_num,
  220. .wLength = 0U
  221. };
  222. usbh_ctlstate_config(puhost, NULL, 0U);
  223. }
  224. status = usbh_ctl_handler(pudev, puhost);
  225. return status;
  226. }
  227. /*!
  228. \brief clear or disable a specific feature
  229. \param[in] pudev: pointer to usb core instance
  230. \param[in] puhost: pointer to usb host
  231. \param[in] ep_addr: endpoint address
  232. \param[in] pp_num: pipe number
  233. \param[out] none
  234. \retval operation status
  235. */
  236. usbh_status usbh_clrfeature(usb_core_driver* pudev,
  237. usbh_host* puhost,
  238. uint8_t ep_addr,
  239. uint8_t pp_num)
  240. {
  241. usbh_status status = USBH_BUSY;
  242. usbh_control* usb_ctl = &puhost->control;
  243. if (CTL_IDLE == usb_ctl->ctl_state) {
  244. usb_ctl->setup.req = (usb_req) {
  245. .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_EP | USB_REQTYPE_STRD,
  246. .bRequest = USB_CLEAR_FEATURE,
  247. .wValue = FEATURE_SELECTOR_EP,
  248. .wIndex = ep_addr,
  249. .wLength = 0
  250. };
  251. if (EP_DIR(ep_addr)) {
  252. pudev->host.pipe[pp_num].data_toggle_in = 0U;
  253. } else {
  254. pudev->host.pipe[pp_num].data_toggle_out = 0U;
  255. }
  256. usbh_ctlstate_config(puhost, NULL, 0U);
  257. }
  258. status = usbh_ctl_handler(pudev, puhost);
  259. return status;
  260. }
  261. /*!
  262. \brief parse the device descriptor
  263. \param[in] dev_desc: pointer to usb device descriptor buffer
  264. \param[in] buf: pointer to the source descriptor buffer
  265. \param[in] len: length of the descriptor
  266. \param[out] none
  267. \retval operation status
  268. */
  269. static void usbh_devdesc_parse(usb_desc_dev* dev_desc, uint8_t* buf, uint16_t len)
  270. {
  271. *dev_desc = (usb_desc_dev) {
  272. .header = {
  273. .bLength = *(uint8_t*)(buf + 0U),
  274. .bDescriptorType = *(uint8_t*)(buf + 1U)
  275. },
  276. .bcdUSB = BYTE_SWAP(buf + 2U),
  277. .bDeviceClass = *(uint8_t*)(buf + 4U),
  278. .bDeviceSubClass = *(uint8_t*)(buf + 5U),
  279. .bDeviceProtocol = *(uint8_t*)(buf + 6U),
  280. .bMaxPacketSize0 = *(uint8_t*)(buf + 7U)
  281. };
  282. if (len > 8U) {
  283. /* for 1st time after device connection, host may issue only 8 bytes for device descriptor length */
  284. dev_desc->idVendor = BYTE_SWAP(buf + 8U);
  285. dev_desc->idProduct = BYTE_SWAP(buf + 10U);
  286. dev_desc->bcdDevice = BYTE_SWAP(buf + 12U);
  287. dev_desc->iManufacturer = *(uint8_t*)(buf + 14U);
  288. dev_desc->iProduct = *(uint8_t*)(buf + 15U);
  289. dev_desc->iSerialNumber = *(uint8_t*)(buf + 16U);
  290. dev_desc->bNumberConfigurations = *(uint8_t*)(buf + 17U);
  291. }
  292. }
  293. /*!
  294. \brief parse the configuration descriptor
  295. \param[in] cfg_desc: pointer to usb configuration descriptor buffer
  296. \param[in] buf: pointer to the source descriptor buffer
  297. \param[out] none
  298. \retval operation status
  299. */
  300. static void usbh_cfgdesc_parse(usb_desc_config* cfg_desc, uint8_t* buf)
  301. {
  302. /* parse configuration descriptor */
  303. *cfg_desc = (usb_desc_config) {
  304. .header = {
  305. .bLength = *(uint8_t*)(buf + 0U),
  306. .bDescriptorType = *(uint8_t*)(buf + 1U),
  307. },
  308. .wTotalLength = BYTE_SWAP(buf + 2U),
  309. .bNumInterfaces = *(uint8_t*)(buf + 4U),
  310. .bConfigurationValue = *(uint8_t*)(buf + 5U),
  311. .iConfiguration = *(uint8_t*)(buf + 6U),
  312. .bmAttributes = *(uint8_t*)(buf + 7U),
  313. .bMaxPower = *(uint8_t*)(buf + 8U)
  314. };
  315. }
  316. /*!
  317. \brief parse the configuration descriptor set
  318. \param[in] udev: pointer to USB core instance
  319. \param[in] buf: pointer to the source descriptor buffer
  320. \param[out] none
  321. \retval operation status
  322. */
  323. static void usbh_cfgset_parse(usb_dev_prop* udev, uint8_t* buf)
  324. {
  325. usb_desc_ep* ep = NULL;
  326. usb_desc_itf* itf = NULL, itf_value;
  327. usb_desc_header* pdesc = (usb_desc_header*)buf;
  328. int8_t itf_index = 0U, ep_index = 0U;
  329. uint16_t ptr;
  330. uint8_t prev_itf = 0U;
  331. uint16_t prev_ep_len = 0U;
  332. /* parse configuration descriptor */
  333. usbh_cfgdesc_parse(&udev->cfg_desc, buf);
  334. ptr = USB_CFG_DESC_LEN;
  335. if (udev->cfg_desc.bNumInterfaces > USBH_MAX_INTERFACES_NUM) {
  336. return;
  337. }
  338. while (ptr < udev->cfg_desc.wTotalLength) {
  339. pdesc = usbh_nextdesc_get((uint8_t*)pdesc, &ptr);
  340. if (pdesc->bDescriptorType == USB_DESCTYPE_ITF) {
  341. itf_index = *(((uint8_t*)pdesc) + 2U);
  342. itf = &udev->itf_desc[itf_index];
  343. if ((*((uint8_t*)pdesc + 3U)) < 3U) {
  344. usbh_itfdesc_parse(&itf_value, (uint8_t*)pdesc);
  345. /* parse endpoint descriptors relative to the current interface */
  346. if (itf_value.bNumEndpoints > USBH_MAX_EP_NUM) {
  347. return;
  348. }
  349. for (ep_index = 0; ep_index < itf_value.bNumEndpoints;) {
  350. pdesc = usbh_nextdesc_get((void*)pdesc, &ptr);
  351. if (pdesc->bDescriptorType == USB_DESCTYPE_EP) {
  352. ep = &udev->ep_desc[itf_index][ep_index];
  353. if (prev_itf != itf_index) {
  354. prev_itf = itf_index;
  355. usbh_itfdesc_parse(itf, (uint8_t*)&itf_value);
  356. } else {
  357. if (prev_ep_len > BYTE_SWAP((uint8_t*)pdesc + 4U)) {
  358. break;
  359. } else {
  360. usbh_itfdesc_parse(itf, (uint8_t*)&itf_value);
  361. }
  362. }
  363. usbh_epdesc_parse(ep, (uint8_t*)pdesc);
  364. prev_ep_len = BYTE_SWAP((uint8_t*)pdesc + 4U);
  365. ep_index++;
  366. }
  367. }
  368. }
  369. }
  370. }
  371. }
  372. /*!
  373. \brief parse the interface descriptor
  374. \param[in] itf_desc: pointer to usb interface descriptor buffer
  375. \param[in] buf: pointer to the source descriptor buffer
  376. \param[out] none
  377. \retval operation status
  378. */
  379. static void usbh_itfdesc_parse(usb_desc_itf* itf_desc, uint8_t* buf)
  380. {
  381. *itf_desc = (usb_desc_itf) {
  382. .header = {
  383. .bLength = *(uint8_t*)(buf + 0U),
  384. .bDescriptorType = *(uint8_t*)(buf + 1U),
  385. },
  386. .bInterfaceNumber = *(uint8_t*)(buf + 2U),
  387. .bAlternateSetting = *(uint8_t*)(buf + 3U),
  388. .bNumEndpoints = *(uint8_t*)(buf + 4U),
  389. .bInterfaceClass = *(uint8_t*)(buf + 5U),
  390. .bInterfaceSubClass = *(uint8_t*)(buf + 6U),
  391. .bInterfaceProtocol = *(uint8_t*)(buf + 7U),
  392. .iInterface = *(uint8_t*)(buf + 8U)
  393. };
  394. }
  395. /*!
  396. \brief parse the endpoint descriptor
  397. \param[in] ep_desc: pointer to usb endpoint descriptor buffer
  398. \param[in] buf: pointer to the source descriptor buffer
  399. \param[out] none
  400. \retval operation status
  401. */
  402. static void usbh_epdesc_parse(usb_desc_ep* ep_desc, uint8_t* buf)
  403. {
  404. *ep_desc = (usb_desc_ep) {
  405. .header = {
  406. .bLength = *(uint8_t*)(buf + 0U),
  407. .bDescriptorType = *(uint8_t*)(buf + 1U)
  408. },
  409. .bEndpointAddress = *(uint8_t*)(buf + 2U),
  410. .bmAttributes = *(uint8_t*)(buf + 3U),
  411. .wMaxPacketSize = BYTE_SWAP(buf + 4U),
  412. .bInterval = *(uint8_t*)(buf + 6U)
  413. };
  414. }
  415. /*!
  416. \brief parse the string descriptor
  417. \param[in] psrc: source pointer containing the descriptor data
  418. \param[in] pdest: destination address pointer
  419. \param[in] len: length of the descriptor
  420. \param[out] none
  421. \retval operation status
  422. */
  423. static void usbh_strdesc_parse(uint8_t* psrc, uint8_t* pdest, uint16_t len)
  424. {
  425. uint16_t str_len = 0U, index = 0U;
  426. /* the unicode string descriptor is not NULL-terminated. The string length is
  427. * computed by substracting two from the value of the first byte of the descriptor.
  428. */
  429. /* check which is lower size, the size of string or the length of bytes read from the device */
  430. if (USB_DESCTYPE_STR == psrc[1]) {
  431. /* make sure the descriptor is string type */
  432. /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */
  433. str_len = USB_MIN(psrc[0] - 2U, len);
  434. psrc += 2U; /* adjust the offset ignoring the string len and descriptor type */
  435. for (index = 0U; index < str_len; index += 2U) {
  436. /* copy only the string and ignore the unicode id, hence add the src */
  437. *pdest = psrc[index];
  438. pdest++;
  439. }
  440. *pdest = 0U; /* mark end of string */
  441. }
  442. }
  443. /*!
  444. \brief get the next descriptor header
  445. \param[in] pbuf: pointer to buffer where the configuration descriptor set is available
  446. \param[in] ptr: data popinter inside the configuration descriptor set
  447. \param[out] none
  448. \retval operation status
  449. */
  450. usb_desc_header* usbh_nextdesc_get(uint8_t* pbuf, uint16_t* ptr)
  451. {
  452. usb_desc_header* pnext;
  453. *ptr += ((usb_desc_header*)pbuf)->bLength;
  454. pnext = (usb_desc_header*)((uint8_t*)pbuf + ((usb_desc_header*)pbuf)->bLength);
  455. return (pnext);
  456. }