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