HID报告描述符INPUT ITEM,OUTPUT ITEM,FEATERU ITEM Bit 1{Array (0) | Variable (1)}和HID_REPORT_ITEM的关系
HID的MAIN ITEM的INPUT ITEM,OUTPUT ITEM,FEATERU ITEM Bit定义如下:
- 0:代表是数组
- 1:代表变量
我们在 HID主条目input item、output item和feature item详解http://www.usbzh.com/article/detail-527.html 一文对此有详细的解释。不过这里我们从源代码的逻辑来解释其和HID_REPORT_ITEM的关系。
HID_REPORT_ITEM结构体在报告描述符的分析过程中至关重要,共代表着一个HID报告数据的最小颗料单元,其描述着数据的大小,最大最小值等情况。大家可以参考使用USB鼠标HID报告描述符分析HID_REPORT及成员HID_REPORT_ITEM关系http://www.usbzh.com/article/detail-967.html 一文来查看。
在HID报告描述符其定义数据功能时,一般会通过以下几种方法:
- 第一种是直接使用LOCAL ITEM的USAGE来定义。一般定义几个USAGE,在其GLOBAL ITEM中会指定REPORT_COUNT为多少。如鼠标的XY定义如下:
USAGE (X) 09 30 USAGE (Y) 09 31 LOGICAL_MINIMUM (-127) 15 81 LOGICAL_MAXIMUM (127) 25 7F REPORT_SIZE (8) 75 08 REPORT_COUNT (2) 95 02 INPUT (Data,Var,Rel) 81 06
另一种情况是可能由于功能比较多,且USAGE的编号连续,可以通过LOGICAL_MINIMUM和LOGICAL_MAXIMUM 来定义,如USB的按键功能.
USAGE_PAGE (Button) 05 09
USAGE_MINIMUM (Button 1) 19 01
USAGE_MAXIMUM (Button 3) 29 03
LOGICAL_MINIMUM (0) 15 00
LOGICAL_MAXIMUM (1) 25 01
REPORT_COUNT (3) 95 03
REPORT_SIZE (1) 75 01
INPUT (Data,Var,Abs) 81 02
所以这个最小和最大的范围内的数量一般也等于REPORT_COUNT。
以上都是INPUT ITEM,OUTPUT ITEM,FEATERU ITEM Bit 1{Array (0)}的情况。
在看多了HID报告描述符的时候,我们也见过USB键盘的报告描述符使用了数组定义,如:
REPORT_COUNT (6) 95 06
REPORT_SIZE (8) 75 08
LOGICAL_MINIMUM (0) 15 00
LOGICAL_MAXIMUM (101) 25 65
USAGE_PAGE (Keyboard) 05 07
USAGE_MINIMUM (Reserved (no event indicated)) 19 00
USAGE_MAXIMUM (Keyboard Application) 29 65
INPUT (Data,Ary,Abs) 81 00
这里使用数组的方式来一定要义,而USAGE_MINIMUM 和USAGE_MAXIMUM退化成和LOGICAL_MINIMUM、LOGICAL_MAXIMUM的功能。这里的含义就变成了定义了1个数组,数组大小为6,每个成员为1个字节。其值范围可以为00~0x65。
其实在使用HidParser_InitReportItem对每个HID_REPORT_ITEM初始化时,就会分为三种情况:
- 第一种为数组时
- 第二种为变量时,未指定USAGE_MINIMUM和USAGE_MAXIMUM,这时使用解析生成的UsageStack按顺序初始化。
- 第三种为变量时,指定了USAGE_MINIMUM和USAGE_MAXIMUM,则从SAGE_MINIMUM+index索引进行初始化HID_REPORT_ITEM的USAGE.
这三种情况在源代码中可以清晰地看到:
HIDPARSER_STATUS
HidParser_InitReportItem(
IN PHID_REPORT Report,
IN PHID_REPORT_ITEM ReportItem,
IN PGLOBAL_ITEM_STATE GlobalItemState,
IN PLOCAL_ITEM_STATE LocalItemState,
IN PMAIN_ITEM_DATA ItemData,
IN ULONG ReportItemIndex)
{
ULONG LogicalMinimum;
ULONG LogicalMaximum;
ULONG PhysicalMinimum;
ULONG PhysicalMaximum;
ULONG UsageMinimum;
ULONG UsageMaximum;
USAGE_VALUE UsageValue;
//
// get logical bounds
//
LogicalMinimum = GlobalItemState->LogicalMinimum;
LogicalMaximum = GlobalItemState->LogicialMaximum;
if (LogicalMinimum > LogicalMaximum)
{
//
// make them signed
//
HidParser_SignRange(LogicalMinimum, LogicalMaximum, &LogicalMinimum, &LogicalMaximum);
}
//ASSERT(LogicalMinimum <= LogicalMaximum);
//
// get physical bounds
//
PhysicalMinimum = GlobalItemState->PhysicalMinimum;
PhysicalMaximum = GlobalItemState->PhysicalMaximum;
if (PhysicalMinimum > PhysicalMaximum)
{
//
// make them signed
//
HidParser_SignRange(PhysicalMinimum, PhysicalMaximum, &PhysicalMinimum, &PhysicalMaximum);
}
//ASSERT(PhysicalMinimum <= PhysicalMaximum);
//
// get usage bounds
//
UsageMinimum = 0;
UsageMaximum = 0;
//Array==0 ARRAY ,Variable==1
if (ItemData->ArrayVariable == FALSE)
{
//
// get usage bounds
//
UsageMinimum = LocalItemState->UsageMinimum.u.Extended;
UsageMaximum = LocalItemState->UsageMaximum.u.Extended;
}
else
{
//
// get usage value from stack
//
if (ReportItemIndex < LocalItemState->UsageStackUsed)
{
//
// use stack item
//
UsageValue = LocalItemState->UsageStack[ReportItemIndex];//使用用户指定的USAGE
}
else
{
//
// get usage minimum from local state
//
UsageValue = LocalItemState->UsageMinimum;
//
// append item index
//
UsageValue.u.Extended += ReportItemIndex;//USAGEid+1
if (LocalItemState->UsageMaximumSet)
{
if (UsageValue.u.Extended > LocalItemState->UsageMaximum.u.Extended)
{
//
// maximum reached
//
UsageValue.u.Extended = LocalItemState->UsageMaximum.u.Extended;
}
}
}
//
// usage usage bounds
//
UsageMinimum = UsageMaximum = UsageValue.u.Extended;
}
//
// now store all values
//
ReportItem->ByteOffset = (Report->ReportSize / 8);
ReportItem->Shift = (Report->ReportSize % 8);
ReportItem->Mask = ~(0xFFFFFFFF << GlobalItemState->ReportSize);
ReportItem->BitCount = GlobalItemState->ReportSize;
ReportItem->HasData = (ItemData->DataConstant == FALSE);
ReportItem->Array = (ItemData->ArrayVariable == 0);
ReportItem->Relative = (ItemData->Relative != FALSE);
ReportItem->Minimum = LogicalMinimum;
ReportItem->Maximum = LogicalMaximum;
ReportItem->UsageMinimum = UsageMinimum;
ReportItem->UsageMaximum = UsageMaximum;
//
// increment report size
//
Report->ReportSize += GlobalItemState->ReportSize;
//
// completed successfully
//
return HIDPARSER_STATUS_SUCCESS;
}