1 /**
2 ******************************************************************************
3 * @file usbh_ctlreq.c
4 * @author MCD Application Team
5 * @brief This file implements the control requests for device enumeration
6 ******************************************************************************
7 * @attention
8 *
9 * <h2><center>© Copyright (c) 2015 STMicroelectronics.
10 * All rights reserved.</center></h2>
11 *
12 * This software component is licensed by ST under Ultimate Liberty license
13 * SLA0044, the "License"; You may not use this file except in compliance with
14 * the License. You may obtain a copy of the License at:
15 * www.st.com/SLA0044
16 *
17 ******************************************************************************
18 */
19
20 /* Includes ------------------------------------------------------------------*/
21 #include "usbh_ctlreq.h"
22
23 /** @addtogroup USBH_LIB
24 * @{
25 */
26
27 /** @addtogroup USBH_LIB_CORE
28 * @{
29 */
30
31 /** @defgroup USBH_CTLREQ
32 * @brief This file implements the standard requests for device enumeration
33 * @{
34 */
35
36
37 /** @defgroup USBH_CTLREQ_Private_Defines
38 * @{
39 */
40 /**
41 * @}
42 */
43
44
45 /** @defgroup USBH_CTLREQ_Private_TypesDefinitions
46 * @{
47 */
48 /**
49 * @}
50 */
51
52
53
54 /** @defgroup USBH_CTLREQ_Private_Macros
55 * @{
56 */
57 /**
58 * @}
59 */
60
61
62 /** @defgroup USBH_CTLREQ_Private_Variables
63 * @{
64 */
65 /**
66 * @}
67 */
68
69 /** @defgroup USBH_CTLREQ_Private_FunctionPrototypes
70 * @{
71 */
72 static USBH_StatusTypeDef USBH_HandleControl(USBH_HandleTypeDef *phost);
73
74 static void USBH_ParseDevDesc(USBH_DevDescTypeDef *dev_desc,
75 uint8_t *buf, uint16_t length);
76
77 static void USBH_ParseCfgDesc(USBH_CfgDescTypeDef *cfg_desc,
78 uint8_t *buf, uint16_t length);
79
80 static void USBH_ParseEPDesc(USBH_EpDescTypeDef *ep_descriptor, uint8_t *buf);
81 static void USBH_ParseStringDesc(uint8_t *psrc, uint8_t *pdest, uint16_t length);
82 static void USBH_ParseInterfaceDesc(USBH_InterfaceDescTypeDef *if_descriptor, uint8_t *buf);
83
84
85 /**
86 * @}
87 */
88
89
90 /** @defgroup USBH_CTLREQ_Private_Functions
91 * @{
92 */
93
94
95 /**
96 * @brief USBH_Get_DevDesc
97 * Issue Get Device Descriptor command to the device. Once the response
98 * received, it parses the device descriptor and updates the status.
99 * @param phost: Host Handle
100 * @param length: Length of the descriptor
101 * @retval USBH Status
102 */
USBH_Get_DevDesc(USBH_HandleTypeDef * phost,uint8_t length)103 USBH_StatusTypeDef USBH_Get_DevDesc(USBH_HandleTypeDef *phost, uint8_t length)
104 {
105 USBH_StatusTypeDef status;
106
107 if ((status = USBH_GetDescriptor(phost,
108 USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
109 USB_DESC_DEVICE, phost->device.Data,
110 (uint16_t)length)) == USBH_OK)
111 {
112 /* Commands successfully sent and Response Received */
113 USBH_ParseDevDesc(&phost->device.DevDesc, phost->device.Data,
114 (uint16_t)length);
115 }
116
117 return status;
118 }
119
120
121 /**
122 * @brief USBH_Get_CfgDesc
123 * Issues Configuration Descriptor to the device. Once the response
124 * received, it parses the configuration descriptor and updates the
125 * status.
126 * @param phost: Host Handle
127 * @param length: Length of the descriptor
128 * @retval USBH Status
129 */
USBH_Get_CfgDesc(USBH_HandleTypeDef * phost,uint16_t length)130 USBH_StatusTypeDef USBH_Get_CfgDesc(USBH_HandleTypeDef *phost,
131 uint16_t length)
132
133 {
134 USBH_StatusTypeDef status;
135 uint8_t *pData = phost->device.CfgDesc_Raw;;
136
137 if ((status = USBH_GetDescriptor(phost, (USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD),
138 USB_DESC_CONFIGURATION, pData, length)) == USBH_OK)
139 {
140 /* Commands successfully sent and Response Received */
141 USBH_ParseCfgDesc(&phost->device.CfgDesc, pData, length);
142 }
143
144 return status;
145 }
146
147
148 /**
149 * @brief USBH_Get_StringDesc
150 * Issues string Descriptor command to the device. Once the response
151 * received, it parses the string descriptor and updates the status.
152 * @param phost: Host Handle
153 * @param string_index: String index for the descriptor
154 * @param buff: Buffer address for the descriptor
155 * @param length: Length of the descriptor
156 * @retval USBH Status
157 */
USBH_Get_StringDesc(USBH_HandleTypeDef * phost,uint8_t string_index,uint8_t * buff,uint16_t length)158 USBH_StatusTypeDef USBH_Get_StringDesc(USBH_HandleTypeDef *phost,
159 uint8_t string_index, uint8_t *buff,
160 uint16_t length)
161 {
162 USBH_StatusTypeDef status;
163
164 if ((status = USBH_GetDescriptor(phost,
165 USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,
166 USB_DESC_STRING | string_index,
167 phost->device.Data, length)) == USBH_OK)
168 {
169 /* Commands successfully sent and Response Received */
170 USBH_ParseStringDesc(phost->device.Data, buff, length);
171 }
172
173 return status;
174 }
175
176
177 /**
178 * @brief USBH_GetDescriptor
179 * Issues Descriptor command to the device. Once the response received,
180 * it parses the descriptor and updates the status.
181 * @param phost: Host Handle
182 * @param req_type: Descriptor type
183 * @param value_idx: Value for the GetDescriptr request
184 * @param buff: Buffer to store the descriptor
185 * @param length: Length of the descriptor
186 * @retval USBH Status
187 */
USBH_GetDescriptor(USBH_HandleTypeDef * phost,uint8_t req_type,uint16_t value_idx,uint8_t * buff,uint16_t length)188 USBH_StatusTypeDef USBH_GetDescriptor(USBH_HandleTypeDef *phost,
189 uint8_t req_type,
190 uint16_t value_idx,
191 uint8_t *buff,
192 uint16_t length)
193 {
194 if (phost->RequestState == CMD_SEND)
195 {
196 phost->Control.setup.b.bmRequestType = USB_D2H | req_type;
197 phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR;
198 phost->Control.setup.b.wValue.w = value_idx;
199
200 if ((value_idx & 0xff00U) == USB_DESC_STRING)
201 {
202 phost->Control.setup.b.wIndex.w = 0x0409U;
203 }
204 else
205 {
206 phost->Control.setup.b.wIndex.w = 0U;
207 }
208 phost->Control.setup.b.wLength.w = length;
209 }
210
211 return USBH_CtlReq(phost, buff, length);
212 }
213
214
215 /**
216 * @brief USBH_SetAddress
217 * This command sets the address to the connected device
218 * @param phost: Host Handle
219 * @param DeviceAddress: Device address to assign
220 * @retval USBH Status
221 */
USBH_SetAddress(USBH_HandleTypeDef * phost,uint8_t DeviceAddress)222 USBH_StatusTypeDef USBH_SetAddress(USBH_HandleTypeDef *phost,
223 uint8_t DeviceAddress)
224 {
225 if (phost->RequestState == CMD_SEND)
226 {
227 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \
228 USB_REQ_TYPE_STANDARD;
229
230 phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS;
231
232 phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress;
233 phost->Control.setup.b.wIndex.w = 0U;
234 phost->Control.setup.b.wLength.w = 0U;
235 }
236
237 return USBH_CtlReq(phost, 0U, 0U);
238 }
239
240
241 /**
242 * @brief USBH_SetCfg
243 * The command sets the configuration value to the connected device
244 * @param phost: Host Handle
245 * @param cfg_idx: Configuration value
246 * @retval USBH Status
247 */
USBH_SetCfg(USBH_HandleTypeDef * phost,uint16_t cfg_idx)248 USBH_StatusTypeDef USBH_SetCfg(USBH_HandleTypeDef *phost, uint16_t cfg_idx)
249 {
250 if (phost->RequestState == CMD_SEND)
251 {
252 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE
253 | USB_REQ_TYPE_STANDARD;
254
255 phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION;
256 phost->Control.setup.b.wValue.w = cfg_idx;
257 phost->Control.setup.b.wIndex.w = 0U;
258 phost->Control.setup.b.wLength.w = 0U;
259 }
260
261 return USBH_CtlReq(phost, 0U, 0U);
262 }
263
264
265 /**
266 * @brief USBH_SetInterface
267 * The command sets the Interface value to the connected device
268 * @param phost: Host Handle
269 * @param altSetting: Interface value
270 * @retval USBH Status
271 */
USBH_SetInterface(USBH_HandleTypeDef * phost,uint8_t ep_num,uint8_t altSetting)272 USBH_StatusTypeDef USBH_SetInterface(USBH_HandleTypeDef *phost, uint8_t ep_num,
273 uint8_t altSetting)
274 {
275 if (phost->RequestState == CMD_SEND)
276 {
277 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE
278 | USB_REQ_TYPE_STANDARD;
279
280 phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE;
281 phost->Control.setup.b.wValue.w = altSetting;
282 phost->Control.setup.b.wIndex.w = ep_num;
283 phost->Control.setup.b.wLength.w = 0U;
284 }
285
286 return USBH_CtlReq(phost, 0U, 0U);
287 }
288
289
290 /**
291 * @brief USBH_SetFeature
292 * The command sets the device features (remote wakeup feature,..)
293 * @param pdev: Selected device
294 * @param itf_idx
295 * @retval Status
296 */
USBH_SetFeature(USBH_HandleTypeDef * phost,uint8_t wValue)297 USBH_StatusTypeDef USBH_SetFeature(USBH_HandleTypeDef *phost, uint8_t wValue)
298 {
299 if (phost->RequestState == CMD_SEND)
300 {
301 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE
302 | USB_REQ_TYPE_STANDARD;
303
304 phost->Control.setup.b.bRequest = USB_REQ_SET_FEATURE;
305 phost->Control.setup.b.wValue.w = wValue;
306 phost->Control.setup.b.wIndex.w = 0U;
307 phost->Control.setup.b.wLength.w = 0U;
308 }
309
310 return USBH_CtlReq(phost, 0U, 0U);
311 }
312
313
314 /**
315 * @brief USBH_ClrFeature
316 * This request is used to clear or disable a specific feature.
317 * @param phost: Host Handle
318 * @param ep_num: endpoint number
319 * @param hc_num: Host channel number
320 * @retval USBH Status
321 */
USBH_ClrFeature(USBH_HandleTypeDef * phost,uint8_t ep_num)322 USBH_StatusTypeDef USBH_ClrFeature(USBH_HandleTypeDef *phost, uint8_t ep_num)
323 {
324 if (phost->RequestState == CMD_SEND)
325 {
326 phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_ENDPOINT
327 | USB_REQ_TYPE_STANDARD;
328
329 phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE;
330 phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT;
331 phost->Control.setup.b.wIndex.w = ep_num;
332 phost->Control.setup.b.wLength.w = 0U;
333 }
334 return USBH_CtlReq(phost, 0U, 0U);
335 }
336
337
338 /**
339 * @brief USBH_ParseDevDesc
340 * This function Parses the device descriptor
341 * @param dev_desc: device_descriptor destination address
342 * @param buf: Buffer where the source descriptor is available
343 * @param length: Length of the descriptor
344 * @retval None
345 */
USBH_ParseDevDesc(USBH_DevDescTypeDef * dev_desc,uint8_t * buf,uint16_t length)346 static void USBH_ParseDevDesc(USBH_DevDescTypeDef *dev_desc, uint8_t *buf,
347 uint16_t length)
348 {
349 dev_desc->bLength = *(uint8_t *)(buf + 0);
350 dev_desc->bDescriptorType = *(uint8_t *)(buf + 1);
351 dev_desc->bcdUSB = LE16(buf + 2);
352 dev_desc->bDeviceClass = *(uint8_t *)(buf + 4);
353 dev_desc->bDeviceSubClass = *(uint8_t *)(buf + 5);
354 dev_desc->bDeviceProtocol = *(uint8_t *)(buf + 6);
355 dev_desc->bMaxPacketSize = *(uint8_t *)(buf + 7);
356
357 if (length > 8U)
358 {
359 /* For 1st time after device connection, Host may issue only 8 bytes for
360 Device Descriptor Length */
361 dev_desc->idVendor = LE16(buf + 8);
362 dev_desc->idProduct = LE16(buf + 10);
363 dev_desc->bcdDevice = LE16(buf + 12);
364 dev_desc->iManufacturer = *(uint8_t *)(buf + 14);
365 dev_desc->iProduct = *(uint8_t *)(buf + 15);
366 dev_desc->iSerialNumber = *(uint8_t *)(buf + 16);
367 dev_desc->bNumConfigurations = *(uint8_t *)(buf + 17);
368 }
369 }
370
371
372 /**
373 * @brief USBH_ParseCfgDesc
374 * This function Parses the configuration descriptor
375 * @param cfg_desc: Configuration Descriptor address
376 * @param buf: Buffer where the source descriptor is available
377 * @param length: Length of the descriptor
378 * @retval None
379 */
USBH_ParseCfgDesc(USBH_CfgDescTypeDef * cfg_desc,uint8_t * buf,uint16_t length)380 static void USBH_ParseCfgDesc(USBH_CfgDescTypeDef *cfg_desc, uint8_t *buf,
381 uint16_t length)
382 {
383 USBH_InterfaceDescTypeDef *pif ;
384 USBH_EpDescTypeDef *pep;
385 USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)(void *)buf;
386 uint16_t ptr;
387 uint8_t if_ix = 0U;
388 uint8_t ep_ix = 0U;
389
390 pdesc = (USBH_DescHeader_t *)(void *)buf;
391
392 /* Parse configuration descriptor */
393 cfg_desc->bLength = *(uint8_t *)(buf + 0);
394 cfg_desc->bDescriptorType = *(uint8_t *)(buf + 1);
395 cfg_desc->wTotalLength = LE16(buf + 2);
396 cfg_desc->bNumInterfaces = *(uint8_t *)(buf + 4);
397 cfg_desc->bConfigurationValue = *(uint8_t *)(buf + 5);
398 cfg_desc->iConfiguration = *(uint8_t *)(buf + 6);
399 cfg_desc->bmAttributes = *(uint8_t *)(buf + 7);
400 cfg_desc->bMaxPower = *(uint8_t *)(buf + 8);
401
402 if (length > USB_CONFIGURATION_DESC_SIZE)
403 {
404 ptr = USB_LEN_CFG_DESC;
405 pif = (USBH_InterfaceDescTypeDef *)0;
406
407 while ((if_ix < USBH_MAX_NUM_INTERFACES) && (ptr < cfg_desc->wTotalLength))
408 {
409 pdesc = USBH_GetNextDesc((uint8_t *)(void *)pdesc, &ptr);
410 if (pdesc->bDescriptorType == USB_DESC_TYPE_INTERFACE)
411 {
412 pif = &cfg_desc->Itf_Desc[if_ix];
413 USBH_ParseInterfaceDesc(pif, (uint8_t *)(void *)pdesc);
414
415 ep_ix = 0U;
416 pep = (USBH_EpDescTypeDef *)0;
417 while ((ep_ix < pif->bNumEndpoints) && (ptr < cfg_desc->wTotalLength))
418 {
419 pdesc = USBH_GetNextDesc((uint8_t *)(void *)pdesc, &ptr);
420 if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT)
421 {
422 pep = &cfg_desc->Itf_Desc[if_ix].Ep_Desc[ep_ix];
423 USBH_ParseEPDesc(pep, (uint8_t *)(void *)pdesc);
424 ep_ix++;
425 }
426 }
427 if_ix++;
428 }
429 }
430 }
431 }
432
433
434 /**
435 * @brief USBH_ParseInterfaceDesc
436 * This function Parses the interface descriptor
437 * @param if_descriptor : Interface descriptor destination
438 * @param buf: Buffer where the descriptor data is available
439 * @retval None
440 */
USBH_ParseInterfaceDesc(USBH_InterfaceDescTypeDef * if_descriptor,uint8_t * buf)441 static void USBH_ParseInterfaceDesc(USBH_InterfaceDescTypeDef *if_descriptor,
442 uint8_t *buf)
443 {
444 if_descriptor->bLength = *(uint8_t *)(buf + 0);
445 if_descriptor->bDescriptorType = *(uint8_t *)(buf + 1);
446 if_descriptor->bInterfaceNumber = *(uint8_t *)(buf + 2);
447 if_descriptor->bAlternateSetting = *(uint8_t *)(buf + 3);
448 if_descriptor->bNumEndpoints = *(uint8_t *)(buf + 4);
449 if_descriptor->bInterfaceClass = *(uint8_t *)(buf + 5);
450 if_descriptor->bInterfaceSubClass = *(uint8_t *)(buf + 6);
451 if_descriptor->bInterfaceProtocol = *(uint8_t *)(buf + 7);
452 if_descriptor->iInterface = *(uint8_t *)(buf + 8);
453 }
454
455
456 /**
457 * @brief USBH_ParseEPDesc
458 * This function Parses the endpoint descriptor
459 * @param ep_descriptor: Endpoint descriptor destination address
460 * @param buf: Buffer where the parsed descriptor stored
461 * @retval None
462 */
USBH_ParseEPDesc(USBH_EpDescTypeDef * ep_descriptor,uint8_t * buf)463 static void USBH_ParseEPDesc(USBH_EpDescTypeDef *ep_descriptor,
464 uint8_t *buf)
465 {
466 ep_descriptor->bLength = *(uint8_t *)(buf + 0);
467 ep_descriptor->bDescriptorType = *(uint8_t *)(buf + 1);
468 ep_descriptor->bEndpointAddress = *(uint8_t *)(buf + 2);
469 ep_descriptor->bmAttributes = *(uint8_t *)(buf + 3);
470 ep_descriptor->wMaxPacketSize = LE16(buf + 4);
471 ep_descriptor->bInterval = *(uint8_t *)(buf + 6);
472 }
473
474
475 /**
476 * @brief USBH_ParseStringDesc
477 * This function Parses the string descriptor
478 * @param psrc: Source pointer containing the descriptor data
479 * @param pdest: Destination address pointer
480 * @param length: Length of the descriptor
481 * @retval None
482 */
USBH_ParseStringDesc(uint8_t * psrc,uint8_t * pdest,uint16_t length)483 static void USBH_ParseStringDesc(uint8_t *psrc, uint8_t *pdest, uint16_t length)
484 {
485 uint16_t strlength;
486 uint16_t idx;
487
488 /* The UNICODE string descriptor is not NULL-terminated. The string length is
489 computed by substracting two from the value of the first byte of the descriptor.
490 */
491
492 /* Check which is lower size, the Size of string or the length of bytes read
493 from the device */
494
495 if (psrc[1] == USB_DESC_TYPE_STRING)
496 {
497 /* Make sure the Descriptor is String Type */
498
499 /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */
500 strlength = ((((uint16_t)psrc[0] - 2U) <= length) ? ((uint16_t)psrc[0] - 2U) : length);
501
502 /* Adjust the offset ignoring the String Len and Descriptor type */
503 psrc += 2U;
504
505 for (idx = 0U; idx < strlength; idx += 2U)
506 {
507 /* Copy Only the string and ignore the UNICODE ID, hence add the src */
508 *pdest = psrc[idx];
509 pdest++;
510 }
511 *pdest = 0U; /* mark end of string */
512 }
513 }
514
515
516 /**
517 * @brief USBH_GetNextDesc
518 * This function return the next descriptor header
519 * @param buf: Buffer where the cfg descriptor is available
520 * @param ptr: data pointer inside the cfg descriptor
521 * @retval next header
522 */
USBH_GetNextDesc(uint8_t * pbuf,uint16_t * ptr)523 USBH_DescHeader_t *USBH_GetNextDesc(uint8_t *pbuf, uint16_t *ptr)
524 {
525 USBH_DescHeader_t *pnext;
526
527 *ptr += ((USBH_DescHeader_t *)(void *)pbuf)->bLength;
528 pnext = (USBH_DescHeader_t *)(void *)((uint8_t *)(void *)pbuf + \
529 ((USBH_DescHeader_t *)(void *)pbuf)->bLength);
530
531 return (pnext);
532 }
533
534
535 /**
536 * @brief USBH_CtlReq
537 * USBH_CtlReq sends a control request and provide the status after
538 * completion of the request
539 * @param phost: Host Handle
540 * @param req: Setup Request Structure
541 * @param buff: data buffer address to store the response
542 * @param length: length of the response
543 * @retval USBH Status
544 */
USBH_CtlReq(USBH_HandleTypeDef * phost,uint8_t * buff,uint16_t length)545 USBH_StatusTypeDef USBH_CtlReq(USBH_HandleTypeDef *phost, uint8_t *buff,
546 uint16_t length)
547 {
548 USBH_StatusTypeDef status;
549 status = USBH_BUSY;
550
551 switch (phost->RequestState)
552 {
553 case CMD_SEND:
554 /* Start a SETUP transfer */
555 phost->Control.buff = buff;
556 phost->Control.length = length;
557 phost->Control.state = CTRL_SETUP;
558 phost->RequestState = CMD_WAIT;
559 status = USBH_BUSY;
560
561 #if (USBH_USE_OS == 1U)
562 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
563 #if (osCMSIS < 0x20000U)
564 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
565 #else
566 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
567 #endif
568 #endif
569 break;
570
571 case CMD_WAIT:
572 status = USBH_HandleControl(phost);
573 if ((status == USBH_OK) || (status == USBH_NOT_SUPPORTED))
574 {
575 /* Transaction completed, move control state to idle */
576 phost->RequestState = CMD_SEND;
577 phost->Control.state = CTRL_IDLE;
578 }
579 else if (status == USBH_FAIL)
580 {
581 /* Failure Mode */
582 phost->RequestState = CMD_SEND;
583 }
584 else
585 {
586 /* .. */
587 }
588 #if (USBH_USE_OS == 1U)
589 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
590 #if (osCMSIS < 0x20000U)
591 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
592 #else
593 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
594 #endif
595 #endif
596 break;
597
598 default:
599 break;
600 }
601 return status;
602 }
603
604
605 /**
606 * @brief USBH_HandleControl
607 * Handles the USB control transfer state machine
608 * @param phost: Host Handle
609 * @retval USBH Status
610 */
USBH_HandleControl(USBH_HandleTypeDef * phost)611 static USBH_StatusTypeDef USBH_HandleControl(USBH_HandleTypeDef *phost)
612 {
613 uint8_t direction;
614 USBH_StatusTypeDef status = USBH_BUSY;
615 USBH_URBStateTypeDef URB_Status = USBH_URB_IDLE;
616
617 switch (phost->Control.state)
618 {
619 case CTRL_SETUP:
620 /* send a SETUP packet */
621 USBH_CtlSendSetup(phost, (uint8_t *)(void *)phost->Control.setup.d8,
622 phost->Control.pipe_out);
623
624 phost->Control.state = CTRL_SETUP_WAIT;
625 break;
626
627 case CTRL_SETUP_WAIT:
628
629 URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
630 /* case SETUP packet sent successfully */
631 if (URB_Status == USBH_URB_DONE)
632 {
633 direction = (phost->Control.setup.b.bmRequestType & USB_REQ_DIR_MASK);
634
635 /* check if there is a data stage */
636 if (phost->Control.setup.b.wLength.w != 0U)
637 {
638 if (direction == USB_D2H)
639 {
640 /* Data Direction is IN */
641 phost->Control.state = CTRL_DATA_IN;
642 }
643 else
644 {
645 /* Data Direction is OUT */
646 phost->Control.state = CTRL_DATA_OUT;
647 }
648 }
649 /* No DATA stage */
650 else
651 {
652 /* If there is No Data Transfer Stage */
653 if (direction == USB_D2H)
654 {
655 /* Data Direction is IN */
656 phost->Control.state = CTRL_STATUS_OUT;
657 }
658 else
659 {
660 /* Data Direction is OUT */
661 phost->Control.state = CTRL_STATUS_IN;
662 }
663 }
664
665 #if (USBH_USE_OS == 1U)
666 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
667 #if (osCMSIS < 0x20000U)
668 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
669 #else
670 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
671 #endif
672 #endif
673 }
674 else
675 {
676 if ((URB_Status == USBH_URB_ERROR) || (URB_Status == USBH_URB_NOTREADY))
677 {
678 phost->Control.state = CTRL_ERROR;
679
680 #if (USBH_USE_OS == 1U)
681 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
682 #if (osCMSIS < 0x20000U)
683 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
684 #else
685 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
686 #endif
687 #endif
688 }
689 }
690 break;
691
692 case CTRL_DATA_IN:
693 /* Issue an IN token */
694 phost->Control.timer = (uint16_t)phost->Timer;
695 USBH_CtlReceiveData(phost, phost->Control.buff, phost->Control.length,
696 phost->Control.pipe_in);
697
698 phost->Control.state = CTRL_DATA_IN_WAIT;
699 break;
700
701 case CTRL_DATA_IN_WAIT:
702
703 URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_in);
704
705 /* check is DATA packet transferred successfully */
706 if (URB_Status == USBH_URB_DONE)
707 {
708 phost->Control.state = CTRL_STATUS_OUT;
709
710 #if (USBH_USE_OS == 1U)
711 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
712 #if (osCMSIS < 0x20000U)
713 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
714 #else
715 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
716 #endif
717 #endif
718 }
719
720 /* manage error cases*/
721 if (URB_Status == USBH_URB_STALL)
722 {
723 /* In stall case, return to previous machine state*/
724 status = USBH_NOT_SUPPORTED;
725
726 #if (USBH_USE_OS == 1U)
727 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
728 #if (osCMSIS < 0x20000U)
729 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
730 #else
731 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
732 #endif
733 #endif
734 }
735 else
736 {
737 if (URB_Status == USBH_URB_ERROR)
738 {
739 /* Device error */
740 phost->Control.state = CTRL_ERROR;
741
742 #if (USBH_USE_OS == 1U)
743 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
744 #if (osCMSIS < 0x20000U)
745 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
746 #else
747 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
748 #endif
749 #endif
750 }
751 }
752 break;
753
754 case CTRL_DATA_OUT:
755
756 USBH_CtlSendData(phost, phost->Control.buff, phost->Control.length,
757 phost->Control.pipe_out, 1U);
758
759 phost->Control.timer = (uint16_t)phost->Timer;
760 phost->Control.state = CTRL_DATA_OUT_WAIT;
761 break;
762
763 case CTRL_DATA_OUT_WAIT:
764
765 URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
766
767 if (URB_Status == USBH_URB_DONE)
768 {
769 /* If the Setup Pkt is sent successful, then change the state */
770 phost->Control.state = CTRL_STATUS_IN;
771
772 #if (USBH_USE_OS == 1U)
773 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
774 #if (osCMSIS < 0x20000U)
775 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
776 #else
777 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
778 #endif
779 #endif
780 }
781
782 /* handle error cases */
783 else if (URB_Status == USBH_URB_STALL)
784 {
785 /* In stall case, return to previous machine state*/
786 phost->Control.state = CTRL_STALLED;
787 status = USBH_NOT_SUPPORTED;
788
789 #if (USBH_USE_OS == 1U)
790 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
791 #if (osCMSIS < 0x20000U)
792 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
793 #else
794 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
795 #endif
796 #endif
797 }
798 else if (URB_Status == USBH_URB_NOTREADY)
799 {
800 /* Nack received from device */
801 phost->Control.state = CTRL_DATA_OUT;
802
803 #if (USBH_USE_OS == 1U)
804 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
805 #if (osCMSIS < 0x20000U)
806 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
807 #else
808 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
809 #endif
810 #endif
811 }
812 else
813 {
814 if (URB_Status == USBH_URB_ERROR)
815 {
816 /* device error */
817 phost->Control.state = CTRL_ERROR;
818 status = USBH_FAIL;
819
820 #if (USBH_USE_OS == 1U)
821 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
822 #if (osCMSIS < 0x20000U)
823 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
824 #else
825 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
826 #endif
827 #endif
828 }
829 }
830 break;
831
832 case CTRL_STATUS_IN:
833 /* Send 0 bytes out packet */
834 USBH_CtlReceiveData(phost, 0U, 0U, phost->Control.pipe_in);
835
836 phost->Control.timer = (uint16_t)phost->Timer;
837 phost->Control.state = CTRL_STATUS_IN_WAIT;
838
839 break;
840
841 case CTRL_STATUS_IN_WAIT:
842
843 URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_in);
844
845 if (URB_Status == USBH_URB_DONE)
846 {
847 /* Control transfers completed, Exit the State Machine */
848 phost->Control.state = CTRL_COMPLETE;
849 status = USBH_OK;
850
851 #if (USBH_USE_OS == 1U)
852 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
853 #if (osCMSIS < 0x20000U)
854 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
855 #else
856 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
857 #endif
858 #endif
859 }
860 else if (URB_Status == USBH_URB_ERROR)
861 {
862 phost->Control.state = CTRL_ERROR;
863
864 #if (USBH_USE_OS == 1U)
865 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
866 #if (osCMSIS < 0x20000U)
867 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
868 #else
869 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
870 #endif
871 #endif
872 }
873 else
874 {
875 if (URB_Status == USBH_URB_STALL)
876 {
877 /* Control transfers completed, Exit the State Machine */
878 status = USBH_NOT_SUPPORTED;
879
880 #if (USBH_USE_OS == 1U)
881 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
882 #if (osCMSIS < 0x20000U)
883 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
884 #else
885 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
886 #endif
887 #endif
888 }
889 }
890 break;
891
892 case CTRL_STATUS_OUT:
893 USBH_CtlSendData(phost, 0U, 0U, phost->Control.pipe_out, 1U);
894
895 phost->Control.timer = (uint16_t)phost->Timer;
896 phost->Control.state = CTRL_STATUS_OUT_WAIT;
897 break;
898
899 case CTRL_STATUS_OUT_WAIT:
900 URB_Status = USBH_LL_GetURBState(phost, phost->Control.pipe_out);
901 if (URB_Status == USBH_URB_DONE)
902 {
903 status = USBH_OK;
904 phost->Control.state = CTRL_COMPLETE;
905
906 #if (USBH_USE_OS == 1U)
907 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
908 #if (osCMSIS < 0x20000U)
909 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
910 #else
911 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
912 #endif
913 #endif
914 }
915 else if (URB_Status == USBH_URB_NOTREADY)
916 {
917 phost->Control.state = CTRL_STATUS_OUT;
918
919 #if (USBH_USE_OS == 1U)
920 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
921 #if (osCMSIS < 0x20000U)
922 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
923 #else
924 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
925 #endif
926 #endif
927 }
928 else
929 {
930 if (URB_Status == USBH_URB_ERROR)
931 {
932 phost->Control.state = CTRL_ERROR;
933
934 #if (USBH_USE_OS == 1U)
935 phost->os_msg = (uint32_t)USBH_CONTROL_EVENT;
936 #if (osCMSIS < 0x20000U)
937 (void)osMessagePut(phost->os_event, phost->os_msg, 0U);
938 #else
939 (void)osMessageQueuePut(phost->os_event, &phost->os_msg, 0U, NULL);
940 #endif
941 #endif
942 }
943 }
944 break;
945
946 case CTRL_ERROR:
947 /*
948 After a halt condition is encountered or an error is detected by the
949 host, a control endpoint is allowed to recover by accepting the next Setup
950 PID; i.e., recovery actions via some other pipe are not required for control
951 endpoints. For the Default Control Pipe, a device reset will ultimately be
952 required to clear the halt or error condition if the next Setup PID is not
953 accepted.
954 */
955 if (++phost->Control.errorcount <= USBH_MAX_ERROR_COUNT)
956 {
957 /* Do the transmission again, starting from SETUP Packet */
958 phost->Control.state = CTRL_SETUP;
959 phost->RequestState = CMD_SEND;
960 }
961 else
962 {
963 phost->pUser(phost, HOST_USER_UNRECOVERED_ERROR);
964 phost->Control.errorcount = 0U;
965 USBH_ErrLog("Control error: Device not responding");
966
967 /* Free control pipes */
968 USBH_FreePipe(phost, phost->Control.pipe_out);
969 USBH_FreePipe(phost, phost->Control.pipe_in);
970
971 phost->gState = HOST_IDLE;
972 status = USBH_FAIL;
973 }
974 break;
975
976 default:
977 break;
978 }
979
980 return status;
981 }
982
983 /**
984 * @}
985 */
986
987 /**
988 * @}
989 */
990
991 /**
992 * @}
993 */
994
995 /**
996 * @}
997 */
998
999 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
1000
1001
1002
1003
1004