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
24 // Include common header file for this module.
26 #include "CommonHeader.h"
32 // DriverBinding Protocol Instance
34 EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver
= {
35 PS2MouseDriverSupported
,
45 PS2MouseDriverSupported (
46 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
47 IN EFI_HANDLE Controller
,
48 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
54 ControllerDriver Protocol Method
61 // GC_TODO: This - add argument and description to function comment
62 // GC_TODO: Controller - add argument and description to function comment
63 // GC_TODO: RemainingDevicePath - add argument and description to function comment
66 EFI_ISA_IO_PROTOCOL
*IsaIo
;
71 // Open the IO Abstraction(s) needed to perform the supported test
73 Status
= gBS
->OpenProtocol (
75 &gEfiIsaIoProtocolGuid
,
77 This
->DriverBindingHandle
,
79 EFI_OPEN_PROTOCOL_BY_DRIVER
81 if (EFI_ERROR (Status
)) {
85 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
87 switch (IsaIo
->ResourceList
->Device
.HID
) {
88 case EISA_PNP_ID (0xF03):
90 // Microsoft PS/2 style mouse
92 case EISA_PNP_ID (0xF13):
94 // PS/2 Port for PS/2-style Mice
98 case EISA_PNP_ID (0x303):
100 // IBM Enhanced (101/102-key, PS/2 mouse support)
102 if (IsaIo
->ResourceList
->Device
.UID
== 1) {
107 Status
= EFI_UNSUPPORTED
;
111 // Close the I/O Abstraction(s) used to perform the supported test
115 &gEfiIsaIoProtocolGuid
,
116 This
->DriverBindingHandle
,
125 PS2MouseDriverStart (
126 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
127 IN EFI_HANDLE Controller
,
128 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath
133 Start protocol interfaces for the mouse device handles.
136 This - Protocol instance pointer.
137 Controller - Handle of device to bind driver to.
138 RemainingDevicePath - Not used.
141 EFI_SUCCESS - This driver is added to DeviceHandle.
142 other - Errors occurred.
147 EFI_STATUS EmptyStatus
;
148 EFI_ISA_IO_PROTOCOL
*IsaIo
;
149 PS2_MOUSE_DEV
*MouseDev
;
152 EFI_STATUS_CODE_VALUE StatusCode
;
153 EFI_DEVICE_PATH_PROTOCOL
*ParentDevicePath
;
160 // Open the device path protocol
162 Status
= gBS
->OpenProtocol (
164 &gEfiDevicePathProtocolGuid
,
165 (VOID
**) &ParentDevicePath
,
166 This
->DriverBindingHandle
,
168 EFI_OPEN_PROTOCOL_BY_DRIVER
170 if (EFI_ERROR (Status
)) {
174 // Report that the keyboard is being enabled
176 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
178 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_ENABLE
,
183 // Get the ISA I/O Protocol on Controller's handle
185 Status
= gBS
->OpenProtocol (
187 &gEfiIsaIoProtocolGuid
,
189 This
->DriverBindingHandle
,
191 EFI_OPEN_PROTOCOL_BY_DRIVER
193 if (EFI_ERROR (Status
)) {
196 &gEfiDevicePathProtocolGuid
,
197 This
->DriverBindingHandle
,
200 return EFI_INVALID_PARAMETER
;
203 // Raise TPL to avoid keyboard operation impact
205 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
208 // Allocate private data
210 MouseDev
= AllocateZeroPool (sizeof (PS2_MOUSE_DEV
));
211 if (MouseDev
== NULL
) {
212 Status
= EFI_OUT_OF_RESOURCES
;
216 // Setup the device instance
218 MouseDev
->Signature
= PS2_MOUSE_DEV_SIGNATURE
;
219 MouseDev
->Handle
= Controller
;
220 MouseDev
->SampleRate
= SSR_20
;
221 MouseDev
->Resolution
= CMR4
;
222 MouseDev
->Scaling
= SF1
;
223 MouseDev
->DataPackageSize
= 3;
224 MouseDev
->IsaIo
= IsaIo
;
225 MouseDev
->DevicePath
= ParentDevicePath
;
228 // Resolution = 4 counts/mm
230 MouseDev
->Mode
.ResolutionX
= 4;
231 MouseDev
->Mode
.ResolutionY
= 4;
232 MouseDev
->Mode
.LeftButton
= TRUE
;
233 MouseDev
->Mode
.RightButton
= TRUE
;
235 MouseDev
->SimplePointerProtocol
.Reset
= MouseReset
;
236 MouseDev
->SimplePointerProtocol
.GetState
= MouseGetState
;
237 MouseDev
->SimplePointerProtocol
.Mode
= &(MouseDev
->Mode
);
240 // Initialize keyboard controller if necessary
242 IsaIo
->Io
.Read (IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
243 if ((Data
& KBC_SYSF
) != KBC_SYSF
) {
244 Status
= KbcSelfTest (IsaIo
);
245 if (EFI_ERROR (Status
)) {
246 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_CONTROLLER_ERROR
;
251 KbcEnableAux (IsaIo
);
253 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
255 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_PRESENCE_DETECT
,
262 Status
= MouseDev
->SimplePointerProtocol
.Reset (&MouseDev
->SimplePointerProtocol
, TRUE
);
263 if (EFI_ERROR (Status
)) {
265 // mouse not connected
267 Status
= EFI_SUCCESS
;
268 StatusCode
= EFI_PERIPHERAL_MOUSE
| EFI_P_EC_NOT_DETECTED
;
272 // Setup the WaitForKey event
274 Status
= gBS
->CreateEvent (
279 &((MouseDev
->SimplePointerProtocol
).WaitForInput
)
281 if (EFI_ERROR (Status
)) {
282 Status
= EFI_OUT_OF_RESOURCES
;
286 // Setup a periodic timer, used to poll mouse state
288 Status
= gBS
->CreateEvent (
289 EVT_TIMER
| EVT_NOTIFY_SIGNAL
,
293 &MouseDev
->TimerEvent
295 if (EFI_ERROR (Status
)) {
296 Status
= EFI_OUT_OF_RESOURCES
;
300 // Start timer to poll mouse (100 samples per second)
302 Status
= gBS
->SetTimer (MouseDev
->TimerEvent
, TimerPeriodic
, 100000);
303 if (EFI_ERROR (Status
)) {
304 Status
= EFI_OUT_OF_RESOURCES
;
308 MouseDev
->ControllerNameTable
= NULL
;
311 gPs2MouseComponentName
.SupportedLanguages
,
312 &MouseDev
->ControllerNameTable
,
317 // Install protocol interfaces for the mouse device.
319 Status
= gBS
->InstallMultipleProtocolInterfaces (
321 &gEfiSimplePointerProtocolGuid
,
322 &MouseDev
->SimplePointerProtocol
,
325 if (EFI_ERROR (Status
)) {
329 gBS
->RestoreTPL (OldTpl
);
335 KbcDisableAux (IsaIo
);
337 if (StatusCode
!= 0) {
338 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
339 EFI_ERROR_CODE
| EFI_ERROR_MINOR
,
345 if ((MouseDev
!= NULL
) && (MouseDev
->SimplePointerProtocol
.WaitForInput
!= NULL
)) {
346 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
349 if ((MouseDev
!= NULL
) && (MouseDev
->TimerEvent
!= NULL
)) {
350 gBS
->CloseEvent (MouseDev
->TimerEvent
);
353 if ((MouseDev
!= NULL
) && (MouseDev
->ControllerNameTable
!= NULL
)) {
354 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
357 // Since there will be no timer handler for mouse input any more,
358 // exhaust input data just in case there is still mouse data left
360 EmptyStatus
= EFI_SUCCESS
;
361 while (!EFI_ERROR (EmptyStatus
)) {
362 EmptyStatus
= In8042Data (IsaIo
, &Data
);
365 if (MouseDev
!= NULL
) {
366 gBS
->FreePool (MouseDev
);
371 &gEfiDevicePathProtocolGuid
,
372 This
->DriverBindingHandle
,
378 &gEfiIsaIoProtocolGuid
,
379 This
->DriverBindingHandle
,
383 gBS
->RestoreTPL (OldTpl
);
391 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
392 IN EFI_HANDLE Controller
,
393 IN UINTN NumberOfChildren
,
394 IN EFI_HANDLE
*ChildHandleBuffer
405 // GC_TODO: This - add argument and description to function comment
406 // GC_TODO: Controller - add argument and description to function comment
407 // GC_TODO: NumberOfChildren - add argument and description to function comment
408 // GC_TODO: ChildHandleBuffer - add argument and description to function comment
409 // GC_TODO: EFI_SUCCESS - add return value to function comment
410 // GC_TODO: EFI_SUCCESS - add return value to function comment
413 EFI_SIMPLE_POINTER_PROTOCOL
*SimplePointerProtocol
;
414 PS2_MOUSE_DEV
*MouseDev
;
417 Status
= gBS
->OpenProtocol (
419 &gEfiSimplePointerProtocolGuid
,
420 (VOID
**) &SimplePointerProtocol
,
421 This
->DriverBindingHandle
,
423 EFI_OPEN_PROTOCOL_GET_PROTOCOL
425 if (EFI_ERROR (Status
)) {
429 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol
);
432 // Report that the keyboard is being disabled
434 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
436 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_DISABLE
,
440 Status
= gBS
->UninstallProtocolInterface (
442 &gEfiSimplePointerProtocolGuid
,
443 &MouseDev
->SimplePointerProtocol
445 if (EFI_ERROR (Status
)) {
449 // Disable mouse on keyboard controller
451 KbcDisableAux (MouseDev
->IsaIo
);
454 // Cancel mouse data polling timer, close timer event
456 gBS
->SetTimer (MouseDev
->TimerEvent
, TimerCancel
, 0);
457 gBS
->CloseEvent (MouseDev
->TimerEvent
);
460 // Since there will be no timer handler for mouse input any more,
461 // exhaust input data just in case there is still mouse data left
463 Status
= EFI_SUCCESS
;
464 while (!EFI_ERROR (Status
)) {
465 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
468 gBS
->CloseEvent (MouseDev
->SimplePointerProtocol
.WaitForInput
);
469 FreeUnicodeStringTable (MouseDev
->ControllerNameTable
);
470 gBS
->FreePool (MouseDev
);
474 &gEfiDevicePathProtocolGuid
,
475 This
->DriverBindingHandle
,
481 &gEfiIsaIoProtocolGuid
,
482 This
->DriverBindingHandle
,
492 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
493 IN BOOLEAN ExtendedVerification
499 Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
503 This - Pointer of simple pointer Protocol.
504 ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
508 EFI_SUCCESS - The command byte is written successfully.
509 EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
514 PS2_MOUSE_DEV
*MouseDev
;
516 BOOLEAN KeyboardEnable
;
519 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
522 // Report reset progress code
524 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
526 EFI_PERIPHERAL_MOUSE
| EFI_P_PC_RESET
,
530 KeyboardEnable
= FALSE
;
533 // Raise TPL to avoid keyboard operation impact
535 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
537 ZeroMem (&MouseDev
->State
, sizeof (EFI_SIMPLE_POINTER_STATE
));
538 MouseDev
->StateChanged
= FALSE
;
541 // Exhaust input data
543 Status
= EFI_SUCCESS
;
544 while (!EFI_ERROR (Status
)) {
545 Status
= In8042Data (MouseDev
->IsaIo
, &Data
);
548 CheckKbStatus (MouseDev
->IsaIo
, &KeyboardEnable
);
550 KbcDisableKb (MouseDev
->IsaIo
);
552 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_CMD_STS_PORT
, 1, &Data
);
555 // if there's data block on KBC data port, read it out
557 if ((Data
& KBC_OUTB
) == KBC_OUTB
) {
558 MouseDev
->IsaIo
->Io
.Read (MouseDev
->IsaIo
, EfiIsaIoWidthUint8
, KBC_DATA_PORT
, 1, &Data
);
561 Status
= EFI_SUCCESS
;
563 // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
564 // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
565 // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
567 if (ExtendedVerification
&& CheckMouseConnect (MouseDev
)) {
569 // Send mouse reset command and set mouse default configure
571 Status
= PS2MouseReset (MouseDev
->IsaIo
);
572 if (EFI_ERROR (Status
)) {
573 Status
= EFI_DEVICE_ERROR
;
577 Status
= PS2MouseSetSampleRate (MouseDev
->IsaIo
, MouseDev
->SampleRate
);
578 if (EFI_ERROR (Status
)) {
579 Status
= EFI_DEVICE_ERROR
;
583 Status
= PS2MouseSetResolution (MouseDev
->IsaIo
, MouseDev
->Resolution
);
584 if (EFI_ERROR (Status
)) {
585 Status
= EFI_DEVICE_ERROR
;
589 Status
= PS2MouseSetScaling (MouseDev
->IsaIo
, MouseDev
->Scaling
);
590 if (EFI_ERROR (Status
)) {
591 Status
= EFI_DEVICE_ERROR
;
595 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
596 if (EFI_ERROR (Status
)) {
597 Status
= EFI_DEVICE_ERROR
;
602 gBS
->RestoreTPL (OldTpl
);
604 if (KeyboardEnable
) {
605 KbcEnableKb (MouseDev
->IsaIo
);
613 IN PS2_MOUSE_DEV
*MouseDev
619 Check whether there is Ps/2 mouse device in system
623 PS2_MOUSE_DEV - Mouse Private Data Structure
627 TRUE - Keyboard in System.
628 FALSE - Keyboard not in System.
634 Status
= PS2MouseEnable (MouseDev
->IsaIo
);
635 if (!EFI_ERROR (Status
)) {
645 IN EFI_SIMPLE_POINTER_PROTOCOL
*This
,
646 IN OUT EFI_SIMPLE_POINTER_STATE
*State
652 GC_TODO: Add function description
656 This - GC_TODO: add argument description
657 State - GC_TODO: add argument description
661 EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
662 EFI_NOT_READY - GC_TODO: Add description for return value
663 EFI_SUCCESS - GC_TODO: Add description for return value
667 PS2_MOUSE_DEV
*MouseDev
;
670 MouseDev
= PS2_MOUSE_DEV_FROM_THIS (This
);
673 return EFI_INVALID_PARAMETER
;
676 if (!MouseDev
->StateChanged
) {
677 return EFI_NOT_READY
;
680 OldTpl
= gBS
->RaiseTPL (TPL_NOTIFY
);
681 CopyMem (State
, &(MouseDev
->State
), sizeof (EFI_SIMPLE_POINTER_STATE
));
686 MouseDev
->State
.RelativeMovementX
= 0;
687 MouseDev
->State
.RelativeMovementY
= 0;
688 MouseDev
->State
.RelativeMovementZ
= 0;
689 MouseDev
->StateChanged
= FALSE
;
690 gBS
->RestoreTPL (OldTpl
);
705 Event notification function for SIMPLE_POINTER.WaitForInput event
706 Signal the event if there is input from mouse
713 // GC_TODO: Event - add argument and description to function comment
714 // GC_TODO: Context - add argument and description to function comment
716 PS2_MOUSE_DEV
*MouseDev
;
718 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
721 // Someone is waiting on the mouse event, if there's
722 // input from mouse, signal the event
724 if (MouseDev
->StateChanged
) {
725 gBS
->SignalEvent (Event
);
740 Event notification function for TimerEvent event
741 If mouse device is connected to system, try to get the mouse packet data
745 Event - TimerEvent in PS2_MOUSE_DEV
746 Context - Pointer to PS2_MOUSE_DEV structure
754 PS2_MOUSE_DEV
*MouseDev
;
756 MouseDev
= (PS2_MOUSE_DEV
*) Context
;
759 // Polling mouse packet data
761 PS2MouseGetPacket (MouseDev
);