481 lines
18 KiB
C
481 lines
18 KiB
C
//*****************************************************************************
|
|
//
|
|
// usbdesc.c - USB descriptor parsing functions.
|
|
//
|
|
// Copyright (c) 2008-2013 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 1.1 of the Tiva USB Library.
|
|
//
|
|
//*****************************************************************************
|
|
|
|
#include <stdbool.h>
|
|
#include <stdint.h>
|
|
#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.
|
|
//! @}
|
|
//
|
|
//*****************************************************************************
|