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/usbdesc.c | 480 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 480 insertions(+) create mode 100644 usblib/usbdesc.c (limited to 'usblib/usbdesc.c') diff --git a/usblib/usbdesc.c b/usblib/usbdesc.c new file mode 100644 index 0000000..ac88082 --- /dev/null +++ b/usblib/usbdesc.c @@ -0,0 +1,480 @@ +//***************************************************************************** +// +// usbdesc.c - USB descriptor parsing functions. +// +// Copyright (c) 2008-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 "usblib/usblib.h" + +//***************************************************************************** +// +// Assumptions: +// ------------ +// +// The following assumptions are made in this module. From reading chapter 9 +// of the USB 2.0 specification, these appear to be perfectly valid. +// +// 1. The interface number, bInterfaceNumber in the interface descriptor, is +// a zero based index and takes values between 0 and +// (pConfigDescriptor->bNumInterfaces - 1) inclusive. +// 2. Similarly, the alternate setting number, bAlternateSetting in the +// interface descriptor, is a zero based index. +// 3. Interface descriptors are ordered by interface number in the +// configuration descriptor. +// 4. If alternate settings are available for an interface, the interface +// descriptors are ordered by alternate setting value bAlternateSetting. +// 5. Although the endpoints associated with a given interface must follow +// their associated interface descriptor, it is possible for other, +// device specific descriptors to be found between an interface descriptor +// and its endpoints or between endpoint descriptors for the same +// interface. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup general_usblib_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +//! Determines the number of individual descriptors of a particular type within +//! a supplied buffer. +//! +//! \param psDesc points to the first byte of a block of standard USB +//! descriptors. +//! \param ui32Size is the number of bytes of descriptor data found at pointer +//! \e psDesc. +//! \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 block of descriptors. 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. +//! +//! \return Returns the number of descriptors found in the supplied block of +//! data. +// +//***************************************************************************** +uint32_t +USBDescGetNum(tDescriptorHeader *psDesc, uint32_t ui32Size, + uint32_t ui32Type) +{ + tDescriptorHeader *psDescCheck; + uint32_t ui32TotLength; + uint32_t ui32Count; + + // + // Set up for our descriptor counting loop. + // + psDescCheck = psDesc; + ui32TotLength = 0; + ui32Count = 0; + + // + // Keep looking through the supplied data until we reach the end. + // + while(ui32TotLength < ui32Size) + { + // + // Does this descriptor match the type passed (if a specific type + // has been specified)? + // + if((ui32Type == USB_DESC_ANY) || + (psDescCheck->bDescriptorType == (uint8_t)(ui32Type & 0xFF))) + { + ui32Count++; + } + + // + // Move on to the next descriptor. + // + ui32TotLength += (uint32_t)psDescCheck->bLength; + psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck); + } + + // + // Return the descriptor count to the caller. + // + return(ui32Count); +} + +//***************************************************************************** +// +//! Determines the number of individual descriptors of a particular type within +//! a supplied buffer. +//! +//! \param psDesc points to the first byte of a block of standard USB +//! descriptors. +//! \param ui32Size is the number of bytes of descriptor data found at pointer +//! \e psDesc. +//! \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. +//! +//! Return a pointer to the n-th descriptor of a particular type found in the +//! block of \e ui32Size bytes starting at \e psDesc. +//! +//! \return Returns a pointer to the header of the required descriptor if +//! found or NULL otherwise. +// +//***************************************************************************** +tDescriptorHeader * +USBDescGet(tDescriptorHeader *psDesc, uint32_t ui32Size, + uint32_t ui32Type, uint32_t ui32Index) +{ + tDescriptorHeader *psDescCheck; + uint32_t ui32TotLength; + uint32_t ui32Count; + + // + // Set up for our descriptor counting loop. + // + psDescCheck = psDesc; + ui32TotLength = 0; + ui32Count = 0; + + // + // Keep looking through the supplied data until we reach the end. + // + while(ui32TotLength < ui32Size) + { + // + // Does this descriptor match the type passed (if a specific type + // has been specified)? + // + if((ui32Type == USB_DESC_ANY) || + (psDescCheck->bDescriptorType == (uint8_t)(ui32Type & 0xFF))) + { + // + // We found a matching descriptor. If our count matches the + // supplied index, we are done so return the pointer. + // + if(ui32Count == ui32Index) + { + return(psDescCheck); + } + + // + // We have not found enough descriptors yet to satisfy the supplied + // index so increment our count and continue. + // + ui32Count++; + } + + // + // Move on to the next descriptor. + // + ui32TotLength += (uint32_t)psDescCheck->bLength; + psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck); + } + + // + // If we get here, we reached the end of the data without finding the + // required descriptor. Return NULL. + // + return((tDescriptorHeader *)0); +} + +//***************************************************************************** +// +//! Determines the number of different alternate configurations for a given +//! interface within a configuration descriptor. +//! +//! \param psConfig points to the first byte of a standard USB configuration +//! descriptor. +//! \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. +//! +//! \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. +// +//***************************************************************************** +uint32_t +USBDescGetNumAlternateInterfaces(tConfigDescriptor *psConfig, + uint8_t ui8InterfaceNumber) +{ + tDescriptorHeader *psDescCheck; + uint32_t ui32TotLength; + uint32_t ui32Count; + + // + // Set up for our descriptor counting loop. + // + psDescCheck = (tDescriptorHeader *)psConfig; + ui32TotLength = 0; + ui32Count = 0; + + // + // Keep looking through the supplied data until we reach the end. + // + while(ui32TotLength < (uint32_t)psConfig->wTotalLength) + { + // + // 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. + // + ui32TotLength += (uint32_t)psDescCheck->bLength; + psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck); + } + + // + // Return the descriptor count to the caller. + // + return(ui32Count); +} + +//***************************************************************************** +// +//! Returns a pointer to the n-th interface descriptor in a config descriptor +//! with the supplied interface number. +//! +//! \param psConfig points to the first byte of a standard USB configuration +//! descriptor. +//! \param ui8InterfaceNumber is the interface number of the descriptor that is +//! being queried. +//! \param ui32Index is the zero based index of the descriptor to return. +//! +//! 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 * +USBDescGetAlternateInterface(tConfigDescriptor *psConfig, + uint8_t ui8InterfaceNumber, + uint32_t ui32Index) +{ + tDescriptorHeader *psDescCheck; + uint32_t ui32TotLength; + uint32_t ui32Count; + + // + // Set up for our descriptor counting loop. + // + psDescCheck = (tDescriptorHeader *)psConfig; + ui32TotLength = 0; + ui32Count = 0; + + // + // Keep looking through the supplied data until we reach the end. + // + while(ui32TotLength < (uint32_t)psConfig->wTotalLength) + { + // + // 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. + // + 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. + // + ui32TotLength += (uint32_t)psDescCheck->bLength; + psDescCheck = NEXT_USB_DESCRIPTOR(psDescCheck); + } + + // + // If we drop out the end of the loop, we did not find the requested + // descriptor so return NULL. + // + return((tInterfaceDescriptor *)0); +} + +//***************************************************************************** +// +//! 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 first byte of a standard USB configuration +//! descriptor. +//! \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 +//! will be 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. +//! +//! 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. +//! +//! \return Returns a pointer to the required interface descriptor if +//! found or NULL otherwise. +// +//***************************************************************************** +tInterfaceDescriptor * +USBDescGetInterface(tConfigDescriptor *psConfig, uint32_t ui32Index, + uint32_t ui32Alt) +{ + // + // 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 *)USBDescGet( + (tDescriptorHeader *)psConfig, + (uint32_t)psConfig->wTotalLength, + USB_DTYPE_INTERFACE, ui32Index)); + } + 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(USBDescGetAlternateInterface(psConfig, ui32Index, ui32Alt)); + } +} + +//***************************************************************************** +// +//! Return a pointer to the n-th endpoint descriptor in the supplied +//! interface descriptor. +//! +//! \param psInterface points to the first byte of a standard USB interface +//! descriptor. +//! \param ui32Index is the zero based index of the endpoint that is to be +//! found. +//! \param ui32Size contains the maximum number of bytes that the function may +//! search beyond \e psInterface while looking for the requested endpoint +//! descriptor. +//! +//! 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 cannot be found within \e ui32Size bytes of the interface +//! descriptor pointer, the function will return NULL. +//! +//! Note that, although the USB 2.0 specification states that endpoint +//! descriptors must follow the interface descriptor that they relate to, it +//! also states that device specific descriptors should follow any standard +//! descriptor that they relate to. As a result, we cannot assume that each +//! interface descriptor will be followed by nothing but an ordered list of +//! its own endpoints and, hence, the function needs to be provided \e ui32Size +//! to limit the search range. +//! +//! \return Returns a pointer to the requested endpoint descriptor if +//! found or NULL otherwise. +// +//***************************************************************************** +tEndpointDescriptor * +USBDescGetInterfaceEndpoint(tInterfaceDescriptor *psInterface, + uint32_t ui32Index, uint32_t ui32Size) +{ + // + // 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. + // + return((tEndpointDescriptor *)USBDescGet( + (tDescriptorHeader *)psInterface, + ui32Size, USB_DTYPE_ENDPOINT, ui32Index)); + } +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** -- cgit v1.3.1