From a86934e351b5dbcab0655db846979828e5d408e4 Mon Sep 17 00:00:00 2001 From: patacongo Date: Sat, 19 Feb 2011 23:07:58 +0000 Subject: [PATCH] Add HID parser from LUFA git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3303 42af7a65-404d-4744-a932-0658087f49c3 --- COPYING | 26 ++ ChangeLog | 4 +- Documentation/NuttX.html | 12 +- drivers/usbhost/Make.defs | 2 +- drivers/usbhost/hid_parser.c | 529 +++++++++++++++++++++++++++++++++ include/nuttx/usb/hid.h | 101 ++++--- include/nuttx/usb/hid_parser.h | 342 +++++++++++++++++++++ 7 files changed, 970 insertions(+), 46 deletions(-) create mode 100644 drivers/usbhost/hid_parser.c create mode 100644 include/nuttx/usb/hid_parser.h diff --git a/COPYING b/COPYING index e5e6238add..3f85e869ed 100755 --- a/COPYING +++ b/COPYING @@ -61,6 +61,32 @@ IGMP support, if enabled in uIP, adds additional logic by Steve Reynolds: Copyright (c) 2002 CITEL Technologies Ltd. All rights reserved. +The HID Parser in drivers/usbhost +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + + Adapted from the LUFA Library (MIT license): + + Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com) + dean [at] fourwalledcubicle [dot] com, www.lufa-lib.org + + 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. + Certain functions in the NuttX C-library derive from other BSD-compatible sources: diff --git a/ChangeLog b/ChangeLog index cf5527d58c..cdb6640344 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1460,6 +1460,8 @@ * The NuttX repository has been converted to SVN and can now be found here http://nuttx.svn.sourceforge.net/viewvc/nuttx/ * configs/mbed/hidkbd -- Added USB host support for the mbed LPC1768 board; add - a USB host HID keyboard configuraion. + a USB host HID keyboard configuraion. + * drivers/usbhost/hid_parser.c -- Leverages the LUFA HID parser written by + Dean Camera. diff --git a/Documentation/NuttX.html b/Documentation/NuttX.html index 2e02a0f612..5ce0d0b1a2 100644 --- a/Documentation/NuttX.html +++ b/Documentation/NuttX.html @@ -8,7 +8,7 @@

NuttX RTOS

-

Last Updated: February 15, 2011

+

Last Updated: February 19, 2011

@@ -2032,12 +2032,14 @@ nuttx-5.18 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> * examplex/wlan, configs/olimex-lpc1766stk/wlan, drivers/usbhost/usbhost_rtl8187.c, Add infrastructure to support RTL18187 wireless USB. * configs/nucleus2g -- backed out USB host changes... wrong board. - * Renamed arc/hc/include/mc9s12ne64 and src/mc9s12ne64 -- m9s12. That name is - shorter and more general. + * Renamed arc/hc/include/mc9s12ne64 and src/mc9s12ne64 -- m9s12. That name is + shorter and more general. * The NuttX repository has been converted to SVN and can now be found here http://nuttx.svn.sourceforge.net/viewvc/nuttx/ - * configs/mbed/hidkbd -- Added USB host support for the mbed LPC1768 board; add - a USB host HID keyboard configuraion. + * configs/mbed/hidkbd -- Added USB host support for the mbed LPC1768 board; add + a USB host HID keyboard configuraion. + * drivers/usbhost/hid_parser.c -- Leverages the LUFA HID parser written by + Dean Camera. pascal-2.1 2011-xx-xx Gregory Nutt <spudmonkey@racsa.co.cr> diff --git a/drivers/usbhost/Make.defs b/drivers/usbhost/Make.defs index 6fcca4b598..531ff983d1 100644 --- a/drivers/usbhost/Make.defs +++ b/drivers/usbhost/Make.defs @@ -34,7 +34,7 @@ ############################################################################ USBHOST_ASRCS = -USBHOST_CSRCS = +USBHOST_CSRCS = hid_parser.c ifeq ($(CONFIG_USBHOST),y) USBHOST_CSRCS += usbhost_registry.c usbhost_registerclass.c usbhost_findclass.c diff --git a/drivers/usbhost/hid_parser.c b/drivers/usbhost/hid_parser.c new file mode 100644 index 0000000000..269aa73de7 --- /dev/null +++ b/drivers/usbhost/hid_parser.c @@ -0,0 +1,529 @@ +/**************************************************************************** + * drivers/usbhost/hid_parser.c + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * + * Adapted from the LUFA Library: + * + * Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com) + * dean [at] fourwalledcubicle [dot] com, www.lufa-lib.org + * + * 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. + * + ****************************************************************************/ + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include + +#include +#include +#include + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/**************************************************************************** + * Private Types + ****************************************************************************/ + +struct hid_state_s +{ + struct hid_rptitem_attributes_s attrib; + uint8_t rptcount; + uint8_t id; +}; + +/**************************************************************************** + * Public Functions + ****************************************************************************/ + +/**************************************************************************** + * Name: hid_parsereport + * + * Description: + * Function to process a given HID report returned from an attached device, + * and store it into a given struct hid_rptinfo_s structure. + * + * Input Parameters: + * report Buffer containing the device's HID report table. + * rptlen Size in bytes of the HID report table. + * filter Callback function to decide if an item should be retained + * rptinfo Pointer to a struct hid_rptinfo_s instance for the parser output. + * + * Returned Value: + * Zero on success, otherwise a negated errno value. + ****************************************************************************/ + +int hid_parsereport(FAR const uint8_t *report, int rptlen, + hid_rptfilter_t filter, FAR struct hid_rptinfo_s *rptinfo) +{ + struct hid_state_s state[HID_STATETABLE_STACK_DEPTH]; + struct hid_state_s *currstate = &state[0]; + struct hid_collectionpath_s *collectionpath = NULL; + struct hid_rptsizeinfo_s *rptidinfo = &rptinfo->rptsize[0]; + uint16_t usage[HID_USAGE_STACK_DEPTH]; + uint8_t nusage = 0; + struct hid_range_s usage_range = { 0, 0 }; + int i; + + DEBUGASSERT(report && filter && rptinfo); + + memset(rptinfo, 0x00, sizeof(struct hid_rptinfo_s)); + memset(currstate, 0x00, sizeof(struct hid_state_s)); + memset(rptidinfo, 0x00, sizeof(struct hid_rptsizeinfo_s)); + + rptinfo->nreports = 1; + + while (rptlen > 0) + { + uint8_t item = *report; + uint32_t data = 0; + + report++; + rptlen--; + + switch (item & USBHID_RPTITEM_SIZE_MASK) + { + case USBHID_RPTITEM_SIZE_4: /* 4 bytes of little endian data follow */ + data = (uint32_t)(*report++); + data |= (uint32_t)(*report++) << 8; + data |= (uint32_t)(*report++) << 16; + data |= (uint32_t)(*report++) << 24; + rptlen -= 4; + break; + + case USBHID_RPTITEM_SIZE_2: /* 2 bytes of little endian data follow */ + data = (uint32_t)(*report++); + data |= (uint32_t)(*report++) << 8; + rptlen -= 2; + break; + + case USBHID_RPTITEM_SIZE_1: /* 1 byte of data follows */ + data = (uint32_t)(*report++); + rptlen -= 1; + break; + + case USBHID_RPTITEM_SIZE_0: /* No data follows */ + default: + break; + } + + switch (item & ~USBHID_RPTITEM_SIZE_MASK) + { + case USBHID_GLOBAL_PUSH_PREFIX: + if (currstate == &state[HID_STATETABLE_STACK_DEPTH - 1]) + { + return -E2BIG; + } + + memcpy((currstate + 1), + currstate, sizeof(struct hid_rptitem_s)); + + currstate++; + break; + + case USBHID_GLOBAL_POP_PREFIX: + if (currstate == &state[0]) + { + return -EINVAL; /* Pop without push? */ + } + + currstate--; + break; + + case USBHID_GLOBAL_USAGEPAGE_PREFIX: + if ((item & USBHID_RPTITEM_SIZE_MASK) == USBHID_RPTITEM_SIZE_4) + { + currstate->attrib.usage.page = (data >> 16); + } + + currstate->attrib.usage.page = data; + break; + + case USBHID_GLOBAL_LOGICALMIN_PREFIX: + currstate->attrib.logical.min = data; + break; + + case USBHID_GLOBAL_LOGICALMAX_PREFIX: + currstate->attrib.logical.max = data; + break; + + case USBHID_GLOBAL_PHYSICALMIN_PREFIX: + currstate->attrib.physical.min = data; + break; + + case USBHID_GLOBAL_PHYSMICALAX_PREFIX: + currstate->attrib.physical.max = data; + break; + + case USBHID_GLOBAL_UNITEXP_PREFIX: + currstate->attrib.unit.exponent = data; + break; + + case USBHID_GLOBAL_UNIT_PREFIX: + currstate->attrib.unit.type = data; + break; + + case USBHID_GLOBAL_REPORTSIZE_PREFIX: + currstate->attrib.bitsize = data; + break; + + case USBHID_GLOBAL_REPORTCOUNT_PREFIX: + currstate->rptcount = data; + break; + + case USBHID_GLOBAL_REPORTID_PREFIX: + currstate->id = data; + + if (rptinfo->haverptid) + { + rptidinfo = NULL; + + for (i = 0; i < rptinfo->nreports; i++) + { + if (rptinfo->rptsize[i].id == currstate->id) + { + rptidinfo = &rptinfo->rptsize[i]; + break; + } + } + + if (rptidinfo == NULL) + { + if (rptinfo->nreports == HID_MAX_REPORT_IDS) + { + return -EINVAL; + } + + rptidinfo = &rptinfo->rptsize[rptinfo->nreports++]; + memset(rptidinfo, 0x00, sizeof(struct hid_rptsizeinfo_s)); + } + } + + rptinfo->haverptid = true; + + rptidinfo->id = currstate->id; + break; + + case USBHID_LOCAL_USAGE_PREFIX: + if (nusage == HID_USAGE_STACK_DEPTH) + { + return -E2BIG; + } + + usage[nusage++] = data; + break; + + case USBHID_LOCAL_USAGEMIN_PREFIX: + usage_range.min = data; + break; + + case USBHID_LOCAL_USAGEMAX_PREFIX: + usage_range.max = data; + break; + + case USBHID_MAIN_COLLECTION_PREFIX: + if (collectionpath == NULL) + { + collectionpath = &rptinfo->collectionpaths[0]; + } + else + { + struct hid_collectionpath_s *ParentCollectionPath = collectionpath; + + collectionpath = &rptinfo->collectionpaths[1]; + + while (collectionpath->parent != NULL) + { + if (collectionpath == &rptinfo->collectionpaths[HID_MAX_COLLECTIONS - 1]) + { + return -EINVAL; + } + + collectionpath++; + } + + collectionpath->parent = ParentCollectionPath; + } + + collectionpath->type = data; + collectionpath->usage.page = currstate->attrib.usage.page; + + if (nusage) + { + collectionpath->usage.usage = usage[0]; + + for (i = 0; i < nusage; i++) + usage[i] = usage[i + 1]; + + nusage--; + } + else if (usage_range.min <= usage_range.max) + { + collectionpath->usage.usage = usage_range.min++; + } + + break; + + case USBHID_MAIN_ENDCOLLECTION_PREFIX: + if (collectionpath == NULL) + { + return -EINVAL; + } + + collectionpath = collectionpath->parent; + break; + + case USBHID_MAIN_INPUT_PREFIX: + case USBHID_MAIN_OUTPUT_PREFIX: + case USBHID_MAIN_FEATURE_PREFIX: + { + int itemno; + for (itemno = 0; itemno < currstate->rptcount; itemno++) + { + struct hid_rptitem_s newitem; + uint8_t tag; + + memcpy(&newitem.attrib, &currstate->attrib, + sizeof(struct hid_rptitem_attributes_s)); + + newitem.flags = data; + newitem.collectionpath = collectionpath; + newitem.id = currstate->id; + + if (nusage) + { + newitem.attrib.usage.usage = usage[0]; + + for (i = 0; i < nusage; i++) + { + usage[i] = usage[i + 1]; + } + nusage--; + } + else if (usage_range.min <= usage_range.max) + { + newitem.attrib.usage.usage = usage_range.min++; + } + + tag = (item & ~USBHID_RPTITEM_SIZE_MASK); + if (tag == USBHID_MAIN_INPUT_PREFIX) + { + newitem.type = USBHID_REPORTTYPE_INPUT; + } + else if (tag == USBHID_MAIN_OUTPUT_PREFIX) + { + newitem.type = USBHID_REPORTTYPE_OUTPUT; + } + else + { + newitem.type = USBHID_REPORTTYPE_FEATURE; + } + + newitem.bitoffset = rptidinfo->size[newitem.type]; + rptidinfo->size[newitem.type] += currstate->attrib.bitsize; + + /* Accumulate the maximum report size */ + + if (rptinfo->maxrptsize < newitem.bitoffset) + { + rptinfo->maxrptsize = newitem.bitoffset; + } + + if ((data & USBHID_MAIN_CONSTANT) == 0 && filter(&newitem)) + { + if (rptinfo->nitems == HID_MAX_REPORTITEMS) + { + return -EINVAL; + } + + memcpy(&rptinfo->items[rptinfo->nitems], + &newitem, sizeof(struct hid_rptitem_s)); + + rptinfo->nitems++; + } + } + } + break; + } + + if ((item & USBHID_RPTITEM_TYPE_MASK) == USBHID_RPTITEM_TYPE_MAIN) + { + usage_range.min = 0; + usage_range.max = 0; + nusage = 0; + } + } + + if (!(rptinfo->nitems)) + { + return -ENOENT; + } + + return OK; +} + +/**************************************************************************** + * Name: hid_getitem + * + * Description: + * Extracts the given report item's value out of the given HID report and + * places it into the value member of the report item's struct hid_rptitem_s + * structure. + * + * When called on a report with an item that exists in that report, this + * copies the report item's Value to it's previous element for easy + * checking to see if an item's value has changed before processing a + * report. If the given item does not exist in the report, the function + * does not modify the report item's data. + * + * Input Parameters + * report Buffer containing an IN or FEATURE report from an attached + * device. + * item Pointer to the report item of interest in a struct hid_rptinfo_s + * item array. + * + * Returned Value: + * Zero on success, otherwise a negated errno value. + * + ****************************************************************************/ + +int hid_getitem(FAR const uint8_t *report, FAR struct hid_rptitem_s *item) +{ + uint16_t remaining = item->attrib.bitsize; + uint16_t offset = item->bitoffset; + uint32_t mask = (1 << 0); + + if (item->id) + { + if (item->id != report[0]) + { + return -ENOENT; + } + + report++; + } + + item->previous = item->value; + item->value = 0; + + while (remaining--) + { + if (report[offset >> 3] & (1 << (offset & 7))) + { + item->value |= mask; + } + + offset++; + mask <<= 1; + } + + return OK; +} + +/**************************************************************************** + * Name: hid_putitem + * + * Desription: + * Retrieves the given report item's value out of the Value member of the + * report item's struct hid_rptitem_s structure and places it into the correct + * position in the HID report buffer. The report buffer is assumed to have + * the appropriate bits cleared before calling this function (i.e., the + * buffer should be explicitly cleared before report values are added). + * + * When called, this copies the report item's Value element to it's + * previous element for easy checking to see if an item's value has + * changed before sending a report. + * + * If the device has multiple HID reports, the first byte in the report is + * set to the report ID of the given item. + * + * Input Parameters: + * report Buffer holding the current OUT or FEATURE report data. + * item Pointer to the report item of interest in a struct hid_rptinfo_s + * item array. + * + ****************************************************************************/ + +#if 0 /* Not needed by host */ +void hid_putitem(FAR uint8_t *report, struct hid_rptitem_s *item) +{ + uint16_t remaining = item->attrib.bitsize; + uint16_t offset = item->bitoffset; + uint32_t mask = (1 << 0); + + if (item->id) + { + report[0] = item->id; + report++; + } + + item->previous = item->value; + + while (remaining--) + { + if (item->value & (1 << (offset & 7))) + { + report[offset >> 3] |= mask; + } + + offset++; + mask <<= 1; + } +} +#endif + +/**************************************************************************** + * Name: hid_reportsize + * + * Description: + * Retrieves the size of a given HID report in bytes from it's Report ID. + * + * InputParameters: + * rptinfo Pointer to a struct hid_rptinfo_s instance containing the parser output. + * id Report ID of the report whose size is to be retrieved. + * rpttype Type of the report whose size is to be determined, a valued from the + * HID_ReportItemTypes_t enum. + * + * Size of the report in bytes, or 0 if the report does not exist. + * + ****************************************************************************/ + +size_t hid_reportsize(FAR struct hid_rptinfo_s *rptinfo, uint8_t id, uint8_t rpttype) +{ + int i; + for (i = 0; i < HID_MAX_REPORT_IDS; i++) + { + size_t size = rptinfo->rptsize[i].size[rpttype]; + + if (rptinfo->rptsize[i].id == id) + { + return ((size >> 3) + ((size & 0x07) ? 1 : 0)); + } + } + + return 0; +} diff --git a/include/nuttx/usb/hid.h b/include/nuttx/usb/hid.h index 81e515b823..e5bea9c32e 100755 --- a/include/nuttx/usb/hid.h +++ b/include/nuttx/usb/hid.h @@ -165,40 +165,63 @@ #define USBHID_COUNTRY_YUGOSLAVIA 0x34 /* Yugoslavia */ #define USBHID_COUNTRY_TURKISHF 0x35 /* Turkish-F */ +/* HID report items */ + +#define USBHID_RPTITEM_SIZE_MASK 0x03 +# define USBHID_RPTITEM_SIZE_0 0x00 /* No data follows */ +# define USBHID_RPTITEM_SIZE_1 0x01 /* 1 byte of data follows */ +# define USBHID_RPTITEM_SIZE_2 0x02 /* 2 bytes of data follow */ +# define USBHID_RPTITEM_SIZE_4 0x03 /* 4 bytes of data follow */ +#define USBHID_RPTITEM_TYPE_MASK 0x0c +# define USBHID_RPTITEM_TYPE_MAIN 0x00 +# define USBHID_RPTITEM_TYPE_GLOBAL 0x04 +# define USBHID_RPTITEM_TYPE_LOCAL 0x08 +#define USBHID_RPTITEM_TAG_MASK 0xf0 + /* Main Items (HID 6.2.2.4) */ -#define USBHID_MAIN_SIZE(pfx) ((pfx) & 3) +#define USBHID_MAIN_CONSTANT (1 << 0) /* Constant(1) vs Data(0) */ +#define USBHID_MAIN_VARIABLE (1 << 1) /* Variable(1) vs Array(0) */ +#define USBHID_MAIN_RELATIVE (1 << 2) /* Relative(1) vs Absolute(0) */ +#define USBHID_MAIN_WRAP (1 << 3) /* Wrap(1) vs No Wrap(0) */ +#define USBHID_MAIN_NONLINEAR (1 << 4) /* Non Linear(1) vs Linear(0) */ +#define USBHID_MAIN_NOPREFERRED (1 << 5) /* No Preferred (1) vs Preferred State(0) */ +#define USBHID_MAIN_NULLSTATE (1 << 6) /* Null state(1) vs No Null position(0) */ +#define USBHID_MAIN_VOLATILE (1 << 7) /* Volatile(1) vs Non volatile(0) */ +#define USBHID_MAIN_BUFFEREDBYTES (1 << 8) /* Buffered Bytes(1) vs Bit Field(0) */ + +#define USBHID_MAIN_SIZE(pfx) ((pfx) & USBHID_RPTITEM_SIZE_MASK) #define USBHID_MAIN_INPUT_PREFIX 0x80 -#define USBHID_MAIN_INPUT_CONSTANT (1 << 0) /* Constant(1) vs Data(0) */ -#define USBHID_MAIN_INPUT_VARIABLE (1 << 1) /* Variable(1) vs Array(0) */ -#define USBHID_MAIN_INPUT_RELATIVE (1 << 2) /* Relative(1) vs Absolute(0) */ -#define USBHID_MAIN_INPUT_WRAP (1 << 3) /* Wrap(1) vs No Wrap(0) */ -#define USBHID_MAIN_INPUT_NONLINEAR (1 << 4) /* Non Linear(1) vs Linear(0) */ -#define USBHID_MAIN_INPUT_NOPREFERRED (1 << 5) /* No Preferred (1) vs Preferred State(0) */ -#define USBHID_MAIN_INPUT_NULLSTATE (1 << 6) /* Null state(1) vs No Null position(0) */ -#define USBHID_MAIN_INPUT_BUFFEREDBYTES (1 << 8) /* Buffered Bytes(1) vs Bit Field(0) */ +#define USBHID_MAIN_INPUT_CONSTANT USBHID_MAIN_CONSTANT +#define USBHID_MAIN_INPUT_VARIABLE USBHID_MAIN_VARIABLE +#define USBHID_MAIN_INPUT_RELATIVE USBHID_MAIN_RELATIVE +#define USBHID_MAIN_INPUT_WRAP USBHID_MAIN_WRAP +#define USBHID_MAIN_INPUT_NONLINEAR USBHID_MAIN_NONLINEAR +#define USBHID_MAIN_INPUT_NOPREFERRED USBHID_MAIN_NOPREFERRED +#define USBHID_MAIN_INPUT_NULLSTATE USBHID_MAIN_NULLSTATE +#define USBHID_MAIN_INPUT_BUFFEREDBYTES USBHID_MAIN_BUFFEREDBYTES #define USBHID_MAIN_OUTPUT_PREFIX 0x90 -#define USBHID_MAIN_OUTPUT_CONSTANT (1 << 0) /* Constant(1) vs Data(0) */ -#define USBHID_MAIN_OUTPUT_VARIABLE (1 << 1) /* Variable(1) vs Array(0) */ -#define USBHID_MAIN_OUTPUT_RELATIVE (1 << 2) /* Relative(1) vs Absolute(0) */ -#define USBHID_MAIN_OUTPUT_WRAP (1 << 3) /* Wrap(1) vs No Wrap(0) */ -#define USBHID_MAIN_OUTPUT_NONLINEAR (1 << 4) /* Non Linear(1) vs Linear(0) */ -#define USBHID_MAIN_OUTPUT_NOPREFERRED (1 << 5) /* No Preferred (1) vs Preferred State(0) */ -#define USBHID_MAIN_OUTPUT_NULLSTATE (1 << 6) /* Null state(1) vs No Null position(0) */ -#define USBHID_MAIN_OUTPUT_VOLATILE (1 << 7) /* Volatile(1) vs Non volatile(0) */ -#define USBHID_MAIN_OUTPUT_BUFFEREDBYTES (1 << 8) /* Buffered Bytes(1) vs Bit Field(0) */ +#define USBHID_MAIN_OUTPUT_CONSTANT USBHID_MAIN_CONSTANT +#define USBHID_MAIN_OUTPUT_VARIABLE USBHID_MAIN_VARIABLE +#define USBHID_MAIN_OUTPUT_RELATIVE USBHID_MAIN_RELATIVE +#define USBHID_MAIN_OUTPUT_WRAP USBHID_MAIN_WRAP +#define USBHID_MAIN_OUTPUT_NONLINEAR USBHID_MAIN_NONLINEAR +#define USBHID_MAIN_OUTPUT_NOPREFERRED USBHID_MAIN_NOPREFERRED +#define USBHID_MAIN_OUTPUT_NULLSTATE USBHID_MAIN_NULLSTATE +#define USBHID_MAIN_OUTPUT_VOLATILE USBHID_MAIN_VOLATILE +#define USBHID_MAIN_OUTPUT_BUFFEREDBYTES USBHID_MAIN_BUFFEREDBYTES #define USBHID_MAIN_FEATURE_PREFIX 0xb0 -#define USBHID_MAIN_FEATURE_CONSTANT (1 << 0) /* Constant(1) vs Data(0) */ -#define USBHID_MAIN_FEATURE_VARIABLE (1 << 1) /* Variable(1) vs Array(0) */ -#define USBHID_MAIN_FEATURE_RELATIVE (1 << 2) /* Relative(1) vs Absolute(0) */ -#define USBHID_MAIN_FEATURE_WRAP (1 << 3) /* Wrap(1) vs No Wrap(0) */ -#define USBHID_MAIN_FEATURE_NONLINEAR (1 << 4) /* Non Linear(1) vs Linear(0) */ -#define USBHID_MAIN_FEATURE_NOPREFERRED (1 << 5) /* No Preferred (1) vs Preferred State(0) */ -#define USBHID_MAIN_FEATURE_NULLSTATE (1 << 6) /* Null state(1) vs No Null position(0) */ -#define USBHID_MAIN_FEATURE_VOLATILE (1 << 7) /* Volatile(1) vs Non volatile(0) */ -#define USBHID_MAIN_FEATURE_BUFFEREDBYTES (1 << 8) /* Buffered Bytes(1) vs Bit Field(0) */ +#define USBHID_MAIN_FEATURE_CONSTANT USBHID_MAIN_CONSTANT +#define USBHID_MAIN_FEATURE_VARIABLE USBHID_MAIN_VARIABLE +#define USBHID_MAIN_FEATURE_RELATIVE USBHID_MAIN_RELATIVE +#define USBHID_MAIN_FEATURE_WRAP USBHID_MAIN_WRAP +#define USBHID_MAIN_FEATURE_NONLINEAR USBHID_MAIN_NONLINEAR +#define USBHID_MAIN_FEATURE_NOPREFERRED USBHID_MAIN_NOPREFERRED +#define USBHID_MAIN_FEATURE_NULLSTATE USBHID_MAIN_NULLSTATE +#define USBHID_MAIN_FEATURE_VOLATILE USBHID_MAIN_VOLATILE +#define USBHID_MAIN_FEATURE_BUFFEREDBYTES USBHID_MAIN_BUFFEREDBYTES #define USBHID_MAIN_COLLECTION_PREFIX 0xa0 #define USBHID_MAIN_COLLECTION_PHYSICAL 0x00 /* Physical (group of axes) */ @@ -213,7 +236,7 @@ /* Global Items (HID 6.2.2.7) */ -#define USBHID_GLOBAL_SIZE(pfx) ((pfx) & 3) +#define USBHID_GLOBAL_SIZE(pfx) ((pfx) & USBHID_RPTITEM_SIZE_MASK) #define USBHID_GLOBAL_USAGEPAGE_PREFIX 0x04 /* Usage Page */ #define USBHID_GLOBAL_LOGICALMIN_PREFIX 0x14 /* Logical Minimum */ #define USBHID_GLOBAL_LOGICALMAX_PREFIX 0x24 /* Logical Maximum */ @@ -229,17 +252,17 @@ /* Local Items (HID 6.2.2.8) */ -#define USBHID_LOCAL_SIZE(pfx) ((pfx) & 3) -#define USBHID_LOCAL_USAGE 0x08 /* Usage */ -#define USBHID_LOCAL_USAGEMIN 0x18 /* Usage Minimum */ -#define USBHID_LOCAL_USAGEMAX 0x28 /* Usage Maximum */ -#define USBHID_LOCAL_DESIGNATORIDX 0x38 /* Designator Index */ -#define USBHID_LOCAL_DESIGNATORMIN 0x48 /* Designator Minimum */ -#define USBHID_LOCAL_DESIGNATORMAX 0x58 /* Designator Maximum */ -#define USBHID_LOCAL_STRINGIDX 0x78 /* String Index */ -#define USBHID_LOCAL_STRINGMIN 0x88 /* String Minimum */ -#define USBHID_LOCAL_STRINGMAX 0x98 /* xx */ -#define USBHID_LOCAL_DELIMITER 0xa8 /*Delimiter */ +#define USBHID_LOCAL_SIZE(pfx) ((pfx) & USBHID_RPTITEM_SIZE_MASK) +#define USBHID_LOCAL_USAGE_PREFIX 0x08 /* Usage */ +#define USBHID_LOCAL_USAGEMIN_PREFIX 0x18 /* Usage Minimum */ +#define USBHID_LOCAL_USAGEMAX_PREFIX 0x28 /* Usage Maximum */ +#define USBHID_LOCAL_DESIGNATORIDX_PREFIX 0x38 /* Designator Index */ +#define USBHID_LOCAL_DESIGNATORMIN_PREFIX 0x48 /* Designator Minimum */ +#define USBHID_LOCAL_DESIGNATORMAX_PREFIX 0x58 /* Designator Maximum */ +#define USBHID_LOCAL_STRINGIDX_PREFIX 0x78 /* String Index */ +#define USBHID_LOCAL_STRINGMIN_PREFIX 0x88 /* String Minimum */ +#define USBHID_LOCAL_STRINGMAX_PREFIX 0x98 /* xx */ +#define USBHID_LOCAL_DELIMITER_PREFIX 0xa8 /*Delimiter */ /* Modifier Keys (HID 8.3) */ diff --git a/include/nuttx/usb/hid_parser.h b/include/nuttx/usb/hid_parser.h new file mode 100644 index 0000000000..23cbf390c4 --- /dev/null +++ b/include/nuttx/usb/hid_parser.h @@ -0,0 +1,342 @@ +/**************************************************************************** + * include/nuttx/usb/hid_parser.h + * + * Copyright (C) 2011 Gregory Nutt. All rights reserved. + * + * Adapted from the LUFA Library: + * + * Copyright 2011 Dean Camera (dean [at] fourwalledcubicle [dot] com) + * dean [at] fourwalledcubicle [dot] com, www.lufa-lib.org + * + * 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. + * + ****************************************************************************/ + +#ifndef __INCLUDE_NUTTX_USB_HID_PARSER_H +#define __INCLUDE_NUTTX_USB_HID_PARSER_H + +/**************************************************************************** + * Included Files + ****************************************************************************/ + +#include +#include + +/**************************************************************************** + * Pre-processor Definitions + ****************************************************************************/ + +/* Configuration ************************************************************/ + +/* HID_STATETABLE_STACK_DEPTH + * Constant indicating the maximum stack depth of the state table. A larger + * state table allows for more PUSH/POP report items to be nested, but + * consumes more memory. By default this is set to 2 levels (allowing non- + * nested PUSH items) but this can be overridden by defining + * HID_STATETABLE_STACK_DEPTH in the Nuttx config file. + * + * HID_USAGE_STACK_DEPTH + * Constant indicating the maximum stack depth of the usage table. A larger + * usage table allows for more USAGE items to be indicated sequentially for + * REPORT COUNT entries of more than one, but requires more stack space. By + * default this is set to 8 levels (allowing for a report item with a count + * of 8) but this can be overridden by defining HID_USAGE_STACK_DEPTH to + * in the Nuttx config file. + * + * HID_MAX_COLLECTIONS + * Constant indicating the maximum number of COLLECTION items (nested or + * unnested) that can be processed in the report item descriptor. A large + * value allows for more COLLECTION items to be processed, but consumes + * more memory. By default this is set to 10 collections, but this can be + * overridden by defining HID_MAX_COLLECTIONS in the Nuttx config file. + * + * Constant indicating the maximum number of report items (IN, OUT or + * FEATURE) that can be processed in the report item descriptor and stored + * in the user HID Report Info structure. A large value allows + * for more report items to be stored, but consumes more memory. By default + * this is set to 20 items, but this can be overridden by defining + * HID_MAX_REPORTITEMS in the Nuttx config file. + * + * Constant indicating the maximum number of unique report IDs that can be + * processed in the report item descriptor for the report size information + * array in the user HID Report Info structure. A large value allows for + * more report ID report sizes to be stored, but consumes more memory. By + * default this is set to 10 items, but this can be overridden by defining + * HID_MAX_REPORT_IDS in the Nuttx config file. Note that IN, OUT and FEATURE + * items sharing the same report ID consume only one size item in the array. + */ + +#ifndef HID_STATETABLE_STACK_DEPTH +# define HID_STATETABLE_STACK_DEPTH 2 +#endif + +#ifndef HID_USAGE_STACK_DEPTH +# define HID_USAGE_STACK_DEPTH 8 +#endif + +#ifndef HID_MAX_COLLECTIONS +# define HID_MAX_COLLECTIONS 10 +#endif + +#ifndef HID_MAX_REPORTITEMS +# define HID_MAX_REPORTITEMS 20 +#endif + +#ifndef HID_MAX_REPORT_IDS +# define HID_MAX_REPORT_IDS 10 +#endif + +/**************************************************************************** + * Public Types + ****************************************************************************/ + +/* HID Parser Report Item Min/Max Structure. Type define for an attribute + * with both minimum and maximum values (e.g. Logical Min/Max). + */ + +struct hid_range_s +{ + uint32_t min; /* Minimum value for the attribute. */ + uint32_t max; /* Maximum value for the attribute. */ +}; + +/* HID Parser Report Item Unit Structure. Type define for the Unit attributes + * of a report item. + */ + +struct hid_unit_t +{ + uint32_t type; /* Unit type (refer to HID specifications for details). */ + uint8_t exponent; /* Unit exponent (refer to HID specifications for details). */ +}; + +/* HID Parser Report Item Usage Structure. Type define for the Usage + * attributes of a report item. + */ + +struct hid_usage_t +{ + uint16_t page; /* Usage page of the report item. */ + uint16_t usage; /* Usage of the report item. */ +}; + +/* HID Parser Report Item Collection Path Structure. Type define for a + * COLLECTION object. Contains the collection attributes and a reference to + * the parent collection if any. + */ + +struct hid_collectionpath_s +{ + uint8_t type; /* Collection type (e.g. "Generic Desktop"). */ + struct hid_usage_t usage; /* Collection usage. */ + struct hid_collectionpath_s *parent; /* Reference to parent collection, or NULL if root collection. */ +}; + +/* HID Parser Report Item Attributes Structure. Type define for all the data + * attributes of a report item, except flags. + */ + +struct hid_rptitem_attributes_s +{ + uint8_t bitsize; /* Size in bits of the report item's data. */ + struct hid_usage_t usage; /* Usage of the report item. */ + struct hid_unit_t unit; /* Unit type and exponent of the report item. */ + struct hid_range_s logical; /* Logical minimum and maximum of the report item. */ + struct hid_range_s physical; /* Physical minimum and maximum of the report item. */ +}; + +/* HID Parser Report Item Details Structure. Type define for a report item + * (IN, OUT or FEATURE) layout attributes and other details. + */ + +struct hid_rptitem_s +{ + uint16_t bitoffset; /* Bit offset in the IN, OUT or FEATURE report of the item. */ + uint8_t type; /* Report item type, a value in HID_ReportItemTypes_t. */ + uint16_t flags; /* Item data flags, a mask of HID_IOF_* constants. */ + uint8_t id; /* Report ID this item belongs to, or 0x00 if device has only one report */ + struct hid_collectionpath_s *collectionpath; /* Collection path of the item. */ + struct hid_rptitem_attributes_s attrib; /* Report item attributes. */ + uint32_t value; /* Current value of the report item */ + uint32_t previous; /* Previous value of the report item. */ +}; + +/* HID Parser Report Size Structure. Type define for a report item size + * information structure, to retain the size of a device's reports by ID. + */ + +struct hid_rptsizeinfo_s +{ + uint8_t id; /* Report ID of the report within the HID interface. */ + uint16_t size[3]; /* Number of bits in each report type for the given Report ID */ +}; + +/* HID Parser State Structure. Type define for a complete processed HID + * report, including all report item data and collections. + */ + +struct hid_rptinfo_s +{ + /* nitems is the number of report items stored in the report items array (rptitems[]). */ + + uint8_t nitems; + struct hid_rptitem_s items[HID_MAX_REPORTITEMS]; + + /* All collection items, referenced by the report items. */ + + struct hid_collectionpath_s collectionpaths[HID_MAX_COLLECTIONS]; + + uint8_t nreports; /* Number of reports within the HID interface */ + struct hid_rptsizeinfo_s rptsize[HID_MAX_REPORT_IDS]; /* Report sizes for each report in the interface */ + uint16_t maxrptsize; /* Largest report that the attached device will generate, in bits */ + bool haverptid; /* Device has at least one REPORT ID in its HID report. */ +}; + +/* Callback routine for the HID Report Parser. This callback must be + * implemented by the user code when the parser is used, to determine what + * report IN, OUT and FEATURE item's information is stored into the user + * struct hid_rptinfo_s structure. This can be used to filter only those + * items the application will be using, so that no RAM is wasted storing + * the attributes for report items which will never be referenced by the + * application. + * + * Input Parameters: + * item Pointer to the current report item for user checking. + * + * Returned value: + * Boolean true if the item should be stored into the struct hid_rptinfo_s + * structure, false if it should be ignored. + */ + +typedef bool (*hid_rptfilter_t)(FAR struct hid_rptitem_s *item); + +/**************************************************************************** + * Public Function Protoypes + ****************************************************************************/ + +#undef EXTERN +#if defined(__cplusplus) +# define EXTERN extern "C" +extern "C" { +#else +# define EXTERN extern +#endif + +/**************************************************************************** + * Name: hid_parsereport + * + * Description: + * Function to process a given HID report returned from an attached device, + * and store it into a given struct hid_rptinfo_s structure. + * + * Input Parameters: + * report Buffer containing the device's HID report table. + * rptlen Size in bytes of the HID report table. + * filter Callback function to decide if an item should be retained + * rptinfo Pointer to a struct hid_rptinfo_s instance for the parser output. + * + * Returned Value: + * Zero on success, otherwise a negated errno value. + ****************************************************************************/ + +EXTERN int hid_parsereport(FAR const uint8_t *report, int rptlen, + hid_rptfilter_t filter, + FAR struct hid_rptinfo_s *rptinfo); + +/**************************************************************************** + * Name: hid_getitem + * + * Description: + * Extracts the given report item's value out of the given HID report and + * places it into the value member of the report item's struct hid_rptitem_s + * structure. + * + * When called on a report with an item that exists in that report, this + * copies the report item's Value to it's previous element for easy + * checking to see if an item's value has changed before processing a + * report. If the given item does not exist in the report, the function + * does not modify the report item's data. + * + * Input Parameters + * report Buffer containing an IN or FEATURE report from an attached + * device. + * item Pointer to the report item of interest in a struct hid_rptinfo_s + * item array. + * + * Returned Value: + * Zero on success, otherwise a negated errno value. + * + ****************************************************************************/ + +EXTERN int hid_getitem(FAR const uint8_t *report, FAR struct hid_rptitem_s *item); + +/**************************************************************************** + * Name: hid_putitem + * + * Desription: + * Retrieves the given report item's value out of the value member of the + * report item's struct hid_rptitem_s structure and places it into the correct + * position in the HID report buffer. The report buffer is assumed to have + * the appropriate bits cleared before calling this function (i.e., the + * buffer should be explicitly cleared before report values are added). + * + * When called, this copies the report item's Value element to it's + * previous element for easy checking to see if an item's value has + * changed before sending a report. + * + * If the device has multiple HID reports, the first byte in the report is + * set to the report ID of the given item. + * + * Input Parameters: + * report Buffer holding the current OUT or FEATURE report data. + * item Pointer to the report item of interest in a struct hid_rptinfo_s + * item array. + * + ****************************************************************************/ + +#if 0 /* Not needed by host */ +EXTERN void hid_putitem(FAR uint8_t *report, FAR struct hid_rptitem_s *item); +#endif + +/**************************************************************************** + * Name: hid_reportsize + * + * Description: + * Retrieves the size of a given HID report in bytes from it's Report ID. + * + * InputParameters: + * rptinfo Pointer to a struct hid_rptinfo_s instance containing the parser output. + * id Report ID of the report whose size is to be retrieved. + * rpttype Type of the report whose size is to be determined, a valued from the + * HID_ReportItemTypes_t enum. + * + * Size of the report in bytes, or 0 if the report does not exist. + * + ****************************************************************************/ + +EXTERN size_t hid_reportsize(FAR struct hid_rptinfo_s *rptinfo, + uint8_t id, uint8_t rpttype); + +#undef EXTERN +#if defined(__cplusplus) +} +#endif + + +#endif /* __INCLUDE_NUTTX_USB_HID_PARSER_H */