From c241dbd7e78c50327781a35d88d9f2db7ff2b271 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Mon, 29 Oct 2012 23:08:53 +0200 Subject: Added usblib --- usblib/device/usbdcdesc.c | 649 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 649 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..2bb1731 --- /dev/null +++ b/usblib/device/usbdcdesc.c @@ -0,0 +1,649 @@ +//***************************************************************************** +// +// usbcdesc.c - Config descriptor parsing functions. +// +// Copyright (c) 2007-2012 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 9453 of the Stellaris USB Library. +// +//***************************************************************************** + +#include "inc/hw_types.h" +#include "driverlib/debug.h" +#include "driverlib/usb.h" +#include "usblib/usblib.h" +#include "usblib/device/usbdevice.h" + +//***************************************************************************** +// +// The functions in this file mirror the descriptor parsing APIs available +// in usblib.h but parse config 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 psDesc. +//! \param pulSec points to a variable containing the section within \e +//! psConfig which contains \e psDesc. +//! \param psDesc points to the descriptor that we want to step past. +//! +//! This function walks forward one descriptor within a config descriptor. The +//! value returned is a pointer to the header of the next descriptor after the +//! descriptor supplied in \e psDesc. If the next descriptor is in the next +//! section, \e *pulSec will be incremented accordlingly. +//! +//! \return Returns a pointer to the next descriptor in the config descrptor. +// +//***************************************************************************** +static tDescriptorHeader * +NextConfigDescGet(const tConfigHeader *psConfig, unsigned long *pulSec, + 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((unsigned char *)psDesc >= (psConfig->psSections[*pulSec]->pucData + + psConfig->psSections[*pulSec]->usSize)) + { + // + // Yes - move to the next section. + // + (*pulSec)++; + + // + // Are we still within the config descriptor? + // + if(*pulSec < psConfig->ucNumSections) + { + // + // Yes - the new descriptor is at the start of the new section. + // + psDesc = + (tDescriptorHeader *)psConfig->psSections[*pulSec]->pucData; + } + 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 config descriptor +//! with the supplied interface number. +//! +//! \param psConfig points to the header structure for the config descriptor +//! that is to be searched. +//! \param ucInterfaceNumber is the interface number of the descriptor that is +//! being queried. +//! \param ulIndex is the zero based index of the descriptor to return. +//! \param pulSection points to storage which will be 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, + unsigned char ucInterfaceNumber, + unsigned long ulIndex, + unsigned long *pulSection) +{ + tDescriptorHeader *psDescCheck; + unsigned long ulCount; + unsigned long ulSec; + + // + // Set up for our descriptor counting loop. + // + psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pucData; + ulCount = 0; + ulSec = 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 == + ucInterfaceNumber)) + { + // + // This is an interface descriptor for interface ucInterfaceNumber. + // Determine if this is the n-th one we have found and, if so, + // return its pointer. + // + if(ulCount == ulIndex) + { + // + // Found it - return the pointer and section number. + // + *pulSection = ulSec; + 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. + // + ulCount++; + } + + // + // Move on to the next descriptor. + // + psDescCheck = NextConfigDescGet(psConfig, &ulSec, 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 config 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 config descriptor will result +//! from concatenating the required sections. +// +//***************************************************************************** +unsigned long +USBDCDConfigDescGetSize(const tConfigHeader *psConfig) +{ + unsigned long ulLoop; + unsigned long ulLen; + + ulLen = 0; + + // + // Determine the size of the whole descriptor by adding the sizes of + // each section which will be concatenated to produce it. + // + for(ulLoop = 0; ulLoop < psConfig->ucNumSections; ulLoop++) + { + ulLen += psConfig->psSections[ulLoop]->usSize; + } + + return(ulLen); +} + +//***************************************************************************** +// +//! \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 ulType 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. +// +//***************************************************************************** +unsigned long +USBDCDConfigDescGetNum(const tConfigHeader *psConfig, unsigned long ulType) +{ + unsigned long ulSection; + unsigned long ulNumDescs; + + // + // Initialize our counts. + // + ulNumDescs = 0; + + // + // Determine the number of descriptors of the given type in each of the + // sections comprising the config descriptor. Note that this assumes each + // section contains only whole descriptors! + // + for(ulSection = 0; ulSection < (unsigned long)psConfig->ucNumSections; + ulSection++) + { + ulNumDescs += USBDescGetNum( + (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData, + psConfig->psSections[ulSection]->usSize, + ulType); + } + + return(ulNumDescs); +} + +//***************************************************************************** +// +//! \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 ulType 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 ulIndex is the zero based index of the descriptor whose pointer is +//! to be returned. For example, passing value 1 in \e ulIndex returns the +//! second matching descriptor. +//! \param pulSection 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, unsigned long ulType, + unsigned long ulIndex, unsigned long *pulSection) +{ + unsigned long ulSection; + unsigned long ulTotalDescs; + unsigned long ulNumDescs; + + // + // Initialize our counts. + // + ulTotalDescs = 0; + + // + // Determine the number of descriptors of the given type in each of the + // sections comprising the config descriptor. This allows us to determine + // which section contains the descriptor we are being asked for. + // + for(ulSection = 0; ulSection < (unsigned long)psConfig->ucNumSections; + ulSection++) + { + // + // How many descriptors of the requested type exist in this section? + // + ulNumDescs = USBDescGetNum( + (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData, + psConfig->psSections[ulSection]->usSize, + ulType); + + // + // Does this section contain the descriptor whose index we are looking + // for? + // + if((ulTotalDescs + ulNumDescs) > ulIndex) + { + // + // We know the requested descriptor exists in the current + // block so write the section number to the caller's storage. + // + *pulSection = ulSection; + + // + // Now find the actual descriptor requested and return its pointer. + // + return(USBDescGet( + (tDescriptorHeader *)psConfig->psSections[ulSection]->pucData, + psConfig->psSections[ulSection]->usSize, + ulType, + ulIndex - ulTotalDescs)); + } + + // + // 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. + // + ulTotalDescs += ulNumDescs; + } + + // + // 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 config descriptor. +//! +//! \param psConfig points to the header structure for the configuration +//! descriptor that is to be searched. +//! \param ucInterfaceNumber 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 config +//! descriptor. +// +//***************************************************************************** +unsigned long +USBDCDConfigGetNumAlternateInterfaces(const tConfigHeader *psConfig, + unsigned char ucInterfaceNumber) +{ + tDescriptorHeader *psDescCheck; + unsigned long ulCount; + unsigned long ulSec; + + // + // Set up for our descriptor counting loop. + // + psDescCheck = (tDescriptorHeader *)psConfig->psSections[0]->pucData; + ulSec = 0; + ulCount = 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 == + ucInterfaceNumber)) + { + // + // Yes - increment our count. + // + ulCount++; + } + + // + // Move on to the next descriptor. + // + psDescCheck = NextConfigDescGet(psConfig, &ulSec, psDescCheck); + } + + // + // Return the descriptor count to the caller. + // + return(ulCount); +} + +//***************************************************************************** +// +//! \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 ulIndex is the zero based index of the interface that is to be +//! found. If \e ulAlt is set to a value other than \b USB_DESC_ANY, this will +//! be equivalent to the interface number being searched for. +//! \param ulAlt 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 pulSection 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 ulAlt 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 +//! ulAlt if \e ulIndex is set to the required interface number and \e ulAlt +//! 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, unsigned long ulIndex, + unsigned long ulAlt, unsigned long *pulSection) +{ + // + // If we are being told to ignore the alternate configuration, this boils + // down to a very simple query. + // + if(ulAlt == USB_DESC_ANY) + { + // + // Return the ulIndex-th interface descriptor we find in the + // configuration descriptor. + // + return((tInterfaceDescriptor *)USBDCDConfigDescGet(psConfig, + USB_DTYPE_INTERFACE, + ulIndex, + pulSection)); + } + else + { + // + // In this case, a specific alternate setting number is required. + // Given that interface numbers are zero based indices, we can + // pass the supplied ulIndex parameter directly as the interface + // number to USBDescGetAlternateInterface to retrieve the requested + // interface descriptor pointer. + // + return(ConfigAlternateInterfaceGet(psConfig, ulIndex, ulAlt, + pulSection)); + } +} + +//***************************************************************************** +// +//! \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 ulInterfaceNumber is the interface number whose endpoint is to be +//! found. +//! \param ulAltCfg is the alternate setting number which is to be searched +//! for. This must be a valid alternate setting number for the requested +//! interface. +//! \param ulIndex 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 ulIndex 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, + unsigned long ulInterfaceNumber, + unsigned long ulAltCfg, unsigned long ulIndex) +{ + tInterfaceDescriptor *psInterface; + tDescriptorHeader *psEndpoint; + unsigned long ulSection; + unsigned long ulCount; + + // + // Find the requested interface descriptor. + // + psInterface = USBDCDConfigGetInterface(psConfig, ulInterfaceNumber, + ulAltCfg, &ulSection); + + // + // Did we find the requested interface? + // + if(psInterface) + { + // + // Is the index passed valid? + // + if(ulIndex >= 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. + // + ulCount = 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(ulCount == ulIndex) + { + // + // Yes - return the descriptor pointer to the caller. + // + return((tEndpointDescriptor *)psEndpoint); + } + + // + // Move on to look for the next endpoint. + // + ulCount++; + } + + // + // Move to the next descriptor. + // + psEndpoint = NextConfigDescGet(psConfig, &ulSection, + psEndpoint); + } + } + } + + // + // We couldn't 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