/** ****************************************************************************** * @file usbh_stdreq.c * @author MCD Application Team * @version V2.1.0 * @date 19-March-2012 * @brief This file implements the standard requests for device enumeration ****************************************************************************** * @attention * *

© COPYRIGHT 2012 STMicroelectronics

* * Licensed under MCD-ST Liberty SW License Agreement V2, (the "License"); * You may not use this file except in compliance with the License. * You may obtain a copy of the License at: * * http://www.st.com/software_license_agreement_liberty_v2 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "usbh_ioreq.h" #include "usbh_stdreq.h" /** @addtogroup USBH_LIB * @{ */ /** @addtogroup USBH_LIB_CORE * @{ */ /** @defgroup USBH_STDREQ * @brief This file implements the standard requests for device enumeration * @{ */ /** @defgroup USBH_STDREQ_Private_Defines * @{ */ /** * @} */ /** @defgroup USBH_STDREQ_Private_TypesDefinitions * @{ */ /** * @} */ /** @defgroup USBH_STDREQ_Private_Macros * @{ */ /** * @} */ /** @defgroup USBH_STDREQ_Private_Variables * @{ */ /** * @} */ #ifdef USB_OTG_HS_INTERNAL_DMA_ENABLED #if defined ( __ICCARM__ ) /*!< IAR Compiler */ #pragma data_alignment=4 #endif #endif /* USB_OTG_HS_INTERNAL_DMA_ENABLED */ __ALIGN_BEGIN uint8_t USBH_CfgDesc[512] __ALIGN_END ; /** @defgroup USBH_STDREQ_Private_FunctionPrototypes * @{ */ static void USBH_ParseDevDesc (USBH_DevDesc_TypeDef* , uint8_t *buf, uint16_t length); static void USBH_ParseCfgDesc (USBH_CfgDesc_TypeDef* cfg_desc, USBH_InterfaceDesc_TypeDef* itf_desc, USBH_EpDesc_TypeDef ep_desc[][USBH_MAX_NUM_ENDPOINTS], uint8_t *buf, uint16_t length); static void USBH_ParseInterfaceDesc (USBH_InterfaceDesc_TypeDef *if_descriptor, uint8_t *buf); static void USBH_ParseEPDesc (USBH_EpDesc_TypeDef *ep_descriptor, uint8_t *buf); static void USBH_ParseStringDesc (uint8_t* psrc, uint8_t* pdest, uint16_t length); /** * @} */ /** @defgroup USBH_STDREQ_Private_Functions * @{ */ /** * @brief USBH_Get_DevDesc * Issue Get Device Descriptor command to the device. Once the response * received, it parses the device descriptor and updates the status. * @param pdev: Selected device * @param dev_desc: Device Descriptor buffer address * @param pdev->host.Rx_Buffer: Receive Buffer address * @param length: Length of the descriptor * @retval Status */ USBH_Status USBH_Get_DevDesc(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t length) { USBH_Status status; if((status = USBH_GetDescriptor(pdev, phost, USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD, USB_DESC_DEVICE, pdev->host.Rx_Buffer, length)) == USBH_OK) { /* Commands successfully sent and Response Received */ USBH_ParseDevDesc(&phost->device_prop.Dev_Desc, pdev->host.Rx_Buffer, length); } return status; } /** * @brief USBH_Get_CfgDesc * Issues Configuration Descriptor to the device. Once the response * received, it parses the configuartion descriptor and updates the * status. * @param pdev: Selected device * @param cfg_desc: Configuration Descriptor address * @param itf_desc: Interface Descriptor address * @param ep_desc: Endpoint Descriptor address * @param length: Length of the descriptor * @retval Status */ USBH_Status USBH_Get_CfgDesc(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint16_t length) { USBH_Status status; uint16_t index = 0; if((status = USBH_GetDescriptor(pdev, phost, USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD, USB_DESC_CONFIGURATION, pdev->host.Rx_Buffer, length)) == USBH_OK) { /*save Cfg descriptor for class parsing usage */ for( ; index < length ; index ++) { USBH_CfgDesc[index] = pdev->host.Rx_Buffer[index]; } /* Commands successfully sent and Response Received */ USBH_ParseCfgDesc (&phost->device_prop.Cfg_Desc, phost->device_prop.Itf_Desc, phost->device_prop.Ep_Desc, pdev->host.Rx_Buffer, length); } return status; } /** * @brief USBH_Get_StringDesc * Issues string Descriptor command to the device. Once the response * received, it parses the string descriptor and updates the status. * @param pdev: Selected device * @param string_index: String index for the descriptor * @param buff: Buffer address for the descriptor * @param length: Length of the descriptor * @retval Status */ USBH_Status USBH_Get_StringDesc(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t string_index, uint8_t *buff, uint16_t length) { USBH_Status status; if((status = USBH_GetDescriptor(pdev, phost, USB_REQ_RECIPIENT_DEVICE | USB_REQ_TYPE_STANDARD, USB_DESC_STRING | string_index, pdev->host.Rx_Buffer, length)) == USBH_OK) { /* Commands successfully sent and Response Received */ USBH_ParseStringDesc(pdev->host.Rx_Buffer,buff, length); } return status; } /** * @brief USBH_GetDescriptor * Issues Descriptor command to the device. Once the response received, * it parses the descriptor and updates the status. * @param pdev: Selected device * @param req_type: Descriptor type * @param value_idx: wValue for the GetDescriptr request * @param buff: Buffer to store the descriptor * @param length: Length of the descriptor * @retval Status */ USBH_Status USBH_GetDescriptor(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t req_type, uint16_t value_idx, uint8_t* buff, uint16_t length ) { phost->Control.setup.b.bmRequestType = USB_D2H | req_type; phost->Control.setup.b.bRequest = USB_REQ_GET_DESCRIPTOR; phost->Control.setup.b.wValue.w = value_idx; if ((value_idx & 0xff00) == USB_DESC_STRING) { phost->Control.setup.b.wIndex.w = 0x0409; } else { phost->Control.setup.b.wIndex.w = 0; } phost->Control.setup.b.wLength.w = length; return USBH_CtlReq(pdev, phost, buff , length ); } /** * @brief USBH_SetAddress * This command sets the address to the connected device * @param pdev: Selected device * @param DeviceAddress: Device address to assign * @retval Status */ USBH_Status USBH_SetAddress(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t DeviceAddress) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE | \ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_ADDRESS; phost->Control.setup.b.wValue.w = (uint16_t)DeviceAddress; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); } /** * @brief USBH_SetCfg * The command sets the configuration value to the connected device * @param pdev: Selected device * @param cfg_idx: Configuration value * @retval Status */ USBH_Status USBH_SetCfg(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint16_t cfg_idx) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_DEVICE |\ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_CONFIGURATION; phost->Control.setup.b.wValue.w = cfg_idx; phost->Control.setup.b.wIndex.w = 0; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); } /** * @brief USBH_SetInterface * The command sets the Interface value to the connected device * @param pdev: Selected device * @param itf_idx: Interface value * @retval Status */ USBH_Status USBH_SetInterface(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t ep_num, uint8_t altSetting) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_INTERFACE | \ USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_SET_INTERFACE; phost->Control.setup.b.wValue.w = altSetting; phost->Control.setup.b.wIndex.w = ep_num; phost->Control.setup.b.wLength.w = 0; return USBH_CtlReq(pdev, phost, 0 , 0 ); } /** * @brief USBH_ClrFeature * This request is used to clear or disable a specific feature. * @param pdev: Selected device * @param ep_num: endpoint number * @param hc_num: Host channel number * @retval Status */ USBH_Status USBH_ClrFeature(USB_OTG_CORE_HANDLE *pdev, USBH_HOST *phost, uint8_t ep_num, uint8_t hc_num) { phost->Control.setup.b.bmRequestType = USB_H2D | USB_REQ_RECIPIENT_ENDPOINT | USB_REQ_TYPE_STANDARD; phost->Control.setup.b.bRequest = USB_REQ_CLEAR_FEATURE; phost->Control.setup.b.wValue.w = FEATURE_SELECTOR_ENDPOINT; phost->Control.setup.b.wIndex.w = ep_num; phost->Control.setup.b.wLength.w = 0; if ((ep_num & USB_REQ_DIR_MASK ) == USB_D2H) { /* EP Type is IN */ pdev->host.hc[hc_num].toggle_in = 0; } else {/* EP Type is OUT */ pdev->host.hc[hc_num].toggle_out = 0; } return USBH_CtlReq(pdev, phost, 0 , 0 ); } /** * @brief USBH_ParseDevDesc * This function Parses the device descriptor * @param dev_desc: device_descriptor destinaton address * @param buf: Buffer where the source descriptor is available * @param length: Length of the descriptor * @retval None */ static void USBH_ParseDevDesc (USBH_DevDesc_TypeDef* dev_desc, uint8_t *buf, uint16_t length) { dev_desc->bLength = *(uint8_t *) (buf + 0); dev_desc->bDescriptorType = *(uint8_t *) (buf + 1); dev_desc->bcdUSB = LE16 (buf + 2); dev_desc->bDeviceClass = *(uint8_t *) (buf + 4); dev_desc->bDeviceSubClass = *(uint8_t *) (buf + 5); dev_desc->bDeviceProtocol = *(uint8_t *) (buf + 6); dev_desc->bMaxPacketSize = *(uint8_t *) (buf + 7); if (length > 8) { /* For 1st time after device connection, Host may issue only 8 bytes for Device Descriptor Length */ dev_desc->idVendor = LE16 (buf + 8); dev_desc->idProduct = LE16 (buf + 10); dev_desc->bcdDevice = LE16 (buf + 12); dev_desc->iManufacturer = *(uint8_t *) (buf + 14); dev_desc->iProduct = *(uint8_t *) (buf + 15); dev_desc->iSerialNumber = *(uint8_t *) (buf + 16); dev_desc->bNumConfigurations = *(uint8_t *) (buf + 17); } } /** * @brief USBH_ParseCfgDesc * This function Parses the configuration descriptor * @param cfg_desc: Configuration Descriptor address * @param itf_desc: Interface Descriptor address * @param ep_desc: Endpoint Descriptor address * @param buf: Buffer where the source descriptor is available * @param length: Length of the descriptor * @retval None */ static void USBH_ParseCfgDesc (USBH_CfgDesc_TypeDef* cfg_desc, USBH_InterfaceDesc_TypeDef* itf_desc, USBH_EpDesc_TypeDef ep_desc[][USBH_MAX_NUM_ENDPOINTS], uint8_t *buf, uint16_t length) { USBH_InterfaceDesc_TypeDef *pif ; USBH_InterfaceDesc_TypeDef temp_pif ; USBH_EpDesc_TypeDef *pep; USBH_DescHeader_t *pdesc = (USBH_DescHeader_t *)buf; uint16_t ptr; int8_t if_ix = 0; int8_t ep_ix = 0; static uint16_t prev_ep_size = 0; static uint8_t prev_itf = 0; pdesc = (USBH_DescHeader_t *)buf; /* Parse configuration descriptor */ cfg_desc->bLength = *(uint8_t *) (buf + 0); cfg_desc->bDescriptorType = *(uint8_t *) (buf + 1); cfg_desc->wTotalLength = LE16 (buf + 2); cfg_desc->bNumInterfaces = *(uint8_t *) (buf + 4); cfg_desc->bConfigurationValue = *(uint8_t *) (buf + 5); cfg_desc->iConfiguration = *(uint8_t *) (buf + 6); cfg_desc->bmAttributes = *(uint8_t *) (buf + 7); cfg_desc->bMaxPower = *(uint8_t *) (buf + 8); if (length > USB_CONFIGURATION_DESC_SIZE) { ptr = USB_LEN_CFG_DESC; if ( cfg_desc->bNumInterfaces <= USBH_MAX_NUM_INTERFACES) { pif = (USBH_InterfaceDesc_TypeDef *)0; while (ptr < cfg_desc->wTotalLength ) { pdesc = USBH_GetNextDesc((uint8_t *)pdesc, &ptr); if (pdesc->bDescriptorType == USB_DESC_TYPE_INTERFACE) { if_ix = *(((uint8_t *)pdesc ) + 2); pif = &itf_desc[if_ix]; if((*((uint8_t *)pdesc + 3)) < 3) { USBH_ParseInterfaceDesc (&temp_pif, (uint8_t *)pdesc); ep_ix = 0; /* Parse Ep descriptors relative to the current interface */ if(temp_pif.bNumEndpoints <= USBH_MAX_NUM_ENDPOINTS) { while (ep_ix < temp_pif.bNumEndpoints) { pdesc = USBH_GetNextDesc((void* )pdesc, &ptr); if (pdesc->bDescriptorType == USB_DESC_TYPE_ENDPOINT) { pep = &ep_desc[if_ix][ep_ix]; if(prev_itf != if_ix) { prev_itf = if_ix; USBH_ParseInterfaceDesc (pif, (uint8_t *)&temp_pif); } else { if(prev_ep_size > LE16((uint8_t *)pdesc + 4)) { break; } else { USBH_ParseInterfaceDesc (pif, (uint8_t *)&temp_pif); } } USBH_ParseEPDesc (pep, (uint8_t *)pdesc); prev_ep_size = LE16((uint8_t *)pdesc + 4); ep_ix++; } } } } } } } prev_ep_size = 0; prev_itf = 0; } } /** * @brief USBH_ParseInterfaceDesc * This function Parses the interface descriptor * @param if_descriptor : Interface descriptor destination * @param buf: Buffer where the descriptor data is available * @retval None */ static void USBH_ParseInterfaceDesc (USBH_InterfaceDesc_TypeDef *if_descriptor, uint8_t *buf) { if_descriptor->bLength = *(uint8_t *) (buf + 0); if_descriptor->bDescriptorType = *(uint8_t *) (buf + 1); if_descriptor->bInterfaceNumber = *(uint8_t *) (buf + 2); if_descriptor->bAlternateSetting = *(uint8_t *) (buf + 3); if_descriptor->bNumEndpoints = *(uint8_t *) (buf + 4); if_descriptor->bInterfaceClass = *(uint8_t *) (buf + 5); if_descriptor->bInterfaceSubClass = *(uint8_t *) (buf + 6); if_descriptor->bInterfaceProtocol = *(uint8_t *) (buf + 7); if_descriptor->iInterface = *(uint8_t *) (buf + 8); } /** * @brief USBH_ParseEPDesc * This function Parses the endpoint descriptor * @param ep_descriptor: Endpoint descriptor destination address * @param buf: Buffer where the parsed descriptor stored * @retval None */ static void USBH_ParseEPDesc (USBH_EpDesc_TypeDef *ep_descriptor, uint8_t *buf) { ep_descriptor->bLength = *(uint8_t *) (buf + 0); ep_descriptor->bDescriptorType = *(uint8_t *) (buf + 1); ep_descriptor->bEndpointAddress = *(uint8_t *) (buf + 2); ep_descriptor->bmAttributes = *(uint8_t *) (buf + 3); ep_descriptor->wMaxPacketSize = LE16 (buf + 4); ep_descriptor->bInterval = *(uint8_t *) (buf + 6); } /** * @brief USBH_ParseStringDesc * This function Parses the string descriptor * @param psrc: Source pointer containing the descriptor data * @param pdest: Destination address pointer * @param length: Length of the descriptor * @retval None */ static void USBH_ParseStringDesc (uint8_t* psrc, uint8_t* pdest, uint16_t length) { uint16_t strlength; uint16_t idx; /* The UNICODE string descriptor is not NULL-terminated. The string length is computed by substracting two from the value of the first byte of the descriptor. */ /* Check which is lower size, the Size of string or the length of bytes read from the device */ if ( psrc[1] == USB_DESC_TYPE_STRING) { /* Make sure the Descriptor is String Type */ /* psrc[0] contains Size of Descriptor, subtract 2 to get the length of string */ strlength = ( ( (psrc[0]-2) <= length) ? (psrc[0]-2) :length); psrc += 2; /* Adjust the offset ignoring the String Len and Descriptor type */ for (idx = 0; idx < strlength; idx+=2 ) {/* Copy Only the string and ignore the UNICODE ID, hence add the src */ *pdest = psrc[idx]; pdest++; } *pdest = 0; /* mark end of string */ } } /** * @brief USBH_GetNextDesc * This function return the next descriptor header * @param buf: Buffer where the cfg descriptor is available * @param ptr: data popinter inside the cfg descriptor * @retval next header */ USBH_DescHeader_t *USBH_GetNextDesc (uint8_t *pbuf, uint16_t *ptr) { USBH_DescHeader_t *pnext; *ptr += ((USBH_DescHeader_t *)pbuf)->bLength; pnext = (USBH_DescHeader_t *)((uint8_t *)pbuf + \ ((USBH_DescHeader_t *)pbuf)->bLength); return(pnext); } /** * @} */ /** * @} */ /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/