Initial implementation, compiles w/o error, not tested

This commit is contained in:
mbanth
2021-05-18 16:48:54 +01:00
parent 89fe6c4d5d
commit a8ba18094f
2 changed files with 417 additions and 0 deletions

View File

@@ -0,0 +1,334 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
#include <assert.h>
#include <stddef.h>
#include <xs1.h>
#include "xua_hid_report_descriptor.h"
#define HID_REPORT_ITEM_HDR_SIZE_MASK ( 0x03 )
#define HID_REPORT_ITEM_HDR_SIZE_SHIFT ( 0 )
#define HID_REPORT_ITEM_HDR_TAG_MASK ( 0xF0 )
#define HID_REPORT_ITEM_HDR_TAG_SHIFT ( 4 )
#define HID_REPORT_ITEM_HDR_TYPE_MASK ( 0x0C )
#define HID_REPORT_ITEM_HDR_TYPE_SHIFT ( 2 )
#define HID_REPORT_ITEM_LOC_BIT_MASK ( 0x70 )
#define HID_REPORT_ITEM_LOC_BIT_SHIFT ( 4 )
#define HID_REPORT_ITEM_LOC_BYTE_MASK ( 0x0F )
#define HID_REPORT_ITEM_LOC_BYTE_SHIFT ( 0 )
#define HID_REPORT_ITEM_USAGE_TAG ( 0 )
#define HID_REPORT_ITEM_USAGE_TYPE ( 2 )
#if 0
/* Existing static report descriptor kept for reference */
unsigned char hidReportDescriptor[] =
{
0x05, 0x01, /* Usage Page (Generic Desktop) */
0x09, 0x06, /* Usage (Keyboard) */
0xa1, 0x01, /* Collection (Application) */
0x75, 0x01, /* Report Size (1) */
0x95, 0x04, /* Report Count (4) */
0x15, 0x00, /* Logical Minimum (0) */
0x25, 0x00, /* Logical Maximum (0) */
0x81, 0x01, /* Input (Cnst, Ary, Abs, No Wrap, Lin, Pref, No Nul) */
0x95, 0x01, /* Report Count (1) */
0x25, 0x01, /* Logical Maximum (1) */
0x05, 0x07, /* Usage Page (Key Codes) */
0x19, 0x17, /* Usage Minimum (Keyboard t or T) */
0x29, 0x17, /* Usage Maximum (Keyboard t or T) */
0x81, 0x02, /* Input (Data, Var, Abs, No Wrap, Lin, Pref, No Nul) */
0x05, 0x0C, /* Usage Page (Consumer) */
0x0a, 0x26, 0x02, /* Usage (AC Stop) */
0x81, 0x02, /* Input (Data, Var, Abs, No Wrap, Lin, Pref, No Nul) */
0x95, 0x02, /* Report Count (2) */
0x05, 0x07, /* Usage Page (Key Codes) */
0x19, 0x72, /* Usage Minimum (Keyboard F23) */
0x29, 0x73, /* Usage Maximum (Keyboard F24) */
0x81, 0x02, /* Input (Data, Var, Abs, No Wrap, Lin, Pref, No Nul) */
0xc0 /* End collection (Application) */
};
#endif
static const USB_HID_Short_Item_t hidCollectionApplication = { .header = 0xA1, .data = { 0x01, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidCollectionEnd = { .header = 0xC0, .data = { 0x00, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidCollectionLogical = { .header = 0xA1, .data = { 0x02, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidInputConstArray = { .header = 0x81, .data = { 0x01, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidInputDataVar = { .header = 0x81, .data = { 0x02, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidLogicalMaximum0 = { .header = 0x25, .data = { 0x00, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidLogicalMaximum1 = { .header = 0x25, .data = { 0x01, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidLogicalMinimum0 = { .header = 0x15, .data = { 0x00, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidReportCount1 = { .header = 0x95, .data = { 0x01, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidReportCount4 = { .header = 0x95, .data = { 0x04, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidReportCount6 = { .header = 0x95, .data = { 0x06, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidReportSize1 = { .header = 0x75, .data = { 0x01, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidUsageConsumerControl = { .header = 0x09, .data = { 0x01, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidUsagePageConsumer = { .header = 0x05, .data = { 0x0C, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidUsagePageKeyboard = { .header = 0x05, .data = { 0x07, 0x00 }, .location = 0x00 };
static const USB_HID_Short_Item_t hidUsagePageTelephony = { .header = 0x05, .data = { 0x0B, 0x00 }, .location = 0x00 };
static USB_HID_Short_Item_t hidUsageByte0Bit3 = { .header = 0x09, .data = { 0x73, 0x00 }, .location = 0x30 }; // F24
static USB_HID_Short_Item_t hidUsageByte0Bit2 = { .header = 0x09, .data = { 0x72, 0x00 }, .location = 0x20 }; // F23
static USB_HID_Short_Item_t hidUsageByte0Bit0 = { .header = 0x09, .data = { 0x17, 0x00 }, .location = 0x00 }; // 't'
static USB_HID_Short_Item_t hidUsageByte1Bit7 = { .header = 0x09, .data = { 0xEA, 0x00 }, .location = 0x71 }; // Vol-
static USB_HID_Short_Item_t hidUsageByte1Bit6 = { .header = 0x09, .data = { 0xE9, 0x00 }, .location = 0x61 }; // Vol+
static USB_HID_Short_Item_t hidUsageByte1Bit4 = { .header = 0x09, .data = { 0x00, 0x00 }, .location = 0x41 }; // Voice Command
static USB_HID_Short_Item_t hidUsageByte1Bit2 = { .header = 0x09, .data = { 0xE2, 0x00 }, .location = 0x21 }; // Mute
static USB_HID_Short_Item_t hidUsageByte1Bit1 = { .header = 0x09, .data = { 0x00, 0x00 }, .location = 0x11 }; // AC Search
static USB_HID_Short_Item_t hidUsageByte1Bit0 = { .header = 0x09, .data = { 0x00, 0x00 }, .location = 0x01 }; // AC Stop
static USB_HID_Short_Item_t hidUsageByte2Bit1 = { .header = 0x09, .data = { 0x2F, 0x00 }, .location = 0x12 }; // Phone Mute
static USB_HID_Short_Item_t hidUsageByte2Bit0 = { .header = 0x09, .data = { 0x20, 0x00 }, .location = 0x02 }; // Hook Switch
static USB_HID_Short_Item_t* const hidConfigurableItems[] = {
&hidUsageByte0Bit0,
&hidUsageByte0Bit2,
&hidUsageByte0Bit3,
&hidUsageByte1Bit0,
&hidUsageByte1Bit1,
&hidUsageByte1Bit2,
&hidUsageByte1Bit4,
&hidUsageByte1Bit6,
&hidUsageByte1Bit7,
&hidUsageByte2Bit0,
&hidUsageByte2Bit1
};
static const USB_HID_Short_Item_t* const hidReportDescriptorItems[] = {
&hidUsagePageConsumer,
&hidUsageConsumerControl,
&hidCollectionApplication,
&hidReportSize1,
&hidLogicalMinimum0,
&hidCollectionLogical, // Byte 0
&hidUsagePageKeyboard,
&hidLogicalMaximum1,
&hidReportCount1,
&hidUsageByte0Bit0,
&hidInputDataVar,
&hidLogicalMaximum0,
&hidInputConstArray,
&hidLogicalMaximum1,
&hidUsageByte0Bit2,
&hidInputDataVar,
&hidUsageByte0Bit3,
&hidInputDataVar,
&hidLogicalMaximum0,
&hidReportCount4,
&hidInputConstArray,
&hidCollectionEnd,
&hidCollectionLogical, // Byte 1
&hidUsagePageConsumer,
&hidLogicalMaximum1,
&hidReportCount1,
&hidUsageByte1Bit0,
&hidInputDataVar,
&hidUsageByte1Bit1,
&hidInputDataVar,
&hidUsageByte1Bit2,
&hidInputDataVar,
&hidLogicalMaximum0,
&hidInputConstArray,
&hidLogicalMaximum1,
&hidUsageByte1Bit4,
&hidInputDataVar,
&hidLogicalMaximum0,
&hidInputConstArray,
&hidLogicalMaximum1,
&hidUsageByte1Bit6,
&hidInputDataVar,
&hidUsageByte1Bit7,
&hidInputDataVar,
&hidCollectionEnd,
&hidCollectionLogical, // Byte 2
&hidUsagePageTelephony,
&hidUsageByte2Bit0,
&hidInputDataVar,
&hidUsageByte2Bit1,
&hidLogicalMaximum0,
&hidReportCount6,
&hidInputConstArray,
&hidCollectionEnd,
&hidCollectionEnd
};
#define HID_REPORT_ITEM_LOCATION_SIZE ( 1 )
#define HID_REPORT_DESCRIPTOR_MAX_LENGTH ( sizeof hidReportDescriptorItems / sizeof ( USB_HID_Short_Item_t ) * \
( sizeof ( USB_HID_Short_Item_t ) - HID_REPORT_ITEM_LOCATION_SIZE ))
static unsigned char hidReportDescriptor[ HID_REPORT_DESCRIPTOR_MAX_LENGTH ];
static unsigned hidReportDescriptorInitialised = 0;
/**
* @brief Get the bit position from the location of an Item
*
* Parameters:
*
* @param[in] location The \c location field from a \c USB_HID_Short_Item
*
* @return The bit position of the Item
*/
static unsigned hidGetItemBitLocation( const unsigned char header );
/**
* @brief Get the byte position from the location of an Item
*
* Parameters:
*
* @param[in] location The \c location field from a \c USB_HID_Short_Item
*
* @return The byte position of the Item within the HID Report
*/
static unsigned hidGetItemByteLocation( const unsigned char header );
/**
* @brief Get the number of data bytes from the header of an Item
*
* Parameters:
*
* @param[in] header The \c header field from a \c USB_HID_Short_Item
*
* @return The amount of data for the Item
*/
static unsigned hidGetItemSize( const unsigned char header );
/**
* @brief Get the Tag from the header of an Item
*
* Parameters:
*
* @param[in] header The \c header field from a \c USB_HID_Short_Item
*
* @return The Tag of the Item
*/
static unsigned hidGetItemTag( const unsigned char header );
/**
* @brief Get the Type from the header of an Item
*
* Parameters:
*
* @param[in] header The \c header field from a \c USB_HID_Short_Item
*
* @return The Type of the Item
*/
static unsigned hidGetItemType( const unsigned char header );
/**
* @brief Translate an Item from the \c USB_HID_Short_Item format to raw bytes
*
* Parameters:
*
* @param[in] inPtr A pointer to a \c USB_HID_Short_Item
* @param[in,out] outPtr A pointer to the next available space in the raw byte buffer
*
* @return The updated \a outPtr
*/
static unsigned char* hidTranslateItem( const USB_HID_Short_Item_t* inPtr, unsigned char* outPtr );
static unsigned hidGetItemBitLocation( const unsigned char location )
{
unsigned bBit = ( location & HID_REPORT_ITEM_LOC_BIT_MASK ) >> HID_REPORT_ITEM_LOC_BIT_SHIFT;
return bBit;
}
static unsigned hidGetItemByteLocation( const unsigned char location )
{
unsigned bByte = ( location & HID_REPORT_ITEM_LOC_BYTE_MASK ) >> HID_REPORT_ITEM_LOC_BYTE_SHIFT;
return bByte;
}
static unsigned hidGetItemSize( const unsigned char header )
{
unsigned bSize = ( header & HID_REPORT_ITEM_HDR_SIZE_MASK ) >> HID_REPORT_ITEM_HDR_SIZE_SHIFT;
assert( bSize <= HID_REPORT_ITEM_MAX_SIZE );
return bSize;
}
static unsigned hidGetItemTag( const unsigned char header )
{
unsigned bTag = ( header & HID_REPORT_ITEM_HDR_TAG_MASK ) >> HID_REPORT_ITEM_HDR_TAG_SHIFT;
return bTag;
}
static unsigned hidGetItemType( const unsigned char header )
{
unsigned bType = ( header & HID_REPORT_ITEM_HDR_TYPE_MASK ) >> HID_REPORT_ITEM_HDR_TYPE_SHIFT;
return bType;
}
unsigned char* hidGetReportDescriptor( void )
{
unsigned char* retVal = NULL;
if( hidReportDescriptorInitialised ) {
retVal = hidReportDescriptor;
}
return retVal;
}
void hidInitReportDescriptor( void )
{
unsigned char* ptr = hidReportDescriptor;
for( unsigned idx = 0; idx < sizeof hidReportDescriptorItems / sizeof( USB_HID_Short_Item_t ); ++idx ) {
ptr = hidTranslateItem( hidReportDescriptorItems[ idx ], ptr );
}
hidReportDescriptorInitialised = 1;
}
unsigned hidSetReportItem( const unsigned byte, const unsigned bit, const unsigned char header, const unsigned char data[] )
{
unsigned retVal = 2;
unsigned bSize = hidGetItemSize( header );
unsigned bTag = hidGetItemTag ( header );
unsigned bType = hidGetItemType( header );
if(( HID_REPORT_ITEM_MAX_SIZE < bSize ) &&
( HID_REPORT_ITEM_USAGE_TAG == bTag ) &&
( HID_REPORT_ITEM_USAGE_TAG == bType )) {
retVal = 1;
} else {
for( unsigned itemIdx = 0; itemIdx < sizeof hidConfigurableItems / sizeof( USB_HID_Short_Item_t ); ++itemIdx ) {
USB_HID_Short_Item_t item = *hidConfigurableItems[ itemIdx ];
unsigned bBit = hidGetItemBitLocation( item.location );
unsigned bByte = hidGetItemByteLocation( item.location );
if(( bit == bBit ) && ( byte == bByte )) {
item.header = header;
for( unsigned dataIdx = 0; dataIdx < bSize; ++dataIdx ) {
item.data[ dataIdx ] = data[ dataIdx ];
}
*hidConfigurableItems[ itemIdx ] = item;
hidReportDescriptorInitialised = 0;
retVal = 0;
}
}
}
return retVal;
}
static unsigned char* hidTranslateItem( const USB_HID_Short_Item_t* inPtr, unsigned char* outPtr )
{
*outPtr++ = inPtr->header;
unsigned dataLength = hidGetItemSize( inPtr->header );
for( unsigned idx = 0; idx < dataLength; ++idx ) {
*outPtr++ = inPtr->data[ idx ];
}
return outPtr;
}

View File

@@ -0,0 +1,83 @@
// Copyright 2021 XMOS LIMITED.
// This Software is subject to the terms of the XMOS Public Licence: Version 1.
/**
* @brief Human Interface Device (HID) Report descriptor
*
* This file defines the structure and default content of the HID Report descriptor.
* Document section numbers refer to the HID Device Class Definition, version 1.11.
*/
#ifndef _HID_REPORT_DESCRIPTOR_
#define _HID_REPORT_DESCRIPTOR_
#define HID_REPORT_ITEM_MAX_SIZE ( 2 )
#define HID_STATUS_GOOD ( 0 )
#define HID_STATUS_BAD_HEADER ( 1 )
#define HID_STATUS_BAD_LOCATION ( 2 )
/**
* @brief USB HID Report Descriptor. Short Item
*
* @note
* To reduce memory use, this type does not support Short Items with 4 data bytes.
* See section 6.2.2.2
*
* Elements:
*
* header - the item prefix containing the size, type and tag fields (see 6.2.2.2)
* Format (bit range): bSize (0:1), bType (2:3), bTag (4:7)
* data - a two byte array for holding the item's data
* The bSize field indicates which data bytes are in use
* location - a non-standard extension locating the item within the HID Report
* Format (bit range): iByte (0:3), iBit (4:6), Reserved (7)
*/
typedef struct
{
unsigned char header;
unsigned char data[ HID_REPORT_ITEM_MAX_SIZE ];
unsigned char location;
} USB_HID_Short_Item_t;
/**
* @brief Get the HID Report descriptor
*
* This function returns a pointer to the USB HID Report descriptor.
* It returns NULL if the Report descriptor has not been initialised,
* i.e., no one has called \c hidInitReportDescriptor().
*
* @return A pointer to a list of unsigned char containing the Report descriptor
*/
unsigned char* hidGetReportDescriptor( void );
/**
* @brief Modify a HID Report descriptor item
*
* Parameters:
*
* @param[in] byte The byte position of the control within the HID Report
* @param[in] bit The bit position of the control within the \a byte
* @param[in] header The LSB of the Item containing the bSize, bType and bTag fields (see 6.2.2.2)
* @param[in] data An array containing data bytes or NULL for an Item with no data
*
* @return A status value
* @retval \c HID_STATUS_GOOD Item successfully updated
* @retval \c HID_STATUS_BAD_HEADER The Item header specified a data size greater than 2 or
* a Tag or Type inconsistent with a Usage Item
* @retval \c HID_STATUS_BAD_LOCATION The \a bit or \a byte arguments specify a location outside
* of the HID Report
*/
unsigned hidSetReportItem( const unsigned byte, const unsigned bit, const unsigned char header, const unsigned char data[] );
/**
* @brief Initialise the USB HID Report descriptor
*
* After initialisation, \c hidGetReportDescriptor() returns a list suitable
* for transmission over USB.
*
* Call this function after altering one or more Report Items using \c hidSetReportItem().
*/
void hidInitReportDescriptor( void );
#endif // _HID_REPORT_DESCRIPTOR_