/** @file | |
Helper functions to parse HID report descriptor and items. | |
Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "UsbMouseAbsolutePointer.h" | |
/** | |
Get next HID item from report descriptor. | |
This function retrieves next HID item from report descriptor, according to | |
the start position. | |
According to USB HID Specification, An item is piece of information | |
about the device. All items have a one-byte prefix that contains | |
the item tag, item type, and item size. | |
There are two basic types of items: short items and long items. | |
If the item is a short item, its optional data size may be 0, 1, 2, or 4 bytes. | |
Only short item is supported here. | |
@param StartPos Start position of the HID item to get. | |
@param EndPos End position of the range to get the next HID item. | |
@param HidItem Buffer for the HID Item to return. | |
@return Pointer to end of the HID item returned. | |
NULL if no HID item retrieved. | |
**/ | |
UINT8 * | |
GetNextHidItem ( | |
IN UINT8 *StartPos, | |
IN UINT8 *EndPos, | |
OUT HID_ITEM *HidItem | |
) | |
{ | |
UINT8 Temp; | |
if (EndPos <= StartPos) { | |
return NULL; | |
} | |
Temp = *StartPos; | |
StartPos++; | |
// | |
// Bit format of prefix byte: | |
// Bits 0-1: Size | |
// Bits 2-3: Type | |
// Bits 4-7: Tag | |
// | |
HidItem->Type = BitFieldRead8 (Temp, 2, 3); | |
HidItem->Tag = BitFieldRead8 (Temp, 4, 7); | |
if (HidItem->Tag == HID_ITEM_TAG_LONG) { | |
// | |
// Long Items are not supported, although we try to parse it. | |
// | |
HidItem->Format = HID_ITEM_FORMAT_LONG; | |
if ((EndPos - StartPos) >= 2) { | |
HidItem->Size = *StartPos++; | |
HidItem->Tag = *StartPos++; | |
if ((EndPos - StartPos) >= HidItem->Size) { | |
HidItem->Data.LongData = StartPos; | |
StartPos += HidItem->Size; | |
return StartPos; | |
} | |
} | |
} else { | |
HidItem->Format = HID_ITEM_FORMAT_SHORT; | |
HidItem->Size = BitFieldRead8 (Temp, 0, 1); | |
switch (HidItem->Size) { | |
case 0: | |
// | |
// No data | |
// | |
return StartPos; | |
case 1: | |
// | |
// 1-byte data | |
// | |
if ((EndPos - StartPos) >= 1) { | |
HidItem->Data.Uint8 = *StartPos++; | |
return StartPos; | |
} | |
case 2: | |
// | |
// 2-byte data | |
// | |
if ((EndPos - StartPos) >= 2) { | |
CopyMem (&HidItem->Data.Uint16, StartPos, sizeof (UINT16)); | |
StartPos += 2; | |
return StartPos; | |
} | |
case 3: | |
// | |
// 4-byte data, adjust size | |
// | |
HidItem->Size = 4; | |
if ((EndPos - StartPos) >= 4) { | |
CopyMem (&HidItem->Data.Uint32, StartPos, sizeof (UINT32)); | |
StartPos += 4; | |
return StartPos; | |
} | |
} | |
} | |
return NULL; | |
} | |
/** | |
Get data from HID item. | |
This function retrieves data from HID item. | |
It only supports short items, which has 4 types of data: | |
0, 1, 2, or 4 bytes. | |
@param HidItem Pointer to the HID item. | |
@return The data of HID item. | |
**/ | |
UINT32 | |
GetItemData ( | |
IN HID_ITEM *HidItem | |
) | |
{ | |
// | |
// Get data from HID item. | |
// | |
switch (HidItem->Size) { | |
case 1: | |
return HidItem->Data.Uint8; | |
case 2: | |
return HidItem->Data.Uint16; | |
case 4: | |
return HidItem->Data.Uint32; | |
} | |
return 0; | |
} | |
/** | |
Parse HID item from report descriptor. | |
There are three item types: Main, Global, and Local. | |
This function parses these types of HID items according | |
to tag info. | |
@param UsbMouse The instance of USB_MOUSE_ABSOLUTE_POINTER_DEV | |
@param HidItem The HID item to parse | |
**/ | |
VOID | |
ParseHidItem ( | |
IN USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouse, | |
IN HID_ITEM *HidItem | |
) | |
{ | |
UINT8 Data; | |
switch (HidItem->Type) { | |
case HID_ITEM_TYPE_MAIN: | |
// | |
// we don't care any main items, just skip | |
// | |
return; | |
case HID_ITEM_TYPE_GLOBAL: | |
// | |
// For global items, we only care Usage Page tag for Button Page here | |
// | |
if (HidItem->Tag == HID_GLOBAL_ITEM_TAG_USAGE_PAGE) { | |
Data = (UINT8)GetItemData (HidItem); | |
if (Data == 0x09) { | |
// | |
// Button Page | |
// | |
UsbMouse->PrivateData.ButtonDetected = TRUE; | |
} | |
} | |
return; | |
case HID_ITEM_TYPE_LOCAL: | |
if (HidItem->Size == 0) { | |
// | |
// No expected data for local item | |
// | |
return; | |
} | |
Data = (UINT8)GetItemData (HidItem); | |
switch (HidItem->Tag) { | |
case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: | |
if (UsbMouse->PrivateData.ButtonDetected) { | |
UsbMouse->PrivateData.ButtonMinIndex = Data; | |
} | |
return; | |
case HID_LOCAL_ITEM_TAG_USAGE_MAXIMUM: | |
{ | |
if (UsbMouse->PrivateData.ButtonDetected) { | |
UsbMouse->PrivateData.ButtonMaxIndex = Data; | |
} | |
return; | |
} | |
default: | |
return; | |
} | |
} | |
} | |
/** | |
Parse Mouse Report Descriptor. | |
According to USB HID Specification, report descriptors are | |
composed of pieces of information. Each piece of information | |
is called an Item. This function retrieves each item from | |
the report descriptor and updates USB_MOUSE_ABSOLUTE_POINTER_DEV. | |
@param UsbMouseAbsolutePointer The instance of USB_MOUSE_ABSOLUTE_POINTER_DEV | |
@param ReportDescriptor Report descriptor to parse | |
@param ReportSize Report descriptor size | |
@retval EFI_SUCCESS Report descriptor successfully parsed. | |
@retval EFI_UNSUPPORTED Report descriptor contains long item. | |
**/ | |
EFI_STATUS | |
ParseMouseReportDescriptor ( | |
OUT USB_MOUSE_ABSOLUTE_POINTER_DEV *UsbMouseAbsolutePointer, | |
IN UINT8 *ReportDescriptor, | |
IN UINTN ReportSize | |
) | |
{ | |
UINT8 *DescriptorEnd; | |
UINT8 *Ptr; | |
HID_ITEM HidItem; | |
DescriptorEnd = ReportDescriptor + ReportSize; | |
Ptr = GetNextHidItem (ReportDescriptor, DescriptorEnd, &HidItem); | |
while (Ptr != NULL) { | |
if (HidItem.Format != HID_ITEM_FORMAT_SHORT) { | |
// | |
// Long Item is not supported at current HID revision | |
// | |
return EFI_UNSUPPORTED; | |
} | |
ParseHidItem (UsbMouseAbsolutePointer, &HidItem); | |
Ptr = GetNextHidItem (Ptr, DescriptorEnd, &HidItem); | |
} | |
UsbMouseAbsolutePointer->NumberOfButtons = (UINT8)(UsbMouseAbsolutePointer->PrivateData.ButtonMaxIndex - UsbMouseAbsolutePointer->PrivateData.ButtonMinIndex + 1); | |
UsbMouseAbsolutePointer->XLogicMax = 1023; | |
UsbMouseAbsolutePointer->YLogicMax = 1023; | |
UsbMouseAbsolutePointer->XLogicMin = -1023; | |
UsbMouseAbsolutePointer->YLogicMin = -1023; | |
return EFI_SUCCESS; | |
} |