From 990090a4cc9070837d31e66b58d40f0c3d038741 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 16 Mar 2014 14:41:11 +0200 Subject: Add usblib and utils --- usblib/device/usbdcdesc.c | 643 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 643 insertions(+) create mode 100644 usblib/device/usbdcdesc.c (limited to 'usblib/device/usbdcdesc.c') diff --git a/usblib/device/usbdcdesc.c b/usblib/device/usbdcdesc.c new file mode 100644 index 0000000..6260d42 --- /dev/null +++ b/usblib/device/usbdcdesc.c @@ -0,0 +1,643 @@ +//***************************************************************************** +// +// usbcdesc.c - Config descriptor parsing functions. +// +// Copyright (c) 2007-2014 Texas Instruments Incorporated. All rights reserved. +// Software License Agreement +// +// Texas Instruments (TI) is supplying this software for use solely and +// exclusively on TI's microcontroller products. The software is owned by +// TI and/or its suppliers, and is protected under applicable copyright +// laws. You may not combine this software with "viral" open-source +// software in order to form a larger program. +// +// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. +// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT +// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY +// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL +// DAMAGES, FOR ANY REASON WHATSOEVER. +// +// This is part of revision 2.1.0.12573 of the Tiva USB Library. +// +//***************************************************************************** + +#include +#include +#include "inc/hw_types.h" +#include "driverlib/debug.h" +#include "driverlib/usb.h" +#include "usblib/usblib.h" +#include "usblib/usblibpriv.h" +#include "usblib/device/usbdevice.h" + +//***************************************************************************** +// +// The functions in this file mirror the descriptor parsing APIs available +// in usblib.h but parse configuration descriptors defined in terms of a list +// of sections rather than as a single block of descriptor data. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup device_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +//! \internal +//! +//! Walk to the next descriptor after the supplied one within a section-based +//! config descriptor. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor which contains \e pi16Desc. +//! \param pui32Sec points to a variable containing the section within +//! \e psConfig which contains \e pi16Desc. +//! \param pi16Desc points to the descriptor that we want to step past. +//! +//! This function walks forward one descriptor within a configuration +//! descriptor. The value returned is a pointer to the header of the next +//! descriptor after the descriptor supplied in \e pi16Desc. If the next +//! descriptor is in the next section, \e *pui32Sec will be incremented +//! accordingly. +//! +//! \return Returns a pointer to the next descriptor in the configuration +//! descriptor. +// +//***************************************************************************** +static tDescriptorHeader * +NextConfigDescGet(const tConfigHeader *psConfig, uint32_t *pui32Sec, + tDescriptorHeader *psDesc) +{ + // + // Determine where the next descriptor after the supplied one should be + // assuming it is within the current section. + // + psDesc = NEXT_USB_DESCRIPTOR(psDesc); + + // + // Did we run off the end of the section? + // + if((uint8_t *)psDesc >= (psConfig->psSections[*pui32Sec]->pui8Data + + psConfig->psSections[*pui32Sec]->ui16Size)) + { + // + // Yes - move to the next section. + // + (*pui32Sec)++; + + // + // Are we still within the configuration descriptor? + // + if(*pui32Sec < psConfig->ui8NumSections) + { + // + // Yes - the new descriptor is at the start of the new section. + // + psDesc = + (tDescriptorHeader *)psConfig->psSections[*pui32Sec]->pui8Data; + } + else + { + // + // No - we ran off the end of the descriptor so return NULL. + // + psDesc = (tDescriptorHeader *)0; + } + } + + // + // Return the new descriptor pointer. + // + return(psDesc); +} + +//***************************************************************************** +// +//! \internal +//! +//! Returns a pointer to the n-th interface descriptor in a configuration +//! descriptor with the supplied interface number. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor to search. +//! \param ui8InterfaceNumber is the interface number of the descriptor to +//! query. +//! \param ui32Index is the zero based index of the descriptor. +//! \param pui32Section points to storage which is written with the index +//! of the section containing the returned descriptor. +//! +//! This function returns a pointer to the n-th interface descriptor in the +//! supplied configuration which has the requested interface number. It may be +//! used by a client to retrieve the descriptors for each alternate setting +//! of a given interface within the configuration passed. +//! +//! \return Returns a pointer to the n-th interface descriptor with interface +//! number as specified or NULL of this descriptor does not exist. +// +//***************************************************************************** +static tInterfaceDescriptor * +ConfigAlternateInterfaceGet(const tConfigHeader *psConfig, + uint8_t ui8InterfaceNumber, uint32_t ui32Index, + uint32_t *pui32Section) +{ + tDescriptorHeader *psDescCheck; + uint32_t ui32Count, ui32Sec; + + // + // Set up for our descriptor counting loop. + // + psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pui8Data; + ui32Count = 0; + ui32Sec = 0; + + // + // Keep looking through the supplied data until we reach the end. + // + while(psDescCheck) + { + // + // Does this descriptor match the type passed (if a specific type + // has been specified)? + // + if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) && + (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber == + ui8InterfaceNumber)) + { + // + // This is an interface descriptor for interface + // ui8InterfaceNumber. Determine if this is the n-th one we have + // found and, if so, return its pointer. + // + if(ui32Count == ui32Index) + { + // + // Found it - return the pointer and section number. + // + *pui32Section = ui32Sec; + return((tInterfaceDescriptor *)psDescCheck); + } + + // + // Increment our count of matching descriptors found and go back + // to look for another since we have not yet reached the n-th + // match. + // + ui32Count++; + } + + // + // Move on to the next descriptor. + // + psDescCheck = NextConfigDescGet(psConfig, &ui32Sec, psDescCheck); + } + + // + // If we drop out the end of the loop, we did not find the requested + // descriptor so return NULL. + // + return((tInterfaceDescriptor *)0); +} + +//***************************************************************************** +// +//! \internal +//! +//! Determines the total length of a configuration descriptor defined in terms +//! of a collection of concatenated sections. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor whose size is to be determined. +//! +//! \return Returns the number of bytes in the configuration descriptor will +//! result from concatenating the required sections. +// +//***************************************************************************** +uint32_t +USBDCDConfigDescGetSize(const tConfigHeader *psConfig) +{ + uint32_t ui32Loop, ui32Len; + + ui32Len = 0; + + // + // Determine the size of the whole descriptor by adding the sizes of + // each section which will be concatenated to produce it. + // + for(ui32Loop = 0; ui32Loop < psConfig->ui8NumSections; ui32Loop++) + { + ui32Len += psConfig->psSections[ui32Loop]->ui16Size; + } + + return(ui32Len); +} + +//***************************************************************************** +// +//! \internal +//! +//! Determines the number of individual descriptors of a particular type within +//! a supplied configuration descriptor. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor that is to be searched. +//! \param ui32Type identifies the type of descriptor that is to be counted. +//! If the value is \b USB_DESC_ANY, the function returns the total number of +//! descriptors regardless of type. +//! +//! This function can be used to count the number of descriptors of a +//! particular type within a configuration descriptor. The caller can provide +//! a specific type value which the function matches against the second byte +//! of each descriptor or, alternatively, can specify \b USB_DESC_ANY to have +//! the function count all descriptors regardless of their type. +//! +//! The search performed by this function traverses through the list of +//! sections comprising the configuration descriptor. Note that the similar +//! top-level function, USBDescGetNum(), searches through a single, contiguous +//! block of data to perform the same enumeration. +//! +//! \return Returns the number of descriptors found in the supplied block of +//! data. +// +//***************************************************************************** +uint32_t +USBDCDConfigDescGetNum(const tConfigHeader *psConfig, uint32_t ui32Type) +{ + uint32_t ui32Section, ui32NumDescs; + + // + // Initialize our counts. + // + ui32NumDescs = 0; + + // + // Determine the number of descriptors of the given type in each of the + // sections comprising the configuration descriptor. Note that this + // assumes each section contains only whole descriptors! + // + for(ui32Section = 0; ui32Section < (uint32_t)psConfig->ui8NumSections; + ui32Section++) + { + ui32NumDescs += USBDescGetNum( + (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data, + psConfig->psSections[ui32Section]->ui16Size, ui32Type); + } + + return(ui32NumDescs); +} + +//***************************************************************************** +// +//! \internal +//! +//! Finds the n-th descriptor of a particular type within the supplied +//! configuration descriptor. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor that is to be searched. +//! \param ui32Type identifies the type of descriptor that is to be found. If +//! the value is \b USB_DESC_ANY, the function returns a pointer to the n-th +//! descriptor regardless of type. +//! \param ui32Index is the zero based index of the descriptor whose pointer is +//! to be returned. For example, passing value 1 in \e ui32Index returns the +//! second matching descriptor. +//! \param pui32Section points to storage which will receive the section index +//! containing the requested descriptor. +//! +//! Return a pointer to the n-th descriptor of a particular type found in the +//! configuration descriptor passed. +//! +//! The search performed by this function traverses through the list of +//! sections comprising the configuration descriptor. Note that the similar +//! top-level function, USBDescGet(), searches through a single, contiguous +//! block of data to perform the same enumeration. +//! +//! \return Returns a pointer to the header of the required descriptor if +//! found or NULL otherwise. +// +//***************************************************************************** +tDescriptorHeader * +USBDCDConfigDescGet(const tConfigHeader *psConfig, uint32_t ui32Type, + uint32_t ui32Index, uint32_t *pui32Section) +{ + uint32_t ui32Section, ui32TotalDescs, ui32NumDescs; + + // + // Initialize our counts. + // + ui32TotalDescs = 0; + + // + // Determine the number of descriptors of the given type in each of the + // sections comprising the configuration descriptor. This allows us to + // determine which section contains the descriptor we are being asked for. + // + for(ui32Section = 0; ui32Section < (uint32_t)psConfig->ui8NumSections; + ui32Section++) + { + // + // How many descriptors of the requested type exist in this section? + // + ui32NumDescs = USBDescGetNum( + (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data, + psConfig->psSections[ui32Section]->ui16Size, ui32Type); + + // + // Does this section contain the descriptor whose index we are looking + // for? + // + if((ui32TotalDescs + ui32NumDescs) > ui32Index) + { + // + // We know the requested descriptor exists in the current + // block so write the section number to the caller's storage. + // + *pui32Section = ui32Section; + + // + // Now find the actual descriptor requested and return its pointer. + // + return(USBDescGet( + (tDescriptorHeader *)psConfig->psSections[ui32Section]->pui8Data, + psConfig->psSections[ui32Section]->ui16Size, + ui32Type, ui32Index - ui32TotalDescs)); + } + + // + // We have not found the required descriptor yet. Update our running + // count of the number of type matches found so far then move on to + // the next section. + // + ui32TotalDescs += ui32NumDescs; + } + + // + // If we drop out of the loop, we can't find the requested descriptor + // so return NULL. + // + return((tDescriptorHeader *)0); +} + +//***************************************************************************** +// +//! \internal +//! +//! Determines the number of different alternate configurations for a given +//! interface within a configuration descriptor. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor that is to be searched. +//! \param ui8InterfaceNumber is the interface number for which the number of +//! alternate configurations is to be counted. +//! +//! This function can be used to count the number of alternate settings for a +//! specific interface within a configuration. +//! +//! The search performed by this function traverses through the list of +//! sections comprising the configuration descriptor. Note that the similar +//! top-level function, USBDescGetNumAlternateInterfaces(), searches through +//! a single, contiguous block of data to perform the same enumeration. +//! +//! \return Returns the number of alternate versions of the specified interface +//! or 0 if the interface number supplied cannot be found in the configuration +//! descriptor. +// +//***************************************************************************** +uint32_t +USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig, + uint8_t ui8InterfaceNumber) +{ + tDescriptorHeader *psDescCheck; + uint32_t ui32Count, ui32Sec; + + // + // Set up for our descriptor counting loop. + // + psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pui8Data; + ui32Sec = 0; + ui32Count = 0; + + // + // Keep looking through the supplied data until we reach the end. + // + while(psDescCheck) + { + // + // Is this an interface descriptor with the required interface number? + // + if((psDescCheck->bDescriptorType == USB_DTYPE_INTERFACE) && + (((tInterfaceDescriptor *)psDescCheck)->bInterfaceNumber == + ui8InterfaceNumber)) + { + // + // Yes - increment our count. + // + ui32Count++; + } + + // + // Move on to the next descriptor. + // + psDescCheck = NextConfigDescGet(psConfig, &ui32Sec, psDescCheck); + } + + // + // Return the descriptor count to the caller. + // + return(ui32Count); +} + +//***************************************************************************** +// +//! \internal +//! +//! Returns a pointer to the n-th interface descriptor in a configuration +//! descriptor that applies to the supplied alternate setting number. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor that is to be searched. +//! \param ui32Index is the zero based index of the interface that is to be +//! found. If \e ui32Alt is set to a value other than \b USB_DESC_ANY, this +//! is equivalent to the interface number being searched for. +//! \param ui32Alt is the alternate setting number which is to be +//! searched for. If this value is \b USB_DESC_ANY, the alternate setting +//! is ignored and all interface descriptors are considered in the search. +//! \param pui32Section points to storage which will receive the index of the +//! config descriptor section which contains the requested interface +//! descriptor. +//! +//! Return a pointer to the n-th interface descriptor found in the supplied +//! configuration descriptor. If \e ui32Alt is not \b USB_DESC_ANY, only +//! interface descriptors which are part of the supplied alternate setting are +//! considered in the search otherwise all interface descriptors are +//! considered. +//! +//! Note that, although alternate settings can be applied on an interface-by- +//! interface basis, the number of interfaces offered is fixed for a given +//! config descriptor. Hence, this function will correctly find the unique +//! interface descriptor for that interface's alternate setting number \e +//! ui32Alt if \e ui32Index is set to the required interface number and +//! \e ui32Alt is set to a valid alternate setting number for that interface. +//! +//! The search performed by this function traverses through the list of +//! sections comprising the configuration descriptor. Note that the similar +//! top-level function, USBDescGetInterface(), searches through a single, +//! contiguous block of data to perform the same enumeration. +//! +//! \return Returns a pointer to the required interface descriptor if +//! found or NULL otherwise. +// +//***************************************************************************** +tInterfaceDescriptor * +USBDCDConfigGetInterface(const tConfigHeader *psConfig, uint32_t ui32Index, + uint32_t ui32Alt, uint32_t *pui32Section) +{ + // + // If we are being told to ignore the alternate configuration, this boils + // down to a very simple query. + // + if(ui32Alt == USB_DESC_ANY) + { + // + // Return the ui32Index-th interface descriptor we find in the + // configuration descriptor. + // + return((tInterfaceDescriptor *)USBDCDConfigDescGet(psConfig, + USB_DTYPE_INTERFACE, + ui32Index, + pui32Section)); + } + else + { + // + // In this case, a specific alternate setting number is required. + // Given that interface numbers are zero based indices, we can + // pass the supplied ui32Index parameter directly as the interface + // number to USBDescGetAlternateInterface() to retrieve the requested + // interface descriptor pointer. + // + return(ConfigAlternateInterfaceGet(psConfig, ui32Index, ui32Alt, + pui32Section)); + } +} + +//***************************************************************************** +// +//! \internal +//! +//! Return a pointer to the n-th endpoint descriptor in a particular interface +//! within a configuration descriptor. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor that is to be searched. +//! \param ui32InterfaceNumber is the interface number whose endpoint is to be +//! found. +//! \param ui32AltCfg is the alternate setting number which is to be searched +//! for. This must be a valid alternate setting number for the requested +//! interface. +//! \param ui32Index is the zero based index of the endpoint that is to be +//! found within the appropriate alternate setting for the interface. +//! +//! Return a pointer to the n-th endpoint descriptor found in the supplied +//! interface descriptor. If the \e ui32Index parameter is invalid (greater +//! than or equal to the bNumEndpoints field of the interface descriptor) or +//! the endpoint descriptor cannot be found, the function will return NULL. +//! +//! The search performed by this function traverses through the list of +//! sections comprising the configuration descriptor. Note that the similar +//! top-level function, USBDescGetInterfaceEndpoint(), searches through a +//! single, contiguous block of data to perform the same enumeration. +//! +//! \return Returns a pointer to the requested endpoint descriptor if +//! found or NULL otherwise. +// +//***************************************************************************** +tEndpointDescriptor * +USBDCDConfigGetInterfaceEndpoint(const tConfigHeader *psConfig, + uint32_t ui32InterfaceNumber, + uint32_t ui32AltCfg, uint32_t ui32Index) +{ + tInterfaceDescriptor *psInterface; + tDescriptorHeader *psEndpoint; + uint32_t ui32Section, ui32Count; + + // + // Find the requested interface descriptor. + // + psInterface = USBDCDConfigGetInterface(psConfig, ui32InterfaceNumber, + ui32AltCfg, &ui32Section); + + // + // Did we find the requested interface? + // + if(psInterface) + { + // + // Is the index passed valid? + // + if(ui32Index >= psInterface->bNumEndpoints) + { + // + // It's out of bounds so return a NULL. + // + return((tEndpointDescriptor *)0); + } + else + { + // + // Endpoint index is valid so find the descriptor. We start from + // the interface descriptor and look for following endpoint + // descriptors. + // + ui32Count = 0; + psEndpoint = (tDescriptorHeader *)psInterface; + + while(psEndpoint) + { + if(psEndpoint->bDescriptorType == USB_DTYPE_ENDPOINT) + { + // + // We found an endpoint descriptor. Have we reached the + // one we want? + // + if(ui32Count == ui32Index) + { + // + // Yes - return the descriptor pointer to the caller. + // + return((tEndpointDescriptor *)psEndpoint); + } + + // + // Move on to look for the next endpoint. + // + ui32Count++; + } + + // + // Move to the next descriptor. + // + psEndpoint = NextConfigDescGet(psConfig, &ui32Section, + psEndpoint); + } + } + } + + // + // We could not find the requested interface or we got to the end of the + // descriptor without finding the requested endpoint. + // + return((tEndpointDescriptor *)0); + +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** -- cgit v1.3.1