924 lines
26 KiB
C
924 lines
26 KiB
C
/** @file
|
|
I2C Mouse driver
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2014 - 2021, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
*/
|
|
|
|
#include "I2cMouse.h"
|
|
|
|
/**
|
|
Get HID Descriptor
|
|
|
|
@param [in] I2cIo Protocol instance pointer.
|
|
@param [in] HidDescReg HID descriptor register
|
|
@param [out] HidDescriptor Point to HID Descriptor
|
|
|
|
@retval EFI_SUCCESS This driver supports this device.
|
|
@retval EFI_DEVICE_ERROR No ack for this command
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetHidDescriptor (
|
|
IN EFI_I2C_IO_PROTOCOL *I2cIo,
|
|
IN UINT32 HidDescReg,
|
|
OUT HID_DESCRIPTOR *HidDescriptor
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_I2C_REQUEST_PACKET *RequestPacket;
|
|
EFI_I2C_OPERATION *Operation;
|
|
UINT8 Buffer[sizeof(EFI_I2C_REQUEST_PACKET) + sizeof(EFI_I2C_OPERATION)];
|
|
|
|
RequestPacket = (EFI_I2C_REQUEST_PACKET*)Buffer;
|
|
Operation = RequestPacket->Operation;
|
|
RequestPacket->OperationCount = 2;
|
|
Operation[0].Flags = 0;
|
|
Operation[0].LengthInBytes = sizeof(UINT16);
|
|
Operation[0].Buffer = (UINT8*)&HidDescReg;
|
|
Operation[1].Flags = I2C_FLAG_READ;
|
|
Operation[1].LengthInBytes = sizeof(HID_DESCRIPTOR);
|
|
Operation[1].Buffer = (UINT8*)HidDescriptor;
|
|
|
|
Status = I2cIo->QueueRequest (
|
|
I2cIo,
|
|
0,
|
|
NULL,
|
|
RequestPacket,
|
|
NULL
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Get Report Descriptor
|
|
|
|
@param [in] I2cIo Protocol instance pointer.
|
|
@param [in] HidDescriptor Point to HID Descriptor
|
|
@param [out] ReportDesc Point to Report Descriptor
|
|
|
|
@retval EFI_SUCCESS This driver supports this device.
|
|
@retval EFI_DEVICE_ERROR No ack for this command
|
|
@retval EFI_INVALID_PARAMETER ReportDesc == NULL
|
|
@retval EFI_OUT_OF_RESOURCES Memory Overflow
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
GetReportDescriptor (
|
|
IN EFI_I2C_IO_PROTOCOL *I2cIo,
|
|
IN HID_DESCRIPTOR *HidDescriptor,
|
|
OUT UINT8 **ReportDesc
|
|
)
|
|
{
|
|
EFI_I2C_REQUEST_PACKET *RequestPacket;
|
|
EFI_I2C_OPERATION *Operation;
|
|
UINT8 Buffer[sizeof(EFI_I2C_REQUEST_PACKET) + sizeof(EFI_I2C_OPERATION)];
|
|
UINT16 ReportDescReg;
|
|
EFI_STATUS Status;
|
|
|
|
if (ReportDesc == NULL) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
*ReportDesc = AllocateZeroPool (HidDescriptor->ReportDescLength);
|
|
|
|
if (*ReportDesc == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Get the Report Descriptor
|
|
//
|
|
RequestPacket = (EFI_I2C_REQUEST_PACKET*)Buffer;
|
|
Operation = RequestPacket->Operation;
|
|
ReportDescReg = HidDescriptor->ReportDescRegister;
|
|
RequestPacket->OperationCount = 2;
|
|
Operation[0].Flags = 0;
|
|
Operation[0].LengthInBytes = sizeof(UINT16);
|
|
Operation[0].Buffer = (UINT8*)&ReportDescReg;
|
|
Operation[1].Flags = I2C_FLAG_READ;
|
|
Operation[1].LengthInBytes = HidDescriptor->ReportDescLength;
|
|
Operation[1].Buffer = *ReportDesc;
|
|
|
|
Status = I2cIo->QueueRequest (
|
|
I2cIo,
|
|
0,
|
|
NULL,
|
|
RequestPacket,
|
|
NULL
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Set the power state
|
|
|
|
@param MouseDev Mouse instance
|
|
@param PowerState Power state
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
SetPower (
|
|
IN I2C_MOUSE_DEV *MouseDev,
|
|
IN UINT16 PowerState
|
|
)
|
|
{
|
|
UINT16 Request[2];
|
|
EFI_STATUS Status;
|
|
EFI_I2C_REQUEST_PACKET RequestPacket;
|
|
EFI_I2C_IO_PROTOCOL *I2cIo;
|
|
|
|
if ((MouseDev == NULL) ||
|
|
((I2cIo = MouseDev->I2cIo) == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Set the power state
|
|
//
|
|
ZeroMem (&RequestPacket, sizeof (RequestPacket));
|
|
Request[0] = MouseDev->HidDescriptor.CommandRegister;
|
|
Request[1] = SET_POWER | PowerState;
|
|
RequestPacket.OperationCount = 1;
|
|
RequestPacket.Operation[0].Flags = 0;
|
|
RequestPacket.Operation[0].LengthInBytes = 4;
|
|
RequestPacket.Operation[0].Buffer = (UINT8*)Request;
|
|
|
|
Status = I2cIo->QueueRequest (
|
|
I2cIo,
|
|
0,
|
|
NULL,
|
|
&RequestPacket,
|
|
NULL
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Reset the device
|
|
|
|
@param MouseDev Mouse instance
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
ResetDevice (
|
|
IN I2C_MOUSE_DEV *MouseDev
|
|
)
|
|
{
|
|
UINT16 Request[2];
|
|
EFI_STATUS Status;
|
|
EFI_I2C_REQUEST_PACKET RequestPacket;
|
|
EFI_I2C_IO_PROTOCOL *I2cIo;
|
|
|
|
if ((MouseDev == NULL) ||
|
|
((I2cIo = MouseDev->I2cIo) == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Reset the device
|
|
//
|
|
ZeroMem (&RequestPacket, sizeof (RequestPacket));
|
|
Request[0] = MouseDev->HidDescriptor.CommandRegister;
|
|
Request[1] = RESET;
|
|
RequestPacket.OperationCount = 1;
|
|
RequestPacket.Operation[0].Flags = 0;
|
|
RequestPacket.Operation[0].LengthInBytes = 4;
|
|
RequestPacket.Operation[0].Buffer = (UINT8*)Request;
|
|
|
|
Status = I2cIo->QueueRequest (
|
|
I2cIo,
|
|
0,
|
|
NULL,
|
|
&RequestPacket,
|
|
NULL
|
|
);
|
|
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Receive the status with flush the transmission buffer
|
|
//
|
|
RequestPacket.OperationCount = 1;
|
|
RequestPacket.Operation[0].Flags = I2C_FLAG_READ;
|
|
RequestPacket.Operation[0].LengthInBytes = 2;
|
|
RequestPacket.Operation[0].Buffer = (UINT8*)Request;
|
|
|
|
Status = I2cIo->QueueRequest (
|
|
I2cIo,
|
|
0,
|
|
NULL,
|
|
&RequestPacket,
|
|
NULL
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Flush data buffer before operation
|
|
|
|
@param MouseDev Mouse instance
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
FlushDataBuffer (
|
|
IN I2C_MOUSE_DEV *MouseDev
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_I2C_REQUEST_PACKET RequestPacket;
|
|
EFI_I2C_IO_PROTOCOL *I2cIo;
|
|
|
|
if ((MouseDev == NULL) ||
|
|
((I2cIo = MouseDev->I2cIo) == NULL)) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
//
|
|
// Receive the status with flush the transmission buffer
|
|
//
|
|
ZeroMem (&RequestPacket, sizeof (RequestPacket));
|
|
RequestPacket.OperationCount = 1;
|
|
RequestPacket.Operation[0].Flags = I2C_FLAG_READ;
|
|
RequestPacket.Operation[0].LengthInBytes = MouseDev->HidDescriptor.MaxInputLength;
|
|
RequestPacket.Operation[0].Buffer = MouseDev->ReportData;
|
|
|
|
Status = I2cIo->QueueRequest (
|
|
I2cIo,
|
|
0,
|
|
NULL,
|
|
&RequestPacket,
|
|
NULL
|
|
);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
It is called whenever there is data received from async interrupt
|
|
transfer.
|
|
|
|
@param Event Wait Event
|
|
@param Context Passed parameter to event handler
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
I2cMouseInterruptOnCompleted (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
I2C_MOUSE_DEV *MouseDev;
|
|
UINTN DataLength;
|
|
UINT8 *ReportData;
|
|
UINTN Index;
|
|
EFI_I2C_IO_PROTOCOL *I2cIo;
|
|
EFI_I2C_REQUEST_PACKET RequestPacket;
|
|
REPORT_GROUP *ReportGroup;
|
|
BOOLEAN LeftButton;
|
|
BOOLEAN RightButton;
|
|
UINTN BufferIn;
|
|
|
|
MouseDev = (I2C_MOUSE_DEV*)Context;
|
|
I2cIo = MouseDev->I2cIo;
|
|
DataLength = *(UINT16*)MouseDev->ReportData;
|
|
if (MouseDev->TransferResult != EFI_SUCCESS || DataLength == 0) goto Exit;
|
|
ReportData = MouseDev->ReportData + sizeof (UINT16);
|
|
DataLength -= sizeof (UINT16);
|
|
ReportGroup = &MouseDev->ReportFieldInfo.ReportGroup[0];
|
|
if (MouseDev->ReportId) {
|
|
//
|
|
// Searching for matched report field
|
|
//
|
|
for (Index = 0; Index < MouseDev->ReportFieldInfo.Total; Index ++) {
|
|
if (MouseDev->ReportFieldInfo.ReportGroup[Index].Id == *ReportData &&
|
|
MouseDev->ReportFieldInfo.ReportGroup[Index].DataType == HID_MAIN_ITEM_TAG_INPUT) {
|
|
ReportGroup = &MouseDev->ReportFieldInfo.ReportGroup[Index];
|
|
break;
|
|
}
|
|
}
|
|
if (Index == MouseDev->ReportFieldInfo.Total) goto Exit;
|
|
}
|
|
MouseDev->StateChanged = TRUE;
|
|
//
|
|
// Check mouse data
|
|
//
|
|
LeftButton = MouseDev->State[MouseDev->BufferIn].LeftButton;
|
|
RightButton = MouseDev->State[MouseDev->BufferIn].RightButton;
|
|
MouseDev->State[MouseDev->BufferIn].LeftButton = (BOOLEAN) GetReportFieldValue (ReportData, DataLength, &ReportGroup->Data.Mouse.FieldButton1);
|
|
MouseDev->State[MouseDev->BufferIn].RightButton = (BOOLEAN) GetReportFieldValue (ReportData, DataLength, &ReportGroup->Data.Mouse.FieldButton2);
|
|
MouseDev->State[MouseDev->BufferIn].RelativeMovementX = (INT8) GetReportFieldValue (ReportData, DataLength, &ReportGroup->Data.Mouse.FieldX);
|
|
MouseDev->State[MouseDev->BufferIn].RelativeMovementY = (INT8) GetReportFieldValue (ReportData, DataLength, &ReportGroup->Data.Mouse.FieldY);
|
|
if (ReportGroup->Data.Mouse.FieldZ.DataValid) {
|
|
MouseDev->State[MouseDev->BufferIn].RelativeMovementZ = (INT8) GetReportFieldValue (ReportData, DataLength, &ReportGroup->Data.Mouse.FieldZ);
|
|
}
|
|
if (LeftButton != MouseDev->State[MouseDev->BufferIn].LeftButton ||
|
|
RightButton != MouseDev->State[MouseDev->BufferIn].RightButton) {
|
|
//
|
|
// Advance the internal buffer only when button state changed to reduce the dragging phenomenon
|
|
//
|
|
BufferIn = MouseDev->BufferIn + 1;
|
|
if (BufferIn == STATE_BUFFER_SIZE) BufferIn = 0;
|
|
if (BufferIn != MouseDev->BufferOut) {
|
|
//
|
|
// Copy last state to new position for use of check procedure of last button state
|
|
//
|
|
CopyMem (
|
|
&MouseDev->State[BufferIn],
|
|
&MouseDev->State[MouseDev->BufferIn],
|
|
sizeof (EFI_SIMPLE_POINTER_STATE)
|
|
);
|
|
MouseDev->BufferIn = BufferIn;
|
|
}
|
|
}
|
|
Exit:
|
|
//
|
|
// Starting next transmission
|
|
//
|
|
RequestPacket.OperationCount = 1;
|
|
RequestPacket.Operation[0].Flags = I2C_FLAG_READ;
|
|
RequestPacket.Operation[0].LengthInBytes = MouseDev->HidDescriptor.MaxInputLength;
|
|
RequestPacket.Operation[0].Buffer = MouseDev->ReportData;
|
|
|
|
I2cIo->QueueRequest (
|
|
I2cIo,
|
|
0,
|
|
MouseDev->OnCompleteEvent,
|
|
&RequestPacket,
|
|
&MouseDev->TransferResult
|
|
);
|
|
}
|
|
|
|
/**
|
|
|
|
Get the mouse state, see SIMPLE POINTER PROTOCOL.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param MouseState Current mouse state
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval EFI_DEVICE_ERROR
|
|
@retval EFI_NOT_READY
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cGetMouseState (
|
|
IN EFI_SIMPLE_POINTER_PROTOCOL *This,
|
|
OUT EFI_SIMPLE_POINTER_STATE *MouseState
|
|
)
|
|
{
|
|
I2C_MOUSE_DEV *MouseDev;
|
|
|
|
if (MouseState == NULL) {
|
|
return EFI_DEVICE_ERROR;
|
|
}
|
|
MouseDev = I2C_MOUSE_DEV_FROM_SIMPLE_POINTER_PROTOCOL (This);
|
|
if (!MouseDev->StateChanged) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
CopyMem (
|
|
MouseState,
|
|
&MouseDev->State[MouseDev->BufferOut],
|
|
sizeof (EFI_SIMPLE_POINTER_STATE)
|
|
);
|
|
if (MouseDev->BufferOut != MouseDev->BufferIn) {
|
|
MouseDev->BufferOut ++;
|
|
if (MouseDev->BufferOut == STATE_BUFFER_SIZE) MouseDev->BufferOut = 0;
|
|
}
|
|
if (MouseDev->BufferOut == MouseDev->BufferIn) {
|
|
MouseDev->StateChanged = FALSE;
|
|
}
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Reset the mouse device, see SIMPLE POINTER PROTOCOL.
|
|
|
|
@param This Protocol instance pointer.
|
|
@param ExtendedVerification Ignored here
|
|
|
|
@retval EFI_SUCCESS
|
|
|
|
**/
|
|
STATIC
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cMouseReset (
|
|
IN EFI_SIMPLE_POINTER_PROTOCOL *This,
|
|
IN BOOLEAN ExtendedVerification
|
|
)
|
|
{
|
|
I2C_MOUSE_DEV *MouseDev;
|
|
|
|
MouseDev = I2C_MOUSE_DEV_FROM_SIMPLE_POINTER_PROTOCOL (This);
|
|
ZeroMem (
|
|
MouseDev->State,
|
|
sizeof (EFI_SIMPLE_POINTER_STATE) * STATE_BUFFER_SIZE
|
|
);
|
|
MouseDev->StateChanged = FALSE;
|
|
MouseDev->BufferIn = 0;
|
|
MouseDev->BufferOut = 0;
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
|
|
Event notification function for SIMPLE_POINTER.WaitForInput event
|
|
Signal the event if there is input from mouse
|
|
|
|
@param Event Wait Event
|
|
@param Context Passed parameter to event handler
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
EFIAPI
|
|
MouseWaitForInput (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
I2C_MOUSE_DEV *MouseDev;
|
|
|
|
MouseDev = (I2C_MOUSE_DEV*) Context;
|
|
//
|
|
// Someone is waiting on the mouse event, if there's
|
|
// input from mouse, signal the event
|
|
//
|
|
if (MouseDev->StateChanged) {
|
|
gBS->SignalEvent (Event);
|
|
}
|
|
}
|
|
|
|
/**
|
|
|
|
Free the resource allocated by I2C Mouse instance
|
|
|
|
@param MouseDev I2C Mouse instance
|
|
@param Controller I2C I/O Controller Handle
|
|
|
|
**/
|
|
STATIC
|
|
VOID
|
|
FreeResource (
|
|
IN I2C_MOUSE_DEV *MouseDev,
|
|
IN EFI_HANDLE Controller
|
|
)
|
|
{
|
|
//
|
|
// Always close protocol even the protocol has not being opened
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiI2cIoProtocolGuid,
|
|
gI2cMouseDriverBinding.DriverBindingHandle,
|
|
Controller
|
|
);
|
|
//
|
|
// Free resources in the instance
|
|
//
|
|
if (MouseDev) {
|
|
if (MouseDev->OnCompleteEvent) {
|
|
gBS->CloseEvent (MouseDev->OnCompleteEvent);
|
|
}
|
|
if (MouseDev->SimplePointerProtocol.WaitForInput) {
|
|
gBS->CloseEvent (MouseDev->SimplePointerProtocol.WaitForInput);
|
|
}
|
|
gBS->UninstallProtocolInterface (
|
|
Controller,
|
|
&gEfiSimplePointerProtocolGuid,
|
|
&MouseDev->SimplePointerProtocol
|
|
);
|
|
if (MouseDev->ReportData) {
|
|
FreePool (MouseDev->ReportData);
|
|
}
|
|
if (MouseDev->ControllerNameTable) {
|
|
FreeUnicodeStringTable (MouseDev->ControllerNameTable);
|
|
}
|
|
FreePool (MouseDev);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Verify the controller type
|
|
|
|
This routine determines if an I2C Mouse is available.
|
|
|
|
This routine is called by the UEFI driver framework during connect
|
|
processing.
|
|
|
|
@param [in] DriverBinding Protocol instance pointer.
|
|
@param [in] Controller Handle of device to test.
|
|
@param [in] RemainingDevicePath Not used.
|
|
|
|
@retval EFI_SUCCESS This driver supports this device.
|
|
@retval other This driver does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cMouseDriverSupported (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_I2C_IO_PROTOCOL *I2cIo;
|
|
H2O_I2C_HID_DEVICE *I2cHidDevice;
|
|
|
|
//
|
|
// Determine if the I2C I/O is available
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiI2cIoProtocolGuid,
|
|
(VOID**) &I2cIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR ( Status )) {
|
|
return Status;
|
|
}
|
|
//
|
|
// The I2C I/O is available
|
|
//
|
|
gBS->CloseProtocol (
|
|
Controller,
|
|
&gEfiI2cIoProtocolGuid,
|
|
This->DriverBindingHandle,
|
|
Controller
|
|
);
|
|
//
|
|
// Inspect the H2O I2C HID specific data in the controller
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gI2cHidDeviceInfoGuid,
|
|
(VOID**) &I2cHidDevice,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
if (I2cHidDevice->ClassType != POINTER_CLASS &&
|
|
I2cHidDevice->ClassType != MOUSE_CLASS) {
|
|
Status = EFI_NOT_FOUND;
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
Connect to the I2C Mouse
|
|
|
|
This routine initializes an instance of the I2C driver for this
|
|
controller.
|
|
|
|
This routine is called by the UEFI driver framework during connect
|
|
processing if the controller passes the tests in I2cBusDriverSupported.
|
|
|
|
@param [in] DriverBinding Protocol instance pointer.
|
|
@param [in] Controller Handle of device to work with.
|
|
@param [in] RemainingDevicePath Not used, always produce all possible children.
|
|
|
|
@retval EFI_SUCCESS This driver is added to Controller.
|
|
@retval other This driver does not support this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cMouseDriverStart (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
I2C_MOUSE_DEV *MouseDev;
|
|
EFI_I2C_IO_PROTOCOL *I2cIo;
|
|
H2O_I2C_HID_DEVICE *I2cHidDevice;
|
|
UINT8 *ReportDescriptor;
|
|
UINTN Index;
|
|
REPORT_GROUP *ReportGroup;
|
|
EFI_I2C_REQUEST_PACKET RequestPacket;
|
|
|
|
MouseDev = NULL;
|
|
//
|
|
// Occupy the I2C I/O protocol
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiI2cIoProtocolGuid,
|
|
(VOID**) &I2cIo,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_BY_DRIVER
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
//
|
|
// Get the H2O I2C HID specific data in the controller
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gI2cHidDeviceInfoGuid,
|
|
(VOID**) &I2cHidDevice,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
|
|
MouseDev = AllocateZeroPool (sizeof (I2C_MOUSE_DEV));
|
|
if (MouseDev == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
MouseDev->Signature = I2C_MOUSE_DEV_SIGNATURE;
|
|
MouseDev->I2cIo = I2cIo;
|
|
CopyMem (&MouseDev->I2cHid, I2cHidDevice, I2cHidDevice->Length);
|
|
|
|
//
|
|
// Get HID descriptor
|
|
//
|
|
Status = GetHidDescriptor (I2cIo, MouseDev->I2cHid.DescReg, &MouseDev->HidDescriptor);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
if (MouseDev->HidDescriptor.HIDDescLength != sizeof(HID_DESCRIPTOR)) {
|
|
Status = EFI_DEVICE_ERROR;
|
|
goto Error;
|
|
}
|
|
MouseDev->I2cHid.VendorID = MouseDev->HidDescriptor.VendorID;
|
|
MouseDev->I2cHid.ProductID = MouseDev->HidDescriptor.ProductID;
|
|
MouseDev->I2cHid.VersionID = MouseDev->HidDescriptor.VersionID;
|
|
//
|
|
// Set the VID/PID/Revision into AIP for use of OEM specific usage
|
|
//
|
|
CopyMem (I2cHidDevice, &MouseDev->I2cHid, I2cHidDevice->Length);
|
|
|
|
MouseDev->ReportData = AllocateZeroPool (MouseDev->HidDescriptor.MaxInputLength);
|
|
if (MouseDev->ReportData == NULL) {
|
|
Status = EFI_OUT_OF_RESOURCES;
|
|
goto Error;
|
|
}
|
|
//
|
|
// Power on the device
|
|
//
|
|
SetPower (MouseDev, POWER_ON);
|
|
//
|
|
// Reset the device
|
|
//
|
|
ResetDevice (MouseDev);
|
|
//
|
|
// Flush the data buffer before operation
|
|
//
|
|
FlushDataBuffer (MouseDev);
|
|
//
|
|
// Get report descriptor
|
|
//
|
|
Status = GetReportDescriptor ( I2cIo, &MouseDev->HidDescriptor, &ReportDescriptor);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
Status = ParseReportDescriptor (
|
|
ReportDescriptor,
|
|
MouseDev->HidDescriptor.ReportDescLength,
|
|
&MouseDev->ReportFieldInfo
|
|
);
|
|
FreePool (ReportDescriptor);
|
|
if (EFI_ERROR(Status)) {
|
|
goto Error;
|
|
}
|
|
//
|
|
// Searching for mouse report
|
|
//
|
|
for (Index = 0, ReportGroup = NULL; Index < MouseDev->ReportFieldInfo.Total; Index ++) {
|
|
if (MouseDev->ReportFieldInfo.ReportGroup[Index].DataValid &&
|
|
(MouseDev->ReportFieldInfo.ReportGroup[Index].DataClass == MOUSE_CLASS ||
|
|
MouseDev->ReportFieldInfo.ReportGroup[Index].DataClass == POINTER_CLASS) &&
|
|
MouseDev->ReportFieldInfo.ReportGroup[Index].DataType == HID_MAIN_ITEM_TAG_INPUT &&
|
|
MouseDev->ReportFieldInfo.ReportGroup[Index].DataSize > 0) {
|
|
ReportGroup = &MouseDev->ReportFieldInfo.ReportGroup[Index];
|
|
break;
|
|
}
|
|
}
|
|
if (ReportGroup == NULL) {
|
|
Status = EFI_UNSUPPORTED;
|
|
goto Error;
|
|
}
|
|
if (MouseDev->NumberOfButtons >= 1) {
|
|
MouseDev->Mode.LeftButton = TRUE;
|
|
}
|
|
if (MouseDev->NumberOfButtons > 1) {
|
|
MouseDev->Mode.RightButton = TRUE;
|
|
}
|
|
MouseDev->ReportId = ReportGroup->Id;
|
|
MouseDev->Mode.ResolutionX = 8;
|
|
MouseDev->Mode.ResolutionY = 8;
|
|
MouseDev->Mode.ResolutionZ = 0;
|
|
MouseDev->SimplePointerProtocol.GetState = I2cGetMouseState;
|
|
MouseDev->SimplePointerProtocol.Reset = I2cMouseReset;
|
|
MouseDev->SimplePointerProtocol.Mode = &MouseDev->Mode;
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_WAIT,
|
|
TPL_NOTIFY,
|
|
MouseWaitForInput,
|
|
MouseDev,
|
|
&MouseDev->SimplePointerProtocol.WaitForInput
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
//
|
|
// Install Simple Pointer Protocol for the I2C mouse device.
|
|
//
|
|
Status = gBS->InstallProtocolInterface (
|
|
&Controller,
|
|
&gEfiSimplePointerProtocolGuid,
|
|
EFI_NATIVE_INTERFACE,
|
|
&MouseDev->SimplePointerProtocol
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
//
|
|
// Create event for interrupt on completed handler
|
|
//
|
|
Status = gBS->CreateEvent (
|
|
EVT_NOTIFY_SIGNAL,
|
|
TPL_NOTIFY,
|
|
I2cMouseInterruptOnCompleted,
|
|
MouseDev,
|
|
&MouseDev->OnCompleteEvent
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
goto Error;
|
|
}
|
|
//
|
|
// Allocate and setup controller name table for ComponentName/2 protocol
|
|
//
|
|
AddUnicodeString2 (
|
|
LANGUAGE_CODE_ENGLISH_ISO639,
|
|
gI2cMouseComponentName.SupportedLanguages,
|
|
&MouseDev->ControllerNameTable,
|
|
CONTROLLER_DRIVER_NAME,
|
|
TRUE
|
|
);
|
|
AddUnicodeString2 (
|
|
LANGUAGE_CODE_ENGLISH_RFC4646,
|
|
gI2cMouseComponentName2.SupportedLanguages,
|
|
&MouseDev->ControllerNameTable,
|
|
CONTROLLER_DRIVER_NAME,
|
|
FALSE
|
|
);
|
|
//
|
|
// Issue async I2C request for data transfer
|
|
//
|
|
RequestPacket.OperationCount = 1;
|
|
RequestPacket.Operation[0].Flags = I2C_FLAG_READ;
|
|
RequestPacket.Operation[0].LengthInBytes = MouseDev->HidDescriptor.MaxInputLength;
|
|
RequestPacket.Operation[0].Buffer = MouseDev->ReportData;
|
|
|
|
Status = I2cIo->QueueRequest (
|
|
I2cIo,
|
|
0,
|
|
MouseDev->OnCompleteEvent,
|
|
&RequestPacket,
|
|
&MouseDev->TransferResult
|
|
);
|
|
Error:
|
|
if (EFI_ERROR (Status)) {
|
|
FreeResource (MouseDev, Controller);
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
/**
|
|
Disconnect from the I2C host controller.
|
|
|
|
This routine disconnects from the Mouse
|
|
|
|
This routine is called by DriverUnload when the Mouse
|
|
is being unloaded.
|
|
|
|
@param [in] DriverBinding Protocol instance pointer.
|
|
@param [in] Controller Handle of device to stop driver on.
|
|
@param [in] NumberOfChildren How many children need to be stopped.
|
|
@param [in] ChildHandleBuffer Not used.
|
|
|
|
@retval EFI_SUCCESS This driver is removed Controller.
|
|
@retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
|
|
@retval other This driver was not removed from this device.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cMouseDriverStop (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Controller,
|
|
IN UINTN NumberOfChildren,
|
|
IN EFI_HANDLE *ChildHandleBuffer
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
I2C_MOUSE_DEV *MouseDev;
|
|
EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
|
|
//
|
|
// Disconnect any connected drivers and locate the context
|
|
// structure
|
|
//
|
|
Status = gBS->OpenProtocol (
|
|
Controller,
|
|
&gEfiSimplePointerProtocolGuid,
|
|
(VOID**) &SimplePointerProtocol,
|
|
This->DriverBindingHandle,
|
|
Controller,
|
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
return Status;
|
|
}
|
|
MouseDev = I2C_MOUSE_DEV_FROM_SIMPLE_POINTER_PROTOCOL (SimplePointerProtocol);
|
|
FreeResource (MouseDev, Controller);
|
|
return Status;
|
|
}
|
|
|
|
/**
|
|
|
|
Driver binding protocol support
|
|
|
|
**/
|
|
EFI_DRIVER_BINDING_PROTOCOL gI2cMouseDriverBinding = {
|
|
I2cMouseDriverSupported,
|
|
I2cMouseDriverStart,
|
|
I2cMouseDriverStop,
|
|
0x12,
|
|
NULL,
|
|
NULL
|
|
};
|
|
|
|
/**
|
|
|
|
Entry point for EFI drivers.
|
|
|
|
@param ImageHandle EFI_HANDLE
|
|
@param SystemTable EFI_SYSTEM_TABLE
|
|
|
|
@retval EFI_SUCCESS
|
|
@retval others
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
I2cMouseEntryPoint (
|
|
IN EFI_HANDLE ImageHandle,
|
|
IN EFI_SYSTEM_TABLE *SystemTable
|
|
)
|
|
{
|
|
//
|
|
// Install binding protocols
|
|
//
|
|
return EfiLibInstallDriverBindingComponentName2 (
|
|
ImageHandle,
|
|
SystemTable,
|
|
&gI2cMouseDriverBinding,
|
|
ImageHandle,
|
|
&gI2cMouseComponentName,
|
|
&gI2cMouseComponentName2
|
|
);
|
|
}
|