2 PS/2 Mouse driver. Routines that interacts with callers,
3 conforming to EFI driver model
5 Copyright (c) 2006 - 2007, Intel Corporation
6 All rights reserved. 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
,
33 PS2MouseDriverSupported (
34 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
35 IN EFI_HANDLE Controller
,
36 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
42 ControllerDriver Protocol Method
49 // GC_TODO: This - add argument and description to function comment
50 // GC_TODO: Controller - add argument and description to function comment
51 // GC_TODO: RemainingDevicePath - add argument and description to function comment
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
,
113 PS2MouseDriverStart (
114 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
115 IN EFI_HANDLE Controller
,
116 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
121 Start protocol interfaces for the mouse device handles.
124 This - Protocol instance pointer.
125 Controller - Handle of device to bind driver to.
126 RemainingDevicePath - Not used.
129 EFI_SUCCESS - This driver is added to DeviceHandle.
130 other - Errors occurred.
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
= SSR_20
;
209 MouseDev
->Resolution
= CMR4
;
210 MouseDev
->Scaling
= SF1
;
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
);
231 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
232 Status
= KbcSelfTest (IsaIo
);
233 if (EFI_ERROR (Status
)) {
234 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
239 KbcEnableAux (IsaIo
);
241 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
243 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
250 Status
= MouseDev
->SimplePointerProtocol
.Reset (&MouseDev
->SimplePointerProtocol
, TRUE
);
251 if (EFI_ERROR (Status
)) {
253 // mouse not connected
255 Status
= EFI_SUCCESS
;
256 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
260 // Setup the WaitForKey event
262 Status
= gBS
->CreateEvent (
267 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
269 if (EFI_ERROR (Status
)) {
270 Status
= EFI_OUT_OF_RESOURCES
;
274 // Setup a periodic timer, used to poll mouse state
276 Status
= gBS
->CreateEvent (
277 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
281 &MouseDev
->TimerEvent
283 if (EFI_ERROR (Status
)) {
284 Status
= EFI_OUT_OF_RESOURCES
;
288 // Start timer to poll mouse (100 samples per second)
290 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
291 if (EFI_ERROR (Status
)) {
292 Status
= EFI_OUT_OF_RESOURCES
;
296 MouseDev
->ControllerNameTable
= NULL
;
299 gPs2MouseComponentName
.SupportedLanguages
,
300 &MouseDev
->ControllerNameTable
,
301 L
"PS/2 Mouse Device",
306 gPs2MouseComponentName2
.SupportedLanguages
,
307 &MouseDev
->ControllerNameTable
,
308 L
"PS/2 Mouse Device",
314 // Install protocol interfaces for the mouse device.
316 Status
= gBS
->InstallMultipleProtocolInterfaces (
318 &gEfiSimplePointerProtocolGuid
,
319 &MouseDev
->SimplePointerProtocol
,
322 if (EFI_ERROR (Status
)) {
326 gBS
->RestoreTPL (OldTpl
);
332 KbcDisableAux (IsaIo
);
334 if (StatusCode
!= 0) {
335 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
336 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
342 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
343 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
346 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
347 gBS
->CloseEvent (MouseDev
->TimerEvent
);
350 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
351 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
354 // Since there will be no timer handler for mouse input any more,
355 // exhaust input data just in case there is still mouse data left
357 EmptyStatus
= EFI_SUCCESS
;
358 while (!EFI_ERROR (EmptyStatus
)) {
359 EmptyStatus
= In8042Data (IsaIo
, &Data
);
362 if (MouseDev
!= NULL
) {
363 gBS
->FreePool (MouseDev
);
368 &gEfiDevicePathProtocolGuid
,
369 This
->DriverBindingHandle
,
375 &gEfiIsaIoProtocolGuid
,
376 This
->DriverBindingHandle
,
380 gBS
->RestoreTPL (OldTpl
);
388 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
389 IN EFI_HANDLE Controller
,
390 IN UINTN NumberOfChildren
,
391 IN EFI_HANDLE
*ChildHandleBuffer
402 // GC_TODO: This - add argument and description to function comment
403 // GC_TODO: Controller - add argument and description to function comment
404 // GC_TODO: NumberOfChildren - add argument and description to function comment
405 // GC_TODO: ChildHandleBuffer - add argument and description to function comment
406 // GC_TODO: EFI_SUCCESS - add return value to function comment
407 // GC_TODO: EFI_SUCCESS - add return value to function comment
410 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
411 PS2_MOUSE_DEV
*MouseDev
;
414 Status
= gBS
->OpenProtocol (
416 &gEfiSimplePointerProtocolGuid
,
417 (VOID
**) &SimplePointerProtocol
,
418 This
->DriverBindingHandle
,
420 EFI_OPEN_PROTOCOL_GET_PROTOCOL
422 if (EFI_ERROR (Status
)) {
426 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
429 // Report that the keyboard is being disabled
431 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
433 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
437 Status
= gBS
->UninstallProtocolInterface (
439 &gEfiSimplePointerProtocolGuid
,
440 &MouseDev
->SimplePointerProtocol
442 if (EFI_ERROR (Status
)) {
446 // Disable mouse on keyboard controller
448 KbcDisableAux (MouseDev
->IsaIo
);
451 // Cancel mouse data polling timer, close timer event
453 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
454 gBS
->CloseEvent (MouseDev
->TimerEvent
);
457 // Since there will be no timer handler for mouse input any more,
458 // exhaust input data just in case there is still mouse data left
460 Status
= EFI_SUCCESS
;
461 while (!EFI_ERROR (Status
)) {
462 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
465 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
466 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
467 gBS
->FreePool (MouseDev
);
471 &gEfiDevicePathProtocolGuid
,
472 This
->DriverBindingHandle
,
478 &gEfiIsaIoProtocolGuid
,
479 This
->DriverBindingHandle
,
489 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
490 IN BOOLEAN ExtendedVerification
496 Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
500 This - Pointer of simple pointer Protocol.
501 ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
505 EFI_SUCCESS - The command byte is written successfully.
506 EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
511 PS2_MOUSE_DEV
*MouseDev
;
513 BOOLEAN KeyboardEnable
;
516 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
519 // Report reset progress code
521 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
523 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
527 KeyboardEnable
= FALSE
;
530 // Raise TPL to avoid keyboard operation impact
532 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
534 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
535 MouseDev
->StateChanged
= FALSE
;
538 // Exhaust input data
540 Status
= EFI_SUCCESS
;
541 while (!EFI_ERROR (Status
)) {
542 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
545 CheckKbStatus (MouseDev
->IsaIo
, &KeyboardEnable
);
547 KbcDisableKb (MouseDev
->IsaIo
);
549 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
552 // if there's data block on KBC data port, read it out
554 if ((Data
& KBC_OUTB
) == KBC_OUTB
) {
555 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Data
);
558 Status
= EFI_SUCCESS
;
560 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
561 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
562 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
564 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
566 // Send mouse reset command and set mouse default configure
568 Status
= PS2MouseReset (MouseDev
->IsaIo
);
569 if (EFI_ERROR (Status
)) {
570 Status
= EFI_DEVICE_ERROR
;
574 Status
= PS2MouseSetSampleRate (MouseDev
->IsaIo
, MouseDev
->SampleRate
);
575 if (EFI_ERROR (Status
)) {
576 Status
= EFI_DEVICE_ERROR
;
580 Status
= PS2MouseSetResolution (MouseDev
->IsaIo
, MouseDev
->Resolution
);
581 if (EFI_ERROR (Status
)) {
582 Status
= EFI_DEVICE_ERROR
;
586 Status
= PS2MouseSetScaling (MouseDev
->IsaIo
, MouseDev
->Scaling
);
587 if (EFI_ERROR (Status
)) {
588 Status
= EFI_DEVICE_ERROR
;
592 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
593 if (EFI_ERROR (Status
)) {
594 Status
= EFI_DEVICE_ERROR
;
599 gBS
->RestoreTPL (OldTpl
);
601 if (KeyboardEnable
) {
602 KbcEnableKb (MouseDev
->IsaIo
);
610 IN PS2_MOUSE_DEV
*MouseDev
616 Check whether there is Ps/2 mouse device in system
620 PS2_MOUSE_DEV - Mouse Private Data Structure
624 TRUE - Keyboard in System.
625 FALSE - Keyboard not in System.
631 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
632 if (!EFI_ERROR (Status
)) {
642 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
643 IN OUT EFI_SIMPLE_POINTER_STATE
*State
649 GC_TODO: Add function description
653 This - GC_TODO: add argument description
654 State - GC_TODO: add argument description
658 EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
659 EFI_NOT_READY - GC_TODO: Add description for return value
660 EFI_SUCCESS - GC_TODO: Add description for return value
664 PS2_MOUSE_DEV
*MouseDev
;
667 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
670 return EFI_INVALID_PARAMETER
;
673 if (!MouseDev
->StateChanged
) {
674 return EFI_NOT_READY
;
677 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
678 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
683 MouseDev
->State
.RelativeMovementX
= 0;
684 MouseDev
->State
.RelativeMovementY
= 0;
685 MouseDev
->State
.RelativeMovementZ
= 0;
686 MouseDev
->StateChanged
= FALSE
;
687 gBS
->RestoreTPL (OldTpl
);
702 Event notification function for SIMPLE_POINTER.WaitForInput event
703 Signal the event if there is input from mouse
710 // GC_TODO: Event - add argument and description to function comment
711 // GC_TODO: Context - add argument and description to function comment
713 PS2_MOUSE_DEV
*MouseDev
;
715 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
718 // Someone is waiting on the mouse event, if there's
719 // input from mouse, signal the event
721 if (MouseDev
->StateChanged
) {
722 gBS
->SignalEvent (Event
);
737 Event notification function for TimerEvent event
738 If mouse device is connected to system, try to get the mouse packet data
742 Event - TimerEvent in PS2_MOUSE_DEV
743 Context - Pointer to PS2_MOUSE_DEV structure
751 PS2_MOUSE_DEV
*MouseDev
;
753 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
756 // Polling mouse packet data
758 PS2MouseGetPacket (MouseDev
);
762 The user Entry Point for module Ps2Mouse. The user code starts with this function.
764 @param[in] ImageHandle The firmware allocated handle for the EFI image.
765 @param[in] SystemTable A pointer to the EFI System Table.
767 @retval EFI_SUCCESS The entry point is executed successfully.
768 @retval other Some error occurs when executing this entry point.
774 IN EFI_HANDLE ImageHandle
,
775 IN EFI_SYSTEM_TABLE
*SystemTable
781 // Install driver model protocol(s).
783 Status
= EfiLibInstallDriverBindingComponentName2 (
788 &gPs2MouseComponentName
,
789 &gPs2MouseComponentName2
791 ASSERT_EFI_ERROR (Status
);