alder_lake_bios/Intel/AlderLake/ClientOneSiliconPkg/IpBlock/Thc/ThcDriver/ThcHid.c

652 lines
24 KiB
C

/** @file
Touch Host Controller Human Interface Device API
@copyright
INTEL CONFIDENTIAL
Copyright 2019 - 2021 Intel Corporation.
The source code contained or described herein and all documents related to the
source code ("Material") are owned by Intel Corporation or its suppliers or
licensors. Title to the Material remains with Intel Corporation or its suppliers
and licensors. The Material may contain trade secrets and proprietary and
confidential information of Intel Corporation and its suppliers and licensors,
and is protected by worldwide copyright and trade secret laws and treaty
provisions. No part of the Material may be used, copied, reproduced, modified,
published, uploaded, posted, transmitted, distributed, or disclosed in any way
without Intel's prior express written permission.
No license under any patent, copyright, trade secret or other intellectual
property right is granted to or conferred upon you by disclosure or delivery
of the Materials, either expressly, by implication, inducement, estoppel or
otherwise. Any license under such intellectual property rights must be
express and approved by Intel in writing.
Unless otherwise agreed by Intel in writing, you may not remove or alter
this notice or any other notice embedded in Materials by Intel or
Intel's suppliers or licensors in any way.
This file contains an 'Intel Peripheral Driver' and is uniquely identified as
"Intel Reference Module" and is licensed for Intel CPUs and chipsets under
the terms of your license agreement with Intel or your vendor. This file may
be modified by the user, subject to additional terms of the license agreement.
@par Specification Reference:
**/
#include "ThcPrivate.h"
#include "ThcDriver.h"
/**
Performs Sanity Checks before write transfer starts
@param[in] ThcDev Context of Thc device
@param[in] Length Size of the buffer
@retval EFI_NOT_READY THC is not ready
@retval EFI_ALREADY_STARTED HID transaction is still active
@retval EFI_NOT_AVAILABLE_YET THC read transaction is ongoing
@retval EFI_SUCCESS All checks passed
**/
EFI_STATUS
STATIC
HidSanityCheck (
IN THC_DEV *ThcDev,
IN UINT32 Length
)
{
if (ThcDev->ThcProtocol.DeviceStatus != EFI_SUCCESS) {
DEBUG ((DEBUG_ERROR, "ThcProtocol HidSanityCheck Error Thc Status: %r\n", ThcDev->ThcProtocol.DeviceStatus));
return EFI_NOT_READY;
}
if (ThcDev->HidActive == TRUE) {
DEBUG ((DEBUG_ERROR, "ThcProtocol HidSanityCheck Error HID transaction is still active: %r\n", EFI_ALREADY_STARTED));
return EFI_ALREADY_STARTED;
}
if (ThcDev->ReadDone == FALSE) {
DEBUG ((DEBUG_ERROR, "ThcProtocol HidSanityCheck Error THC is still recieving data: %r\n", EFI_NOT_AVAILABLE_YET));
return EFI_NOT_AVAILABLE_YET;
}
return EFI_SUCCESS;
}
/**
Wrapper function for Set/Get Feauture support
@param[in] ThcDev Context of Thc device
@param[in] WriteData Write Data Header
@param[in] Buffer Data Container that will be sent to external device
@param[in] Timeout 0 - No timeout, do not wait for response
1 or higher - will wait for that amount of time and copy response results to the same buffer.
@param[in] Length Size of buffer.
@retval EFI_NOT_READY THC is not ready
@retval EFI_ALREADY_STARTED HID transaction is still active
@retval EFI_NOT_AVAILABLE_YET THC read transaction is ongoing
@retval EFI_TIMEOUT a) Response did not come in time OR
b) DMA transaction did not finish in time
@retval EFI_BUFFER_TOO_SMALL THC DMA buffer is unable to fit that much data
@retval EFI_SUCCESS Hid Operation Completed
**/
EFI_STATUS
STATIC
HidGetSetFeature (
IN THC_DEV *ThcDev,
IN THC_WRITE_DATA_HDR *WriteData,
IN OUT UINT8 *Buffer,
IN UINTN Timeout,
IN UINT32 Length
)
{
EFI_STATUS Status;
//
// Sanity checks before transfer
//
Status = HidSanityCheck (ThcDev, Length);
if (EFI_ERROR (Status)) {
return Status;
}
if (Timeout > 0) {
ThcDev->HidDataAvailable = FALSE;
ThcDev->HidActive = TRUE;
ThcDev->HidBuffer = Buffer;
}
Status = ThcDmaWriteTx (ThcDev, Buffer, WriteData);
if (EFI_ERROR (Status)) {
goto THC_HID_EXIT;
}
//
// Wait for Response only if Timeout was set
//
if (Timeout > 0) {
THC_LOCAL_DEBUG(L"ThcProtocol HidGetSetFeature Waiting for Response \n")
DEBUG ((DEBUG_INFO, "ThcProtocol HidGetSetFeature Waiting for Response \n"));
do {
if (ThcDev->HidDataAvailable == TRUE && ThcDev->ReadDone == TRUE) {
Status = EFI_SUCCESS;
break;
}
MicroSecondDelay (1000);
Timeout--;
} while (Timeout > 0);
if (Timeout == 0) {
Status = EFI_TIMEOUT;
THC_LOCAL_DEBUG(L"ThcProtocol HidGetSetFeature Response Timeout\n")
DEBUG ((DEBUG_ERROR, "ThcProtocol HidGetSetFeature Response Timeout\n"));
}
}
THC_HID_EXIT:
//
// Restore Thc Hid state to default
//
ThcDev->HidDataAvailable = FALSE;
ThcDev->HidActive = FALSE;
ThcDev->HidBuffer = NULL;
return Status;
}
/**
Performs SetFeature function as described in Human Interface Device specification.
@param[in] This Pointer to instance of protocol.
@param[in] Length Size of the buffer.
@param[in] Buffer On input, contains data to be sent to external device. If timeout is set BIOS expects response for which same buffer is consumed.
@param[in] Timeout 0 - No timeout, do not wait for response
1 or higher - will wait for that amount of time and copy response results to the same buffer.
@retval EFI_NOT_READY THC is not ready
@retval EFI_ALREADY_STARTED HID transaction is still active
@retval EFI_NOT_AVAILABLE_YET THC read transaction is ongoing
@retval EFI_TIMEOUT a) Response did not come in time OR
b) DMA transaction did not finish in time
@retval EFI_BUFFER_TOO_SMALL THC DMA buffer is unable to fit that much data
@retval EFI_SUCCESS Set feature completed
**/
EFI_STATUS
EFIAPI
HidSetFeature (
IN THC_PROTOCOL *This,
IN UINT32 Length,
IN OUT UINT8 *Buffer,
IN UINTN Timeout
)
{
THC_DEV *ThcDev;
THC_WRITE_DATA_HDR WriteData;
EFI_STATUS Status;
ThcDev = THC_CONTEXT_FROM_THC_PROTOCOL (This);
WriteData.WriteDataType = SET_FEATURES_DATA;
WriteData.WriteDataLength = Length;
Status = HidGetSetFeature (ThcDev, &WriteData, Buffer, Timeout, Length);
return Status;
}
/**
Performs GetFeature function as described in Human Interface Device specification.
@param[in] This Pointer to instance of protocol.
@param[in] Length Size of buffer.
@param[in] Buffer On input, contains ReportId in 1st byte. On output, filled with Feature data from external device.
@param[in] Timeout 0 - No timeout, do not wait for response
1 or higher - will wait for that amount of time and copy response results to the same buffer.
@retval EFI_NOT_READY THC is not ready
@retval EFI_ALREADY_STARTED HID transaction is still active
@retval EFI_NOT_AVAILABLE_YET THC read transaction is ongoing
@retval EFI_TIMEOUT a) Response did not come in time OR
b) DMA transaction did not finish in time
@retval EFI_BUFFER_TOO_SMALL THC DMA buffer is unable to fit that much data
@retval EFI_SUCCESS Get feature completed
**/
EFI_STATUS
EFIAPI
HidGetFeature (
IN THC_PROTOCOL *This,
IN UINT32 Length,
IN OUT UINT8 *Buffer,
IN UINTN Timeout
)
{
THC_DEV *ThcDev;
THC_WRITE_DATA_HDR WriteData;
EFI_STATUS Status;
ThcDev = THC_CONTEXT_FROM_THC_PROTOCOL (This);
WriteData.WriteDataType = GET_FEATURES_DATA;
WriteData.WriteDataLength = Length;
Status = HidGetSetFeature (ThcDev, &WriteData, Buffer, Timeout, Length);
return Status;
}
/**
Enables end point device.
- Reads all Touch Panels devices registers
- Sets TouchEnable
@param[in] ThcDev Context of Thc device
@retval EFI_SUCCESS Enabling completed
@retval EFI_DEVICE_ERROR TSSDONE not set or ERR set
@retval EFI_TIMEOUT Timeout
**/
EFI_STATUS
EFIAPI
HidEnableAfterReset (
IN THC_PROTOCOL *This
)
{
THC_DEV *ThcDev;
EFI_STATUS Status;
ThcDev = THC_CONTEXT_FROM_THC_PROTOCOL (This);
Status = ThcEnableAfterReset (ThcDev);
return Status;
}
/*
HID's InputReportDescriptor consists of variable length tokens.
On entry, Descriptor points to InputReportDescriptor's start or a boundary
between two tokens somewhere inside descriptor. Size means number of bytes
before end of Descriptor.
Function returns a single Token.
On exit, Descriptor points next boundary between tokens, just after the token
that was returned. Size is decreased by as many bytes as Descriptor pointer
was moved forward.
Tokens in Long Item format are only partially supported; they will return
invalid value but Descriptor pointer and Size will be updated correctly to
allow further parsing
*/
HID_TOKEN
STATIC
HidGetToken (
IN OUT UINT8 **Descriptor,
IN OUT UINT32 *Size
)
{
HID_TOKEN Token;
UINT32 Length;
UINT8 DataSize;
Token.ID = ((**Descriptor)>>2);
Token.Value = 0;
DataSize = (**Descriptor)&0x3;
if (**Descriptor==0xFE) {
// Long Item format
Token.ID = *(*Descriptor+2);
//don't care about value - Long Items are not supported
Length = *(*Descriptor+1);
(*Descriptor)+=Length;
(*Size)-=Length;
return Token;
}
switch(DataSize) {
case 0:
Token.Value = 0;
break;
case 1:
Token.Value = *(*Descriptor+1);
break;
case 2:
Token.Value = *(*Descriptor+1) + (*(*Descriptor+2)<<8);
break;
case 3:
Token.Value = *(*Descriptor+1) + ((*(*Descriptor+2))<<8) + ((*(*Descriptor+3))<<16) + ((*(*Descriptor+4))<<24);
DataSize = 4;
break;
default: ;
}
// move descriptor pointer and decrease size by datasize + 1 byte for ID
(*Descriptor) += (1+DataSize);
(*Size) -= (1+DataSize);
return Token;
}
/*
Stack contains a set of data retrieved from parsing InputReportDescriptor.
This function checks if that set of data constitutes a valid InputData
dictionary, and if so then puts it into ReportTable, table of dictionaries.
Unless this is the 1st dictionary for a particular device, this means
allocating new bigger table and deallocating old table
@param[in] Stack A pointer to the PARSER_STACK
@param[in/out] ReportTable Pointer to the final report table that contains all the Reports
*/
VOID
STATIC
HidExportReport (
IN HID_PARSER_STACK *Stack,
IN OUT HID_INPUT_REPORT_TABLE *ReportTable
)
{
HID_INPUT_REPORT_FORMAT *ArrayOfReports;
if (Stack->TouchPanelUsage) {
ReportTable->TouchPanel = 1;
}
ArrayOfReports = (HID_INPUT_REPORT_FORMAT*) AllocatePool(sizeof(HID_INPUT_REPORT_FORMAT) * (ReportTable->Quantity + 1));
ASSERT (ArrayOfReports != NULL);
if (ArrayOfReports != NULL) {
if (ReportTable->Quantity != 0) {
CopyMem(ArrayOfReports, ReportTable->Report, sizeof(HID_INPUT_REPORT_FORMAT) * ReportTable->Quantity);
FreePool(ReportTable->Report);
}
ReportTable->Report = ArrayOfReports;
CopyMem(&(ReportTable->Report[ReportTable->Quantity]), &(Stack->TempReport), sizeof(HID_INPUT_REPORT_FORMAT));
ReportTable->Quantity++;
}
}
/*
Stack is pointer to a not-yet-complete InputReport dictionary.
This function consumes Token retrieved from InputReportDescriptor stream
and uses it to update the dictionary.
Once a dictionary is completed, it calls ExportReport() which puts the
dictionary in a table of dictionaries. Then it clears internal data
and prepares to build a new one.
This implementation of Descriptor parser ignores all types of data except for
information on how to decode Button presses and X/Y touch coordinates, as this
is the only info relevant for touchpanels.
@param[in/out] Stack A pointer to the PARSER_STACK
@param[in] Token Current Token
@param[in/out] ReportTable Pointer to the final report table that contains all the Reports
*/
VOID
STATIC
HidUpdateStack(
IN OUT HID_PARSER_STACK *Stack,
IN HID_TOKEN Token,
IN OUT HID_INPUT_REPORT_TABLE *ReportTable
)
{
switch (Token.ID) {
case USE_PAGE: Stack->GlobalUsage = Token.Value; break;
case USAGE:
if (Token.Value > 0xFFFF) { //special case for 32 bit usages - they indicate Usage + Use Page together
Stack->GlobalUsage = Token.Value >> 16;
Token.Value = Token.Value & 0xFFFF;
}
Stack->Usages++;
if (Stack->GlobalUsage == DIGITIZER && Token.Value == TOUCHPANEL) { Stack->TouchPanelUsage = 1; }
if (Stack->GlobalUsage == DIGITIZER && Token.Value == TIP_SWITCH) { Stack->UsageB = Stack->Usages;}
if (Stack->GlobalUsage == DESKTOP && Token.Value == X_AXIS) { Stack->UsageX = Stack->Usages; }
if (Stack->GlobalUsage == DESKTOP && Token.Value == Y_AXIS) { Stack->UsageY = Stack->Usages; }
break;
case LOG_MIN: Stack->LogMin = Token.Value; break;
case LOG_MAX: Stack->LogMax = Token.Value; break;
case REP_SIZE: Stack->ReportSize = Token.Value; break;
case REP_COUNT: Stack->ReportCount = Token.Value; break;
case REPORT_ID:
//
// Is new report?
//
if (Stack->TempReport.Id != 0xFFFF) { // && Stack->TempReport.Id != Token.Value
HidExportReport (Stack, ReportTable);
}
Stack->Usages = 0;
Stack->UsageX = 0;
Stack->UsageY = 0;
Stack->UsageB = 0;
Stack->LogMin = 0;
Stack->LogMax = 0;
Stack->TouchPanelUsage = 0;
Stack->ReportSize = 0;
Stack->ReportCount = 0;
Stack->TempReport.Id = Token.Value;
//
// New Report does not indicate new collection set!
//
ZeroMem (Stack->TempReport.Collection, sizeof(HID_INPUT_REPORT_COLLECTION) * MAX_HID_COLLECTION);
Stack->TempReport.CollectionCount = 1;
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].ValidCollection = FALSE;
break;
case INPUT:
if (Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStopB == 0 && Stack->UsageB != 0 && Stack->Usages == Stack->UsageB) {
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStartB = Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitsTotal;
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStopB = Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitsTotal + (Stack->ReportSize * Stack->ReportCount);
Stack->LogMax = 0;
Stack->LogMin = 0;
}
if (Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStopX == 0 && Stack->UsageX != 0 && Stack->Usages == Stack->UsageX) {
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStartX = Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitsTotal;
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStopX = Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitsTotal + (Stack->ReportSize * Stack->ReportCount);
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].LogMaxX = Stack->LogMax;
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].LogMinX = Stack->LogMin;
Stack->LogMax = 0;
Stack->LogMin = 0;
}
if (Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStopY == 0 && Stack->UsageY != 0 && Stack->Usages == Stack->UsageY) {
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStartY = Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitsTotal;
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitStopY = Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitsTotal + (Stack->ReportSize * Stack->ReportCount);
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].LogMaxY = Stack->LogMax;
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].LogMinY = Stack->LogMin;
Stack->LogMax = 0;
Stack->LogMin = 0;
}
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitsTotal += (Stack->ReportSize * Stack->ReportCount);
break;
case COLLECTION:
if (Token.Value == APPLICATION) { }
else if (Token.Value == LOGICAL) {
if (Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].ValidCollection == TRUE) {
Stack->TempReport.CollectionCount += 1;
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].BitsTotal = Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 2].BitsTotal;
}
Stack->TempReport.Collection[Stack->TempReport.CollectionCount - 1].ValidCollection = TRUE;
}
break;
case END_COLLECTION:
Stack->Usages = 0;
Stack->UsageB = 0;
Stack->UsageX = 0;
Stack->UsageY = 0;
Stack->LogMin = 0;
Stack->LogMax = 0;
Stack->ReportSize = 0;
Stack->ReportCount = 0;
break;
default:;
}
}
/*
Retrieves single bit from multi-byte stream
@param[in] InputStream Data
@param[in] Bit Bit offset
*/
UINT32
STATIC
HidAccessBit (
IN UINT8 *InputStream,
IN UINT32 Bit
)
{
return ( ( InputStream[Bit/8] & (1<<(Bit%8)) ) ? 1:0 );
}
/**
Dump report table
- shows the amount of parsed Reports along with their collections
@param[in] ReportTable Pointer to the final report table that contains all the Reports
**/
VOID
STATIC
HidShowReportTable (
IN HID_INPUT_REPORT_TABLE ReportTable
)
{
UINT32 Index;
UINT32 Collections;
for (Index = 0; Index < ReportTable.Quantity; Index++) {
DEBUG((DEBUG_INFO, "Report Id_%x \n", ReportTable.Report[Index].Id));
THC_LOCAL_DEBUG(L"Report Id_%x \n", ReportTable.Report[Index].Id)
for (Collections = 0; Collections < ReportTable.Report[Index].CollectionCount; Collections++) {
DEBUG((DEBUG_INFO, " Collection Id_%x ", Collections));
DEBUG((DEBUG_INFO, "MaxX_%x ", ReportTable.Report[Index].Collection[Collections].LogMaxX));
DEBUG((DEBUG_INFO, "MinX_%x ", ReportTable.Report[Index].Collection[Collections].LogMinX));
DEBUG((DEBUG_INFO, "MaxY_%x ", ReportTable.Report[Index].Collection[Collections].LogMaxY));
DEBUG((DEBUG_INFO, "MinY_%x ", ReportTable.Report[Index].Collection[Collections].LogMinY));
DEBUG((DEBUG_INFO, "BitB_%d-%d ", ReportTable.Report[Index].Collection[Collections].BitStartB, ReportTable.Report[Index].Collection[Collections].BitStopB));
DEBUG((DEBUG_INFO, "BitX_%d-%d ", ReportTable.Report[Index].Collection[Collections].BitStartX, ReportTable.Report[Index].Collection[Collections].BitStopX));
DEBUG((DEBUG_INFO, "BitY_%d-%d ", ReportTable.Report[Index].Collection[Collections].BitStartY, ReportTable.Report[Index].Collection[Collections].BitStopY));
DEBUG((DEBUG_INFO, "\n"));
THC_LOCAL_DEBUG(L" Collection Id_%x ", Collections)
THC_LOCAL_DEBUG(L"MaxX_%x ", ReportTable.Report[Index].Collection[Collections].LogMaxX)
THC_LOCAL_DEBUG(L"MinX_%x ", ReportTable.Report[Index].Collection[Collections].LogMinX)
THC_LOCAL_DEBUG(L"MaxY_%x ", ReportTable.Report[Index].Collection[Collections].LogMaxY)
THC_LOCAL_DEBUG(L"MinY_%x ", ReportTable.Report[Index].Collection[Collections].LogMinY)
THC_LOCAL_DEBUG(L"BitB_%d-%d ", ReportTable.Report[Index].Collection[Collections].BitStartB, ReportTable.Report[Index].Collection[Collections].BitStopB)
THC_LOCAL_DEBUG(L"BitX_%d-%d ", ReportTable.Report[Index].Collection[Collections].BitStartX, ReportTable.Report[Index].Collection[Collections].BitStopX)
THC_LOCAL_DEBUG(L"BitY_%d-%d ", ReportTable.Report[Index].Collection[Collections].BitStartY, ReportTable.Report[Index].Collection[Collections].BitStopY)
THC_LOCAL_DEBUG(L"\n")
}
}
}
/**
Parses HID Descriptor and creates Report Tables
@param[in] ThcDev Context of Thc device
@param[in] Descriptor Pointer to the descriptor
@param[in] DescriptorLength Size of the descriptor to parse
**/
VOID
HidParseDescriptor (
IN THC_DEV *ThcDev,
IN UINT8 *Descriptor,
IN UINT32 DescriptorLength
)
{
UINT8 *MovingPointer;
HID_PARSER_STACK ParseStack;
HID_TOKEN Token;
DEBUG((DEBUG_INFO, "%a \n", __FUNCTION__));
ZeroMem (&ParseStack, sizeof(HID_PARSER_STACK));
MovingPointer = Descriptor;
ParseStack.TempReport.Id = 0xFFFF; //Invalid/Default report
while (DescriptorLength > 0) {
Token = HidGetToken (&MovingPointer, &DescriptorLength);
HidUpdateStack (&ParseStack, Token, &(ThcDev->InputReportTable) );
}
HidExportReport (&ParseStack, &(ThcDev->InputReportTable) );
HidShowReportTable (ThcDev->InputReportTable);
}
/*
This function uses dictionaries to parse incoming InputReport and convert it into X/Y coordinates plus Button info.
@param[in] ReportTable Report Table with all supported HID reports
@param[in] InputStream Pointer to the HID report
@param[in] Output Result X/Y/B data
@param[in] MinMax X/Y Min and Max data
@retval EFI_SUCCESS Parsing completed
@retval EFI_NOT_FOUND Corresponding Report ID was not found in the Report Table.
*/
EFI_STATUS
HidParseInput (
IN HID_INPUT_REPORT_TABLE ReportTable,
IN UINT8 *InputStream,
IN HID_TOUCH_OUTPUT *Output,
IN HID_XY_BOUNDARY *MinMax
)
{
UINT32 Index;
UINT32 BitIndex;
UINT8* RawData;
UINT32 Collections;
Output->X = 0;
Output->Y = 0;
Output->B = 0;
MinMax->MaxX = 0;
MinMax->MinX = 0;
MinMax->MaxY = 0;
MinMax->MinY = 0;
RawData = InputStream;
RawData++; //Skip Report ID
//
// Incoming data is parsed using proper dictionary selected by ReportID. In cases where
// ReportID is not provided, it is guaranteed that only a single dictionary exists
//
// Dictionary describes which bits from input stream hold X / Y / Button data.
// There's no guarantee coordinates will be byte-aligned, therefore we use bit access
//
for (Index = 0; Index < ReportTable.Quantity; Index++) {
if (InputStream[0] == ReportTable.Report[Index].Id) {
Collections = 0;
for (Collections = 0; Collections < ReportTable.Report[Index].CollectionCount; Collections++) {
//
// ignore other collections if already got valid data
//
if (Output->X != 0 && Output->Y != 0) {
return EFI_SUCCESS;
}
Output->B = 0;
Output->X = 0;
Output->Y = 0;
MinMax->MaxX = 0;
MinMax->MinX = 0;
MinMax->MaxY = 0;
MinMax->MinY = 0;
for (BitIndex = ReportTable.Report[Index].Collection[Collections].BitStartX; BitIndex<ReportTable.Report[Index].Collection[Collections].BitStopX; BitIndex++) {
Output->X += HidAccessBit(RawData, BitIndex) << (BitIndex - ReportTable.Report[Index].Collection[Collections].BitStartX);
}
MinMax->MinX = ReportTable.Report[Index].Collection[Collections].LogMinX;
MinMax->MaxX = ReportTable.Report[Index].Collection[Collections].LogMaxX;
for (BitIndex = ReportTable.Report[Index].Collection[Collections].BitStartY; BitIndex<ReportTable.Report[Index].Collection[Collections].BitStopY; BitIndex++) {
Output->Y += HidAccessBit(RawData, BitIndex) << (BitIndex - ReportTable.Report[Index].Collection[Collections].BitStartY);
}
MinMax->MinY = ReportTable.Report[Index].Collection[Collections].LogMinY;
MinMax->MaxY = ReportTable.Report[Index].Collection[Collections].LogMaxY;
for (BitIndex = ReportTable.Report[Index].Collection[Collections].BitStartB; BitIndex<ReportTable.Report[Index].Collection[Collections].BitStopB; BitIndex++) {
Output->B += HidAccessBit(RawData, BitIndex) << (BitIndex - ReportTable.Report[Index].Collection[Collections].BitStartB);
}
}
return EFI_SUCCESS;
}
}
return EFI_NOT_FOUND;
}