]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c
Update to BSD license header.
[mirror_edk2.git] / IntelFrameworkModulePkg / Bus / Isa / Ps2MouseDxe / Ps2Mouse.c
1 /*++
2
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
8
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.
11
12 Module Name:
13
14 Ps2Mouse.c
15
16 Abstract:
17
18 PS/2 Mouse driver. Routines that interacts with callers,
19 conforming to EFI driver model
20
21 --*/
22
23 //
24 // Include common header file for this module.
25 //
26 #include "CommonHeader.h"
27
28 #include "Ps2Mouse.h"
29 #include "CommPs2.h"
30
31 //
32 // DriverBinding Protocol Instance
33 //
34 EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver = {
35 PS2MouseDriverSupported,
36 PS2MouseDriverStart,
37 PS2MouseDriverStop,
38 0xa,
39 NULL,
40 NULL
41 };
42
43 EFI_STATUS
44 EFIAPI
45 PS2MouseDriverSupported (
46 IN EFI_DRIVER_BINDING_PROTOCOL *This,
47 IN EFI_HANDLE Controller,
48 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
49 )
50 /*++
51
52 Routine Description:
53
54 ControllerDriver Protocol Method
55
56 Arguments:
57
58 Returns:
59
60 --*/
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
64 {
65 EFI_STATUS Status;
66 EFI_ISA_IO_PROTOCOL *IsaIo;
67
68 Status = EFI_SUCCESS;
69
70 //
71 // Open the IO Abstraction(s) needed to perform the supported test
72 //
73 Status = gBS->OpenProtocol (
74 Controller,
75 &gEfiIsaIoProtocolGuid,
76 (VOID **) &IsaIo,
77 This->DriverBindingHandle,
78 Controller,
79 EFI_OPEN_PROTOCOL_BY_DRIVER
80 );
81 if (EFI_ERROR (Status)) {
82 return Status;
83 }
84 //
85 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
86 //
87 switch (IsaIo->ResourceList->Device.HID) {
88 case EISA_PNP_ID (0xF03):
89 //
90 // Microsoft PS/2 style mouse
91 //
92 case EISA_PNP_ID (0xF13):
93 //
94 // PS/2 Port for PS/2-style Mice
95 //
96 break;
97
98 case EISA_PNP_ID (0x303):
99 //
100 // IBM Enhanced (101/102-key, PS/2 mouse support)
101 //
102 if (IsaIo->ResourceList->Device.UID == 1) {
103 break;
104 }
105
106 default:
107 Status = EFI_UNSUPPORTED;
108 break;
109 }
110 //
111 // Close the I/O Abstraction(s) used to perform the supported test
112 //
113 gBS->CloseProtocol (
114 Controller,
115 &gEfiIsaIoProtocolGuid,
116 This->DriverBindingHandle,
117 Controller
118 );
119
120 return Status;
121 }
122
123 EFI_STATUS
124 EFIAPI
125 PS2MouseDriverStart (
126 IN EFI_DRIVER_BINDING_PROTOCOL *This,
127 IN EFI_HANDLE Controller,
128 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
129 )
130 /*++
131
132 Routine Description:
133 Start protocol interfaces for the mouse device handles.
134
135 Arguments:
136 This - Protocol instance pointer.
137 Controller - Handle of device to bind driver to.
138 RemainingDevicePath - Not used.
139
140 Returns:
141 EFI_SUCCESS - This driver is added to DeviceHandle.
142 other - Errors occurred.
143
144 --*/
145 {
146 EFI_STATUS Status;
147 EFI_STATUS EmptyStatus;
148 EFI_ISA_IO_PROTOCOL *IsaIo;
149 PS2_MOUSE_DEV *MouseDev;
150 UINT8 Data;
151 EFI_TPL OldTpl;
152 EFI_STATUS_CODE_VALUE StatusCode;
153 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
154
155 StatusCode = 0;
156 MouseDev = NULL;
157 IsaIo = NULL;
158
159 //
160 // Open the device path protocol
161 //
162 Status = gBS->OpenProtocol (
163 Controller,
164 &gEfiDevicePathProtocolGuid,
165 (VOID **) &ParentDevicePath,
166 This->DriverBindingHandle,
167 Controller,
168 EFI_OPEN_PROTOCOL_BY_DRIVER
169 );
170 if (EFI_ERROR (Status)) {
171 return Status;
172 }
173 //
174 // Report that the keyboard is being enabled
175 //
176 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
177 EFI_PROGRESS_CODE,
178 EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE,
179 ParentDevicePath
180 );
181
182 //
183 // Get the ISA I/O Protocol on Controller's handle
184 //
185 Status = gBS->OpenProtocol (
186 Controller,
187 &gEfiIsaIoProtocolGuid,
188 (VOID **) &IsaIo,
189 This->DriverBindingHandle,
190 Controller,
191 EFI_OPEN_PROTOCOL_BY_DRIVER
192 );
193 if (EFI_ERROR (Status)) {
194 gBS->CloseProtocol (
195 Controller,
196 &gEfiDevicePathProtocolGuid,
197 This->DriverBindingHandle,
198 Controller
199 );
200 return EFI_INVALID_PARAMETER;
201 }
202 //
203 // Raise TPL to avoid keyboard operation impact
204 //
205 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
206
207 //
208 // Allocate private data
209 //
210 MouseDev = AllocateZeroPool (sizeof (PS2_MOUSE_DEV));
211 if (MouseDev == NULL) {
212 Status = EFI_OUT_OF_RESOURCES;
213 goto ErrorExit;
214 }
215 //
216 // Setup the device instance
217 //
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;
226
227 //
228 // Resolution = 4 counts/mm
229 //
230 MouseDev->Mode.ResolutionX = 4;
231 MouseDev->Mode.ResolutionY = 4;
232 MouseDev->Mode.LeftButton = TRUE;
233 MouseDev->Mode.RightButton = TRUE;
234
235 MouseDev->SimplePointerProtocol.Reset = MouseReset;
236 MouseDev->SimplePointerProtocol.GetState = MouseGetState;
237 MouseDev->SimplePointerProtocol.Mode = &(MouseDev->Mode);
238
239 //
240 // Initialize keyboard controller if necessary
241 //
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;
247 goto ErrorExit;
248 }
249 }
250
251 KbcEnableAux (IsaIo);
252
253 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
254 EFI_PROGRESS_CODE,
255 EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT,
256 ParentDevicePath
257 );
258
259 //
260 // Reset the mouse
261 //
262 Status = MouseDev->SimplePointerProtocol.Reset (&MouseDev->SimplePointerProtocol, TRUE);
263 if (EFI_ERROR (Status)) {
264 //
265 // mouse not connected
266 //
267 Status = EFI_SUCCESS;
268 StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED;
269 goto ErrorExit;
270 }
271 //
272 // Setup the WaitForKey event
273 //
274 Status = gBS->CreateEvent (
275 EVT_NOTIFY_WAIT,
276 TPL_NOTIFY,
277 MouseWaitForInput,
278 MouseDev,
279 &((MouseDev->SimplePointerProtocol).WaitForInput)
280 );
281 if (EFI_ERROR (Status)) {
282 Status = EFI_OUT_OF_RESOURCES;
283 goto ErrorExit;
284 }
285 //
286 // Setup a periodic timer, used to poll mouse state
287 //
288 Status = gBS->CreateEvent (
289 EVT_TIMER | EVT_NOTIFY_SIGNAL,
290 TPL_NOTIFY,
291 PollMouse,
292 MouseDev,
293 &MouseDev->TimerEvent
294 );
295 if (EFI_ERROR (Status)) {
296 Status = EFI_OUT_OF_RESOURCES;
297 goto ErrorExit;
298 }
299 //
300 // Start timer to poll mouse (100 samples per second)
301 //
302 Status = gBS->SetTimer (MouseDev->TimerEvent, TimerPeriodic, 100000);
303 if (EFI_ERROR (Status)) {
304 Status = EFI_OUT_OF_RESOURCES;
305 goto ErrorExit;
306 }
307
308 MouseDev->ControllerNameTable = NULL;
309 AddUnicodeString (
310 "eng",
311 gPs2MouseComponentName.SupportedLanguages,
312 &MouseDev->ControllerNameTable,
313 L"PS/2 Mouse Device"
314 );
315
316 //
317 // Install protocol interfaces for the mouse device.
318 //
319 Status = gBS->InstallMultipleProtocolInterfaces (
320 &Controller,
321 &gEfiSimplePointerProtocolGuid,
322 &MouseDev->SimplePointerProtocol,
323 NULL
324 );
325 if (EFI_ERROR (Status)) {
326 goto ErrorExit;
327 }
328
329 gBS->RestoreTPL (OldTpl);
330
331 return Status;
332
333 ErrorExit:
334
335 KbcDisableAux (IsaIo);
336
337 if (StatusCode != 0) {
338 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
339 EFI_ERROR_CODE | EFI_ERROR_MINOR,
340 StatusCode,
341 ParentDevicePath
342 );
343 }
344
345 if ((MouseDev != NULL) && (MouseDev->SimplePointerProtocol.WaitForInput != NULL)) {
346 gBS->CloseEvent (MouseDev->SimplePointerProtocol.WaitForInput);
347 }
348
349 if ((MouseDev != NULL) && (MouseDev->TimerEvent != NULL)) {
350 gBS->CloseEvent (MouseDev->TimerEvent);
351 }
352
353 if ((MouseDev != NULL) && (MouseDev->ControllerNameTable != NULL)) {
354 FreeUnicodeStringTable (MouseDev->ControllerNameTable);
355 }
356 //
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
359 //
360 EmptyStatus = EFI_SUCCESS;
361 while (!EFI_ERROR (EmptyStatus)) {
362 EmptyStatus = In8042Data (IsaIo, &Data);
363 }
364
365 if (MouseDev != NULL) {
366 gBS->FreePool (MouseDev);
367 }
368
369 gBS->CloseProtocol (
370 Controller,
371 &gEfiDevicePathProtocolGuid,
372 This->DriverBindingHandle,
373 Controller
374 );
375
376 gBS->CloseProtocol (
377 Controller,
378 &gEfiIsaIoProtocolGuid,
379 This->DriverBindingHandle,
380 Controller
381 );
382
383 gBS->RestoreTPL (OldTpl);
384
385 return Status;
386 }
387
388 EFI_STATUS
389 EFIAPI
390 PS2MouseDriverStop (
391 IN EFI_DRIVER_BINDING_PROTOCOL *This,
392 IN EFI_HANDLE Controller,
393 IN UINTN NumberOfChildren,
394 IN EFI_HANDLE *ChildHandleBuffer
395 )
396 /*++
397
398 Routine Description:
399
400 Arguments:
401
402 Returns:
403
404 --*/
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
411 {
412 EFI_STATUS Status;
413 EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
414 PS2_MOUSE_DEV *MouseDev;
415 UINT8 Data;
416
417 Status = gBS->OpenProtocol (
418 Controller,
419 &gEfiSimplePointerProtocolGuid,
420 (VOID **) &SimplePointerProtocol,
421 This->DriverBindingHandle,
422 Controller,
423 EFI_OPEN_PROTOCOL_GET_PROTOCOL
424 );
425 if (EFI_ERROR (Status)) {
426 return EFI_SUCCESS;
427 }
428
429 MouseDev = PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol);
430
431 //
432 // Report that the keyboard is being disabled
433 //
434 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
435 EFI_PROGRESS_CODE,
436 EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE,
437 MouseDev->DevicePath
438 );
439
440 Status = gBS->UninstallProtocolInterface (
441 Controller,
442 &gEfiSimplePointerProtocolGuid,
443 &MouseDev->SimplePointerProtocol
444 );
445 if (EFI_ERROR (Status)) {
446 return Status;
447 }
448 //
449 // Disable mouse on keyboard controller
450 //
451 KbcDisableAux (MouseDev->IsaIo);
452
453 //
454 // Cancel mouse data polling timer, close timer event
455 //
456 gBS->SetTimer (MouseDev->TimerEvent, TimerCancel, 0);
457 gBS->CloseEvent (MouseDev->TimerEvent);
458
459 //
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
462 //
463 Status = EFI_SUCCESS;
464 while (!EFI_ERROR (Status)) {
465 Status = In8042Data (MouseDev->IsaIo, &Data);
466 }
467
468 gBS->CloseEvent (MouseDev->SimplePointerProtocol.WaitForInput);
469 FreeUnicodeStringTable (MouseDev->ControllerNameTable);
470 gBS->FreePool (MouseDev);
471
472 gBS->CloseProtocol (
473 Controller,
474 &gEfiDevicePathProtocolGuid,
475 This->DriverBindingHandle,
476 Controller
477 );
478
479 gBS->CloseProtocol (
480 Controller,
481 &gEfiIsaIoProtocolGuid,
482 This->DriverBindingHandle,
483 Controller
484 );
485
486 return EFI_SUCCESS;
487 }
488
489 EFI_STATUS
490 EFIAPI
491 MouseReset (
492 IN EFI_SIMPLE_POINTER_PROTOCOL *This,
493 IN BOOLEAN ExtendedVerification
494 )
495 /*++
496
497 Routine Description:
498
499 Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
500
501 Arguments:
502
503 This - Pointer of simple pointer Protocol.
504 ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
505
506 Returns:
507
508 EFI_SUCCESS - The command byte is written successfully.
509 EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
510
511 --*/
512 {
513 EFI_STATUS Status;
514 PS2_MOUSE_DEV *MouseDev;
515 EFI_TPL OldTpl;
516 BOOLEAN KeyboardEnable;
517 UINT8 Data;
518
519 MouseDev = PS2_MOUSE_DEV_FROM_THIS (This);
520
521 //
522 // Report reset progress code
523 //
524 REPORT_STATUS_CODE_WITH_DEVICE_PATH (
525 EFI_PROGRESS_CODE,
526 EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET,
527 MouseDev->DevicePath
528 );
529
530 KeyboardEnable = FALSE;
531
532 //
533 // Raise TPL to avoid keyboard operation impact
534 //
535 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
536
537 ZeroMem (&MouseDev->State, sizeof (EFI_SIMPLE_POINTER_STATE));
538 MouseDev->StateChanged = FALSE;
539
540 //
541 // Exhaust input data
542 //
543 Status = EFI_SUCCESS;
544 while (!EFI_ERROR (Status)) {
545 Status = In8042Data (MouseDev->IsaIo, &Data);
546 }
547
548 CheckKbStatus (MouseDev->IsaIo, &KeyboardEnable);
549
550 KbcDisableKb (MouseDev->IsaIo);
551
552 MouseDev->IsaIo->Io.Read (MouseDev->IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
553
554 //
555 // if there's data block on KBC data port, read it out
556 //
557 if ((Data & KBC_OUTB) == KBC_OUTB) {
558 MouseDev->IsaIo->Io.Read (MouseDev->IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Data);
559 }
560
561 Status = EFI_SUCCESS;
562 //
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
566 //
567 if (ExtendedVerification && CheckMouseConnect (MouseDev)) {
568 //
569 // Send mouse reset command and set mouse default configure
570 //
571 Status = PS2MouseReset (MouseDev->IsaIo);
572 if (EFI_ERROR (Status)) {
573 Status = EFI_DEVICE_ERROR;
574 goto Exit;
575 }
576
577 Status = PS2MouseSetSampleRate (MouseDev->IsaIo, MouseDev->SampleRate);
578 if (EFI_ERROR (Status)) {
579 Status = EFI_DEVICE_ERROR;
580 goto Exit;
581 }
582
583 Status = PS2MouseSetResolution (MouseDev->IsaIo, MouseDev->Resolution);
584 if (EFI_ERROR (Status)) {
585 Status = EFI_DEVICE_ERROR;
586 goto Exit;
587 }
588
589 Status = PS2MouseSetScaling (MouseDev->IsaIo, MouseDev->Scaling);
590 if (EFI_ERROR (Status)) {
591 Status = EFI_DEVICE_ERROR;
592 goto Exit;
593 }
594
595 Status = PS2MouseEnable (MouseDev->IsaIo);
596 if (EFI_ERROR (Status)) {
597 Status = EFI_DEVICE_ERROR;
598 goto Exit;
599 }
600 }
601 Exit:
602 gBS->RestoreTPL (OldTpl);
603
604 if (KeyboardEnable) {
605 KbcEnableKb (MouseDev->IsaIo);
606 }
607
608 return Status;
609 }
610
611 BOOLEAN
612 CheckMouseConnect (
613 IN PS2_MOUSE_DEV *MouseDev
614 )
615 /*++
616
617 Routine Description:
618
619 Check whether there is Ps/2 mouse device in system
620
621 Arguments:
622
623 PS2_MOUSE_DEV - Mouse Private Data Structure
624
625 Returns:
626
627 TRUE - Keyboard in System.
628 FALSE - Keyboard not in System.
629
630 --*/
631 {
632 EFI_STATUS Status;
633
634 Status = PS2MouseEnable (MouseDev->IsaIo);
635 if (!EFI_ERROR (Status)) {
636 return TRUE;
637 }
638
639 return FALSE;
640 }
641
642 EFI_STATUS
643 EFIAPI
644 MouseGetState (
645 IN EFI_SIMPLE_POINTER_PROTOCOL *This,
646 IN OUT EFI_SIMPLE_POINTER_STATE *State
647 )
648 /*++
649
650 Routine Description:
651
652 GC_TODO: Add function description
653
654 Arguments:
655
656 This - GC_TODO: add argument description
657 State - GC_TODO: add argument description
658
659 Returns:
660
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
664
665 --*/
666 {
667 PS2_MOUSE_DEV *MouseDev;
668 EFI_TPL OldTpl;
669
670 MouseDev = PS2_MOUSE_DEV_FROM_THIS (This);
671
672 if (State == NULL) {
673 return EFI_INVALID_PARAMETER;
674 }
675
676 if (!MouseDev->StateChanged) {
677 return EFI_NOT_READY;
678 }
679
680 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
681 CopyMem (State, &(MouseDev->State), sizeof (EFI_SIMPLE_POINTER_STATE));
682
683 //
684 // clear mouse state
685 //
686 MouseDev->State.RelativeMovementX = 0;
687 MouseDev->State.RelativeMovementY = 0;
688 MouseDev->State.RelativeMovementZ = 0;
689 MouseDev->StateChanged = FALSE;
690 gBS->RestoreTPL (OldTpl);
691
692 return EFI_SUCCESS;
693 }
694
695 VOID
696 EFIAPI
697 MouseWaitForInput (
698 IN EFI_EVENT Event,
699 IN VOID *Context
700 )
701 /*++
702
703 Routine Description:
704
705 Event notification function for SIMPLE_POINTER.WaitForInput event
706 Signal the event if there is input from mouse
707
708 Arguments:
709
710 Returns:
711
712 --*/
713 // GC_TODO: Event - add argument and description to function comment
714 // GC_TODO: Context - add argument and description to function comment
715 {
716 PS2_MOUSE_DEV *MouseDev;
717
718 MouseDev = (PS2_MOUSE_DEV *) Context;
719
720 //
721 // Someone is waiting on the mouse event, if there's
722 // input from mouse, signal the event
723 //
724 if (MouseDev->StateChanged) {
725 gBS->SignalEvent (Event);
726 }
727
728 }
729
730 VOID
731 EFIAPI
732 PollMouse (
733 IN EFI_EVENT Event,
734 IN VOID *Context
735 )
736 /*++
737
738 Routine Description:
739
740 Event notification function for TimerEvent event
741 If mouse device is connected to system, try to get the mouse packet data
742
743 Arguments:
744
745 Event - TimerEvent in PS2_MOUSE_DEV
746 Context - Pointer to PS2_MOUSE_DEV structure
747
748 Returns:
749
750 None
751
752 --*/
753 {
754 PS2_MOUSE_DEV *MouseDev;
755
756 MouseDev = (PS2_MOUSE_DEV *) Context;
757
758 //
759 // Polling mouse packet data
760 //
761 PS2MouseGetPacket (MouseDev);
762 }