| /** @file | |
| Helper functions to parse HID report descriptor and items. | |
| Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR> | |
| This program and the accompanying materials | |
| are licensed and made available under the terms and conditions of the BSD License | |
| which accompanies this distribution. The full text of the license may be found at | |
| http://opensource.org/licenses/bsd-license.php | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
| **/ | |
| #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 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; | |
| } |