1 /*!
2 \file usbh_enum.c
3 \brief USB host mode enumeration driver
4
5 \version 2020-08-04, V1.1.0, firmware for GD32VF103
6 */
7
8 /*
9 Copyright (c) 2020, GigaDevice Semiconductor Inc.
10
11 Redistribution and use in source and binary forms, with or without modification,
12 are permitted provided that the following conditions are met:
13
14 1. Redistributions of source code must retain the above copyright notice, this
15 list of conditions and the following disclaimer.
16 2. Redistributions in binary form must reproduce the above copyright notice,
17 this list of conditions and the following disclaimer in the documentation
18 and/or other materials provided with the distribution.
19 3. Neither the name of the copyright holder nor the names of its contributors
20 may be used to endorse or promote products derived from this software without
21 specific prior written permission.
22
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
24 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
27 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
30 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 OF SUCH DAMAGE.
33 */
34
35 #include "usbh_pipe.h"
36 #include "usbh_transc.h"
37 #include "usbh_enum.h"
38
39 /* local function prototypes ('static') */
40 static void usbh_devdesc_parse (usb_desc_dev *dev_desc, uint8_t *buf, uint16_t len);
41 static void usbh_cfgdesc_parse (usb_desc_config *cfg_desc, uint8_t *buf);
42 static void usbh_cfgset_parse (usb_dev_prop *udev, uint8_t *buf);
43 static void usbh_itfdesc_parse (usb_desc_itf *itf_desc, uint8_t *buf);
44 static void usbh_epdesc_parse (usb_desc_ep *ep_desc, uint8_t *buf);
45 static void usbh_strdesc_parse (uint8_t *psrc, uint8_t *pdest, uint16_t len);
46
47 /*!
48 \brief configure USB control status parameters
49 \param[in] puhost: pointer to usb host
50 \param[in] buf: control transfer data buffer pointer
51 \param[in] len: length of the data buffer
52 \param[out] none
53 \retval none
54 */
usbh_ctlstate_config(usbh_host * puhost,uint8_t * buf,uint16_t len)55 void usbh_ctlstate_config (usbh_host *puhost, uint8_t *buf, uint16_t len)
56 {
57 /* prepare the transactions */
58 puhost->control.buf = buf;
59 puhost->control.ctl_len = len;
60
61 puhost->control.ctl_state = CTL_SETUP;
62 }
63
64 /*!
65 \brief get device descriptor from the USB device
66 \param[in] puhost: pointer to usb host
67 \param[in] len: length of the descriptor
68 \param[out] none
69 \retval operation status
70 */
usbh_devdesc_get(usbh_host * puhost,uint8_t len)71 usbh_status usbh_devdesc_get (usbh_host *puhost, uint8_t len)
72 {
73 usbh_status status = USBH_BUSY;
74
75 usbh_control *usb_ctl = &puhost->control;
76
77 if (CTL_IDLE == usb_ctl->ctl_state) {
78 usb_ctl->setup.req = (usb_req) {
79 .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
80 .bRequest = USB_GET_DESCRIPTOR,
81 .wValue = USBH_DESC(USB_DESCTYPE_DEV),
82 .wIndex = 0U,
83 .wLength = len
84 };
85
86 usbh_ctlstate_config (puhost, puhost->dev_prop.data, (uint16_t)len);
87 }
88
89 status = usbh_ctl_handler (puhost);
90
91 if (USBH_OK == status) {
92 /* commands successfully sent and response received */
93 usbh_devdesc_parse (&puhost->dev_prop.dev_desc, puhost->dev_prop.data, (uint16_t)len);
94 }
95
96 return status;
97 }
98
99 /*!
100 \brief get configuration descriptor from the USB device
101 \param[in] puhost: pointer to usb host
102 \param[in] len: length of the descriptor
103 \param[out] none
104 \retval operation status
105 */
usbh_cfgdesc_get(usbh_host * puhost,uint16_t len)106 usbh_status usbh_cfgdesc_get (usbh_host *puhost, uint16_t len)
107 {
108 uint8_t *pdata = NULL;
109
110 usbh_status status = USBH_BUSY;
111
112 usbh_control *usb_ctl = &puhost->control;
113
114 #if (USBH_KEEP_CFG_DESCRIPTOR == 1U)
115 pdata = puhost->dev_prop.cfgdesc_rawdata;
116 #else
117 pdata = puhost->dev_prop.data;
118 #endif
119
120 if (CTL_IDLE == usb_ctl->ctl_state) {
121 usb_ctl->setup.req = (usb_req) {
122 .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
123 .bRequest = USB_GET_DESCRIPTOR,
124 .wValue = USBH_DESC(USB_DESCTYPE_CONFIG),
125 .wIndex = 0U,
126 .wLength = len
127 };
128
129 usbh_ctlstate_config (puhost, pdata, len);
130 }
131
132 status = usbh_ctl_handler (puhost);
133
134 if (USBH_OK == status) {
135 if (len <= USB_CFG_DESC_LEN) {
136 usbh_cfgdesc_parse (&puhost->dev_prop.cfg_desc_set.cfg_desc, pdata);
137 } else {
138 usbh_cfgset_parse (&puhost->dev_prop, pdata);
139 }
140 }
141
142 return status;
143 }
144
145 /*!
146 \brief get string descriptor from the USB device
147 \param[in] puhost: pointer to usb host
148 \param[in] str_index: index for the string descriptor
149 \param[in] buf: buffer pointer to the string descriptor
150 \param[in] len: length of the descriptor
151 \param[out] none
152 \retval operation status
153 */
usbh_strdesc_get(usbh_host * puhost,uint8_t str_index,uint8_t * buf,uint16_t len)154 usbh_status usbh_strdesc_get (usbh_host *puhost,
155 uint8_t str_index,
156 uint8_t *buf,
157 uint16_t len)
158 {
159 usbh_status status = USBH_BUSY;
160
161 usbh_control *usb_ctl = &puhost->control;
162
163 if (CTL_IDLE == usb_ctl->ctl_state) {
164 usb_ctl->setup.req = (usb_req) {
165 .bmRequestType = USB_TRX_IN | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
166 .bRequest = USB_GET_DESCRIPTOR,
167 .wValue = USBH_DESC(USB_DESCTYPE_STR) | str_index,
168 .wIndex = 0x0409U,
169 .wLength = len
170 };
171
172 usbh_ctlstate_config (puhost, puhost->dev_prop.data, len);
173 }
174
175 status = usbh_ctl_handler (puhost);
176
177 if (USBH_OK == status) {
178 /* commands successfully sent and response received */
179 usbh_strdesc_parse (puhost->dev_prop.data, buf, len);
180 }
181
182 return status;
183 }
184
185 /*!
186 \brief set the address to the connected device
187 \param[in] puhost: pointer to usb host
188 \param[in] dev_addr: device address to assign
189 \param[out] none
190 \retval operation status
191 */
usbh_setaddress(usbh_host * puhost,uint8_t dev_addr)192 usbh_status usbh_setaddress (usbh_host *puhost, uint8_t dev_addr)
193 {
194 usbh_status status = USBH_BUSY;
195
196 usbh_control *usb_ctl = &puhost->control;
197
198 if (CTL_IDLE == usb_ctl->ctl_state) {
199 usb_ctl->setup.req = (usb_req) {
200 .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
201 .bRequest = USB_SET_ADDRESS,
202 .wValue = (uint16_t)dev_addr,
203 .wIndex = 0U,
204 .wLength = 0U
205 };
206
207 usbh_ctlstate_config (puhost, NULL, 0U);
208 }
209
210 status = usbh_ctl_handler (puhost);
211
212 return status;
213 }
214
215 /*!
216 \brief set the configuration value to the connected device
217 \param[in] puhost: pointer to usb host
218 \param[in] config_index: configuration value
219 \param[out] none
220 \retval operation status
221 */
usbh_setcfg(usbh_host * puhost,uint16_t config_index)222 usbh_status usbh_setcfg (usbh_host *puhost, uint16_t config_index)
223 {
224 usbh_status status = USBH_BUSY;
225
226 usbh_control *usb_ctl = &puhost->control;
227
228 if (CTL_IDLE == usb_ctl->ctl_state) {
229 usb_ctl->setup.req = (usb_req) {
230 .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
231 .bRequest = USB_SET_CONFIGURATION,
232 .wValue = config_index,
233 .wIndex = 0U,
234 .wLength = 0U
235 };
236
237 usbh_ctlstate_config (puhost, NULL, 0U);
238 }
239
240 status = usbh_ctl_handler (puhost);
241
242 return status;
243 }
244
245 /*!
246 \brief set the interface value to the connected device
247 \param[in] puhost: pointer to usb host
248 \param[in] itf_num: interface number
249 \param[in] set: alternated setting value
250 \param[out] none
251 \retval operation status
252 */
usbh_setinterface(usbh_host * puhost,uint8_t itf_num,uint8_t set)253 usbh_status usbh_setinterface (usbh_host *puhost, uint8_t itf_num, uint8_t set)
254 {
255 usbh_status status = USBH_BUSY;
256
257 usbh_control *usb_ctl = &puhost->control;
258
259 if (CTL_IDLE == usb_ctl->ctl_state) {
260 usb_ctl->setup.req = (usb_req) {
261 .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_ITF | USB_REQTYPE_STRD,
262 .bRequest = USB_SET_INTERFACE,
263 .wValue = set,
264 .wIndex = itf_num,
265 .wLength = 0U
266 };
267
268 usbh_ctlstate_config (puhost, NULL, 0U);
269 }
270
271 status = usbh_ctl_handler (puhost);
272
273 return status;
274 }
275
276 /*!
277 \brief set the interface value to the connected device
278 \param[in] puhost: pointer to usb host
279 \param[in] feature_selector: feature selector
280 \param[in] windex: index value
281 \param[out] none
282 \retval operation status
283 */
usbh_setdevfeature(usbh_host * puhost,uint8_t feature_selector,uint16_t windex)284 usbh_status usbh_setdevfeature (usbh_host *puhost, uint8_t feature_selector, uint16_t windex)
285 {
286 usbh_status status = USBH_BUSY;
287
288 usbh_control *usb_ctl = &puhost->control;
289
290 if (CTL_IDLE == usb_ctl->ctl_state) {
291 usb_ctl->setup.req = (usb_req) {
292 .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
293 .bRequest = USB_SET_FEATURE,
294 .wValue = feature_selector,
295 .wIndex = windex,
296 .wLength = 0U
297 };
298
299 usbh_ctlstate_config (puhost, NULL, 0U);
300 }
301
302 status = usbh_ctl_handler (puhost);
303
304 return status;
305 }
306
307 /*!
308 \brief clear the interface value to the connected device
309 \param[in] puhost: pointer to usb host
310 \param[in] feature_selector: feature selector
311 \param[in] windex: index value
312 \param[out] none
313 \retval operation status
314 */
usbh_clrdevfeature(usbh_host * puhost,uint8_t feature_selector,uint16_t windex)315 usbh_status usbh_clrdevfeature (usbh_host *puhost, uint8_t feature_selector, uint16_t windex)
316 {
317 usbh_status status = USBH_BUSY;
318
319 usbh_control *usb_ctl = &puhost->control;
320
321 if (CTL_IDLE == usb_ctl->ctl_state) {
322 usb_ctl->setup.req = (usb_req) {
323 .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_DEV | USB_REQTYPE_STRD,
324 .bRequest = USB_CLEAR_FEATURE,
325 .wValue = feature_selector,
326 .wIndex = windex,
327 .wLength = 0U
328 };
329
330 usbh_ctlstate_config (puhost, NULL, 0U);
331 }
332
333 status = usbh_ctl_handler (puhost);
334
335 return status;
336 }
337
338 /*!
339 \brief clear or disable a specific feature
340 \param[in] puhost: pointer to usb host
341 \param[in] ep_addr: endpoint address
342 \param[in] pp_num: pipe number
343 \param[out] none
344 \retval operation status
345 */
usbh_clrfeature(usbh_host * puhost,uint8_t ep_addr,uint8_t pp_num)346 usbh_status usbh_clrfeature (usbh_host *puhost, uint8_t ep_addr, uint8_t pp_num)
347 {
348 usbh_status status = USBH_BUSY;
349 usbh_control *usb_ctl = &puhost->control;
350 usb_core_driver *pudev = (usb_core_driver *)puhost->data;
351
352 if (CTL_IDLE == usb_ctl->ctl_state) {
353 usb_ctl->setup.req = (usb_req) {
354 .bmRequestType = USB_TRX_OUT | USB_RECPTYPE_EP | USB_REQTYPE_STRD,
355 .bRequest = USB_CLEAR_FEATURE,
356 .wValue = FEATURE_SELECTOR_EP,
357 .wIndex = ep_addr,
358 .wLength = 0U
359 };
360
361 if (EP_ID(ep_addr) == pudev->host.pipe[pp_num].ep.num) {
362 usbh_pipe_toggle_set(pudev, pp_num, 0U);
363 } else {
364 return USBH_FAIL;
365 }
366
367 usbh_ctlstate_config (puhost, NULL, 0U);
368 }
369
370 status = usbh_ctl_handler (puhost);
371
372 return status;
373 }
374
375 /*!
376 \brief get the next descriptor header
377 \param[in] pbuf: pointer to buffer where the configuration descriptor set is available
378 \param[in] ptr: data pointer inside the configuration descriptor set
379 \param[out] none
380 \retval return descriptor header
381 */
usbh_nextdesc_get(uint8_t * pbuf,uint16_t * ptr)382 usb_desc_header *usbh_nextdesc_get (uint8_t *pbuf, uint16_t *ptr)
383 {
384 usb_desc_header *pnext;
385
386 *ptr += ((usb_desc_header *)pbuf)->bLength;
387
388 pnext = (usb_desc_header *)((uint8_t *)pbuf + ((usb_desc_header *)pbuf)->bLength);
389
390 return (pnext);
391 }
392
393 /*!
394 \brief get the next descriptor header
395 \param[in] udev: pointer to device property
396 \param[in] interface: interface number
397 \param[out] none
398 \retval operation status
399 */
usbh_interface_select(usb_dev_prop * udev,uint8_t interface)400 usbh_status usbh_interface_select (usb_dev_prop *udev, uint8_t interface)
401 {
402 usbh_status status = USBH_OK;
403
404 if (interface < udev->cfg_desc_set.cfg_desc.bNumInterfaces) {
405 udev->cur_itf = interface;
406 } else {
407 status = USBH_FAIL;
408 }
409
410 return status;
411 }
412
413 /*!
414 \brief find the interface index for a specific class
415 \param[in] udev: pointer to device property
416 \param[in] main_class: class code
417 \param[in] sub_class: subclass code
418 \param[in] protocol: Protocol code
419 \param[out] none
420 \retval interface index in the configuration structure
421 \note interface index 0xFF means interface index not found
422 */
usbh_interface_find(usb_dev_prop * udev,uint8_t main_class,uint8_t sub_class,uint8_t protocol)423 uint8_t usbh_interface_find (usb_dev_prop *udev, uint8_t main_class, uint8_t sub_class, uint8_t protocol)
424 {
425 usb_desc_itf *pif;
426
427 uint8_t if_ix = 0U;
428
429 pif = (usb_desc_itf *)0;
430
431 while (if_ix < udev->cfg_desc_set.cfg_desc.bNumInterfaces) {
432 pif = &udev->cfg_desc_set.itf_desc_set[if_ix][0].itf_desc;
433
434 if (((pif->bInterfaceClass == main_class) || (main_class == 0xFFU))&&
435 ((pif->bInterfaceSubClass == sub_class) || (sub_class == 0xFFU))&&
436 ((pif->bInterfaceProtocol == protocol) || (protocol == 0xFFU))) {
437 return if_ix;
438 }
439
440 if_ix++;
441 }
442
443 return 0xFFU;
444 }
445
446 /*!
447 \brief find the interface index for a specific class interface and alternate setting number
448 \param[in] udev: pointer to device property
449 \param[in] interface_number: interface number
450 \param[in] alt_settings: alternate setting number
451 \param[out] none
452 \retval interface index in the configuration structure
453 \note interface index 0xFF means interface index not found
454 */
usbh_interfaceindex_find(usb_dev_prop * udev,uint8_t interface_number,uint8_t alt_settings)455 uint8_t usbh_interfaceindex_find (usb_dev_prop *udev, uint8_t interface_number, uint8_t alt_settings)
456 {
457 usb_desc_itf *pif;
458
459 uint8_t if_ix = 0U;
460
461 pif = (usb_desc_itf *)0;
462
463 while (if_ix < USBH_MAX_INTERFACES_NUM) {
464 pif = &udev->cfg_desc_set.itf_desc_set[if_ix][alt_settings].itf_desc;
465
466 if ((pif->bInterfaceNumber == interface_number) && (pif->bAlternateSetting == alt_settings)) {
467 return if_ix;
468 }
469
470 if_ix++;
471 }
472
473 return 0xFFU;
474 }
475
476 /*!
477 \brief parse the device descriptor
478 \param[in] dev_desc: pointer to usb device descriptor buffer
479 \param[in] buf: pointer to the source descriptor buffer
480 \param[in] len: length of the descriptor
481 \param[out] none
482 \retval none
483 */
usbh_devdesc_parse(usb_desc_dev * dev_desc,uint8_t * buf,uint16_t len)484 static void usbh_devdesc_parse (usb_desc_dev *dev_desc, uint8_t *buf, uint16_t len)
485 {
486 *dev_desc = (usb_desc_dev) {
487 .header = {
488 .bLength = *(uint8_t *)(buf + 0U),
489 .bDescriptorType = *(uint8_t *)(buf + 1U)
490 },
491
492 .bcdUSB = BYTE_SWAP(buf + 2U),
493 .bDeviceClass = *(uint8_t *)(buf + 4U),
494 .bDeviceSubClass = *(uint8_t *)(buf + 5U),
495 .bDeviceProtocol = *(uint8_t *)(buf + 6U),
496 .bMaxPacketSize0 = *(uint8_t *)(buf + 7U)
497 };
498
499 if (len > 8U) {
500 /* for 1st time after device connection, host may issue only 8 bytes for device descriptor length */
501 dev_desc->idVendor = BYTE_SWAP(buf + 8U);
502 dev_desc->idProduct = BYTE_SWAP(buf + 10U);
503 dev_desc->bcdDevice = BYTE_SWAP(buf + 12U);
504 dev_desc->iManufacturer = *(uint8_t *)(buf + 14U);
505 dev_desc->iProduct = *(uint8_t *)(buf + 15U);
506 dev_desc->iSerialNumber = *(uint8_t *)(buf + 16U);
507 dev_desc->bNumberConfigurations = *(uint8_t *)(buf + 17U);
508 }
509 }
510
511 /*!
512 \brief parse the configuration descriptor
513 \param[in] cfg_desc: pointer to usb configuration descriptor buffer
514 \param[in] buf: pointer to the source descriptor buffer
515 \param[out] none
516 \retval none
517 */
usbh_cfgdesc_parse(usb_desc_config * cfg_desc,uint8_t * buf)518 static void usbh_cfgdesc_parse (usb_desc_config *cfg_desc, uint8_t *buf)
519 {
520 /* parse configuration descriptor */
521 *cfg_desc = (usb_desc_config) {
522 .header = {
523 .bLength = *(uint8_t *)(buf + 0U),
524 .bDescriptorType = *(uint8_t *)(buf + 1U),
525 },
526
527 .wTotalLength = BYTE_SWAP(buf + 2U),
528 .bNumInterfaces = *(uint8_t *)(buf + 4U),
529 .bConfigurationValue = *(uint8_t *)(buf + 5U),
530 .iConfiguration = *(uint8_t *)(buf + 6U),
531 .bmAttributes = *(uint8_t *)(buf + 7U),
532 .bMaxPower = *(uint8_t *)(buf + 8U)
533 };
534 }
535
536 /*!
537 \brief parse the configuration descriptor set
538 \param[in] udev: pointer to device property
539 \param[in] buf: pointer to the source descriptor buffer
540 \param[out] none
541 \retval none
542 */
usbh_cfgset_parse(usb_dev_prop * udev,uint8_t * buf)543 static void usbh_cfgset_parse (usb_dev_prop *udev, uint8_t *buf)
544 {
545 usb_desc_ep *ep = NULL;
546 usb_desc_itf_set *itf = NULL;
547 usb_desc_itf itf_value;
548 usb_desc_config *cfg = NULL;
549
550 usb_desc_header *pdesc = (usb_desc_header *)buf;
551
552 uint8_t itf_index = 0U, ep_index = 0U, alt_setting = 0U;
553 uint8_t pre_itf_index = 0U;
554 uint16_t ptr;
555
556 /* parse configuration descriptor */
557 usbh_cfgdesc_parse (&udev->cfg_desc_set.cfg_desc, buf);
558 cfg = &udev->cfg_desc_set.cfg_desc;
559 ptr = USB_CFG_DESC_LEN;
560
561 if (cfg->bNumInterfaces > USBH_MAX_INTERFACES_NUM) {
562 return;
563 }
564
565 while (ptr < cfg->wTotalLength) {
566 pdesc = usbh_nextdesc_get ((uint8_t *)pdesc, &ptr);
567
568 if (pdesc->bDescriptorType == USB_DESCTYPE_ITF) {
569 itf_index = *(((uint8_t *)pdesc) + 2U);
570
571 if (pre_itf_index != itf_index) {
572 alt_setting = 0U;
573 }
574
575 itf = &udev->cfg_desc_set.itf_desc_set[itf_index][alt_setting];
576
577 alt_setting++;
578
579 if ((*((uint8_t *)pdesc + 3U)) < 3U) {
580 usbh_itfdesc_parse (&itf_value, (uint8_t *)pdesc);
581
582 /* parse endpoint descriptors relative to the current interface */
583 if (itf_value.bNumEndpoints > USBH_MAX_EP_NUM) {
584 return;
585 }
586
587 usbh_itfdesc_parse (&itf->itf_desc, (uint8_t *)&itf_value);
588
589 /* store the previous interface index */
590 pre_itf_index = itf_index;
591
592 if (0U == itf_value.bNumEndpoints) {
593 continue;
594 }
595
596 for (ep_index = 0U; ep_index < itf_value.bNumEndpoints; ) {
597 pdesc = usbh_nextdesc_get ((void*)pdesc, &ptr);
598
599 if (pdesc->bDescriptorType == USB_DESCTYPE_EP) {
600 ep = &itf->ep_desc[ep_index];
601
602 usbh_epdesc_parse (ep, (uint8_t *)pdesc);
603
604 ep_index++;
605 }
606 }
607 }
608 }
609 }
610 }
611
612 /*!
613 \brief parse the interface descriptor
614 \param[in] itf_desc: pointer to usb interface descriptor buffer
615 \param[in] buf: pointer to the source descriptor buffer
616 \param[out] none
617 \retval none
618 */
usbh_itfdesc_parse(usb_desc_itf * itf_desc,uint8_t * buf)619 static void usbh_itfdesc_parse (usb_desc_itf *itf_desc, uint8_t *buf)
620 {
621 *itf_desc = (usb_desc_itf) {
622 .header = {
623 .bLength = *(uint8_t *)(buf + 0U),
624 .bDescriptorType = *(uint8_t *)(buf + 1U),
625 },
626
627 .bInterfaceNumber = *(uint8_t *)(buf + 2U),
628 .bAlternateSetting = *(uint8_t *)(buf + 3U),
629 .bNumEndpoints = *(uint8_t *)(buf + 4U),
630 .bInterfaceClass = *(uint8_t *)(buf + 5U),
631 .bInterfaceSubClass = *(uint8_t *)(buf + 6U),
632 .bInterfaceProtocol = *(uint8_t *)(buf + 7U),
633 .iInterface = *(uint8_t *)(buf + 8U)
634 };
635 }
636
637 /*!
638 \brief parse the endpoint descriptor
639 \param[in] ep_desc: pointer to usb endpoint descriptor buffer
640 \param[in] buf: pointer to the source descriptor buffer
641 \param[out] none
642 \retval none
643 */
usbh_epdesc_parse(usb_desc_ep * ep_desc,uint8_t * buf)644 static void usbh_epdesc_parse (usb_desc_ep *ep_desc, uint8_t *buf)
645 {
646 *ep_desc = (usb_desc_ep) {
647 .header = {
648 .bLength = *(uint8_t *)(buf + 0U),
649 .bDescriptorType = *(uint8_t *)(buf + 1U)
650 },
651
652 .bEndpointAddress = *(uint8_t *)(buf + 2U),
653 .bmAttributes = *(uint8_t *)(buf + 3U),
654 .wMaxPacketSize = BYTE_SWAP(buf + 4U),
655 .bInterval = *(uint8_t *)(buf + 6U)
656 };
657 }
658
659 /*!
660 \brief parse the string descriptor
661 \param[in] psrc: source pointer containing the descriptor data
662 \param[in] pdest: destination address pointer
663 \param[in] len: length of the descriptor
664 \param[out] none
665 \retval none
666 */
usbh_strdesc_parse(uint8_t * psrc,uint8_t * pdest,uint16_t len)667 static void usbh_strdesc_parse (uint8_t *psrc, uint8_t *pdest, uint16_t len)
668 {
669 uint16_t str_len = 0U, index = 0U;
670
671 /* the unicode string descriptor is not NULL-terminated. The string length is
672 * computed by substracting two from the value of the first byte of the descriptor.
673 */
674
675 /* check which is lower size, the size of string or the length of bytes read from the device */
676 if (USB_DESCTYPE_STR == psrc[1]) {
677 /* make sure the descriptor is string type */
678
679 /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */
680 str_len = USB_MIN((uint16_t)psrc[0] - 2U, len);
681
682 psrc += 2U; /* adjust the offset ignoring the string len and descriptor type */
683
684 for (index = 0U; index < str_len; index += 2U) {
685 /* copy only the string and ignore the unicode id, hence add the src */
686 *pdest = psrc[index];
687
688 pdest++;
689 }
690
691 *pdest = 0U; /* mark end of string */
692 }
693 }
694