summaryrefslogtreecommitdiff
path: root/usblib/device/usbdcdesc.c
diff options
context:
space:
mode:
authorYuval Adam <yuv.adm@gmail.com>2012-10-29 23:08:53 +0200
committerYuval Adam <yuv.adm@gmail.com>2012-10-29 23:08:53 +0200
commitc241dbd7e78c50327781a35d88d9f2db7ff2b271 (patch)
tree2c84fe512c0cd3ee328244bca2f8ed4f9622074d /usblib/device/usbdcdesc.c
parent4ba8614c006f9828f0796c140bc3e13c9e67938c (diff)
Added usblib
Diffstat (limited to 'usblib/device/usbdcdesc.c')
-rw-r--r--usblib/device/usbdcdesc.c649
1 files changed, 649 insertions, 0 deletions
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.
+//! @}
+//
+//*****************************************************************************