652 lines
24 KiB
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;
|
|
}
|
|
|