3 Copyright (c) 2006 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
18 PS/2 Mouse driver. Routines that interacts with callers,
19 conforming to EFI driver model
27 // DriverBinding Protocol Instance
29 EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver
= {
30 PS2MouseDriverSupported
,
40 PS2MouseDriverSupported (
41 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
42 IN EFI_HANDLE Controller
,
43 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
49 ControllerDriver Protocol Method
56 // GC_TODO: This - add argument and description to function comment
57 // GC_TODO: Controller - add argument and description to function comment
58 // GC_TODO: RemainingDevicePath - add argument and description to function comment
61 EFI_ISA_IO_PROTOCOL
*IsaIo
;
66 // Open the IO Abstraction(s) needed to perform the supported test
68 Status
= gBS
->OpenProtocol (
70 &gEfiIsaIoProtocolGuid
,
72 This
->DriverBindingHandle
,
74 EFI_OPEN_PROTOCOL_BY_DRIVER
76 if (EFI_ERROR (Status
)) {
80 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
82 switch (IsaIo
->ResourceList
->Device
.HID
) {
83 case EISA_PNP_ID (0xF03):
85 // Microsoft PS/2 style mouse
87 case EISA_PNP_ID (0xF13):
89 // PS/2 Port for PS/2-style Mice
93 case EISA_PNP_ID (0x303):
95 // IBM Enhanced (101/102-key, PS/2 mouse support)
97 if (IsaIo
->ResourceList
->Device
.UID
== 1) {
102 Status
= EFI_UNSUPPORTED
;
106 // Close the I/O Abstraction(s) used to perform the supported test
110 &gEfiIsaIoProtocolGuid
,
111 This
->DriverBindingHandle
,
120 PS2MouseDriverStart (
121 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
122 IN EFI_HANDLE Controller
,
123 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
128 Start protocol interfaces for the mouse device handles.
131 This - Protocol instance pointer.
132 Controller - Handle of device to bind driver to.
133 RemainingDevicePath - Not used.
136 EFI_SUCCESS - This driver is added to DeviceHandle.
137 other - Errors occurred.
142 EFI_STATUS EmptyStatus
;
143 EFI_ISA_IO_PROTOCOL
*IsaIo
;
144 PS2_MOUSE_DEV
*MouseDev
;
147 EFI_STATUS_CODE_VALUE StatusCode
;
148 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
155 // Open the device path protocol
157 Status
= gBS
->OpenProtocol (
159 &gEfiDevicePathProtocolGuid
,
160 (VOID
**) &ParentDevicePath
,
161 This
->DriverBindingHandle
,
163 EFI_OPEN_PROTOCOL_BY_DRIVER
165 if (EFI_ERROR (Status
)) {
169 // Report that the keyboard is being enabled
171 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
173 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
178 // Get the ISA I/O Protocol on Controller's handle
180 Status
= gBS
->OpenProtocol (
182 &gEfiIsaIoProtocolGuid
,
184 This
->DriverBindingHandle
,
186 EFI_OPEN_PROTOCOL_BY_DRIVER
188 if (EFI_ERROR (Status
)) {
191 &gEfiDevicePathProtocolGuid
,
192 This
->DriverBindingHandle
,
195 return EFI_INVALID_PARAMETER
;
198 // Raise TPL to avoid keyboard operation impact
200 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
203 // Allocate private data
205 MouseDev
= AllocateZeroPool (sizeof (PS2_MOUSE_DEV
));
206 if (MouseDev
== NULL
) {
207 Status
= EFI_OUT_OF_RESOURCES
;
211 // Setup the device instance
213 MouseDev
->Signature
= PS2_MOUSE_DEV_SIGNATURE
;
214 MouseDev
->Handle
= Controller
;
215 MouseDev
->SampleRate
= SSR_20
;
216 MouseDev
->Resolution
= CMR4
;
217 MouseDev
->Scaling
= SF1
;
218 MouseDev
->DataPackageSize
= 3;
219 MouseDev
->IsaIo
= IsaIo
;
220 MouseDev
->DevicePath
= ParentDevicePath
;
223 // Resolution = 4 counts/mm
225 MouseDev
->Mode
.ResolutionX
= 4;
226 MouseDev
->Mode
.ResolutionY
= 4;
227 MouseDev
->Mode
.LeftButton
= TRUE
;
228 MouseDev
->Mode
.RightButton
= TRUE
;
230 MouseDev
->SimplePointerProtocol
.Reset
= MouseReset
;
231 MouseDev
->SimplePointerProtocol
.GetState
= MouseGetState
;
232 MouseDev
->SimplePointerProtocol
.Mode
= &(MouseDev
->Mode
);
235 // Initialize keyboard controller if necessary
237 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
238 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
239 Status
= KbcSelfTest (IsaIo
);
240 if (EFI_ERROR (Status
)) {
241 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
246 KbcEnableAux (IsaIo
);
248 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
250 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
257 Status
= MouseDev
->SimplePointerProtocol
.Reset (&MouseDev
->SimplePointerProtocol
, TRUE
);
258 if (EFI_ERROR (Status
)) {
260 // mouse not connected
262 Status
= EFI_SUCCESS
;
263 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
267 // Setup the WaitForKey event
269 Status
= gBS
->CreateEvent (
274 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
276 if (EFI_ERROR (Status
)) {
277 Status
= EFI_OUT_OF_RESOURCES
;
281 // Setup a periodic timer, used to poll mouse state
283 Status
= gBS
->CreateEvent (
284 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
288 &MouseDev
->TimerEvent
290 if (EFI_ERROR (Status
)) {
291 Status
= EFI_OUT_OF_RESOURCES
;
295 // Start timer to poll mouse (100 samples per second)
297 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
298 if (EFI_ERROR (Status
)) {
299 Status
= EFI_OUT_OF_RESOURCES
;
303 MouseDev
->ControllerNameTable
= NULL
;
306 gPs2MouseComponentName
.SupportedLanguages
,
307 &MouseDev
->ControllerNameTable
,
312 // Install protocol interfaces for the mouse device.
314 Status
= gBS
->InstallMultipleProtocolInterfaces (
316 &gEfiSimplePointerProtocolGuid
,
317 &MouseDev
->SimplePointerProtocol
,
320 if (EFI_ERROR (Status
)) {
324 gBS
->RestoreTPL (OldTpl
);
330 KbcDisableAux (IsaIo
);
332 if (StatusCode
!= 0) {
333 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
334 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
340 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
341 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
344 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
345 gBS
->CloseEvent (MouseDev
->TimerEvent
);
348 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
349 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
352 // Since there will be no timer handler for mouse input any more,
353 // exhaust input data just in case there is still mouse data left
355 EmptyStatus
= EFI_SUCCESS
;
356 while (!EFI_ERROR (EmptyStatus
)) {
357 EmptyStatus
= In8042Data (IsaIo
, &Data
);
360 if (MouseDev
!= NULL
) {
361 gBS
->FreePool (MouseDev
);
366 &gEfiDevicePathProtocolGuid
,
367 This
->DriverBindingHandle
,
373 &gEfiIsaIoProtocolGuid
,
374 This
->DriverBindingHandle
,
378 gBS
->RestoreTPL (OldTpl
);
386 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
387 IN EFI_HANDLE Controller
,
388 IN UINTN NumberOfChildren
,
389 IN EFI_HANDLE
*ChildHandleBuffer
400 // GC_TODO: This - add argument and description to function comment
401 // GC_TODO: Controller - add argument and description to function comment
402 // GC_TODO: NumberOfChildren - add argument and description to function comment
403 // GC_TODO: ChildHandleBuffer - add argument and description to function comment
404 // GC_TODO: EFI_SUCCESS - add return value to function comment
405 // GC_TODO: EFI_SUCCESS - add return value to function comment
408 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
409 PS2_MOUSE_DEV
*MouseDev
;
412 Status
= gBS
->OpenProtocol (
414 &gEfiSimplePointerProtocolGuid
,
415 (VOID
**) &SimplePointerProtocol
,
416 This
->DriverBindingHandle
,
418 EFI_OPEN_PROTOCOL_GET_PROTOCOL
420 if (EFI_ERROR (Status
)) {
424 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
427 // Report that the keyboard is being disabled
429 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
431 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
435 Status
= gBS
->UninstallProtocolInterface (
437 &gEfiSimplePointerProtocolGuid
,
438 &MouseDev
->SimplePointerProtocol
440 if (EFI_ERROR (Status
)) {
444 // Disable mouse on keyboard controller
446 KbcDisableAux (MouseDev
->IsaIo
);
449 // Cancel mouse data polling timer, close timer event
451 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
452 gBS
->CloseEvent (MouseDev
->TimerEvent
);
455 // Since there will be no timer handler for mouse input any more,
456 // exhaust input data just in case there is still mouse data left
458 Status
= EFI_SUCCESS
;
459 while (!EFI_ERROR (Status
)) {
460 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
463 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
464 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
465 gBS
->FreePool (MouseDev
);
469 &gEfiDevicePathProtocolGuid
,
470 This
->DriverBindingHandle
,
476 &gEfiIsaIoProtocolGuid
,
477 This
->DriverBindingHandle
,
487 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
488 IN BOOLEAN ExtendedVerification
494 Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
498 This - Pointer of simple pointer Protocol.
499 ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
503 EFI_SUCCESS - The command byte is written successfully.
504 EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
509 PS2_MOUSE_DEV
*MouseDev
;
511 BOOLEAN KeyboardEnable
;
514 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
517 // Report reset progress code
519 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
521 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
525 KeyboardEnable
= FALSE
;
528 // Raise TPL to avoid keyboard operation impact
530 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
532 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
533 MouseDev
->StateChanged
= FALSE
;
536 // Exhaust input data
538 Status
= EFI_SUCCESS
;
539 while (!EFI_ERROR (Status
)) {
540 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
543 CheckKbStatus (MouseDev
->IsaIo
, &KeyboardEnable
);
545 KbcDisableKb (MouseDev
->IsaIo
);
547 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
550 // if there's data block on KBC data port, read it out
552 if ((Data
& KBC_OUTB
) == KBC_OUTB
) {
553 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Data
);
556 Status
= EFI_SUCCESS
;
558 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
559 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
560 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
562 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
564 // Send mouse reset command and set mouse default configure
566 Status
= PS2MouseReset (MouseDev
->IsaIo
);
567 if (EFI_ERROR (Status
)) {
568 Status
= EFI_DEVICE_ERROR
;
572 Status
= PS2MouseSetSampleRate (MouseDev
->IsaIo
, MouseDev
->SampleRate
);
573 if (EFI_ERROR (Status
)) {
574 Status
= EFI_DEVICE_ERROR
;
578 Status
= PS2MouseSetResolution (MouseDev
->IsaIo
, MouseDev
->Resolution
);
579 if (EFI_ERROR (Status
)) {
580 Status
= EFI_DEVICE_ERROR
;
584 Status
= PS2MouseSetScaling (MouseDev
->IsaIo
, MouseDev
->Scaling
);
585 if (EFI_ERROR (Status
)) {
586 Status
= EFI_DEVICE_ERROR
;
590 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
591 if (EFI_ERROR (Status
)) {
592 Status
= EFI_DEVICE_ERROR
;
597 gBS
->RestoreTPL (OldTpl
);
599 if (KeyboardEnable
) {
600 KbcEnableKb (MouseDev
->IsaIo
);
608 IN PS2_MOUSE_DEV
*MouseDev
614 Check whether there is Ps/2 mouse device in system
618 PS2_MOUSE_DEV - Mouse Private Data Structure
622 TRUE - Keyboard in System.
623 FALSE - Keyboard not in System.
629 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
630 if (!EFI_ERROR (Status
)) {
640 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
641 IN OUT EFI_SIMPLE_POINTER_STATE
*State
647 GC_TODO: Add function description
651 This - GC_TODO: add argument description
652 State - GC_TODO: add argument description
656 EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
657 EFI_NOT_READY - GC_TODO: Add description for return value
658 EFI_SUCCESS - GC_TODO: Add description for return value
662 PS2_MOUSE_DEV
*MouseDev
;
665 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
668 return EFI_INVALID_PARAMETER
;
671 if (!MouseDev
->StateChanged
) {
672 return EFI_NOT_READY
;
675 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
676 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
681 MouseDev
->State
.RelativeMovementX
= 0;
682 MouseDev
->State
.RelativeMovementY
= 0;
683 MouseDev
->State
.RelativeMovementZ
= 0;
684 MouseDev
->StateChanged
= FALSE
;
685 gBS
->RestoreTPL (OldTpl
);
700 Event notification function for SIMPLE_POINTER.WaitForInput event
701 Signal the event if there is input from mouse
708 // GC_TODO: Event - add argument and description to function comment
709 // GC_TODO: Context - add argument and description to function comment
711 PS2_MOUSE_DEV
*MouseDev
;
713 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
716 // Someone is waiting on the mouse event, if there's
717 // input from mouse, signal the event
719 if (MouseDev
->StateChanged
) {
720 gBS
->SignalEvent (Event
);
735 Event notification function for TimerEvent event
736 If mouse device is connected to system, try to get the mouse packet data
740 Event - TimerEvent in PS2_MOUSE_DEV
741 Context - Pointer to PS2_MOUSE_DEV structure
749 PS2_MOUSE_DEV
*MouseDev
;
751 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
754 // Polling mouse packet data
756 PS2MouseGetPacket (MouseDev
);
760 The user Entry Point for module Ps2Mouse. The user code starts with this function.
762 @param[in] ImageHandle The firmware allocated handle for the EFI image.
763 @param[in] SystemTable A pointer to the EFI System Table.
765 @retval EFI_SUCCESS The entry point is executed successfully.
766 @retval other Some error occurs when executing this entry point.
772 IN EFI_HANDLE ImageHandle
,
773 IN EFI_SYSTEM_TABLE
*SystemTable
779 // Install driver model protocol(s).
781 Status
= EfiLibInstallAllDriverProtocols (
786 &gPs2MouseComponentName
,
790 ASSERT_EFI_ERROR (Status
);