mirror of
https://gitee.com/mirrors_PX4/PX4-Autopilot.git
synced 2026-10-22 12:53:34 +08:00
Resync new repository with old repo r5166
git-svn-id: http://svn.code.sf.net/p/nuttx/code/trunk@5153 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
@@ -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 <nuttx/config.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
#include <nuttx/usb/hid.h>
|
||||
#include <nuttx/usb/hid_parser.h>
|
||||
|
||||
/****************************************************************************
|
||||
* 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[CONFIG_HID_STATEDEPTH];
|
||||
struct hid_state_s *currstate = &state[0];
|
||||
struct hid_collectionpath_s *collectionpath = NULL;
|
||||
struct hid_rptsizeinfo_s *rptidinfo = &rptinfo->rptsize[0];
|
||||
uint16_t usage[CONFIG_HID_USAGEDEPTH];
|
||||
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[CONFIG_HID_STATEDEPTH - 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 == CONFIG_HID_MAXIDS)
|
||||
{
|
||||
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 == CONFIG_HID_USAGEDEPTH)
|
||||
{
|
||||
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[CONFIG_HID_MAXCOLLECTIONS - 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 = HID_REPORT_ITEM_IN;
|
||||
}
|
||||
else if (tag == USBHID_MAIN_OUTPUT_PREFIX)
|
||||
{
|
||||
newitem.type = HID_REPORT_ITEM_OUT;
|
||||
}
|
||||
else
|
||||
{
|
||||
newitem.type = HID_REPORT_ITEM_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 == CONFIG_HID_MAXITEMS)
|
||||
{
|
||||
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 < CONFIG_HID_MAXIDS; i++)
|
||||
{
|
||||
size_t size = rptinfo->rptsize[i].size[rpttype];
|
||||
|
||||
if (rptinfo->rptsize[i].id == id)
|
||||
{
|
||||
return ((size >> 3) + ((size & 0x07) ? 1 : 0));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user