2 PS/2 Mouse driver. Routines that interacts with callers,
3 conforming to EFI driver model.
5 Copyright (c) 2006 - 2012, 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_ISA_IO_PROTOCOL
*IsaIo
;
59 // Open the IO Abstraction(s) needed to perform the supported test
61 Status
= gBS
->OpenProtocol (
63 &gEfiIsaIoProtocolGuid
,
65 This
->DriverBindingHandle
,
67 EFI_OPEN_PROTOCOL_BY_DRIVER
69 if (EFI_ERROR (Status
)) {
73 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
75 switch (IsaIo
->ResourceList
->Device
.HID
) {
76 case EISA_PNP_ID (0xF03):
78 // Microsoft PS/2 style mouse
80 case EISA_PNP_ID (0xF13):
82 // PS/2 Port for PS/2-style Mice
86 case EISA_PNP_ID (0x303):
88 // IBM Enhanced (101/102-key, PS/2 mouse support)
90 if (IsaIo
->ResourceList
->Device
.UID
== 1) {
95 Status
= EFI_UNSUPPORTED
;
99 // Close the I/O Abstraction(s) used to perform the supported test
103 &gEfiIsaIoProtocolGuid
,
104 This
->DriverBindingHandle
,
112 Start this driver on ControllerHandle by opening a IsaIo protocol, creating
113 PS2_MOUSE_ABSOLUTE_POINTER_DEV device and install gEfiAbsolutePointerProtocolGuid
116 @param This Protocol instance pointer.
117 @param ControllerHandle Handle of device to bind driver to
118 @param RemainingDevicePath Optional parameter use to pick a specific child
121 @retval EFI_SUCCESS This driver is added to ControllerHandle
122 @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
123 @retval other This driver does not support this device
128 PS2MouseDriverStart (
129 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
130 IN EFI_HANDLE Controller
,
131 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
135 EFI_STATUS EmptyStatus
;
136 EFI_ISA_IO_PROTOCOL
*IsaIo
;
137 PS2_MOUSE_DEV
*MouseDev
;
140 EFI_STATUS_CODE_VALUE StatusCode
;
141 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
148 // Open the device path protocol
150 Status
= gBS
->OpenProtocol (
152 &gEfiDevicePathProtocolGuid
,
153 (VOID
**) &ParentDevicePath
,
154 This
->DriverBindingHandle
,
156 EFI_OPEN_PROTOCOL_BY_DRIVER
158 if (EFI_ERROR (Status
)) {
162 // Report that the keyboard is being enabled
164 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
166 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
171 // Get the ISA I/O Protocol on Controller's handle
173 Status
= gBS
->OpenProtocol (
175 &gEfiIsaIoProtocolGuid
,
177 This
->DriverBindingHandle
,
179 EFI_OPEN_PROTOCOL_BY_DRIVER
181 if (EFI_ERROR (Status
)) {
184 &gEfiDevicePathProtocolGuid
,
185 This
->DriverBindingHandle
,
188 return EFI_INVALID_PARAMETER
;
191 // Raise TPL to avoid keyboard operation impact
193 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
196 // Allocate private data
198 MouseDev
= AllocateZeroPool (sizeof (PS2_MOUSE_DEV
));
199 if (MouseDev
== NULL
) {
200 Status
= EFI_OUT_OF_RESOURCES
;
204 // Setup the device instance
206 MouseDev
->Signature
= PS2_MOUSE_DEV_SIGNATURE
;
207 MouseDev
->Handle
= Controller
;
208 MouseDev
->SampleRate
= SampleRate20
;
209 MouseDev
->Resolution
= MouseResolution4
;
210 MouseDev
->Scaling
= Scaling1
;
211 MouseDev
->DataPackageSize
= 3;
212 MouseDev
->IsaIo
= IsaIo
;
213 MouseDev
->DevicePath
= ParentDevicePath
;
216 // Resolution = 4 counts/mm
218 MouseDev
->Mode
.ResolutionX
= 4;
219 MouseDev
->Mode
.ResolutionY
= 4;
220 MouseDev
->Mode
.LeftButton
= TRUE
;
221 MouseDev
->Mode
.RightButton
= TRUE
;
223 MouseDev
->SimplePointerProtocol
.Reset
= MouseReset
;
224 MouseDev
->SimplePointerProtocol
.GetState
= MouseGetState
;
225 MouseDev
->SimplePointerProtocol
.Mode
= &(MouseDev
->Mode
);
228 // Initialize keyboard controller if necessary
230 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
232 // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
234 if ((Data
& (KBC_PARE
| KBC_TIM
)) == (KBC_PARE
| KBC_TIM
)) {
236 // If nobody decodes KBC I/O port, it will read back as 0xFF.
237 // Check the Time-Out and Parity bit to see if it has an active KBC in system
239 Status
= EFI_DEVICE_ERROR
;
240 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
244 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
246 EFI_PERIPHERAL_MOUSE
| EFI_P_MOUSE_PC_SELF_TEST
,
250 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
251 Status
= KbcSelfTest (IsaIo
);
252 if (EFI_ERROR (Status
)) {
253 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
258 KbcEnableAux (IsaIo
);
260 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
262 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
269 Status
= MouseDev
->SimplePointerProtocol
.Reset (
270 &MouseDev
->SimplePointerProtocol
,
271 FeaturePcdGet (PcdPs2MouseExtendedVerification
)
273 if (EFI_ERROR (Status
)) {
275 // mouse not connected
277 Status
= EFI_SUCCESS
;
278 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
282 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
284 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DETECTED
,
289 // Setup the WaitForKey event
291 Status
= gBS
->CreateEvent (
296 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
298 if (EFI_ERROR (Status
)) {
299 Status
= EFI_OUT_OF_RESOURCES
;
303 // Setup a periodic timer, used to poll mouse state
305 Status
= gBS
->CreateEvent (
306 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
310 &MouseDev
->TimerEvent
312 if (EFI_ERROR (Status
)) {
313 Status
= EFI_OUT_OF_RESOURCES
;
317 // Start timer to poll mouse (100 samples per second)
319 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
320 if (EFI_ERROR (Status
)) {
321 Status
= EFI_OUT_OF_RESOURCES
;
325 MouseDev
->ControllerNameTable
= NULL
;
328 gPs2MouseComponentName
.SupportedLanguages
,
329 &MouseDev
->ControllerNameTable
,
330 L
"PS/2 Mouse Device",
335 gPs2MouseComponentName2
.SupportedLanguages
,
336 &MouseDev
->ControllerNameTable
,
337 L
"PS/2 Mouse Device",
343 // Install protocol interfaces for the mouse device.
345 Status
= gBS
->InstallMultipleProtocolInterfaces (
347 &gEfiSimplePointerProtocolGuid
,
348 &MouseDev
->SimplePointerProtocol
,
351 if (EFI_ERROR (Status
)) {
355 gBS
->RestoreTPL (OldTpl
);
361 if (Status
!= EFI_DEVICE_ERROR
) {
362 KbcDisableAux (IsaIo
);
365 if (StatusCode
!= 0) {
366 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
367 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
373 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
374 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
377 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
378 gBS
->CloseEvent (MouseDev
->TimerEvent
);
381 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
382 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
385 if (Status
!= EFI_DEVICE_ERROR
) {
387 // Since there will be no timer handler for mouse input any more,
388 // exhaust input data just in case there is still mouse data left
390 EmptyStatus
= EFI_SUCCESS
;
391 while (!EFI_ERROR (EmptyStatus
)) {
392 EmptyStatus
= In8042Data (IsaIo
, &Data
);
396 if (MouseDev
!= NULL
) {
402 &gEfiDevicePathProtocolGuid
,
403 This
->DriverBindingHandle
,
409 &gEfiIsaIoProtocolGuid
,
410 This
->DriverBindingHandle
,
414 gBS
->RestoreTPL (OldTpl
);
420 Stop this driver on ControllerHandle. Support stoping any child handles
421 created by this driver.
423 @param This Protocol instance pointer.
424 @param ControllerHandle Handle of device to stop driver on
425 @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
426 children is zero stop the entire bus driver.
427 @param ChildHandleBuffer List of Child Handles to Stop.
429 @retval EFI_SUCCESS This driver is removed ControllerHandle
430 @retval other This driver was not removed from this device
436 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
437 IN EFI_HANDLE Controller
,
438 IN UINTN NumberOfChildren
,
439 IN EFI_HANDLE
*ChildHandleBuffer
443 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
444 PS2_MOUSE_DEV
*MouseDev
;
447 Status
= gBS
->OpenProtocol (
449 &gEfiSimplePointerProtocolGuid
,
450 (VOID
**) &SimplePointerProtocol
,
451 This
->DriverBindingHandle
,
453 EFI_OPEN_PROTOCOL_GET_PROTOCOL
455 if (EFI_ERROR (Status
)) {
459 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
462 // Report that the keyboard is being disabled
464 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
466 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
470 Status
= gBS
->UninstallProtocolInterface (
472 &gEfiSimplePointerProtocolGuid
,
473 &MouseDev
->SimplePointerProtocol
475 if (EFI_ERROR (Status
)) {
480 // Cancel mouse data polling timer, close timer event
482 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
483 gBS
->CloseEvent (MouseDev
->TimerEvent
);
486 // Since there will be no timer handler for mouse input any more,
487 // exhaust input data just in case there is still mouse data left
489 Status
= EFI_SUCCESS
;
490 while (!EFI_ERROR (Status
)) {
491 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
494 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
495 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
500 &gEfiDevicePathProtocolGuid
,
501 This
->DriverBindingHandle
,
507 &gEfiIsaIoProtocolGuid
,
508 This
->DriverBindingHandle
,
516 Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
518 @param This - Pointer of simple pointer Protocol.
519 @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
522 @retval EFI_SUCCESS - The command byte is written successfully.
523 @retval EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
529 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
530 IN BOOLEAN ExtendedVerification
534 PS2_MOUSE_DEV
*MouseDev
;
536 BOOLEAN KeyboardEnable
;
539 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
542 // Report reset progress code
544 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
546 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
550 KeyboardEnable
= FALSE
;
553 // Raise TPL to avoid keyboard operation impact
555 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
557 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
558 MouseDev
->StateChanged
= FALSE
;
561 // Exhaust input data
563 Status
= EFI_SUCCESS
;
564 while (!EFI_ERROR (Status
)) {
565 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
568 CheckKbStatus (MouseDev
->IsaIo
, &KeyboardEnable
);
570 KbcDisableKb (MouseDev
->IsaIo
);
572 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
575 // if there's data block on KBC data port, read it out
577 if ((Data
& KBC_OUTB
) == KBC_OUTB
) {
578 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Data
);
581 Status
= EFI_SUCCESS
;
583 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
584 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
585 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
587 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
589 // Send mouse reset command and set mouse default configure
591 Status
= PS2MouseReset (MouseDev
->IsaIo
);
592 if (EFI_ERROR (Status
)) {
593 Status
= EFI_DEVICE_ERROR
;
597 Status
= PS2MouseSetSampleRate (MouseDev
->IsaIo
, MouseDev
->SampleRate
);
598 if (EFI_ERROR (Status
)) {
599 Status
= EFI_DEVICE_ERROR
;
603 Status
= PS2MouseSetResolution (MouseDev
->IsaIo
, MouseDev
->Resolution
);
604 if (EFI_ERROR (Status
)) {
605 Status
= EFI_DEVICE_ERROR
;
609 Status
= PS2MouseSetScaling (MouseDev
->IsaIo
, MouseDev
->Scaling
);
610 if (EFI_ERROR (Status
)) {
611 Status
= EFI_DEVICE_ERROR
;
615 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
616 if (EFI_ERROR (Status
)) {
617 Status
= EFI_DEVICE_ERROR
;
622 gBS
->RestoreTPL (OldTpl
);
624 if (KeyboardEnable
) {
625 KbcEnableKb (MouseDev
->IsaIo
);
632 Check whether there is Ps/2 mouse device in system
634 @param MouseDev - Mouse Private Data Structure
636 @retval TRUE - Keyboard in System.
637 @retval FALSE - Keyboard not in System.
642 IN PS2_MOUSE_DEV
*MouseDev
648 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
649 if (!EFI_ERROR (Status
)) {
657 Get and Clear mouse status.
659 @param This - Pointer of simple pointer Protocol.
660 @param State - Output buffer holding status.
662 @retval EFI_INVALID_PARAMETER Output buffer is invalid.
663 @retval EFI_NOT_READY Mouse is not changed status yet.
664 @retval EFI_SUCCESS Mouse status is changed and get successful.
669 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
670 IN OUT EFI_SIMPLE_POINTER_STATE
*State
673 PS2_MOUSE_DEV
*MouseDev
;
676 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
679 return EFI_INVALID_PARAMETER
;
682 if (!MouseDev
->StateChanged
) {
683 return EFI_NOT_READY
;
686 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
687 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
692 MouseDev
->State
.RelativeMovementX
= 0;
693 MouseDev
->State
.RelativeMovementY
= 0;
694 MouseDev
->State
.RelativeMovementZ
= 0;
695 MouseDev
->StateChanged
= FALSE
;
696 gBS
->RestoreTPL (OldTpl
);
703 Event notification function for SIMPLE_POINTER.WaitForInput event.
704 Signal the event if there is input from mouse.
706 @param Event event object
707 @param Context event context
717 PS2_MOUSE_DEV
*MouseDev
;
719 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
722 // Someone is waiting on the mouse event, if there's
723 // input from mouse, signal the event
725 if (MouseDev
->StateChanged
) {
726 gBS
->SignalEvent (Event
);
732 Event notification function for TimerEvent event.
733 If mouse device is connected to system, try to get the mouse packet data.
735 @param Event - TimerEvent in PS2_MOUSE_DEV
736 @param Context - Pointer to PS2_MOUSE_DEV structure
747 PS2_MOUSE_DEV
*MouseDev
;
749 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
752 // Polling mouse packet data
754 PS2MouseGetPacket (MouseDev
);
758 The user Entry Point for module Ps2Mouse. The user code starts with this function.
760 @param[in] ImageHandle The firmware allocated handle for the EFI image.
761 @param[in] SystemTable A pointer to the EFI System Table.
763 @retval EFI_SUCCESS The entry point is executed successfully.
764 @retval other Some error occurs when executing this entry point.
770 IN EFI_HANDLE ImageHandle
,
771 IN EFI_SYSTEM_TABLE
*SystemTable
777 // Install driver model protocol(s).
779 Status
= EfiLibInstallDriverBindingComponentName2 (
784 &gPs2MouseComponentName
,
785 &gPs2MouseComponentName2
787 ASSERT_EFI_ERROR (Status
);