xref: /btstack/port/stm32-f4discovery-usb/Middlewares/ST/STM32_USB_Host_Library/Core/Src/usbh_ctlreq.c (revision a8f7f3fcbcd51f8d2e92aca076b6a9f812db358c)
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>&copy; 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