2 PS/2 Mouse driver. Routines that interacts with callers,
3 conforming to EFI driver model.
5 Copyright (c) 2006 - 2016, Intel Corporation. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
20 /// DriverBinding Protocol Instance
22 EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver
= {
23 PS2MouseDriverSupported
,
32 Test to see if this driver supports ControllerHandle. Any ControllerHandle
33 than contains a IsaIo protocol can be supported.
35 @param This Protocol instance pointer.
36 @param ControllerHandle Handle of device to test
37 @param RemainingDevicePath Optional parameter use to pick a specific child
40 @retval EFI_SUCCESS This driver supports this device
41 @retval EFI_ALREADY_STARTED This driver is already running on this device
42 @retval other This driver does not support this device
47 PS2MouseDriverSupported (
48 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
49 IN EFI_HANDLE Controller
,
50 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
54 EFI_SIO_PROTOCOL
*Sio
;
55 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
56 ACPI_HID_DEVICE_PATH
*Acpi
;
59 // Check whether the controller is keyboard.
61 Status
= gBS
->OpenProtocol (
63 &gEfiDevicePathProtocolGuid
,
64 (VOID
**) &DevicePath
,
65 This
->DriverBindingHandle
,
67 EFI_OPEN_PROTOCOL_GET_PROTOCOL
69 if (EFI_ERROR (Status
)) {
74 Acpi
= (ACPI_HID_DEVICE_PATH
*) DevicePath
;
75 DevicePath
= NextDevicePathNode (DevicePath
);
76 } while (!IsDevicePathEnd (DevicePath
));
78 if (DevicePathType (Acpi
) != ACPI_DEVICE_PATH
||
79 (DevicePathSubType (Acpi
) != ACPI_DP
&& DevicePathSubType (Acpi
) != ACPI_EXTENDED_DP
)) {
80 return EFI_UNSUPPORTED
;
84 case EISA_PNP_ID (0xF03):
86 // Microsoft PS/2 style mouse
88 case EISA_PNP_ID (0xF13):
90 // PS/2 Port for PS/2-style Mice
94 case EISA_PNP_ID (0x303):
96 // IBM Enhanced (101/102-key, PS/2 mouse support)
103 return EFI_UNSUPPORTED
;
108 // Open the IO Abstraction(s) needed to perform the supported test
110 Status
= gBS
->OpenProtocol (
112 &gEfiSioProtocolGuid
,
114 This
->DriverBindingHandle
,
116 EFI_OPEN_PROTOCOL_BY_DRIVER
118 if (EFI_ERROR (Status
)) {
123 // Close the I/O Abstraction(s) used to perform the supported test
127 &gEfiSioProtocolGuid
,
128 This
->DriverBindingHandle
,
136 Start this driver on ControllerHandle by opening a Sio protocol, creating
137 PS2_MOUSE_DEV device and install gEfiSimplePointerProtocolGuid finally.
139 @param This Protocol instance pointer.
140 @param ControllerHandle Handle of device to bind driver to
141 @param RemainingDevicePath Optional parameter use to pick a specific child
144 @retval EFI_SUCCESS This driver is added to ControllerHandle
145 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
146 @retval other This driver does not support this device
151 PS2MouseDriverStart (
152 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
153 IN EFI_HANDLE Controller
,
154 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
158 EFI_STATUS EmptyStatus
;
159 EFI_SIO_PROTOCOL
*Sio
;
160 PS2_MOUSE_DEV
*MouseDev
;
163 EFI_STATUS_CODE_VALUE StatusCode
;
164 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
169 // Open the device path protocol
171 Status
= gBS
->OpenProtocol (
173 &gEfiDevicePathProtocolGuid
,
174 (VOID
**) &DevicePath
,
175 This
->DriverBindingHandle
,
177 EFI_OPEN_PROTOCOL_GET_PROTOCOL
179 if (EFI_ERROR (Status
)) {
183 // Report that the keyboard is being enabled
185 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
187 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
192 // Get the ISA I/O Protocol on Controller's handle
194 Status
= gBS
->OpenProtocol (
196 &gEfiSioProtocolGuid
,
198 This
->DriverBindingHandle
,
200 EFI_OPEN_PROTOCOL_BY_DRIVER
202 if (EFI_ERROR (Status
)) {
206 // Raise TPL to avoid keyboard operation impact
208 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
211 // Allocate private data
213 MouseDev
= AllocateZeroPool (sizeof (PS2_MOUSE_DEV
));
214 if (MouseDev
== NULL
) {
215 Status
= EFI_OUT_OF_RESOURCES
;
219 // Setup the device instance
221 MouseDev
->Signature
= PS2_MOUSE_DEV_SIGNATURE
;
222 MouseDev
->Handle
= Controller
;
223 MouseDev
->SampleRate
= SampleRate20
;
224 MouseDev
->Resolution
= MouseResolution4
;
225 MouseDev
->Scaling
= Scaling1
;
226 MouseDev
->DataPackageSize
= 3;
227 MouseDev
->DevicePath
= DevicePath
;
230 // Resolution = 4 counts/mm
232 MouseDev
->Mode
.ResolutionX
= 4;
233 MouseDev
->Mode
.ResolutionY
= 4;
234 MouseDev
->Mode
.LeftButton
= TRUE
;
235 MouseDev
->Mode
.RightButton
= TRUE
;
237 MouseDev
->SimplePointerProtocol
.Reset
= MouseReset
;
238 MouseDev
->SimplePointerProtocol
.GetState
= MouseGetState
;
239 MouseDev
->SimplePointerProtocol
.Mode
= &(MouseDev
->Mode
);
242 // Initialize keyboard controller if necessary
244 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
246 EFI_PERIPHERAL_MOUSE
| EFI_P_MOUSE_PC_SELF_TEST
,
250 Data
= IoRead8 (KBC_CMD_STS_PORT
);
252 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
254 if ((Data
& (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
256 // If nobody decodes KBC I/O port, it will read back as 0xFF.
257 // Check the Time-Out and Parity bit to see if it has an active KBC in system
259 Status
= EFI_DEVICE_ERROR
;
260 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
264 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
265 Status
= KbcSelfTest ();
266 if (EFI_ERROR (Status
)) {
267 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
274 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
276 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
283 Status
= MouseDev
->SimplePointerProtocol
.Reset (
284 &MouseDev
->SimplePointerProtocol
,
285 FeaturePcdGet (PcdPs2MouseExtendedVerification
)
287 if (EFI_ERROR (Status
)) {
289 // mouse not connected
291 Status
= EFI_SUCCESS
;
292 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
296 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
298 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DETECTED
,
303 // Setup the WaitForKey event
305 Status
= gBS
->CreateEvent (
310 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
312 if (EFI_ERROR (Status
)) {
313 Status
= EFI_OUT_OF_RESOURCES
;
317 // Setup a periodic timer, used to poll mouse state
319 Status
= gBS
->CreateEvent (
320 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
324 &MouseDev
->TimerEvent
326 if (EFI_ERROR (Status
)) {
327 Status
= EFI_OUT_OF_RESOURCES
;
331 // Start timer to poll mouse (100 samples per second)
333 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
334 if (EFI_ERROR (Status
)) {
335 Status
= EFI_OUT_OF_RESOURCES
;
339 MouseDev
->ControllerNameTable
= NULL
;
342 gPs2MouseComponentName
.SupportedLanguages
,
343 &MouseDev
->ControllerNameTable
,
344 L
"PS/2 Mouse Device",
349 gPs2MouseComponentName2
.SupportedLanguages
,
350 &MouseDev
->ControllerNameTable
,
351 L
"PS/2 Mouse Device",
357 // Install protocol interfaces for the mouse device.
359 Status
= gBS
->InstallMultipleProtocolInterfaces (
361 &gEfiSimplePointerProtocolGuid
,
362 &MouseDev
->SimplePointerProtocol
,
365 if (EFI_ERROR (Status
)) {
369 gBS
->RestoreTPL (OldTpl
);
375 if (Status
!= EFI_DEVICE_ERROR
) {
379 if (StatusCode
!= 0) {
380 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
381 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
387 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
388 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
391 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
392 gBS
->CloseEvent (MouseDev
->TimerEvent
);
395 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
396 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
399 if (Status
!= EFI_DEVICE_ERROR
) {
401 // Since there will be no timer handler for mouse input any more,
402 // exhaust input data just in case there is still mouse data left
404 EmptyStatus
= EFI_SUCCESS
;
405 while (!EFI_ERROR (EmptyStatus
)) {
406 EmptyStatus
= In8042Data (&Data
);
410 if (MouseDev
!= NULL
) {
416 &gEfiDevicePathProtocolGuid
,
417 This
->DriverBindingHandle
,
423 &gEfiSioProtocolGuid
,
424 This
->DriverBindingHandle
,
428 gBS
->RestoreTPL (OldTpl
);
434 Stop this driver on ControllerHandle. Support stoping any child handles
435 created by this driver.
437 @param This Protocol instance pointer.
438 @param ControllerHandle Handle of device to stop driver on
439 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
440 children is zero stop the entire bus driver.
441 @param ChildHandleBuffer List of Child Handles to Stop.
443 @retval EFI_SUCCESS This driver is removed ControllerHandle
444 @retval other This driver was not removed from this device
450 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
451 IN EFI_HANDLE Controller
,
452 IN UINTN NumberOfChildren
,
453 IN EFI_HANDLE
*ChildHandleBuffer
457 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
458 PS2_MOUSE_DEV
*MouseDev
;
461 Status
= gBS
->OpenProtocol (
463 &gEfiSimplePointerProtocolGuid
,
464 (VOID
**) &SimplePointerProtocol
,
465 This
->DriverBindingHandle
,
467 EFI_OPEN_PROTOCOL_GET_PROTOCOL
469 if (EFI_ERROR (Status
)) {
473 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
476 // Report that the keyboard is being disabled
478 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
480 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
484 Status
= gBS
->UninstallProtocolInterface (
486 &gEfiSimplePointerProtocolGuid
,
487 &MouseDev
->SimplePointerProtocol
489 if (EFI_ERROR (Status
)) {
494 // Cancel mouse data polling timer, close timer event
496 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
497 gBS
->CloseEvent (MouseDev
->TimerEvent
);
500 // Since there will be no timer handler for mouse input any more,
501 // exhaust input data just in case there is still mouse data left
503 Status
= EFI_SUCCESS
;
504 while (!EFI_ERROR (Status
)) {
505 Status
= In8042Data (&Data
);
508 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
509 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
514 &gEfiDevicePathProtocolGuid
,
515 This
->DriverBindingHandle
,
521 &gEfiSioProtocolGuid
,
522 This
->DriverBindingHandle
,
530 Reset the Mouse and do BAT test for it, if ExtendedVerification is TRUE and
531 there is a mouse device connectted to system.
533 @param This - Pointer of simple pointer Protocol.
534 @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
537 @retval EFI_SUCCESS - The command byte is written successfully.
538 @retval EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
544 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
545 IN BOOLEAN ExtendedVerification
549 PS2_MOUSE_DEV
*MouseDev
;
551 BOOLEAN KeyboardEnable
;
554 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
557 // Report reset progress code
559 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
561 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
565 KeyboardEnable
= FALSE
;
568 // Raise TPL to avoid keyboard operation impact
570 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
572 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
573 MouseDev
->StateChanged
= FALSE
;
576 // Exhaust input data
578 Status
= EFI_SUCCESS
;
579 while (!EFI_ERROR (Status
)) {
580 Status
= In8042Data (&Data
);
583 CheckKbStatus (&KeyboardEnable
);
588 // if there's data block on KBC data port, read it out
590 if ((IoRead8 (KBC_CMD_STS_PORT
) & KBC_OUTB
) == KBC_OUTB
) {
591 IoRead8 (KBC_DATA_PORT
);
594 Status
= EFI_SUCCESS
;
596 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
597 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
598 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
600 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
602 // Send mouse reset command and set mouse default configure
604 Status
= PS2MouseReset ();
605 if (EFI_ERROR (Status
)) {
606 Status
= EFI_DEVICE_ERROR
;
610 Status
= PS2MouseSetSampleRate (MouseDev
->SampleRate
);
611 if (EFI_ERROR (Status
)) {
612 Status
= EFI_DEVICE_ERROR
;
616 Status
= PS2MouseSetResolution (MouseDev
->Resolution
);
617 if (EFI_ERROR (Status
)) {
618 Status
= EFI_DEVICE_ERROR
;
622 Status
= PS2MouseSetScaling (MouseDev
->Scaling
);
623 if (EFI_ERROR (Status
)) {
624 Status
= EFI_DEVICE_ERROR
;
628 Status
= PS2MouseEnable ();
629 if (EFI_ERROR (Status
)) {
630 Status
= EFI_DEVICE_ERROR
;
635 gBS
->RestoreTPL (OldTpl
);
637 if (KeyboardEnable
) {
645 Check whether there is Ps/2 mouse device in system
647 @param MouseDev - Mouse Private Data Structure
649 @retval TRUE - Keyboard in System.
650 @retval FALSE - Keyboard not in System.
655 IN PS2_MOUSE_DEV
*MouseDev
661 Status
= PS2MouseEnable ();
662 if (!EFI_ERROR (Status
)) {
670 Get and Clear mouse status.
672 @param This - Pointer of simple pointer Protocol.
673 @param State - Output buffer holding status.
675 @retval EFI_INVALID_PARAMETER Output buffer is invalid.
676 @retval EFI_NOT_READY Mouse is not changed status yet.
677 @retval EFI_SUCCESS Mouse status is changed and get successful.
682 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
683 IN OUT EFI_SIMPLE_POINTER_STATE
*State
686 PS2_MOUSE_DEV
*MouseDev
;
689 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
692 return EFI_INVALID_PARAMETER
;
695 if (!MouseDev
->StateChanged
) {
696 return EFI_NOT_READY
;
699 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
700 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
705 MouseDev
->State
.RelativeMovementX
= 0;
706 MouseDev
->State
.RelativeMovementY
= 0;
707 MouseDev
->State
.RelativeMovementZ
= 0;
708 MouseDev
->StateChanged
= FALSE
;
709 gBS
->RestoreTPL (OldTpl
);
716 Event notification function for SIMPLE_POINTER.WaitForInput event.
717 Signal the event if there is input from mouse.
719 @param Event event object
720 @param Context event context
730 PS2_MOUSE_DEV
*MouseDev
;
732 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
735 // Someone is waiting on the mouse event, if there's
736 // input from mouse, signal the event
738 if (MouseDev
->StateChanged
) {
739 gBS
->SignalEvent (Event
);
745 Event notification function for TimerEvent event.
746 If mouse device is connected to system, try to get the mouse packet data.
748 @param Event - TimerEvent in PS2_MOUSE_DEV
749 @param Context - Pointer to PS2_MOUSE_DEV structure
760 PS2_MOUSE_DEV
*MouseDev
;
762 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
765 // Polling mouse packet data
767 PS2MouseGetPacket (MouseDev
);
771 The user Entry Point for module Ps2Mouse. The user code starts with this function.
773 @param[in] ImageHandle The firmware allocated handle for the EFI image.
774 @param[in] SystemTable A pointer to the EFI System Table.
776 @retval EFI_SUCCESS The entry point is executed successfully.
777 @retval other Some error occurs when executing this entry point.
783 IN EFI_HANDLE ImageHandle
,
784 IN EFI_SYSTEM_TABLE
*SystemTable
790 // Install driver model protocol(s).
792 Status
= EfiLibInstallDriverBindingComponentName2 (
797 &gPs2MouseComponentName
,
798 &gPs2MouseComponentName2
800 ASSERT_EFI_ERROR (Status
);