Signed-off-by: Li Elvin <elvin.li@intel.com> Reviewed-by: Yao Jiewen <jiewen.yao@intel.com> Reviewed-by: Ni Ruiyu <ruiyu.ni@intel.com> Reviewed-by: Gao Liming <liming.gao@intel.com> Reviewed-by: Tian Feng <feng.tian@intel.com> Reviewed-by: Fan Jeff <jeff.fan@intel.com> git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@13889 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			793 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			793 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   PS/2 Mouse driver. Routines that interacts with callers,
 | |
|   conforming to EFI driver model.
 | |
|   
 | |
| Copyright (c) 2006 - 2012, 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 "Ps2Mouse.h"
 | |
| #include "CommPs2.h"
 | |
| 
 | |
| ///
 | |
| /// DriverBinding Protocol Instance
 | |
| ///
 | |
| EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver = {
 | |
|   PS2MouseDriverSupported,
 | |
|   PS2MouseDriverStart,
 | |
|   PS2MouseDriverStop,
 | |
|   0xa,
 | |
|   NULL,
 | |
|   NULL
 | |
| };
 | |
| 
 | |
| /**
 | |
|   Test to see if this driver supports ControllerHandle. Any ControllerHandle
 | |
|   than contains a IsaIo protocol can be supported.
 | |
| 
 | |
|   @param  This                Protocol instance pointer.
 | |
|   @param  ControllerHandle    Handle of device to test
 | |
|   @param  RemainingDevicePath Optional parameter use to pick a specific child
 | |
|                               device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS         This driver supports this device
 | |
|   @retval EFI_ALREADY_STARTED This driver is already running on this device
 | |
|   @retval other               This driver does not support this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PS2MouseDriverSupported (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_ISA_IO_PROTOCOL                 *IsaIo;
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
| 
 | |
|   //
 | |
|   // Open the IO Abstraction(s) needed to perform the supported test
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiIsaIoProtocolGuid,
 | |
|                   (VOID **) &IsaIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
 | |
|   //
 | |
|   switch (IsaIo->ResourceList->Device.HID) {
 | |
|   case EISA_PNP_ID (0xF03):
 | |
|   //
 | |
|   // Microsoft PS/2 style mouse
 | |
|   //
 | |
|   case EISA_PNP_ID (0xF13):
 | |
|     //
 | |
|     // PS/2 Port for PS/2-style Mice
 | |
|     //
 | |
|     break;
 | |
| 
 | |
|   case EISA_PNP_ID (0x303):
 | |
|     //
 | |
|     // IBM Enhanced (101/102-key, PS/2 mouse support)
 | |
|     //
 | |
|     if (IsaIo->ResourceList->Device.UID == 1) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   default:
 | |
|     Status = EFI_UNSUPPORTED;
 | |
|     break;
 | |
|   }
 | |
|   //
 | |
|   // Close the I/O Abstraction(s) used to perform the supported test
 | |
|   //
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiIsaIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Start this driver on ControllerHandle by opening a IsaIo protocol, creating 
 | |
|   PS2_MOUSE_ABSOLUTE_POINTER_DEV device and install gEfiAbsolutePointerProtocolGuid
 | |
|   finally.
 | |
| 
 | |
|   @param  This                 Protocol instance pointer.
 | |
|   @param  ControllerHandle     Handle of device to bind driver to
 | |
|   @param  RemainingDevicePath  Optional parameter use to pick a specific child
 | |
|                                device to start.
 | |
| 
 | |
|   @retval EFI_SUCCESS          This driver is added to ControllerHandle
 | |
|   @retval EFI_ALREADY_STARTED  This driver is already running on ControllerHandle
 | |
|   @retval other                This driver does not support this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PS2MouseDriverStart (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN EFI_DEVICE_PATH_PROTOCOL       *RemainingDevicePath
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_STATUS                          EmptyStatus;
 | |
|   EFI_ISA_IO_PROTOCOL                 *IsaIo;
 | |
|   PS2_MOUSE_DEV                       *MouseDev;
 | |
|   UINT8                               Data;
 | |
|   EFI_TPL                             OldTpl;
 | |
|   EFI_STATUS_CODE_VALUE               StatusCode;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *ParentDevicePath;
 | |
| 
 | |
|   StatusCode  = 0;
 | |
|   MouseDev    = NULL;
 | |
|   IsaIo       = NULL;
 | |
| 
 | |
|   //
 | |
|   // Open the device path protocol
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiDevicePathProtocolGuid,
 | |
|                   (VOID **) &ParentDevicePath,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // Report that the keyboard is being enabled
 | |
|   //
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE,
 | |
|     ParentDevicePath
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Get the ISA I/O Protocol on Controller's handle
 | |
|   //
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiIsaIoProtocolGuid,
 | |
|                   (VOID **) &IsaIo,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_BY_DRIVER
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     gBS->CloseProtocol (
 | |
|            Controller,
 | |
|            &gEfiDevicePathProtocolGuid,
 | |
|            This->DriverBindingHandle,
 | |
|            Controller
 | |
|            );
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
|   //
 | |
|   // Raise TPL to avoid keyboard operation impact
 | |
|   //
 | |
|   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   //
 | |
|   // Allocate private data
 | |
|   //
 | |
|   MouseDev = AllocateZeroPool (sizeof (PS2_MOUSE_DEV));
 | |
|   if (MouseDev == NULL) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
|   //
 | |
|   // Setup the device instance
 | |
|   //
 | |
|   MouseDev->Signature       = PS2_MOUSE_DEV_SIGNATURE;
 | |
|   MouseDev->Handle          = Controller;
 | |
|   MouseDev->SampleRate      = SampleRate20;
 | |
|   MouseDev->Resolution      = MouseResolution4;
 | |
|   MouseDev->Scaling         = Scaling1;
 | |
|   MouseDev->DataPackageSize = 3;
 | |
|   MouseDev->IsaIo           = IsaIo;
 | |
|   MouseDev->DevicePath      = ParentDevicePath;
 | |
| 
 | |
|   //
 | |
|   // Resolution = 4 counts/mm
 | |
|   //
 | |
|   MouseDev->Mode.ResolutionX                = 4;
 | |
|   MouseDev->Mode.ResolutionY                = 4;
 | |
|   MouseDev->Mode.LeftButton                 = TRUE;
 | |
|   MouseDev->Mode.RightButton                = TRUE;
 | |
| 
 | |
|   MouseDev->SimplePointerProtocol.Reset     = MouseReset;
 | |
|   MouseDev->SimplePointerProtocol.GetState  = MouseGetState;
 | |
|   MouseDev->SimplePointerProtocol.Mode      = &(MouseDev->Mode);
 | |
| 
 | |
|   //
 | |
|   // Initialize keyboard controller if necessary
 | |
|   //
 | |
|   IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
 | |
|   //
 | |
|   // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
 | |
|   //
 | |
|   if ((Data & (KBC_PARE | KBC_TIM)) == (KBC_PARE | KBC_TIM)) {
 | |
|     //
 | |
|     // If nobody decodes KBC I/O port, it will read back as 0xFF.
 | |
|     // Check the Time-Out and Parity bit to see if it has an active KBC in system
 | |
|     //
 | |
|     Status     = EFI_DEVICE_ERROR;
 | |
|     StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED;
 | |
|     goto ErrorExit;
 | |
|   } 
 | |
| 
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_MOUSE | EFI_P_MOUSE_PC_SELF_TEST,
 | |
|     ParentDevicePath
 | |
|     );
 | |
| 
 | |
|   if ((Data & KBC_SYSF) != KBC_SYSF) {
 | |
|     Status = KbcSelfTest (IsaIo);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_CONTROLLER_ERROR;
 | |
|       goto ErrorExit;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   KbcEnableAux (IsaIo);
 | |
| 
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT,
 | |
|     ParentDevicePath
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Reset the mouse
 | |
|   //
 | |
|   Status = MouseDev->SimplePointerProtocol.Reset (
 | |
|                      &MouseDev->SimplePointerProtocol,
 | |
|                      FeaturePcdGet (PcdPs2MouseExtendedVerification)
 | |
|                      );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // mouse not connected
 | |
|     //
 | |
|     Status      = EFI_SUCCESS;
 | |
|     StatusCode  = EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
| 
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED,
 | |
|     ParentDevicePath
 | |
|     );
 | |
| 
 | |
|   //
 | |
|   // Setup the WaitForKey event
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_NOTIFY_WAIT,
 | |
|                   TPL_NOTIFY,
 | |
|                   MouseWaitForInput,
 | |
|                   MouseDev,
 | |
|                   &((MouseDev->SimplePointerProtocol).WaitForInput)
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
|   //
 | |
|   // Setup a periodic timer, used to poll mouse state
 | |
|   //
 | |
|   Status = gBS->CreateEvent (
 | |
|                   EVT_TIMER | EVT_NOTIFY_SIGNAL,
 | |
|                   TPL_NOTIFY,
 | |
|                   PollMouse,
 | |
|                   MouseDev,
 | |
|                   &MouseDev->TimerEvent
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
|   //
 | |
|   // Start timer to poll mouse (100 samples per second)
 | |
|   //
 | |
|   Status = gBS->SetTimer (MouseDev->TimerEvent, TimerPeriodic, 100000);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     Status = EFI_OUT_OF_RESOURCES;
 | |
|     goto ErrorExit;
 | |
|   }
 | |
| 
 | |
|   MouseDev->ControllerNameTable = NULL;
 | |
|   AddUnicodeString2 (
 | |
|     "eng",
 | |
|     gPs2MouseComponentName.SupportedLanguages,
 | |
|     &MouseDev->ControllerNameTable,
 | |
|     L"PS/2 Mouse Device",
 | |
|     TRUE
 | |
|     );
 | |
|   AddUnicodeString2 (
 | |
|     "en",
 | |
|     gPs2MouseComponentName2.SupportedLanguages,
 | |
|     &MouseDev->ControllerNameTable,
 | |
|     L"PS/2 Mouse Device",
 | |
|     FALSE
 | |
|     );
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // Install protocol interfaces for the mouse device.
 | |
|   //
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &Controller,
 | |
|                   &gEfiSimplePointerProtocolGuid,
 | |
|                   &MouseDev->SimplePointerProtocol,
 | |
|                   NULL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     goto ErrorExit;
 | |
|   }
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return Status;
 | |
| 
 | |
| ErrorExit:
 | |
| 
 | |
|   if (Status != EFI_DEVICE_ERROR) {
 | |
|     KbcDisableAux (IsaIo);
 | |
|   }
 | |
| 
 | |
|   if (StatusCode != 0) {
 | |
|     REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|       EFI_ERROR_CODE | EFI_ERROR_MINOR,
 | |
|       StatusCode,
 | |
|       ParentDevicePath
 | |
|       );
 | |
|   }
 | |
| 
 | |
|   if ((MouseDev != NULL) && (MouseDev->SimplePointerProtocol.WaitForInput != NULL)) {
 | |
|     gBS->CloseEvent (MouseDev->SimplePointerProtocol.WaitForInput);
 | |
|   }
 | |
| 
 | |
|   if ((MouseDev != NULL) && (MouseDev->TimerEvent != NULL)) {
 | |
|     gBS->CloseEvent (MouseDev->TimerEvent);
 | |
|   }
 | |
| 
 | |
|   if ((MouseDev != NULL) && (MouseDev->ControllerNameTable != NULL)) {
 | |
|     FreeUnicodeStringTable (MouseDev->ControllerNameTable);
 | |
|   }
 | |
|   
 | |
|   if (Status != EFI_DEVICE_ERROR) {
 | |
|     //
 | |
|     // Since there will be no timer handler for mouse input any more,
 | |
|     // exhaust input data just in case there is still mouse data left
 | |
|     //
 | |
|     EmptyStatus = EFI_SUCCESS;
 | |
|     while (!EFI_ERROR (EmptyStatus)) {
 | |
|       EmptyStatus = In8042Data (IsaIo, &Data);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (MouseDev != NULL) {
 | |
|     FreePool (MouseDev);
 | |
|   }
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiDevicePathProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiIsaIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Stop this driver on ControllerHandle. Support stoping any child handles
 | |
|   created by this driver.
 | |
| 
 | |
|   @param  This              Protocol instance pointer.
 | |
|   @param  ControllerHandle  Handle of device to stop driver on
 | |
|   @param  NumberOfChildren  Number of Handles in ChildHandleBuffer. If number of
 | |
|                             children is zero stop the entire bus driver.
 | |
|   @param  ChildHandleBuffer List of Child Handles to Stop.
 | |
| 
 | |
|   @retval EFI_SUCCESS       This driver is removed ControllerHandle
 | |
|   @retval other             This driver was not removed from this device
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| PS2MouseDriverStop (
 | |
|   IN EFI_DRIVER_BINDING_PROTOCOL    *This,
 | |
|   IN EFI_HANDLE                     Controller,
 | |
|   IN UINTN                          NumberOfChildren,
 | |
|   IN EFI_HANDLE                     *ChildHandleBuffer
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
 | |
|   PS2_MOUSE_DEV               *MouseDev;
 | |
|   UINT8                       Data;
 | |
| 
 | |
|   Status = gBS->OpenProtocol (
 | |
|                   Controller,
 | |
|                   &gEfiSimplePointerProtocolGuid,
 | |
|                   (VOID **) &SimplePointerProtocol,
 | |
|                   This->DriverBindingHandle,
 | |
|                   Controller,
 | |
|                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   MouseDev = PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol);
 | |
| 
 | |
|   //
 | |
|   // Report that the keyboard is being disabled
 | |
|   //
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE,
 | |
|     MouseDev->DevicePath
 | |
|     );
 | |
| 
 | |
|   Status = gBS->UninstallProtocolInterface (
 | |
|                   Controller,
 | |
|                   &gEfiSimplePointerProtocolGuid,
 | |
|                   &MouseDev->SimplePointerProtocol
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Cancel mouse data polling timer, close timer event
 | |
|   //
 | |
|   gBS->SetTimer (MouseDev->TimerEvent, TimerCancel, 0);
 | |
|   gBS->CloseEvent (MouseDev->TimerEvent);
 | |
| 
 | |
|   //
 | |
|   // Since there will be no timer handler for mouse input any more,
 | |
|   // exhaust input data just in case there is still mouse data left
 | |
|   //
 | |
|   Status = EFI_SUCCESS;
 | |
|   while (!EFI_ERROR (Status)) {
 | |
|     Status = In8042Data (MouseDev->IsaIo, &Data);
 | |
|   }
 | |
| 
 | |
|   gBS->CloseEvent (MouseDev->SimplePointerProtocol.WaitForInput);
 | |
|   FreeUnicodeStringTable (MouseDev->ControllerNameTable);
 | |
|   FreePool (MouseDev);
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiDevicePathProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   gBS->CloseProtocol (
 | |
|          Controller,
 | |
|          &gEfiIsaIoProtocolGuid,
 | |
|          This->DriverBindingHandle,
 | |
|          Controller
 | |
|          );
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
 | |
| 
 | |
|   @param This                 - Pointer of simple pointer Protocol.
 | |
|   @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
 | |
| 
 | |
| 
 | |
|   @retval EFI_SUCCESS         - The command byte is written successfully.
 | |
|   @retval EFI_DEVICE_ERROR    - Errors occurred during reseting keyboard.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MouseReset (
 | |
|   IN EFI_SIMPLE_POINTER_PROTOCOL    *This,
 | |
|   IN BOOLEAN                        ExtendedVerification
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS    Status;
 | |
|   PS2_MOUSE_DEV *MouseDev;
 | |
|   EFI_TPL       OldTpl;
 | |
|   BOOLEAN       KeyboardEnable;
 | |
|   UINT8         Data;
 | |
| 
 | |
|   MouseDev = PS2_MOUSE_DEV_FROM_THIS (This);
 | |
| 
 | |
|   //
 | |
|   // Report reset progress code
 | |
|   //
 | |
|   REPORT_STATUS_CODE_WITH_DEVICE_PATH (
 | |
|     EFI_PROGRESS_CODE,
 | |
|     EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET,
 | |
|     MouseDev->DevicePath
 | |
|     );
 | |
| 
 | |
|   KeyboardEnable = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Raise TPL to avoid keyboard operation impact
 | |
|   //
 | |
|   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
| 
 | |
|   ZeroMem (&MouseDev->State, sizeof (EFI_SIMPLE_POINTER_STATE));
 | |
|   MouseDev->StateChanged = FALSE;
 | |
| 
 | |
|   //
 | |
|   // Exhaust input data
 | |
|   //
 | |
|   Status = EFI_SUCCESS;
 | |
|   while (!EFI_ERROR (Status)) {
 | |
|     Status = In8042Data (MouseDev->IsaIo, &Data);
 | |
|   }
 | |
| 
 | |
|   CheckKbStatus (MouseDev->IsaIo, &KeyboardEnable);
 | |
| 
 | |
|   KbcDisableKb (MouseDev->IsaIo);
 | |
| 
 | |
|   MouseDev->IsaIo->Io.Read (MouseDev->IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
 | |
| 
 | |
|   //
 | |
|   // if there's data block on KBC data port, read it out
 | |
|   //
 | |
|   if ((Data & KBC_OUTB) == KBC_OUTB) {
 | |
|     MouseDev->IsaIo->Io.Read (MouseDev->IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Data);
 | |
|   }
 | |
| 
 | |
|   Status = EFI_SUCCESS;
 | |
|   //
 | |
|   // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
 | |
|   // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
 | |
|   // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
 | |
|   //
 | |
|   if (ExtendedVerification && CheckMouseConnect (MouseDev)) {
 | |
|     //
 | |
|     // Send mouse reset command and set mouse default configure
 | |
|     //
 | |
|     Status = PS2MouseReset (MouseDev->IsaIo);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = PS2MouseSetSampleRate (MouseDev->IsaIo, MouseDev->SampleRate);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = PS2MouseSetResolution (MouseDev->IsaIo, MouseDev->Resolution);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = PS2MouseSetScaling (MouseDev->IsaIo, MouseDev->Scaling);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Exit;
 | |
|     }
 | |
| 
 | |
|     Status = PS2MouseEnable (MouseDev->IsaIo);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       Status = EFI_DEVICE_ERROR;
 | |
|       goto Exit;
 | |
|     }
 | |
|   }
 | |
| Exit:
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   if (KeyboardEnable) {
 | |
|     KbcEnableKb (MouseDev->IsaIo);
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check whether there is Ps/2 mouse device in system
 | |
| 
 | |
|   @param MouseDev   - Mouse Private Data Structure
 | |
| 
 | |
|   @retval TRUE      - Keyboard in System.
 | |
|   @retval FALSE     - Keyboard not in System.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| CheckMouseConnect (
 | |
|   IN  PS2_MOUSE_DEV     *MouseDev
 | |
|   )
 | |
| 
 | |
| {
 | |
|   EFI_STATUS     Status;
 | |
| 
 | |
|   Status = PS2MouseEnable (MouseDev->IsaIo);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     return TRUE;
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get and Clear mouse status.
 | |
|   
 | |
|   @param This                 - Pointer of simple pointer Protocol.
 | |
|   @param State                - Output buffer holding status.
 | |
| 
 | |
|   @retval EFI_INVALID_PARAMETER Output buffer is invalid.
 | |
|   @retval EFI_NOT_READY         Mouse is not changed status yet.
 | |
|   @retval EFI_SUCCESS           Mouse status is changed and get successful.
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| MouseGetState (
 | |
|   IN EFI_SIMPLE_POINTER_PROTOCOL    *This,
 | |
|   IN OUT EFI_SIMPLE_POINTER_STATE   *State
 | |
|   )
 | |
| {
 | |
|   PS2_MOUSE_DEV *MouseDev;
 | |
|   EFI_TPL       OldTpl;
 | |
| 
 | |
|   MouseDev = PS2_MOUSE_DEV_FROM_THIS (This);
 | |
| 
 | |
|   if (State == NULL) {
 | |
|     return EFI_INVALID_PARAMETER;
 | |
|   }
 | |
| 
 | |
|   if (!MouseDev->StateChanged) {
 | |
|     return EFI_NOT_READY;
 | |
|   }
 | |
| 
 | |
|   OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
 | |
|   CopyMem (State, &(MouseDev->State), sizeof (EFI_SIMPLE_POINTER_STATE));
 | |
| 
 | |
|   //
 | |
|   // clear mouse state
 | |
|   //
 | |
|   MouseDev->State.RelativeMovementX = 0;
 | |
|   MouseDev->State.RelativeMovementY = 0;
 | |
|   MouseDev->State.RelativeMovementZ = 0;
 | |
|   MouseDev->StateChanged            = FALSE;
 | |
|   gBS->RestoreTPL (OldTpl);
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
| 
 | |
|   Event notification function for SIMPLE_POINTER.WaitForInput event.
 | |
|   Signal the event if there is input from mouse.
 | |
| 
 | |
|   @param Event    event object
 | |
|   @param Context  event context
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| MouseWaitForInput (
 | |
|   IN  EFI_EVENT               Event,
 | |
|   IN  VOID                    *Context
 | |
|   )
 | |
| {
 | |
|   PS2_MOUSE_DEV *MouseDev;
 | |
| 
 | |
|   MouseDev = (PS2_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);
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Event notification function for TimerEvent event.
 | |
|   If mouse device is connected to system, try to get the mouse packet data.
 | |
| 
 | |
|   @param Event      -  TimerEvent in PS2_MOUSE_DEV
 | |
|   @param Context    -  Pointer to PS2_MOUSE_DEV structure
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| PollMouse (
 | |
|   IN EFI_EVENT  Event,
 | |
|   IN VOID       *Context
 | |
|   )
 | |
| 
 | |
| {
 | |
|   PS2_MOUSE_DEV *MouseDev;
 | |
| 
 | |
|   MouseDev = (PS2_MOUSE_DEV *) Context;
 | |
| 
 | |
|   //
 | |
|   // Polling mouse packet data
 | |
|   //
 | |
|   PS2MouseGetPacket (MouseDev);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   The user Entry Point for module Ps2Mouse. The user code starts with this function.
 | |
| 
 | |
|   @param[in] ImageHandle    The firmware allocated handle for the EFI image.  
 | |
|   @param[in] SystemTable    A pointer to the EFI System Table.
 | |
|   
 | |
|   @retval EFI_SUCCESS       The entry point is executed successfully.
 | |
|   @retval other             Some error occurs when executing this entry point.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| InitializePs2Mouse(
 | |
|   IN EFI_HANDLE           ImageHandle,
 | |
|   IN EFI_SYSTEM_TABLE     *SystemTable
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
| 
 | |
|   //
 | |
|   // Install driver model protocol(s).
 | |
|   //
 | |
|   Status = EfiLibInstallDriverBindingComponentName2 (
 | |
|              ImageHandle,
 | |
|              SystemTable,
 | |
|              &gPS2MouseDriver,
 | |
|              ImageHandle,
 | |
|              &gPs2MouseComponentName,
 | |
|              &gPs2MouseComponentName2
 | |
|              );
 | |
|   ASSERT_EFI_ERROR (Status);
 | |
| 
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 |