3 Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved. <BR>
4 This software and associated documentation (if any) is furnished
5 under a license and may only be used or copied in accordance
6 with the terms of the license. Except as permitted by such
7 license, no part of this software or documentation may be
8 reproduced, stored in a retrieval system, or transmitted in any
9 form or by any means without the express written consent of
19 PS/2 Mouse driver. Routines that interacts with callers,
20 conforming to EFI driver model
25 // Include common header file for this module.
27 #include "CommonHeader.h"
33 // DriverBinding Protocol Instance
35 EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver
= {
36 PS2MouseDriverSupported
,
46 PS2MouseDriverSupported (
47 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
48 IN EFI_HANDLE Controller
,
49 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
55 ControllerDriver Protocol Method
62 // GC_TODO: This - add argument and description to function comment
63 // GC_TODO: Controller - add argument and description to function comment
64 // GC_TODO: RemainingDevicePath - add argument and description to function comment
67 EFI_ISA_IO_PROTOCOL
*IsaIo
;
72 // Open the IO Abstraction(s) needed to perform the supported test
74 Status
= gBS
->OpenProtocol (
76 &gEfiIsaIoProtocolGuid
,
78 This
->DriverBindingHandle
,
80 EFI_OPEN_PROTOCOL_BY_DRIVER
82 if (EFI_ERROR (Status
)) {
86 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
88 switch (IsaIo
->ResourceList
->Device
.HID
) {
89 case EISA_PNP_ID (0xF03):
91 // Microsoft PS/2 style mouse
93 case EISA_PNP_ID (0xF13):
95 // PS/2 Port for PS/2-style Mice
99 case EISA_PNP_ID (0x303):
101 // IBM Enhanced (101/102-key, PS/2 mouse support)
103 if (IsaIo
->ResourceList
->Device
.UID
== 1) {
108 Status
= EFI_UNSUPPORTED
;
112 // Close the I/O Abstraction(s) used to perform the supported test
116 &gEfiIsaIoProtocolGuid
,
117 This
->DriverBindingHandle
,
126 PS2MouseDriverStart (
127 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
128 IN EFI_HANDLE Controller
,
129 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
134 Start protocol interfaces for the mouse device handles.
137 This - Protocol instance pointer.
138 Controller - Handle of device to bind driver to.
139 RemainingDevicePath - Not used.
142 EFI_SUCCESS - This driver is added to DeviceHandle.
143 other - Errors occurred.
148 EFI_STATUS EmptyStatus
;
149 EFI_ISA_IO_PROTOCOL
*IsaIo
;
150 PS2_MOUSE_DEV
*MouseDev
;
153 EFI_STATUS_CODE_VALUE StatusCode
;
154 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
161 // Open the device path protocol
163 Status
= gBS
->OpenProtocol (
165 &gEfiDevicePathProtocolGuid
,
166 (VOID
**) &ParentDevicePath
,
167 This
->DriverBindingHandle
,
169 EFI_OPEN_PROTOCOL_BY_DRIVER
171 if (EFI_ERROR (Status
)) {
175 // Report that the keyboard is being enabled
177 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
179 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
184 // Get the ISA I/O Protocol on Controller's handle
186 Status
= gBS
->OpenProtocol (
188 &gEfiIsaIoProtocolGuid
,
190 This
->DriverBindingHandle
,
192 EFI_OPEN_PROTOCOL_BY_DRIVER
194 if (EFI_ERROR (Status
)) {
197 &gEfiDevicePathProtocolGuid
,
198 This
->DriverBindingHandle
,
201 return EFI_INVALID_PARAMETER
;
204 // Raise TPL to avoid keyboard operation impact
206 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
209 // Allocate private data
211 MouseDev
= AllocateZeroPool (sizeof (PS2_MOUSE_DEV
));
212 if (MouseDev
== NULL
) {
213 Status
= EFI_OUT_OF_RESOURCES
;
217 // Setup the device instance
219 MouseDev
->Signature
= PS2_MOUSE_DEV_SIGNATURE
;
220 MouseDev
->Handle
= Controller
;
221 MouseDev
->SampleRate
= SSR_20
;
222 MouseDev
->Resolution
= CMR4
;
223 MouseDev
->Scaling
= SF1
;
224 MouseDev
->DataPackageSize
= 3;
225 MouseDev
->IsaIo
= IsaIo
;
226 MouseDev
->DevicePath
= ParentDevicePath
;
229 // Resolution = 4 counts/mm
231 MouseDev
->Mode
.ResolutionX
= 4;
232 MouseDev
->Mode
.ResolutionY
= 4;
233 MouseDev
->Mode
.LeftButton
= TRUE
;
234 MouseDev
->Mode
.RightButton
= TRUE
;
236 MouseDev
->SimplePointerProtocol
.Reset
= MouseReset
;
237 MouseDev
->SimplePointerProtocol
.GetState
= MouseGetState
;
238 MouseDev
->SimplePointerProtocol
.Mode
= &(MouseDev
->Mode
);
241 // Initialize keyboard controller if necessary
243 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
244 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
245 Status
= KbcSelfTest (IsaIo
);
246 if (EFI_ERROR (Status
)) {
247 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
252 KbcEnableAux (IsaIo
);
254 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
256 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
263 Status
= MouseDev
->SimplePointerProtocol
.Reset (&MouseDev
->SimplePointerProtocol
, TRUE
);
264 if (EFI_ERROR (Status
)) {
266 // mouse not connected
268 Status
= EFI_SUCCESS
;
269 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
273 // Setup the WaitForKey event
275 Status
= gBS
->CreateEvent (
280 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
282 if (EFI_ERROR (Status
)) {
283 Status
= EFI_OUT_OF_RESOURCES
;
287 // Setup a periodic timer, used to poll mouse state
289 Status
= gBS
->CreateEvent (
290 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
294 &MouseDev
->TimerEvent
296 if (EFI_ERROR (Status
)) {
297 Status
= EFI_OUT_OF_RESOURCES
;
301 // Start timer to poll mouse (100 samples per second)
303 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
304 if (EFI_ERROR (Status
)) {
305 Status
= EFI_OUT_OF_RESOURCES
;
309 MouseDev
->ControllerNameTable
= NULL
;
312 gPs2MouseComponentName
.SupportedLanguages
,
313 &MouseDev
->ControllerNameTable
,
318 // Install protocol interfaces for the mouse device.
320 Status
= gBS
->InstallMultipleProtocolInterfaces (
322 &gEfiSimplePointerProtocolGuid
,
323 &MouseDev
->SimplePointerProtocol
,
326 if (EFI_ERROR (Status
)) {
330 gBS
->RestoreTPL (OldTpl
);
336 KbcDisableAux (IsaIo
);
338 if (StatusCode
!= 0) {
339 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
340 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
346 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
347 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
350 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
351 gBS
->CloseEvent (MouseDev
->TimerEvent
);
354 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
355 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
358 // Since there will be no timer handler for mouse input any more,
359 // exhaust input data just in case there is still mouse data left
361 EmptyStatus
= EFI_SUCCESS
;
362 while (!EFI_ERROR (EmptyStatus
)) {
363 EmptyStatus
= In8042Data (IsaIo
, &Data
);
366 if (MouseDev
!= NULL
) {
367 gBS
->FreePool (MouseDev
);
372 &gEfiDevicePathProtocolGuid
,
373 This
->DriverBindingHandle
,
379 &gEfiIsaIoProtocolGuid
,
380 This
->DriverBindingHandle
,
384 gBS
->RestoreTPL (OldTpl
);
392 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
393 IN EFI_HANDLE Controller
,
394 IN UINTN NumberOfChildren
,
395 IN EFI_HANDLE
*ChildHandleBuffer
406 // GC_TODO: This - add argument and description to function comment
407 // GC_TODO: Controller - add argument and description to function comment
408 // GC_TODO: NumberOfChildren - add argument and description to function comment
409 // GC_TODO: ChildHandleBuffer - add argument and description to function comment
410 // GC_TODO: EFI_SUCCESS - add return value to function comment
411 // GC_TODO: EFI_SUCCESS - add return value to function comment
414 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
415 PS2_MOUSE_DEV
*MouseDev
;
418 Status
= gBS
->OpenProtocol (
420 &gEfiSimplePointerProtocolGuid
,
421 (VOID
**) &SimplePointerProtocol
,
422 This
->DriverBindingHandle
,
424 EFI_OPEN_PROTOCOL_GET_PROTOCOL
426 if (EFI_ERROR (Status
)) {
430 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
433 // Report that the keyboard is being disabled
435 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
437 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
441 Status
= gBS
->UninstallProtocolInterface (
443 &gEfiSimplePointerProtocolGuid
,
444 &MouseDev
->SimplePointerProtocol
446 if (EFI_ERROR (Status
)) {
450 // Disable mouse on keyboard controller
452 KbcDisableAux (MouseDev
->IsaIo
);
455 // Cancel mouse data polling timer, close timer event
457 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
458 gBS
->CloseEvent (MouseDev
->TimerEvent
);
461 // Since there will be no timer handler for mouse input any more,
462 // exhaust input data just in case there is still mouse data left
464 Status
= EFI_SUCCESS
;
465 while (!EFI_ERROR (Status
)) {
466 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
469 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
470 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
471 gBS
->FreePool (MouseDev
);
475 &gEfiDevicePathProtocolGuid
,
476 This
->DriverBindingHandle
,
482 &gEfiIsaIoProtocolGuid
,
483 This
->DriverBindingHandle
,
493 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
494 IN BOOLEAN ExtendedVerification
500 Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
504 This - Pointer of simple pointer Protocol.
505 ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
509 EFI_SUCCESS - The command byte is written successfully.
510 EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
515 PS2_MOUSE_DEV
*MouseDev
;
517 BOOLEAN KeyboardEnable
;
520 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
523 // Report reset progress code
525 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
527 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
531 KeyboardEnable
= FALSE
;
534 // Raise TPL to avoid keyboard operation impact
536 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
538 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
539 MouseDev
->StateChanged
= FALSE
;
542 // Exhaust input data
544 Status
= EFI_SUCCESS
;
545 while (!EFI_ERROR (Status
)) {
546 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
549 CheckKbStatus (MouseDev
->IsaIo
, &KeyboardEnable
);
551 KbcDisableKb (MouseDev
->IsaIo
);
553 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
556 // if there's data block on KBC data port, read it out
558 if ((Data
& KBC_OUTB
) == KBC_OUTB
) {
559 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Data
);
562 Status
= EFI_SUCCESS
;
564 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
565 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
566 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
568 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
570 // Send mouse reset command and set mouse default configure
572 Status
= PS2MouseReset (MouseDev
->IsaIo
);
573 if (EFI_ERROR (Status
)) {
574 Status
= EFI_DEVICE_ERROR
;
578 Status
= PS2MouseSetSampleRate (MouseDev
->IsaIo
, MouseDev
->SampleRate
);
579 if (EFI_ERROR (Status
)) {
580 Status
= EFI_DEVICE_ERROR
;
584 Status
= PS2MouseSetResolution (MouseDev
->IsaIo
, MouseDev
->Resolution
);
585 if (EFI_ERROR (Status
)) {
586 Status
= EFI_DEVICE_ERROR
;
590 Status
= PS2MouseSetScaling (MouseDev
->IsaIo
, MouseDev
->Scaling
);
591 if (EFI_ERROR (Status
)) {
592 Status
= EFI_DEVICE_ERROR
;
596 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
597 if (EFI_ERROR (Status
)) {
598 Status
= EFI_DEVICE_ERROR
;
603 gBS
->RestoreTPL (OldTpl
);
605 if (KeyboardEnable
) {
606 KbcEnableKb (MouseDev
->IsaIo
);
614 IN PS2_MOUSE_DEV
*MouseDev
620 Check whether there is Ps/2 mouse device in system
624 PS2_MOUSE_DEV - Mouse Private Data Structure
628 TRUE - Keyboard in System.
629 FALSE - Keyboard not in System.
635 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
636 if (!EFI_ERROR (Status
)) {
646 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
647 IN OUT EFI_SIMPLE_POINTER_STATE
*State
653 GC_TODO: Add function description
657 This - GC_TODO: add argument description
658 State - GC_TODO: add argument description
662 EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
663 EFI_NOT_READY - GC_TODO: Add description for return value
664 EFI_SUCCESS - GC_TODO: Add description for return value
668 PS2_MOUSE_DEV
*MouseDev
;
671 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
674 return EFI_INVALID_PARAMETER
;
677 if (!MouseDev
->StateChanged
) {
678 return EFI_NOT_READY
;
681 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
682 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
687 MouseDev
->State
.RelativeMovementX
= 0;
688 MouseDev
->State
.RelativeMovementY
= 0;
689 MouseDev
->State
.RelativeMovementZ
= 0;
690 MouseDev
->StateChanged
= FALSE
;
691 gBS
->RestoreTPL (OldTpl
);
706 Event notification function for SIMPLE_POINTER.WaitForInput event
707 Signal the event if there is input from mouse
714 // GC_TODO: Event - add argument and description to function comment
715 // GC_TODO: Context - add argument and description to function comment
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
);
741 Event notification function for TimerEvent event
742 If mouse device is connected to system, try to get the mouse packet data
746 Event - TimerEvent in PS2_MOUSE_DEV
747 Context - Pointer to PS2_MOUSE_DEV structure
755 PS2_MOUSE_DEV
*MouseDev
;
757 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
760 // Polling mouse packet data
762 PS2MouseGetPacket (MouseDev
);