Merge branch 'tmaster' into future
[fw/stlink] / example / stm32f4 / STM32_USB_HOST_Library / Core / src / usbh_stdreq.c
1 /**
2   ******************************************************************************
3   * @file    usbh_stdreq.c 
4   * @author  MCD Application Team
5   * @version V2.0.0
6   * @date    22-July-2011
7   * @brief   This file implements the standard requests for device enumeration
8   ******************************************************************************
9   * @attention
10   *
11   * THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
12   * WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
13   * TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
14   * DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
15   * FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
16   * CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
17   *
18   * <h2><center>&copy; COPYRIGHT 2011 STMicroelectronics</center></h2>
19   ******************************************************************************
20   */ 
21 /* Includes ------------------------------------------------------------------*/
22
23 #include "usbh_ioreq.h"
24 #include "usbh_stdreq.h"
25
26 /** @addtogroup USBH_LIB
27 * @{
28 */
29
30 /** @addtogroup USBH_LIB_CORE
31 * @{
32 */
33
34 /** @defgroup USBH_STDREQ 
35 * @brief This file implements the standard requests for device enumeration
36 * @{
37 */
38
39
40 /** @defgroup USBH_STDREQ_Private_Defines
41 * @{
42 */ 
43 /**
44 * @}
45 */ 
46
47
48 /** @defgroup USBH_STDREQ_Private_TypesDefinitions
49 * @{
50 */ 
51 /**
52 * @}
53 */ 
54
55
56
57 /** @defgroup USBH_STDREQ_Private_Macros
58 * @{
59 */ 
60 /**
61 * @}
62 */ 
63
64
65 /** @defgroup USBH_STDREQ_Private_Variables
66 * @{
67 */
68 /**
69 * @}
70 */ 
71
72
73 /** @defgroup USBH_STDREQ_Private_FunctionPrototypes
74 * @{
75 */
76 static void USBH_ParseDevDesc (USBH_DevDesc_TypeDef* , uint8_t *buf, uint16_t length);
77
78 static void USBH_ParseCfgDesc (USBH_CfgDesc_TypeDef* cfg_desc,
79                                USBH_InterfaceDesc_TypeDef* itf_desc,
80                                USBH_EpDesc_TypeDef*  ep_desc,                                                           
81                                uint8_t *buf, 
82                                uint16_t length);
83 static  USBH_DescHeader_t      *USBH_GetNextDesc (uint8_t   *pbuf, 
84                                                   uint16_t  *ptr);
85
86 static void USBH_ParseInterfaceDesc (USBH_InterfaceDesc_TypeDef  *if_descriptor, uint8_t *buf);
87 static void USBH_ParseEPDesc (USBH_EpDesc_TypeDef  *ep_descriptor, uint8_t *buf);
88
89 static void USBH_ParseStringDesc (uint8_t* psrc, uint8_t* pdest, uint16_t length);
90 /**
91 * @}
92 */ 
93
94
95 /** @defgroup USBH_STDREQ_Private_Functions
96 * @{
97 */ 
98
99
100 /**
101 * @brief  USBH_Get_DevDesc
102 *         Issue Get Device Descriptor command to the device. Once the response 
103 *         received, it parses the device descriptor and updates the status.
104 * @param  pdev: Selected device
105 * @param  dev_desc: Device Descriptor buffer address
106 * @param  pdev->host.Rx_Buffer: Receive Buffer address
107 * @param  length: Length of the descriptor
108 * @retval Status
109 */
110 USBH_Status USBH_Get_DevDesc(USB_OTG_CORE_HANDLE *pdev,
111                              USBH_HOST *phost,
112                              uint8_t length)
113 {
114   
115   USBH_Status status;
116   
117   if((status = USBH_GetDescriptor(pdev, 
118                                   phost,
119                                   USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,                          
120                                   USB_DESC_DEVICE, 
121                                   pdev->host.Rx_Buffer,
122                                   length)) == USBH_OK)
123   {
124     /* Commands successfully sent and Response Received */       
125     USBH_ParseDevDesc(&phost->device_prop.Dev_Desc, pdev->host.Rx_Buffer, length);
126   }
127   return status;      
128 }
129
130 /**
131 * @brief  USBH_Get_CfgDesc
132 *         Issues Configuration Descriptor to the device. Once the response 
133 *         received, it parses the configuartion descriptor and updates the 
134 *         status.
135 * @param  pdev: Selected device
136 * @param  cfg_desc: Configuration Descriptor address
137 * @param  itf_desc: Interface Descriptor address
138 * @param  ep_desc: Endpoint Descriptor address
139 * @param  length: Length of the descriptor
140 * @retval Status
141 */
142 USBH_Status USBH_Get_CfgDesc(USB_OTG_CORE_HANDLE *pdev, 
143                              USBH_HOST           *phost,                      
144                              uint16_t length)
145
146 {
147   USBH_Status status;
148   
149   if((status = USBH_GetDescriptor(pdev,
150                                   phost,
151                                   USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,                          
152                                   USB_DESC_CONFIGURATION, 
153                                   pdev->host.Rx_Buffer,
154                                   length)) == USBH_OK)
155   {
156     /* Commands successfully sent and Response Received  */       
157     USBH_ParseCfgDesc (&phost->device_prop.Cfg_Desc,
158                        phost->device_prop.Itf_Desc,
159                        phost->device_prop.Ep_Desc[0], 
160                        pdev->host.Rx_Buffer,
161                        length); 
162     
163   }
164   return status;
165 }
166
167
168 /**
169 * @brief  USBH_Get_StringDesc
170 *         Issues string Descriptor command to the device. Once the response 
171 *         received, it parses the string descriptor and updates the status.
172 * @param  pdev: Selected device
173 * @param  string_index: String index for the descriptor
174 * @param  buff: Buffer address for the descriptor
175 * @param  length: Length of the descriptor
176 * @retval Status
177 */
178 USBH_Status USBH_Get_StringDesc(USB_OTG_CORE_HANDLE *pdev,
179                                 USBH_HOST *phost,
180                                 uint8_t string_index, 
181                                 uint8_t *buff, 
182                                 uint16_t length)
183 {
184   USBH_Status status;
185   
186   if((status = USBH_GetDescriptor(pdev,
187                                   phost,
188                                   USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD,                                    
189                                   USB_DESC_STRING | string_index, 
190                                   pdev->host.Rx_Buffer,
191                                   length)) == USBH_OK)
192   {
193     /* Commands successfully sent and Response Received  */       
194     USBH_ParseStringDesc(pdev->host.Rx_Buffer,buff, length);    
195   }
196   return status;
197 }
198
199 /**
200 * @brief  USBH_GetDescriptor
201 *         Issues Descriptor command to the device. Once the response received,
202 *         it parses the descriptor and updates the status.
203 * @param  pdev: Selected device
204 * @param  req_type: Descriptor type
205 * @param  value_idx: wValue for the GetDescriptr request
206 * @param  buff: Buffer to store the descriptor
207 * @param  length: Length of the descriptor
208 * @retval Status
209 */
210 USBH_Status USBH_GetDescriptor(USB_OTG_CORE_HANDLE *pdev,
211                                USBH_HOST           *phost,                                
212                                uint8_t  req_type,
213                                uint16_t value_idx, 
214                                uint8_t* buff, 
215                                uint16_t length )
216
217   phost->Control.setup.b.bmRequestType = USB_D2H | req_type;
218   phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR;
219   phost->Control.setup.b.wValue.w = value_idx;
220   
221   if ((value_idx & 0xff00) == USB_DESC_STRING)
222   {
223     phost->Control.setup.b.wIndex.w = 0x0409;
224   }
225   else
226   {
227     phost->Control.setup.b.wIndex.w = 0;
228   }
229   phost->Control.setup.b.wLength.w = length;           
230   return USBH_CtlReq(pdev, phost, buff , length );     
231 }
232
233 /**
234 * @brief  USBH_SetAddress
235 *         This command sets the address to the connected device
236 * @param  pdev: Selected device
237 * @param  DeviceAddress: Device address to assign
238 * @retval Status
239 */
240 USBH_Status USBH_SetAddress(USB_OTG_CORE_HANDLE *pdev, 
241                             USBH_HOST *phost,
242                             uint8_t DeviceAddress)
243 {
244   phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \
245     USB_REQ_TYPE_STANDARD;
246   
247   phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS;
248   
249   phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress;
250   phost->Control.setup.b.wIndex.w = 0;
251   phost->Control.setup.b.wLength.w = 0;
252   
253   return USBH_CtlReq(pdev, phost, 0 , 0 );
254 }
255
256 /**
257 * @brief  USBH_SetCfg
258 *         The command sets the configuration value to the connected device
259 * @param  pdev: Selected device
260 * @param  cfg_idx: Configuration value
261 * @retval Status
262 */
263 USBH_Status USBH_SetCfg(USB_OTG_CORE_HANDLE *pdev, 
264                         USBH_HOST *phost,
265                         uint16_t cfg_idx)
266 {
267   
268   phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE |\
269     USB_REQ_TYPE_STANDARD;
270   phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION;
271   phost->Control.setup.b.wValue.w = cfg_idx;
272   phost->Control.setup.b.wIndex.w = 0;
273   phost->Control.setup.b.wLength.w = 0;           
274   
275   return USBH_CtlReq(pdev, phost, 0 , 0 );      
276 }
277
278 /**
279 * @brief  USBH_ClrFeature
280 *         This request is used to clear or disable a specific feature.
281
282 * @param  pdev: Selected device
283 * @param  ep_num: endpoint number 
284 * @param  hc_num: Host channel number 
285 * @retval Status
286 */
287 USBH_Status USBH_ClrFeature(USB_OTG_CORE_HANDLE *pdev,
288                             USBH_HOST *phost,
289                             uint8_t ep_num, 
290                             uint8_t hc_num) 
291 {
292   
293   phost->Control.setup.b.bmRequestType = USB_H2D | 
294                                          USB_REQ_RECIPIENT_ENDPOINT |
295                                          USB_REQ_TYPE_STANDARD;
296   
297   phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE;
298   phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT;
299   phost->Control.setup.b.wIndex.w = ep_num;
300   phost->Control.setup.b.wLength.w = 0;           
301   
302   if ((ep_num & USB_REQ_DIR_MASK ) == USB_D2H)
303   { /* EP Type is IN */
304     pdev->host.hc[hc_num].toggle_in = 0; 
305   }
306   else
307   {/* EP Type is OUT */
308     pdev->host.hc[hc_num].toggle_out = 0; 
309   }
310   
311   return USBH_CtlReq(pdev, phost, 0 , 0 );   
312 }
313
314 /**
315 * @brief  USBH_ParseDevDesc 
316 *         This function Parses the device descriptor
317 * @param  dev_desc: device_descriptor destinaton address 
318 * @param  buf: Buffer where the source descriptor is available
319 * @param  length: Length of the descriptor
320 * @retval None
321 */
322 static void  USBH_ParseDevDesc (USBH_DevDesc_TypeDef* dev_desc,
323                                 uint8_t *buf, 
324                                 uint16_t length)
325 {
326   dev_desc->bLength            = *(uint8_t  *) (buf +  0);
327   dev_desc->bDescriptorType    = *(uint8_t  *) (buf +  1);
328   dev_desc->bcdUSB             = LE16 (buf +  2);
329   dev_desc->bDeviceClass       = *(uint8_t  *) (buf +  4);
330   dev_desc->bDeviceSubClass    = *(uint8_t  *) (buf +  5);
331   dev_desc->bDeviceProtocol    = *(uint8_t  *) (buf +  6);
332   dev_desc->bMaxPacketSize     = *(uint8_t  *) (buf +  7);
333   
334   if (length > 8)
335   { /* For 1st time after device connection, Host may issue only 8 bytes for 
336     Device Descriptor Length  */
337     dev_desc->idVendor           = LE16 (buf +  8);
338     dev_desc->idProduct          = LE16 (buf + 10);
339     dev_desc->bcdDevice          = LE16 (buf + 12);
340     dev_desc->iManufacturer      = *(uint8_t  *) (buf + 14);
341     dev_desc->iProduct           = *(uint8_t  *) (buf + 15);
342     dev_desc->iSerialNumber      = *(uint8_t  *) (buf + 16);
343     dev_desc->bNumConfigurations = *(uint8_t  *) (buf + 17);
344   }
345 }
346
347 /**
348 * @brief  USBH_ParseCfgDesc 
349 *         This function Parses the configuration descriptor
350 * @param  cfg_desc: Configuration Descriptor address
351 * @param  itf_desc: Interface Descriptor address
352 * @param  ep_desc: Endpoint Descriptor address
353 * @param  buf: Buffer where the source descriptor is available
354 * @param  length: Length of the descriptor
355 * @retval None
356 */
357 static void  USBH_ParseCfgDesc (USBH_CfgDesc_TypeDef* cfg_desc,
358                                 USBH_InterfaceDesc_TypeDef* itf_desc,
359                                 USBH_EpDesc_TypeDef*  ep_desc, 
360                                 uint8_t *buf, 
361                                 uint16_t length)
362 {  
363   USBH_InterfaceDesc_TypeDef    *pif ;
364   USBH_EpDesc_TypeDef           *pep;  
365   USBH_DescHeader_t             *pdesc = (USBH_DescHeader_t *)buf;
366   uint16_t                      ptr;
367   int8_t                        if_ix;
368   int8_t                        ep_ix;  
369   
370   pdesc   = (USBH_DescHeader_t *)buf;
371   
372   /* Parse configuration descriptor */
373   cfg_desc->bLength             = *(uint8_t  *) (buf + 0);
374   cfg_desc->bDescriptorType     = *(uint8_t  *) (buf + 1);
375   cfg_desc->wTotalLength        = LE16 (buf + 2);
376   cfg_desc->bNumInterfaces      = *(uint8_t  *) (buf + 4);
377   cfg_desc->bConfigurationValue = *(uint8_t  *) (buf + 5);
378   cfg_desc->iConfiguration      = *(uint8_t  *) (buf + 6);
379   cfg_desc->bmAttributes        = *(uint8_t  *) (buf + 7);
380   cfg_desc->bMaxPower           = *(uint8_t  *) (buf + 8);    
381   
382   
383   if (length > USB_CONFIGURATION_DESC_SIZE)
384   {
385     ptr = USB_LEN_CFG_DESC;
386     
387     if ( cfg_desc->bNumInterfaces <= USBH_MAX_NUM_INTERFACES) 
388     {
389       if_ix = 0;
390       pif = (USBH_InterfaceDesc_TypeDef *)0;
391       
392       /* Parse Interface descriptor relative to the current configuration */
393       if(cfg_desc->bNumInterfaces <= USBH_MAX_NUM_INTERFACES)
394       {
395         while (if_ix < cfg_desc->bNumInterfaces) 
396         {
397           pdesc = USBH_GetNextDesc((uint8_t *)pdesc, &ptr);
398           if (pdesc->bDescriptorType   == USB_DESC_TYPE_INTERFACE) 
399           {  
400             pif               = &itf_desc[if_ix];
401             USBH_ParseInterfaceDesc (pif, (uint8_t *)pdesc);
402             ep_ix = 0;
403             
404             /* Parse Ep descriptors relative to the current interface */
405             if(pif->bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS)
406             {          
407               while (ep_ix < pif->bNumEndpoints) 
408               {
409                 pdesc = USBH_GetNextDesc((void* )pdesc, &ptr);
410                 if (pdesc->bDescriptorType   == USB_DESC_TYPE_ENDPOINT) 
411                 {  
412                   pep               = &ep_desc[ep_ix];
413                   USBH_ParseEPDesc (pep, (uint8_t *)pdesc);
414                   ep_ix++;
415                 }
416                 else
417                 {
418                   ptr += pdesc->bLength;
419                 }
420               }
421             }
422             if_ix++;
423           }
424           else
425           {
426             ptr += pdesc->bLength;
427           }
428         }
429       }
430     }
431   }  
432 }
433
434
435 /**
436 * @brief  USBH_ParseInterfaceDesc 
437 *         This function Parses the interface descriptor
438 * @param  if_descriptor : Interface descriptor destination
439 * @param  buf: Buffer where the descriptor data is available
440 * @retval None
441 */
442 static void  USBH_ParseInterfaceDesc (USBH_InterfaceDesc_TypeDef *if_descriptor, 
443                                       uint8_t *buf)
444 {
445   if_descriptor->bLength            = *(uint8_t  *) (buf + 0);
446   if_descriptor->bDescriptorType    = *(uint8_t  *) (buf + 1);
447   if_descriptor->bInterfaceNumber   = *(uint8_t  *) (buf + 2);
448   if_descriptor->bAlternateSetting  = *(uint8_t  *) (buf + 3);
449   if_descriptor->bNumEndpoints      = *(uint8_t  *) (buf + 4);
450   if_descriptor->bInterfaceClass    = *(uint8_t  *) (buf + 5);
451   if_descriptor->bInterfaceSubClass = *(uint8_t  *) (buf + 6);
452   if_descriptor->bInterfaceProtocol = *(uint8_t  *) (buf + 7);
453   if_descriptor->iInterface         = *(uint8_t  *) (buf + 8);
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 */
463 static void  USBH_ParseEPDesc (USBH_EpDesc_TypeDef  *ep_descriptor, 
464                                uint8_t *buf)
465 {
466   
467   ep_descriptor->bLength          = *(uint8_t  *) (buf + 0);
468   ep_descriptor->bDescriptorType  = *(uint8_t  *) (buf + 1);
469   ep_descriptor->bEndpointAddress = *(uint8_t  *) (buf + 2);
470   ep_descriptor->bmAttributes     = *(uint8_t  *) (buf + 3);
471   ep_descriptor->wMaxPacketSize   = LE16 (buf + 4);
472   ep_descriptor->bInterval        = *(uint8_t  *) (buf + 6);
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 */
483 static void USBH_ParseStringDesc (uint8_t* psrc, 
484                                   uint8_t* pdest, 
485                                   uint16_t length)
486 {
487   uint16_t strlength;
488   uint16_t idx;
489   
490   /* The UNICODE string descriptor is not NULL-terminated. The string length is
491   computed by substracting two from the value of the first byte of the descriptor.
492   */
493   
494   /* Check which is lower size, the Size of string or the length of bytes read 
495   from the device */
496   
497   if ( psrc[1] == USB_DESC_TYPE_STRING)
498   { /* Make sure the Descriptor is String Type */
499     
500     /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */      
501     strlength = ( ( (psrc[0]-2) <= length) ? (psrc[0]-2) :length); 
502     psrc += 2; /* Adjust the offset ignoring the String Len and Descriptor type */
503     
504     for (idx = 0; idx < strlength; idx+=2 )
505     {/* Copy Only the string and ignore the UNICODE ID, hence add the src */
506       *pdest =  psrc[idx];
507       pdest++;
508     }  
509     *pdest = 0; /* mark end of string */  
510   }
511 }
512
513 /**
514 * @brief  USBH_GetNextDesc 
515 *         This function return the next descriptor header
516 * @param  buf: Buffer where the cfg descriptor is available
517 * @param  ptr: data popinter inside the cfg descriptor
518 * @retval next header
519 */
520 static  USBH_DescHeader_t  *USBH_GetNextDesc (uint8_t   *pbuf, uint16_t  *ptr)
521 {
522   USBH_DescHeader_t  *pnext;
523  
524   *ptr += ((USBH_DescHeader_t *)pbuf)->bLength;  
525   pnext = (USBH_DescHeader_t *)((uint8_t *)pbuf + \
526          ((USBH_DescHeader_t *)pbuf)->bLength);
527  
528   return(pnext);
529 }
530
531 /**
532 * @}
533 */ 
534
535 /**
536 * @}
537 */ 
538
539 /**
540 * @}
541 */
542
543 /**
544 * @}
545 */ 
546
547 /******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
548
549
550
551