You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
14 KiB
286 lines
14 KiB
/* |
|
LUFA Library |
|
Copyright (C) Dean Camera, 2010. |
|
|
|
dean [at] fourwalledcubicle [dot] com |
|
www.fourwalledcubicle.com |
|
*/ |
|
|
|
/* |
|
Copyright 2010 Dean Camera (dean [at] fourwalledcubicle [dot] com) |
|
|
|
Permission to use, copy, modify, distribute, and sell this |
|
software and its documentation for any purpose is hereby granted |
|
without fee, provided that the above copyright notice appear in |
|
all copies and that both that the copyright notice and this |
|
permission notice and warranty disclaimer appear in supporting |
|
documentation, and that the name of the author not be used in |
|
advertising or publicity pertaining to distribution of the |
|
software without specific, written prior permission. |
|
|
|
The author disclaim all warranties with regard to this |
|
software, including all implied warranties of merchantability |
|
and fitness. In no event shall the author be liable for any |
|
special, indirect or consequential damages or any damages |
|
whatsoever resulting from loss of use, data or profits, whether |
|
in an action of contract, negligence or other tortious action, |
|
arising out of or in connection with the use or performance of |
|
this software. |
|
*/ |
|
|
|
/** \file |
|
* \brief Configuration descriptor parser API. |
|
* |
|
* This section of the library gives a friendly API which can be used in host applications to easily |
|
* parse an attached device's configuration descriptor so that endpoint, interface and other descriptor |
|
* data can be extracted and used as needed. |
|
* |
|
* \note This file should not be included directly. It is automatically included as needed by the USB driver |
|
* dispatch header located in LUFA/Drivers/USB/USB.h. |
|
*/ |
|
|
|
/** \ingroup Group_Descriptors |
|
* @defgroup Group_ConfigDescriptorParser Configuration Descriptor Parser |
|
* |
|
* Functions, macros, variables, enums and types related to the parsing of Configuration Descriptors. |
|
* |
|
* @{ |
|
*/ |
|
|
|
#ifndef __CONFIGDESCRIPTOR_H__ |
|
#define __CONFIGDESCRIPTOR_H__ |
|
|
|
/* Includes: */ |
|
#include <stdint.h> |
|
|
|
#include "../../../Common/Common.h" |
|
#include "HostStandardReq.h" |
|
#include "USBMode.h" |
|
#include "StdDescriptors.h" |
|
|
|
/* Enable C linkage for C++ Compilers: */ |
|
#if defined(__cplusplus) |
|
extern "C" { |
|
#endif |
|
|
|
/* Preprocessor Checks: */ |
|
#if !defined(__INCLUDE_FROM_USB_DRIVER) |
|
#error Do not include this file directly. Include LUFA/Drivers/USB/USB.h instead. |
|
#endif |
|
|
|
/* Public Interface - May be used in end-application: */ |
|
/* Macros: */ |
|
/** Mask for determining the type of an endpoint from an endpoint descriptor. This should then be compared |
|
* with the EP_TYPE_* masks to determine the exact type of the endpoint. |
|
*/ |
|
#define EP_TYPE_MASK 0x03 |
|
|
|
/** Casts a pointer to a descriptor inside the configuration descriptor into a pointer to the given |
|
* descriptor type. |
|
* |
|
* Usage Example: |
|
* \code |
|
* uint8_t* CurrDescriptor = &ConfigDescriptor[0]; // Pointing to the configuration header |
|
* USB_Descriptor_Configuration_Header_t* ConfigHeaderPtr = DESCRIPTOR_PCAST(CurrDescriptor, |
|
* USB_Descriptor_Configuration_Header_t); |
|
* |
|
* // Can now access elements of the configuration header struct using the -> indirection operator |
|
* \endcode |
|
*/ |
|
#define DESCRIPTOR_PCAST(DescriptorPtr, Type) ((Type*)(DescriptorPtr)) |
|
|
|
/** Casts a pointer to a descriptor inside the configuration descriptor into the given descriptor |
|
* type (as an actual struct instance rather than a pointer to a struct). |
|
* |
|
* Usage Example: |
|
* \code |
|
* uint8_t* CurrDescriptor = &ConfigDescriptor[0]; // Pointing to the configuration header |
|
* USB_Descriptor_Configuration_Header_t ConfigHeader = DESCRIPTOR_CAST(CurrDescriptor, |
|
* USB_Descriptor_Configuration_Header_t); |
|
* |
|
* // Can now access elements of the configuration header struct using the . operator |
|
* \endcode |
|
*/ |
|
#define DESCRIPTOR_CAST(DescriptorPtr, Type) (*DESCRIPTOR_PCAST(DescriptorPtr, Type)) |
|
|
|
/** Returns the descriptor's type, expressed as the 8-bit type value in the header of the descriptor. |
|
* This value's meaning depends on the descriptor's placement in the descriptor, but standard type |
|
* values can be accessed in the \ref USB_DescriptorTypes_t enum. |
|
*/ |
|
#define DESCRIPTOR_TYPE(DescriptorPtr) DESCRIPTOR_CAST(DescriptorPtr, USB_Descriptor_Header_t).Type |
|
|
|
/** Returns the descriptor's size, expressed as the 8-bit value indicating the number of bytes. */ |
|
#define DESCRIPTOR_SIZE(DescriptorPtr) DESCRIPTOR_CAST(DescriptorPtr, USB_Descriptor_Header_t).Size |
|
|
|
/* Type Defines: */ |
|
/** Type define for a Configuration Descriptor comparator function (function taking a pointer to an array |
|
* of type void, returning a uint8_t value). |
|
* |
|
* \see \ref USB_GetNextDescriptorComp function for more details. |
|
*/ |
|
typedef uint8_t (* ConfigComparatorPtr_t)(void*); |
|
|
|
/* Enums: */ |
|
/** Enum for the possible return codes of the \ref USB_Host_GetDeviceConfigDescriptor() function. */ |
|
enum USB_Host_GetConfigDescriptor_ErrorCodes_t |
|
{ |
|
HOST_GETCONFIG_Successful = 0, /**< No error occurred while retrieving the configuration descriptor. */ |
|
HOST_GETCONFIG_DeviceDisconnect = 1, /**< The attached device was disconnected while retrieving the configuration |
|
* descriptor. |
|
*/ |
|
HOST_GETCONFIG_PipeError = 2, /**< An error occurred in the pipe while sending the request. */ |
|
HOST_GETCONFIG_SetupStalled = 3, /**< The attached device stalled the request to retrieve the configuration |
|
* descriptor. |
|
*/ |
|
HOST_GETCONFIG_SoftwareTimeOut = 4, /**< The request or data transfer timed out. */ |
|
HOST_GETCONFIG_BuffOverflow = 5, /**< The device's configuration descriptor is too large to fit into the allocated |
|
* buffer. |
|
*/ |
|
HOST_GETCONFIG_InvalidData = 6, /**< The device returned invalid configuration descriptor data. */ |
|
}; |
|
|
|
/** Enum for return values of a descriptor comparator function. */ |
|
enum DSearch_Return_ErrorCodes_t |
|
{ |
|
DESCRIPTOR_SEARCH_Found = 0, /**< Current descriptor matches comparator criteria. */ |
|
DESCRIPTOR_SEARCH_Fail = 1, /**< No further descriptor could possibly match criteria, fail the search. */ |
|
DESCRIPTOR_SEARCH_NotFound = 2, /**< Current descriptor does not match comparator criteria. */ |
|
}; |
|
|
|
/** Enum for return values of \ref USB_GetNextDescriptorComp(). */ |
|
enum DSearch_Comp_Return_ErrorCodes_t |
|
{ |
|
DESCRIPTOR_SEARCH_COMP_Found = 0, /**< Configuration descriptor now points to descriptor which matches |
|
* search criteria of the given comparator function. */ |
|
DESCRIPTOR_SEARCH_COMP_Fail = 1, /**< Comparator function returned Descriptor_Search_Fail. */ |
|
DESCRIPTOR_SEARCH_COMP_EndOfDescriptor = 2, /**< End of configuration descriptor reached before match found. */ |
|
}; |
|
|
|
/* Function Prototypes: */ |
|
/** Retrieves the configuration descriptor data from an attached device via a standard request into a buffer, |
|
* including validity and size checking to prevent a buffer overflow. |
|
* |
|
* \param[in] ConfigNumber Device configuration descriptor number to fetch from the device (usually set to 1 for |
|
* single configuration devices). |
|
* \param[in,out] ConfigSizePtr Pointer to a uint16_t for storing the retrieved configuration descriptor size. |
|
* \param[out] BufferPtr Pointer to the buffer for storing the configuration descriptor data. |
|
* \param[out] BufferSize Size of the allocated buffer where the configuration descriptor is to be stored. |
|
* |
|
* \return A value from the \ref USB_Host_GetConfigDescriptor_ErrorCodes_t enum. |
|
*/ |
|
uint8_t USB_Host_GetDeviceConfigDescriptor(uint8_t ConfigNumber, uint16_t* const ConfigSizePtr, void* BufferPtr, |
|
uint16_t BufferSize) ATTR_NON_NULL_PTR_ARG(2) ATTR_NON_NULL_PTR_ARG(3); |
|
|
|
/** Skips to the next sub-descriptor inside the configuration descriptor of the specified type value. |
|
* The bytes remaining value is automatically decremented. |
|
* |
|
* \param[in,out] BytesRem Pointer to the number of bytes remaining of the configuration descriptor. |
|
* \param[in,out] CurrConfigLoc Pointer to the current descriptor inside the configuration descriptor. |
|
* \param[in] Type Descriptor type value to search for. |
|
*/ |
|
void USB_GetNextDescriptorOfType(uint16_t* const BytesRem, |
|
void** const CurrConfigLoc, |
|
const uint8_t Type) |
|
ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); |
|
|
|
/** Skips to the next sub-descriptor inside the configuration descriptor of the specified type value, |
|
* which must come before a descriptor of the second given type value. If the BeforeType type |
|
* descriptor is reached first, the number of bytes remaining to process is set to zero and the |
|
* function exits. The bytes remaining value is automatically decremented. |
|
* |
|
* \param[in,out] BytesRem Pointer to the number of bytes remaining of the configuration descriptor. |
|
* \param[in,out] CurrConfigLoc Pointer to the current descriptor inside the configuration descriptor. |
|
* \param[in] Type Descriptor type value to search for. |
|
* \param[in] BeforeType Descriptor type value which must not be reached before the given Type descriptor. |
|
*/ |
|
void USB_GetNextDescriptorOfTypeBefore(uint16_t* const BytesRem, |
|
void** const CurrConfigLoc, |
|
const uint8_t Type, |
|
const uint8_t BeforeType) |
|
ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); |
|
|
|
/** Skips to the next sub-descriptor inside the configuration descriptor of the specified type value, |
|
* which must come after a descriptor of the second given type value. The bytes remaining value is |
|
* automatically decremented. |
|
* |
|
* \param[in,out] BytesRem Pointer to the number of bytes remaining of the configuration descriptor. |
|
* \param[in,out] CurrConfigLoc Pointer to the current descriptor inside the configuration descriptor. |
|
* \param[in] Type Descriptor type value to search for. |
|
* \param[in] AfterType Descriptor type value which must be reached before the given Type descriptor. |
|
*/ |
|
void USB_GetNextDescriptorOfTypeAfter(uint16_t* const BytesRem, |
|
void** const CurrConfigLoc, |
|
const uint8_t Type, |
|
const uint8_t AfterType) |
|
ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); |
|
|
|
/** Searches for the next descriptor in the given configuration descriptor using a pre-made comparator |
|
* function. The routine updates the position and remaining configuration descriptor bytes values |
|
* automatically. If a comparator routine fails a search, the descriptor pointer is retreated back |
|
* so that the next descriptor search invocation will start from the descriptor which first caused the |
|
* original search to fail. This behaviour allows for one comparator to be used immediately after another |
|
* has failed, starting the second search from the descriptor which failed the first. |
|
* |
|
* Comparator functions should be standard functions which accept a pointer to the header of the current |
|
* descriptor inside the configuration descriptor which is being compared, and should return a value from |
|
* the \ref DSearch_Return_ErrorCodes_t enum as a uint8_t value. |
|
* |
|
* \note This function is available in USB Host mode only. |
|
* |
|
* \param[in,out] BytesRem Pointer to an int storing the remaining bytes in the configuration descriptor. |
|
* \param[in,out] CurrConfigLoc Pointer to the current position in the configuration descriptor. |
|
* \param[in] ComparatorRoutine Name of the comparator search function to use on the configuration descriptor. |
|
* |
|
* \return Value of one of the members of the \ref DSearch_Comp_Return_ErrorCodes_t enum. |
|
* |
|
* Usage Example: |
|
* \code |
|
* uint8_t EndpointSearcher(void* CurrentDescriptor); // Comparator Prototype |
|
* |
|
* uint8_t EndpointSearcher(void* CurrentDescriptor) |
|
* { |
|
* if (DESCRIPTOR_TYPE(CurrentDescriptor) == DTYPE_Endpoint) |
|
* return DESCRIPTOR_SEARCH_Found; |
|
* else |
|
* return DESCRIPTOR_SEARCH_NotFound; |
|
* } |
|
* |
|
* //... |
|
* // After retrieving configuration descriptor: |
|
* if (USB_Host_GetNextDescriptorComp(&BytesRemaining, &CurrentConfigLoc, EndpointSearcher) == |
|
* Descriptor_Search_Comp_Found) |
|
* { |
|
* // Do something with the endpoint descriptor |
|
* } |
|
* \endcode |
|
*/ |
|
uint8_t USB_GetNextDescriptorComp(uint16_t* const BytesRem, |
|
void** const CurrConfigLoc, |
|
ConfigComparatorPtr_t const ComparatorRoutine); |
|
|
|
/* Inline Functions: */ |
|
/** Skips over the current sub-descriptor inside the configuration descriptor, so that the pointer then |
|
points to the next sub-descriptor. The bytes remaining value is automatically decremented. |
|
* |
|
* \param[in,out] BytesRem Pointer to the number of bytes remaining of the configuration descriptor. |
|
* \param[in,out] CurrConfigLoc Pointer to the current descriptor inside the configuration descriptor. |
|
*/ |
|
static inline void USB_GetNextDescriptor(uint16_t* const BytesRem, |
|
void** CurrConfigLoc) ATTR_NON_NULL_PTR_ARG(1) ATTR_NON_NULL_PTR_ARG(2); |
|
static inline void USB_GetNextDescriptor(uint16_t* const BytesRem, |
|
void** CurrConfigLoc) |
|
{ |
|
uint16_t CurrDescriptorSize = DESCRIPTOR_CAST(*CurrConfigLoc, USB_Descriptor_Header_t).Size; |
|
|
|
*CurrConfigLoc = ((uint8_t*)*CurrConfigLoc) + CurrDescriptorSize; |
|
*BytesRem -= CurrDescriptorSize; |
|
} |
|
|
|
/* Disable C linkage for C++ Compilers: */ |
|
#if defined(__cplusplus) |
|
} |
|
#endif |
|
|
|
#endif |
|
|
|
/** @} */
|
|
|