]> git.proxmox.com Git - mirror_edk2.git/blame - IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c
1. Add Partial Keystroke Support in Ps2Kb drivers. See the Uefi2.3.1a chapter 11.2
[mirror_edk2.git] / IntelFrameworkModulePkg / Csm / BiosThunk / KeyboardDxe / BiosKeyboard.c
CommitLineData
bcecde14 1/** @file\r
2 ConsoleOut Routines that speak VGA.\r
3\r
4Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>\r
5\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions\r
8of the BSD License which accompanies this distribution. The\r
9full text of the license may be found at\r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "BiosKeyboard.h"\r
18\r
19//\r
20// EFI Driver Binding Protocol Instance\r
21//\r
22EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding = {\r
23 BiosKeyboardDriverBindingSupported,\r
24 BiosKeyboardDriverBindingStart,\r
25 BiosKeyboardDriverBindingStop,\r
26 0x3,\r
27 NULL,\r
28 NULL\r
29};\r
30\r
31\r
32/**\r
33 Enqueue the key.\r
34\r
35 @param Queue The queue to be enqueued.\r
36 @param KeyData The key data to be enqueued.\r
37\r
38 @retval EFI_NOT_READY The queue is full.\r
39 @retval EFI_SUCCESS Successfully enqueued the key data.\r
40\r
41**/\r
42EFI_STATUS\r
43Enqueue (\r
44 IN SIMPLE_QUEUE *Queue,\r
45 IN EFI_KEY_DATA *KeyData\r
46 )\r
47{\r
48 if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {\r
49 return EFI_NOT_READY;\r
50 }\r
51\r
52 CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));\r
53 Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;\r
54\r
55 return EFI_SUCCESS;\r
56}\r
57\r
58\r
59/**\r
60 Dequeue the key.\r
61 \r
62 @param Queue The queue to be dequeued.\r
63 @param KeyData The key data to be dequeued.\r
64\r
65 @retval EFI_NOT_READY The queue is empty.\r
66 @retval EFI_SUCCESS Successfully dequeued the key data.\r
67\r
68**/\r
69EFI_STATUS\r
70Dequeue (\r
71 IN SIMPLE_QUEUE *Queue,\r
72 IN EFI_KEY_DATA *KeyData\r
73 )\r
74{\r
75 if (Queue->Front == Queue->Rear) {\r
76 return EFI_NOT_READY;\r
77 }\r
78\r
79 CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));\r
80 Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT;\r
81\r
82 return EFI_SUCCESS;\r
83}\r
84\r
85\r
86/**\r
87 Check whether the queue is empty.\r
88 \r
89 @param Queue The queue to be checked.\r
90\r
91 @retval EFI_NOT_READY The queue is empty.\r
92 @retval EFI_SUCCESS The queue is not empty.\r
93\r
94**/\r
95EFI_STATUS\r
96CheckQueue (\r
97 IN SIMPLE_QUEUE *Queue\r
98 )\r
99{\r
100 if (Queue->Front == Queue->Rear) {\r
101 return EFI_NOT_READY;\r
102 }\r
103\r
104 return EFI_SUCCESS;\r
105}\r
106\r
107//\r
108// EFI Driver Binding Protocol Functions\r
109//\r
110\r
111/**\r
112 Check whether the driver supports this device.\r
113\r
114 @param This The Udriver binding protocol.\r
115 @param Controller The controller handle to check.\r
116 @param RemainingDevicePath The remaining device path.\r
117\r
118 @retval EFI_SUCCESS The driver supports this controller.\r
119 @retval other This device isn't supported.\r
120\r
121**/\r
122EFI_STATUS\r
123EFIAPI\r
124BiosKeyboardDriverBindingSupported (\r
125 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
126 IN EFI_HANDLE Controller,\r
127 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
128 )\r
129{\r
130 EFI_STATUS Status;\r
131 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
132 EFI_ISA_IO_PROTOCOL *IsaIo;\r
133\r
134 //\r
135 // See if the Legacy BIOS Protocol is available\r
136 //\r
137 Status = gBS->LocateProtocol (\r
138 &gEfiLegacyBiosProtocolGuid,\r
139 NULL,\r
140 (VOID **) &LegacyBios\r
141 );\r
142\r
143 if (EFI_ERROR (Status)) {\r
144 return Status;\r
145 }\r
146 //\r
147 // Open the IO Abstraction(s) needed to perform the supported test\r
148 //\r
149 Status = gBS->OpenProtocol (\r
150 Controller,\r
151 &gEfiIsaIoProtocolGuid,\r
152 (VOID **) &IsaIo,\r
153 This->DriverBindingHandle,\r
154 Controller,\r
155 EFI_OPEN_PROTOCOL_BY_DRIVER\r
156 );\r
157\r
158 if (EFI_ERROR (Status)) {\r
159 return Status;\r
160 }\r
161 //\r
162 // Use the ISA I/O Protocol to see if Controller is the Keyboard controller\r
163 //\r
164 if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {\r
165 Status = EFI_UNSUPPORTED;\r
166 }\r
167\r
168 gBS->CloseProtocol (\r
169 Controller,\r
170 &gEfiIsaIoProtocolGuid,\r
171 This->DriverBindingHandle,\r
172 Controller\r
173 );\r
174\r
175 return Status;\r
176}\r
177\r
178/**\r
179 Starts the device with this driver.\r
180\r
181 @param This The driver binding instance.\r
182 @param Controller Handle of device to bind driver to.\r
183 @param RemainingDevicePath Optional parameter use to pick a specific child\r
184 device to start.\r
185\r
186 @retval EFI_SUCCESS The controller is controlled by the driver.\r
187 @retval Other This controller cannot be started.\r
188\r
189**/\r
190EFI_STATUS\r
191EFIAPI\r
192BiosKeyboardDriverBindingStart (\r
193 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
194 IN EFI_HANDLE Controller,\r
195 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath\r
196 )\r
197{\r
198 EFI_STATUS Status;\r
199 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
200 EFI_ISA_IO_PROTOCOL *IsaIo;\r
201 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
202 EFI_IA32_REGISTER_SET Regs;\r
203 BOOLEAN CarryFlag;\r
204 EFI_PS2_POLICY_PROTOCOL *Ps2Policy;\r
205 UINT8 Command;\r
206 EFI_STATUS_CODE_VALUE StatusCode;\r
207\r
208 BiosKeyboardPrivate = NULL;\r
209 IsaIo = NULL;\r
210 StatusCode = 0;\r
211\r
212 //\r
213 // Get Ps2 policy to set. Will be use if present.\r
214 //\r
215 gBS->LocateProtocol (\r
216 &gEfiPs2PolicyProtocolGuid,\r
217 NULL,\r
218 (VOID **) &Ps2Policy\r
219 );\r
220\r
221 //\r
222 // See if the Legacy BIOS Protocol is available\r
223 //\r
224 Status = gBS->LocateProtocol (\r
225 &gEfiLegacyBiosProtocolGuid,\r
226 NULL,\r
227 (VOID **) &LegacyBios\r
228 );\r
229\r
230 if (EFI_ERROR (Status)) {\r
231 return Status;\r
232 }\r
233 //\r
234 // Open the IO Abstraction(s) needed\r
235 //\r
236 Status = gBS->OpenProtocol (\r
237 Controller,\r
238 &gEfiIsaIoProtocolGuid,\r
239 (VOID **) &IsaIo,\r
240 This->DriverBindingHandle,\r
241 Controller,\r
242 EFI_OPEN_PROTOCOL_BY_DRIVER\r
243 );\r
244 if (EFI_ERROR (Status)) {\r
245 return Status;\r
246 }\r
247\r
248 //\r
249 // Allocate the private device structure\r
250 //\r
251 BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV));\r
252 if (NULL == BiosKeyboardPrivate) {\r
253 Status = EFI_OUT_OF_RESOURCES;\r
254 goto Done;\r
255 }\r
256\r
257 //\r
258 // Initialize the private device structure\r
259 //\r
260 BiosKeyboardPrivate->Signature = BIOS_KEYBOARD_DEV_SIGNATURE;\r
261 BiosKeyboardPrivate->Handle = Controller;\r
262 BiosKeyboardPrivate->LegacyBios = LegacyBios;\r
263 BiosKeyboardPrivate->IsaIo = IsaIo;\r
264\r
265 BiosKeyboardPrivate->SimpleTextIn.Reset = BiosKeyboardReset;\r
266 BiosKeyboardPrivate->SimpleTextIn.ReadKeyStroke = BiosKeyboardReadKeyStroke;\r
267\r
268 BiosKeyboardPrivate->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER;\r
269 BiosKeyboardPrivate->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER;\r
270 BiosKeyboardPrivate->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;\r
271 BiosKeyboardPrivate->ExtendedKeyboard = TRUE;\r
272 \r
273 BiosKeyboardPrivate->Queue.Front = 0;\r
274 BiosKeyboardPrivate->Queue.Rear = 0;\r
275 BiosKeyboardPrivate->SimpleTextInputEx.Reset = BiosKeyboardResetEx;\r
276 BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = BiosKeyboardReadKeyStrokeEx;\r
277 BiosKeyboardPrivate->SimpleTextInputEx.SetState = BiosKeyboardSetState;\r
278 BiosKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = BiosKeyboardRegisterKeyNotify; \r
279 BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify; \r
280 InitializeListHead (&BiosKeyboardPrivate->NotifyList);\r
281\r
282 Status = gBS->HandleProtocol (\r
283 Controller,\r
284 &gEfiDevicePathProtocolGuid,\r
285 (VOID **) &BiosKeyboardPrivate->DevicePath\r
286 );\r
287\r
288 //\r
289 // Report that the keyboard is being enabled\r
290 //\r
291 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
292 EFI_PROGRESS_CODE,\r
293 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,\r
294 BiosKeyboardPrivate->DevicePath\r
295 );\r
296\r
297 //\r
298 // Setup the WaitForKey event\r
299 //\r
300 Status = gBS->CreateEvent (\r
301 EVT_NOTIFY_WAIT,\r
302 TPL_NOTIFY,\r
303 BiosKeyboardWaitForKey,\r
304 &(BiosKeyboardPrivate->SimpleTextIn),\r
305 &((BiosKeyboardPrivate->SimpleTextIn).WaitForKey)\r
306 );\r
307 if (EFI_ERROR (Status)) {\r
308 (BiosKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;\r
309 goto Done;\r
310 }\r
311 Status = gBS->CreateEvent (\r
312 EVT_NOTIFY_WAIT,\r
313 TPL_NOTIFY,\r
314 BiosKeyboardWaitForKeyEx,\r
315 &(BiosKeyboardPrivate->SimpleTextInputEx),\r
316 &(BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)\r
317 );\r
318 if (EFI_ERROR (Status)) {\r
319 BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;\r
320 goto Done;\r
321 } \r
322\r
323 //\r
324 // Setup a periodic timer, used for reading keystrokes at a fixed interval\r
325 //\r
326 Status = gBS->CreateEvent (\r
327 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
328 TPL_NOTIFY,\r
329 BiosKeyboardTimerHandler,\r
330 BiosKeyboardPrivate,\r
331 &BiosKeyboardPrivate->TimerEvent\r
332 );\r
333 if (EFI_ERROR (Status)) {\r
334 Status = EFI_OUT_OF_RESOURCES;\r
335 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
336 goto Done;\r
337 }\r
338\r
339 Status = gBS->SetTimer (\r
340 BiosKeyboardPrivate->TimerEvent,\r
341 TimerPeriodic,\r
342 KEYBOARD_TIMER_INTERVAL\r
343 );\r
344 if (EFI_ERROR (Status)) {\r
345 Status = EFI_OUT_OF_RESOURCES;\r
346 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;\r
347 goto Done;\r
348 }\r
349 \r
350 //\r
351 // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system\r
352 //\r
353 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
354 EFI_PROGRESS_CODE,\r
355 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,\r
356 BiosKeyboardPrivate->DevicePath\r
357 );\r
358\r
359 //\r
360 // Reset the keyboard device\r
361 //\r
362 Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset (\r
363 &BiosKeyboardPrivate->SimpleTextInputEx,\r
f6c014fb 364 FeaturePcdGet (PcdPs2KbdExtendedVerification)\r
bcecde14 365 );\r
bcecde14 366 if (EFI_ERROR (Status)) {\r
f6c014fb 367 DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status)); \r
bcecde14 368 StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;\r
369 goto Done;\r
370 }\r
371 //\r
372 // Do platform specific policy like port swapping and keyboard light default\r
373 //\r
374 if (Ps2Policy != NULL) {\r
375\r
376 Ps2Policy->Ps2InitHardware (Controller);\r
377\r
378 Command = 0;\r
379 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {\r
380 Command |= 4;\r
381 }\r
382\r
383 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {\r
384 Command |= 2;\r
385 }\r
386\r
387 if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {\r
388 Command |= 1;\r
389 }\r
390\r
391 KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
392 KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
393 KeyboardWrite (BiosKeyboardPrivate, Command);\r
394 //\r
395 // Call Legacy BIOS Protocol to set whatever is necessary\r
396 //\r
397 LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);\r
398 }\r
399 //\r
400 // Get Configuration\r
401 //\r
402 Regs.H.AH = 0xc0;\r
403 CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (\r
404 BiosKeyboardPrivate->LegacyBios,\r
405 0x15,\r
406 &Regs\r
407 );\r
408\r
409 if (!CarryFlag) {\r
410 //\r
411 // Check bit 6 of Feature Byte 2.\r
412 // If it is set, then Int 16 Func 09 is supported\r
413 //\r
414 if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {\r
415 //\r
416 // Get Keyboard Functionality\r
417 //\r
418 Regs.H.AH = 0x09;\r
419 CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (\r
420 BiosKeyboardPrivate->LegacyBios,\r
421 0x16,\r
422 &Regs\r
423 );\r
424\r
425 if (!CarryFlag) {\r
426 //\r
427 // Check bit 5 of AH.\r
428 // If it is set, then INT 16 Finc 10-12 are supported.\r
429 //\r
430 if ((Regs.H.AL & 0x40) != 0) {\r
431 //\r
432 // Set the flag to use INT 16 Func 10-12\r
433 //\r
434 BiosKeyboardPrivate->ExtendedKeyboard = TRUE;\r
435 }\r
436 }\r
437 }\r
438 }\r
f6c014fb 439 DEBUG ((EFI_D_INFO, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN)BiosKeyboardPrivate->ExtendedKeyboard));\r
bcecde14 440 //\r
441 // Install protocol interfaces for the keyboard device.\r
442 //\r
443 Status = gBS->InstallMultipleProtocolInterfaces (\r
444 &Controller,\r
445 &gEfiSimpleTextInProtocolGuid,\r
446 &BiosKeyboardPrivate->SimpleTextIn,\r
447 &gEfiSimpleTextInputExProtocolGuid,\r
448 &BiosKeyboardPrivate->SimpleTextInputEx,\r
449 NULL\r
450 );\r
451\r
452Done:\r
453 if (StatusCode != 0) {\r
454 //\r
455 // Report an Error Code for failing to start the keyboard device\r
456 //\r
457 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
458 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
459 StatusCode,\r
460 BiosKeyboardPrivate->DevicePath\r
461 );\r
462 }\r
463\r
464 if (EFI_ERROR (Status)) {\r
465\r
466 if (BiosKeyboardPrivate != NULL) { \r
467 if ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {\r
468 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
469 }\r
470\r
471 if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {\r
472 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx); \r
473 }\r
474 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
475\r
476 if (BiosKeyboardPrivate->TimerEvent != NULL) {\r
477 gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent); \r
478 }\r
479\r
480 FreePool (BiosKeyboardPrivate);\r
481 }\r
482\r
483 if (IsaIo != NULL) {\r
484 gBS->CloseProtocol (\r
485 Controller,\r
486 &gEfiIsaIoProtocolGuid,\r
487 This->DriverBindingHandle,\r
488 Controller\r
489 );\r
490 }\r
491 }\r
492\r
493 return Status;\r
494}\r
495\r
496/**\r
497 Stop the device handled by this driver.\r
498\r
499 @param This The driver binding protocol.\r
500 @param Controller The controller to release.\r
501 @param NumberOfChildren The number of handles in ChildHandleBuffer.\r
502 @param ChildHandleBuffer The array of child handle.\r
503\r
504 @retval EFI_SUCCESS The device was stopped.\r
505 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
506 @retval Others Fail to uninstall protocols attached on the device.\r
507\r
508**/\r
509EFI_STATUS\r
510EFIAPI\r
511BiosKeyboardDriverBindingStop (\r
512 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
513 IN EFI_HANDLE Controller,\r
514 IN UINTN NumberOfChildren,\r
515 IN EFI_HANDLE *ChildHandleBuffer\r
516 )\r
517{\r
518 EFI_STATUS Status;\r
519 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn;\r
520 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
521\r
522 //\r
523 // Disable Keyboard\r
524 //\r
525 Status = gBS->OpenProtocol (\r
526 Controller,\r
527 &gEfiSimpleTextInProtocolGuid,\r
528 (VOID **) &SimpleTextIn,\r
529 This->DriverBindingHandle,\r
530 Controller,\r
531 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
532 );\r
533 if (EFI_ERROR (Status)) {\r
534 return Status;\r
535 }\r
536\r
537 Status = gBS->OpenProtocol (\r
538 Controller,\r
539 &gEfiSimpleTextInputExProtocolGuid,\r
540 NULL,\r
541 This->DriverBindingHandle,\r
542 Controller,\r
543 EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r
544 );\r
545 if (EFI_ERROR (Status)) {\r
546 return Status;\r
547 }\r
548 \r
549 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn);\r
550\r
551 Status = gBS->UninstallMultipleProtocolInterfaces (\r
552 Controller,\r
553 &gEfiSimpleTextInProtocolGuid,\r
554 &BiosKeyboardPrivate->SimpleTextIn,\r
555 &gEfiSimpleTextInputExProtocolGuid,\r
556 &BiosKeyboardPrivate->SimpleTextInputEx,\r
557 NULL\r
558 );\r
559 if (EFI_ERROR (Status)) {\r
560 return Status;\r
561 }\r
562 //\r
563 // Release the IsaIo protocol on the controller handle\r
564 //\r
565 gBS->CloseProtocol (\r
566 Controller,\r
567 &gEfiIsaIoProtocolGuid,\r
568 This->DriverBindingHandle,\r
569 Controller\r
570 );\r
571\r
572 //\r
573 // Free other resources\r
574 //\r
575 gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);\r
576 gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);\r
577 gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);\r
578 BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);\r
579\r
580 FreePool (BiosKeyboardPrivate);\r
581\r
582 return EFI_SUCCESS;\r
583}\r
584\r
585/**\r
586 Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.\r
587\r
588 @param BiosKeyboardPrivate Keyboard instance pointer.\r
589\r
590 @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.\r
591\r
592**/\r
593UINT8\r
594KeyReadDataRegister (\r
595 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate\r
596 )\r
597{\r
598 UINT8 Data;\r
599\r
600 //\r
601 // Use IsaIo protocol to perform IO operations\r
602 //\r
603 BiosKeyboardPrivate->IsaIo->Io.Read (\r
604 BiosKeyboardPrivate->IsaIo,\r
605 EfiIsaIoWidthUint8,\r
606 BiosKeyboardPrivate->DataRegisterAddress,\r
607 1,\r
608 &Data\r
609 );\r
610\r
611 return Data;\r
612}\r
613\r
614/**\r
615 Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.\r
616\r
617 @param BiosKeyboardPrivate Keyboard instance pointer.\r
618\r
619 @return The status byte read from status register of Keyboard Controller from command port which often is port 64H.\r
620\r
621**/\r
622UINT8\r
623KeyReadStatusRegister (\r
624 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate\r
625 )\r
626{\r
627 UINT8 Data;\r
628\r
629 //\r
630 // Use IsaIo protocol to perform IO operations\r
631 //\r
632 BiosKeyboardPrivate->IsaIo->Io.Read (\r
633 BiosKeyboardPrivate->IsaIo,\r
634 EfiIsaIoWidthUint8,\r
635 BiosKeyboardPrivate->StatusRegisterAddress,\r
636 1,\r
637 &Data\r
638 );\r
639\r
640 return Data;\r
641}\r
642\r
643/**\r
644 Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.\r
645\r
646 @param BiosKeyboardPrivate Keyboard instance pointer.\r
647 @param Data Data byte to write.\r
648\r
649**/\r
650VOID\r
651KeyWriteCommandRegister (\r
652 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
653 IN UINT8 Data\r
654 )\r
655{\r
656 //\r
657 // Use IsaIo protocol to perform IO operations\r
658 //\r
659 BiosKeyboardPrivate->IsaIo->Io.Write (\r
660 BiosKeyboardPrivate->IsaIo,\r
661 EfiIsaIoWidthUint8,\r
662 BiosKeyboardPrivate->CommandRegisterAddress,\r
663 1,\r
664 &Data\r
665 );\r
666}\r
667\r
668/**\r
669 Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.\r
670\r
671 @param BiosKeyboardPrivate Keyboard instance pointer.\r
672 @param Data Data byte to write.\r
673\r
674**/\r
675VOID\r
676KeyWriteDataRegister (\r
677 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
678 IN UINT8 Data\r
679 )\r
680{\r
681 //\r
682 // Use IsaIo protocol to perform IO operations\r
683 //\r
684 BiosKeyboardPrivate->IsaIo->Io.Write (\r
685 BiosKeyboardPrivate->IsaIo,\r
686 EfiIsaIoWidthUint8,\r
687 BiosKeyboardPrivate->DataRegisterAddress,\r
688 1,\r
689 &Data\r
690 );\r
691}\r
692\r
693/**\r
694 Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.\r
695\r
696 @param BiosKeyboardPrivate Keyboard instance pointer.\r
697 @param Data The pointer for data that being read out.\r
698\r
699 @retval EFI_SUCCESS The data byte read out successfully.\r
700 @retval EFI_TIMEOUT Timeout occurred during reading out data byte.\r
701\r
702**/\r
703EFI_STATUS\r
704KeyboardRead (\r
705 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
706 OUT UINT8 *Data\r
707 )\r
708{\r
709 UINT32 TimeOut;\r
710 UINT32 RegFilled;\r
711\r
712 TimeOut = 0;\r
713 RegFilled = 0;\r
714\r
715 //\r
716 // wait till output buffer full then perform the read\r
717 //\r
718 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
719 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {\r
720 RegFilled = 1;\r
721 *Data = KeyReadDataRegister (BiosKeyboardPrivate);\r
722 break;\r
723 }\r
724\r
725 gBS->Stall (30);\r
726 }\r
727\r
728 if (RegFilled == 0) {\r
729 return EFI_TIMEOUT;\r
730 }\r
731\r
732 return EFI_SUCCESS;\r
733}\r
734\r
735/**\r
736 Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.\r
737\r
738 @param BiosKeyboardPrivate Keyboard instance pointer.\r
739 @param Data Data byte to write.\r
740\r
741 @retval EFI_SUCCESS The data byte is written successfully.\r
742 @retval EFI_TIMEOUT Timeout occurred during writing.\r
743\r
744**/\r
745EFI_STATUS\r
746KeyboardWrite (\r
747 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
748 IN UINT8 Data\r
749 )\r
750{\r
751 UINT32 TimeOut;\r
752 UINT32 RegEmptied;\r
753\r
754 TimeOut = 0;\r
755 RegEmptied = 0;\r
756\r
757 //\r
758 // wait for input buffer empty\r
759 //\r
760 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
761 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
762 RegEmptied = 1;\r
763 break;\r
764 }\r
765\r
766 gBS->Stall (30);\r
767 }\r
768\r
769 if (RegEmptied == 0) {\r
770 return EFI_TIMEOUT;\r
771 }\r
772 //\r
773 // Write it\r
774 //\r
775 KeyWriteDataRegister (BiosKeyboardPrivate, Data);\r
776\r
777 return EFI_SUCCESS;\r
778}\r
779\r
780/**\r
781 Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.\r
782\r
783 @param BiosKeyboardPrivate Keyboard instance pointer.\r
784 @param Data Command byte to write.\r
785\r
786 @retval EFI_SUCCESS The command byte is written successfully.\r
787 @retval EFI_TIMEOUT Timeout occurred during writing.\r
788\r
789**/\r
790EFI_STATUS\r
791KeyboardCommand (\r
792 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
793 IN UINT8 Data\r
794 )\r
795{\r
796 UINT32 TimeOut;\r
797 UINT32 RegEmptied;\r
798\r
799 TimeOut = 0;\r
800 RegEmptied = 0;\r
801\r
802 //\r
803 // Wait For Input Buffer Empty\r
804 //\r
805 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
806 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
807 RegEmptied = 1;\r
808 break;\r
809 }\r
810\r
811 gBS->Stall (30);\r
812 }\r
813\r
814 if (RegEmptied == 0) {\r
815 return EFI_TIMEOUT;\r
816 }\r
817 //\r
818 // issue the command\r
819 //\r
820 KeyWriteCommandRegister (BiosKeyboardPrivate, Data);\r
821\r
822 //\r
823 // Wait For Input Buffer Empty again\r
824 //\r
825 RegEmptied = 0;\r
826 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
827 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {\r
828 RegEmptied = 1;\r
829 break;\r
830 }\r
831\r
832 gBS->Stall (30);\r
833 }\r
834\r
835 if (RegEmptied == 0) {\r
836 return EFI_TIMEOUT;\r
837 }\r
838\r
839 return EFI_SUCCESS;\r
840}\r
841\r
842/**\r
843 Wait for a specific value to be presented in\r
844 Data register of Keyboard Controller by keyboard and then read it,\r
845 used in keyboard commands ack\r
846\r
847 @param BiosKeyboardPrivate Keyboard instance pointer.\r
848 @param Value The value to be waited for\r
849 @param WaitForValueTimeOut The limit of microseconds for timeout\r
850\r
851 @retval EFI_SUCCESS The command byte is written successfully.\r
852 @retval EFI_TIMEOUT Timeout occurred during writing.\r
853\r
854**/\r
855EFI_STATUS\r
856KeyboardWaitForValue (\r
857 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
858 IN UINT8 Value,\r
859 IN UINTN WaitForValueTimeOut\r
860 )\r
861{\r
862 UINT8 Data;\r
863 UINT32 TimeOut;\r
864 UINT32 SumTimeOut;\r
865 UINT32 GotIt;\r
866\r
867 GotIt = 0;\r
868 TimeOut = 0;\r
869 SumTimeOut = 0;\r
870\r
871 //\r
872 // Make sure the initial value of 'Data' is different from 'Value'\r
873 //\r
874 Data = 0;\r
875 if (Data == Value) {\r
876 Data = 1;\r
877 }\r
878 //\r
879 // Read from 8042 (multiple times if needed)\r
880 // until the expected value appears\r
881 // use SumTimeOut to control the iteration\r
882 //\r
883 while (1) {\r
884 //\r
885 // Perform a read\r
886 //\r
887 for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {\r
888 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {\r
889 Data = KeyReadDataRegister (BiosKeyboardPrivate);\r
890 break;\r
891 }\r
892\r
893 gBS->Stall (30);\r
894 }\r
895\r
896 SumTimeOut += TimeOut;\r
897\r
898 if (Data == Value) {\r
899 GotIt = 1;\r
900 break;\r
901 }\r
902\r
903 if (SumTimeOut >= WaitForValueTimeOut) {\r
904 break;\r
905 }\r
906 }\r
907 //\r
908 // Check results\r
909 //\r
910 if (GotIt != 0) {\r
911 return EFI_SUCCESS;\r
912 } else {\r
913 return EFI_TIMEOUT;\r
914 }\r
915\r
916}\r
917\r
918/**\r
919 Reads the next keystroke from the input device. The WaitForKey Event can \r
920 be used to test for existance of a keystroke via WaitForEvent () call.\r
921\r
922 @param BiosKeyboardPrivate Bioskeyboard driver private structure.\r
923 @param KeyData A pointer to a buffer that is filled in with the keystroke \r
924 state data for the key that was pressed.\r
925\r
926 @retval EFI_SUCCESS The keystroke information was returned.\r
927 @retval EFI_NOT_READY There was no keystroke data availiable.\r
928 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to \r
929 hardware errors.\r
930 @retval EFI_INVALID_PARAMETER KeyData is NULL. \r
931 \r
932**/\r
933EFI_STATUS\r
934KeyboardReadKeyStrokeWorker (\r
935 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,\r
936 OUT EFI_KEY_DATA *KeyData\r
937 )\r
938{\r
939 EFI_STATUS Status;\r
940 EFI_TPL OldTpl;\r
941 if (KeyData == NULL) {\r
942 return EFI_INVALID_PARAMETER;\r
943 }\r
944\r
945 //\r
946 // Use TimerEvent callback funciton to check whether there's any key pressed\r
947 //\r
948 \r
949 //\r
950 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.\r
951 // Csm will be used to check whether there is a key pending, but the csm will disable all \r
952 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer\r
953 // event will stop work during the compatibility16. And If a caller recursivly invoke this function, \r
954 // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period, \r
955 // e.g. usb keyboard driver. \r
956 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.\r
957 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.\r
958 //\r
959 gBS->Stall (1000);\r
960\r
961 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
962\r
963 BiosKeyboardTimerHandler (NULL, BiosKeyboardPrivate);\r
964 //\r
965 // If there's no key, just return\r
966 //\r
967 Status = CheckQueue (&BiosKeyboardPrivate->Queue);\r
968 if (EFI_ERROR (Status)) {\r
969 gBS->RestoreTPL (OldTpl);\r
970 return EFI_NOT_READY;\r
971 }\r
972\r
973 Status = Dequeue (&BiosKeyboardPrivate->Queue, KeyData);\r
974\r
975 gBS->RestoreTPL (OldTpl);\r
976\r
977 return EFI_SUCCESS;\r
978}\r
979\r
980//\r
981// EFI Simple Text In Protocol Functions\r
982//\r
983/**\r
984 Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.\r
985\r
986 @param This Pointer of simple text Protocol.\r
987 @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.\r
988\r
989 @retval EFI_SUCCESS The command byte is written successfully.\r
990 @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard.\r
991\r
992**/\r
993EFI_STATUS\r
994EFIAPI\r
995BiosKeyboardReset (\r
996 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
997 IN BOOLEAN ExtendedVerification\r
998 )\r
999{\r
1000 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
1001 EFI_STATUS Status;\r
1002 EFI_TPL OldTpl;\r
1003 UINT8 CommandByte;\r
1004 BOOLEAN MouseEnable;\r
1005 EFI_INPUT_KEY Key;\r
1006\r
1007 MouseEnable = FALSE;\r
1008 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
1009\r
1010 //\r
1011 // 1\r
1012 // Report reset progress code\r
1013 //\r
1014 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1015 EFI_PROGRESS_CODE,\r
1016 EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET,\r
1017 BiosKeyboardPrivate->DevicePath\r
1018 );\r
1019\r
1020 //\r
1021 // Report a Progress Code for clearing the keyboard buffer\r
1022 //\r
1023 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1024 EFI_PROGRESS_CODE,\r
1025 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER,\r
1026 BiosKeyboardPrivate->DevicePath\r
1027 );\r
1028\r
1029 //\r
1030 // 2\r
1031 // Raise TPL to avoid mouse operation impact\r
1032 //\r
1033 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1034\r
1035 //\r
1036 //\r
1037 // Exhaust output buffer data\r
1038 //\r
1039 do {\r
1040 Status = BiosKeyboardReadKeyStroke (\r
1041 This,\r
1042 &Key\r
1043 );\r
1044 } while (!EFI_ERROR (Status));\r
1045 //\r
1046 // 3\r
1047 // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H\r
1048 // if not skip step 4&5 and jump to step 6 to selftest KBC and report this\r
1049 // else go step 4\r
1050 //\r
1051 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {\r
1052 //\r
1053 // 4\r
1054 // CheckMouseStatus to decide enable it later or not\r
1055 //\r
1056 //\r
1057 // Read the command byte of KBC\r
1058 //\r
1059 Status = KeyboardCommand (\r
1060 BiosKeyboardPrivate,\r
1061 KBC_CMDREG_VIA64_CMDBYTE_R\r
1062 );\r
1063\r
1064 if (EFI_ERROR (Status)) {\r
1065 Status = EFI_DEVICE_ERROR;\r
1066 goto Exit;\r
1067 }\r
1068\r
1069 Status = KeyboardRead (\r
1070 BiosKeyboardPrivate,\r
1071 &CommandByte\r
1072 );\r
1073\r
1074 if (EFI_ERROR (Status)) {\r
1075 Status = EFI_DEVICE_ERROR;\r
1076 goto Exit;\r
1077 }\r
1078 //\r
1079 // Check mouse enabled or not before\r
1080 //\r
1081 if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {\r
1082 MouseEnable = FALSE;\r
1083 } else {\r
1084 MouseEnable = TRUE;\r
1085 }\r
1086 //\r
1087 // 5\r
1088 // disable mouse (via KBC) and Keyborad device\r
1089 //\r
1090 Status = KeyboardCommand (\r
1091 BiosKeyboardPrivate,\r
1092 KBC_CMDREG_VIA64_AUX_DISABLE\r
1093 );\r
1094\r
1095 if (EFI_ERROR (Status)) {\r
1096 Status = EFI_DEVICE_ERROR;\r
1097 goto Exit;\r
1098 }\r
1099\r
1100 Status = KeyboardCommand (\r
1101 BiosKeyboardPrivate,\r
1102 KBC_CMDREG_VIA64_KB_DISABLE\r
1103 );\r
1104\r
1105 if (EFI_ERROR (Status)) {\r
1106 Status = EFI_DEVICE_ERROR;\r
1107 goto Exit;\r
1108 }\r
1109\r
1110 } else {\r
1111 //\r
1112 // 6\r
1113 // KBC Self Test\r
1114 //\r
1115 //\r
1116 // Report a Progress Code for performing a self test on the keyboard controller\r
1117 //\r
1118 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1119 EFI_PROGRESS_CODE,\r
1120 EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST,\r
1121 BiosKeyboardPrivate->DevicePath\r
1122 );\r
1123\r
1124 Status = KeyboardCommand (\r
1125 BiosKeyboardPrivate,\r
1126 KBC_CMDREG_VIA64_KBC_SLFTEST\r
1127 );\r
1128 if (EFI_ERROR (Status)) {\r
1129 Status = EFI_DEVICE_ERROR;\r
1130 goto Exit;\r
1131 }\r
1132\r
1133 Status = KeyboardWaitForValue (\r
1134 BiosKeyboardPrivate,\r
1135 KBC_CMDECHO_KBCSLFTEST_OK,\r
1136 KEYBOARD_WAITFORVALUE_TIMEOUT\r
1137 );\r
1138 if (EFI_ERROR (Status)) {\r
1139 Status = EFI_DEVICE_ERROR;\r
1140 goto Exit;\r
1141 }\r
1142 }\r
1143 //\r
1144 // 7\r
1145 // Disable Mouse interface, enable Keyboard interface and declare selftest success\r
1146 //\r
1147 // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.\r
1148 //\r
1149 Status = KeyboardCommand (\r
1150 BiosKeyboardPrivate,\r
1151 KBC_CMDREG_VIA64_CMDBYTE_W\r
1152 );\r
1153\r
1154 if (EFI_ERROR (Status)) {\r
1155 Status = EFI_DEVICE_ERROR;\r
1156 goto Exit;\r
1157 }\r
1158\r
1159 //\r
1160 // Write 8042 Command Byte, set System Flag\r
1161 // While at the same time:\r
1162 // 1. disable mouse interface,\r
1163 // 2. enable kbd interface,\r
1164 // 3. enable PC/XT kbd translation mode\r
1165 // 4. enable mouse and kbd interrupts\r
1166 //\r
1167 //Command Byte bits:\r
1168 // 7: Reserved\r
1169 // 6: PC/XT translation mode\r
1170 // 5: Disable Auxiliary device interface\r
1171 // 4: Disable keyboard interface\r
1172 // 3: Reserved\r
1173 // 2: System Flag\r
1174 // 1: Enable Auxiliary device interrupt\r
1175 // 0: Enable Keyboard interrupt\r
1176 //\r
1177 CommandByte = 0;\r
1178 Status = KeyboardWrite (\r
1179 BiosKeyboardPrivate,\r
1180 (UINT8) ((CommandByte &\r
1181 (~KB_CMMBYTE_DISABLE_KB)) |\r
1182 KB_CMMBYTE_KSCAN2UNI_COV |\r
1183 KB_CMMBYTE_ENABLE_AUXINT |\r
1184 KB_CMMBYTE_ENABLE_KBINT |\r
1185 KB_CMMBYTE_SLFTEST_SUCC |\r
1186 KB_CMMBYTE_DISABLE_AUX)\r
1187 );\r
1188\r
1189 //\r
1190 // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,\r
1191 // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.\r
1192 // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,\r
1193 // Real reset will not do.\r
1194 //\r
1195 if (ExtendedVerification && CheckKeyboardConnect (BiosKeyboardPrivate)) {\r
1196 //\r
1197 // 8\r
1198 // Send keyboard reset command then read ACK\r
1199 //\r
1200 Status = KeyboardWrite (\r
1201 BiosKeyboardPrivate,\r
1202 KBC_INPBUF_VIA60_KBRESET\r
1203 );\r
1204\r
1205 if (EFI_ERROR (Status)) {\r
1206 Status = EFI_DEVICE_ERROR;\r
1207 goto Exit;\r
1208 }\r
1209\r
1210 Status = KeyboardWaitForValue (\r
1211 BiosKeyboardPrivate,\r
1212 KBC_CMDECHO_ACK,\r
1213 KEYBOARD_WAITFORVALUE_TIMEOUT\r
1214 );\r
1215\r
1216 if (EFI_ERROR (Status)) {\r
1217 Status = EFI_DEVICE_ERROR;\r
1218 goto Exit;\r
1219 }\r
1220 //\r
1221 // 9\r
1222 // Wait for keyboard return test OK.\r
1223 //\r
1224 Status = KeyboardWaitForValue (\r
1225 BiosKeyboardPrivate,\r
1226 KBC_CMDECHO_BATTEST_OK,\r
1227 KEYBOARD_WAITFORVALUE_TIMEOUT\r
1228 );\r
1229\r
1230 if (EFI_ERROR (Status)) {\r
1231 Status = EFI_DEVICE_ERROR;\r
1232 goto Exit;\r
1233 }\r
1234 //\r
1235 // 10\r
1236 // set keyboard scan code set = 02 (standard configuration)\r
1237 //\r
1238 Status = KeyboardWrite (\r
1239 BiosKeyboardPrivate,\r
1240 KBC_INPBUF_VIA60_KBSCODE\r
1241 );\r
1242 if (EFI_ERROR (Status)) {\r
1243 Status = EFI_DEVICE_ERROR;\r
1244 goto Exit;\r
1245 }\r
1246\r
1247 Status = KeyboardWaitForValue (\r
1248 BiosKeyboardPrivate,\r
1249 KBC_CMDECHO_ACK,\r
1250 KEYBOARD_WAITFORVALUE_TIMEOUT\r
1251 );\r
1252\r
1253 if (EFI_ERROR (Status)) {\r
1254 Status = EFI_DEVICE_ERROR;\r
1255 goto Exit;\r
1256 }\r
1257\r
1258 Status = KeyboardWrite (\r
1259 BiosKeyboardPrivate,\r
1260 KBC_INPBUF_VIA60_SCODESET2\r
1261 );\r
1262 if (EFI_ERROR (Status)) {\r
1263 Status = EFI_DEVICE_ERROR;\r
1264 goto Exit;\r
1265 }\r
1266\r
1267 Status = KeyboardWaitForValue (\r
1268 BiosKeyboardPrivate,\r
1269 KBC_CMDECHO_ACK,\r
1270 KEYBOARD_WAITFORVALUE_TIMEOUT\r
1271 );\r
1272\r
1273 if (EFI_ERROR (Status)) {\r
1274 Status = EFI_DEVICE_ERROR;\r
1275 goto Exit;\r
1276 }\r
1277 //\r
1278 // 11\r
1279 // enable keyboard itself (not via KBC) by writing CMD F4 via 60H\r
1280 //\r
1281 Status = KeyboardWrite (\r
1282 BiosKeyboardPrivate,\r
1283 KBC_INPBUF_VIA60_KBEN\r
1284 );\r
1285 if (EFI_ERROR (Status)) {\r
1286 Status = EFI_DEVICE_ERROR;\r
1287 goto Exit;\r
1288 }\r
1289\r
1290 Status = KeyboardWaitForValue (\r
1291 BiosKeyboardPrivate,\r
1292 KBC_CMDECHO_ACK,\r
1293 KEYBOARD_WAITFORVALUE_TIMEOUT\r
1294 );\r
1295\r
1296 if (EFI_ERROR (Status)) {\r
1297 Status = EFI_DEVICE_ERROR;\r
1298 goto Exit;\r
1299 }\r
1300 //\r
1301 // 12\r
1302 // Additional validation, do it as follow:\r
1303 // 1). check for status register of PARE && TIM via 64H\r
1304 // 2). perform KB checking by writing ABh via 64H\r
1305 //\r
1306 if ((KeyReadStatusRegister (BiosKeyboardPrivate) & (KBC_STSREG_VIA64_PARE | KBC_STSREG_VIA64_TIM)) != 0) {\r
1307 Status = EFI_DEVICE_ERROR;\r
1308 goto Exit;\r
1309 }\r
1310\r
1311 Status = KeyboardCommand (\r
1312 BiosKeyboardPrivate,\r
1313 KBC_CMDREG_VIA64_KB_CKECK\r
1314 );\r
1315 if (EFI_ERROR (Status)) {\r
1316 Status = EFI_DEVICE_ERROR;\r
1317 goto Exit;\r
1318 }\r
1319\r
1320 Status = KeyboardWaitForValue (\r
1321 BiosKeyboardPrivate,\r
1322 KBC_CMDECHO_KBCHECK_OK,\r
1323 KEYBOARD_WAITFORVALUE_TIMEOUT\r
1324 );\r
1325\r
1326 if (EFI_ERROR (Status)) {\r
1327 Status = EFI_DEVICE_ERROR;\r
1328 goto Exit;\r
1329 }\r
1330 }\r
1331 //\r
1332 // 13\r
1333 // Done for validating keyboard. Enable keyboard (via KBC)\r
1334 // and recover the command byte to proper value\r
1335 //\r
1336 Status = KeyboardCommand (\r
1337 BiosKeyboardPrivate,\r
1338 KBC_CMDREG_VIA64_KB_ENABLE\r
1339 );\r
1340\r
1341 if (EFI_ERROR (Status)) {\r
1342 Status = EFI_DEVICE_ERROR;\r
1343 goto Exit;\r
1344 }\r
1345\r
1346 //\r
1347 // 14\r
1348 // conditionally enable mouse (via KBC)\r
1349 //\r
1350 if (MouseEnable) {\r
1351 Status = KeyboardCommand (\r
1352 BiosKeyboardPrivate,\r
1353 KBC_CMDREG_VIA64_AUX_ENABLE\r
1354 );\r
1355\r
1356 if (EFI_ERROR (Status)) {\r
1357 Status = EFI_DEVICE_ERROR;\r
1358\r
1359 }\r
1360 }\r
1361\r
1362Exit:\r
1363 //\r
1364 // 15\r
1365 // resume priority of task level\r
1366 //\r
1367 gBS->RestoreTPL (OldTpl);\r
1368\r
1369 return Status;\r
1370\r
1371}\r
1372\r
1373/**\r
1374 Read out the scan code of the key that has just been stroked.\r
1375\r
1376 @param This Pointer of simple text Protocol.\r
1377 @param Key Pointer for store the key that read out.\r
1378\r
1379 @retval EFI_SUCCESS The key is read out successfully.\r
1380 @retval other The key reading failed.\r
1381\r
1382**/\r
1383EFI_STATUS\r
1384EFIAPI\r
1385BiosKeyboardReadKeyStroke (\r
1386 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,\r
1387 OUT EFI_INPUT_KEY *Key\r
1388 )\r
1389{\r
1390 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
1391 EFI_STATUS Status;\r
1392 EFI_KEY_DATA KeyData;\r
1393\r
1394 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
1395\r
1396 Status = KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, &KeyData);\r
1397 if (EFI_ERROR (Status)) {\r
1398 return Status;\r
1399 }\r
1400\r
1401 CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY)); \r
1402\r
1403 return EFI_SUCCESS;\r
1404}\r
1405\r
1406/**\r
1407 Waiting on the keyboard event, if there's any key pressed by the user, signal the event\r
1408\r
1409 @param Event The event that be siganlled when any key has been stroked.\r
1410 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.\r
1411\r
1412**/\r
1413VOID\r
1414EFIAPI\r
1415BiosKeyboardWaitForKey (\r
1416 IN EFI_EVENT Event,\r
1417 IN VOID *Context\r
1418 )\r
1419{\r
1420 //\r
1421 // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.\r
1422 // Csm will be used to check whether there is a key pending, but the csm will disable all\r
1423 // interrupt before switch to compatibility16, which mean all the efiCompatibility timer\r
1424 // event will stop work during the compatibility16. And If a caller recursivly invoke this function,\r
1425 // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,\r
1426 // e.g. usb keyboard driver.\r
1427 // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.\r
1428 // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.\r
1429 //\r
1430 gBS->Stall (1000);\r
1431 //\r
1432 // Use TimerEvent callback funciton to check whether there's any key pressed\r
1433 //\r
1434 BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));\r
1435\r
1436 if (!EFI_ERROR (BiosKeyboardCheckForKey (Context))) {\r
1437 gBS->SignalEvent (Event);\r
1438 }\r
1439}\r
1440\r
1441/**\r
1442 Check key buffer to get the key stroke status.\r
1443\r
1444 @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.\r
1445 \r
1446 @retval EFI_SUCCESS A key is being pressed now.\r
1447 @retval Other No key is now pressed.\r
1448\r
1449**/\r
1450EFI_STATUS\r
1451EFIAPI\r
1452BiosKeyboardCheckForKey (\r
1453 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This\r
1454 )\r
1455{\r
1456 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
1457\r
1458 BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
1459\r
1460 return CheckQueue (&BiosKeyboardPrivate->Queue);\r
1461}\r
1462//\r
1463// Private worker functions\r
1464//\r
1465#define TABLE_END 0x0\r
1466\r
1467typedef struct _CONVERT_TABLE_ENTRY {\r
1468 UINT16 ScanCode;\r
1469 UINT16 EfiScanCode;\r
1470} CONVERT_TABLE_ENTRY;\r
1471\r
1472CONVERT_TABLE_ENTRY mConvertTable[] = {\r
1473 {\r
1474 0x47,\r
1475 SCAN_HOME\r
1476 },\r
1477 {\r
1478 0x48,\r
1479 SCAN_UP\r
1480 },\r
1481 {\r
1482 0x49,\r
1483 SCAN_PAGE_UP\r
1484 },\r
1485 {\r
1486 0x4b,\r
1487 SCAN_LEFT\r
1488 },\r
1489 {\r
1490 0x4d,\r
1491 SCAN_RIGHT\r
1492 },\r
1493 {\r
1494 0x4f,\r
1495 SCAN_END\r
1496 },\r
1497 {\r
1498 0x50,\r
1499 SCAN_DOWN\r
1500 },\r
1501 {\r
1502 0x51,\r
1503 SCAN_PAGE_DOWN\r
1504 },\r
1505 {\r
1506 0x52,\r
1507 SCAN_INSERT\r
1508 },\r
1509 {\r
1510 0x53,\r
1511 SCAN_DELETE\r
1512 },\r
1513 //\r
1514 // Function Keys are only valid if KeyChar == 0x00\r
1515 // This function does not require KeyChar to be 0x00\r
1516 //\r
1517 {\r
1518 0x3b,\r
1519 SCAN_F1\r
1520 },\r
1521 {\r
1522 0x3c,\r
1523 SCAN_F2\r
1524 },\r
1525 {\r
1526 0x3d,\r
1527 SCAN_F3\r
1528 },\r
1529 {\r
1530 0x3e,\r
1531 SCAN_F4\r
1532 },\r
1533 {\r
1534 0x3f,\r
1535 SCAN_F5\r
1536 },\r
1537 {\r
1538 0x40,\r
1539 SCAN_F6\r
1540 },\r
1541 {\r
1542 0x41,\r
1543 SCAN_F7\r
1544 },\r
1545 {\r
1546 0x42,\r
1547 SCAN_F8\r
1548 },\r
1549 {\r
1550 0x43,\r
1551 SCAN_F9\r
1552 },\r
1553 {\r
1554 0x44,\r
1555 SCAN_F10\r
1556 },\r
1557 {\r
1558 0x85,\r
1559 SCAN_F11\r
1560 },\r
1561 {\r
1562 0x86,\r
1563 SCAN_F12\r
1564 },\r
1565 //\r
1566 // Convert ALT + Fn keys\r
1567 //\r
1568 {\r
1569 0x68,\r
1570 SCAN_F1\r
1571 },\r
1572 {\r
1573 0x69,\r
1574 SCAN_F2\r
1575 },\r
1576 {\r
1577 0x6a,\r
1578 SCAN_F3\r
1579 },\r
1580 {\r
1581 0x6b,\r
1582 SCAN_F4\r
1583 },\r
1584 {\r
1585 0x6c,\r
1586 SCAN_F5\r
1587 },\r
1588 {\r
1589 0x6d,\r
1590 SCAN_F6\r
1591 },\r
1592 {\r
1593 0x6e,\r
1594 SCAN_F7\r
1595 },\r
1596 {\r
1597 0x6f,\r
1598 SCAN_F8\r
1599 },\r
1600 {\r
1601 0x70,\r
1602 SCAN_F9\r
1603 },\r
1604 {\r
1605 0x71,\r
1606 SCAN_F10\r
1607 },\r
1608 {\r
1609 TABLE_END,\r
1610 SCAN_NULL\r
1611 },\r
1612};\r
1613\r
1614/**\r
1615 Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.\r
1616\r
1617 @param KeyChar Unicode of key.\r
1618 @param ScanCode Scan code of key.\r
1619\r
1620 @return The value of EFI Scancode for the key. \r
1621 @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.\r
1622\r
1623**/\r
1624UINT16\r
1625ConvertToEFIScanCode (\r
1626 IN CHAR16 KeyChar,\r
1627 IN UINT16 ScanCode\r
1628 )\r
1629{\r
1630 UINT16 EfiScanCode;\r
1631 UINT16 Index;\r
1632\r
1633 if (KeyChar == CHAR_ESC) {\r
1634 EfiScanCode = SCAN_ESC;\r
1635 } else if (KeyChar == 0x00 || KeyChar == 0xe0) {\r
1636 //\r
1637 // Movement & Function Keys\r
1638 //\r
1639 for (Index = 0; (Index < sizeof (mConvertTable) / sizeof (CONVERT_TABLE_ENTRY)) && (mConvertTable[Index].ScanCode != TABLE_END); Index += 1) {\r
1640 if (ScanCode == mConvertTable[Index].ScanCode) {\r
1641 return mConvertTable[Index].EfiScanCode;\r
1642 }\r
1643 }\r
1644 //\r
1645 // Reach Table end, return default value\r
1646 //\r
1647 return SCAN_NULL;\r
1648 } else {\r
1649 return SCAN_NULL;\r
1650 }\r
1651\r
1652 return EfiScanCode;\r
1653}\r
1654\r
1655/**\r
1656 Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command\r
1657 If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device\r
1658 should not be in system. \r
1659\r
1660 @param BiosKeyboardPrivate Keyboard Private Data Struture\r
1661\r
1662 @retval TRUE Keyboard in System.\r
1663 @retval FALSE Keyboard not in System.\r
1664\r
1665**/\r
1666BOOLEAN\r
1667CheckKeyboardConnect (\r
1668 IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate\r
1669 )\r
1670{\r
1671 EFI_STATUS Status;\r
1672\r
1673 Status = EFI_SUCCESS;\r
1674 //\r
1675 // enable keyboard itself and wait for its ack\r
1676 // If can't receive ack, Keyboard should not be connected.\r
1677 //\r
1678 Status = KeyboardWrite (\r
1679 BiosKeyboardPrivate,\r
1680 KBC_INPBUF_VIA60_KBEN\r
1681 );\r
1682 if (EFI_ERROR (Status)) {\r
f6c014fb 1683 DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));\r
1684 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1685 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1686 EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR,\r
1687 BiosKeyboardPrivate->DevicePath\r
1688 );\r
bcecde14 1689 return FALSE;\r
1690 }\r
1691\r
1692 Status = KeyboardWaitForValue (\r
1693 BiosKeyboardPrivate,\r
1694 KBC_CMDECHO_ACK,\r
1695 KEYBOARD_WAITFORVALUE_TIMEOUT\r
1696 );\r
1697\r
1698 if (EFI_ERROR (Status)) {\r
f6c014fb 1699 DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n"));\r
1700 REPORT_STATUS_CODE_WITH_DEVICE_PATH (\r
1701 EFI_ERROR_CODE | EFI_ERROR_MINOR,\r
1702 EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR,\r
1703 BiosKeyboardPrivate->DevicePath\r
1704 );\r
bcecde14 1705 return FALSE;\r
1706 }\r
1707\r
1708 return TRUE;\r
1709}\r
1710\r
1711/**\r
1712 Timer event handler: read a series of key stroke from 8042\r
1713 and put them into memory key buffer. \r
1714 It is registered as running under TPL_NOTIFY\r
1715 \r
1716 @param Event The timer event\r
1717 @param Context A BIOS_KEYBOARD_DEV pointer\r
1718\r
1719**/\r
1720VOID\r
1721EFIAPI\r
1722BiosKeyboardTimerHandler (\r
1723 IN EFI_EVENT Event,\r
1724 IN VOID *Context\r
1725 )\r
1726{\r
1727 EFI_TPL OldTpl;\r
1728 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
1729 EFI_IA32_REGISTER_SET Regs;\r
1730 UINT8 KbFlag1; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1\r
1731 UINT8 KbFlag2; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2\r
1732 EFI_KEY_DATA KeyData;\r
1733 LIST_ENTRY *Link;\r
1734 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
1735\r
1736 BiosKeyboardPrivate = Context;\r
1737\r
1738 //\r
1739 // Enter critical section\r
1740 //\r
1741 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
1742\r
1743 //\r
1744 // if there is no key present, just return\r
1745 //\r
1746 if (BiosKeyboardPrivate->ExtendedKeyboard) {\r
1747 Regs.H.AH = 0x11;\r
1748 } else {\r
1749 Regs.H.AH = 0x01;\r
1750 }\r
1751\r
1752 BiosKeyboardPrivate->LegacyBios->Int86 (\r
1753 BiosKeyboardPrivate->LegacyBios,\r
1754 0x16,\r
1755 &Regs\r
1756 );\r
1757 if (Regs.X.Flags.ZF != 0) {\r
1758 gBS->RestoreTPL (OldTpl);\r
1759 return;\r
1760 } \r
1761\r
1762 //\r
1763 // Read the key\r
1764 //\r
1765 if (BiosKeyboardPrivate->ExtendedKeyboard) {\r
1766 Regs.H.AH = 0x10;\r
1767 } else {\r
1768 Regs.H.AH = 0x00;\r
1769 }\r
1770\r
1771 BiosKeyboardPrivate->LegacyBios->Int86 (\r
1772 BiosKeyboardPrivate->LegacyBios,\r
1773 0x16,\r
1774 &Regs\r
1775 );\r
1776\r
1777 KeyData.Key.ScanCode = (UINT16) Regs.H.AH;\r
1778 KeyData.Key.UnicodeChar = (UINT16) Regs.H.AL;\r
f6c014fb 1779 DEBUG ((\r
1780 EFI_D_INFO,\r
1781 "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",\r
1782 KeyData.Key.ScanCode,\r
1783 KeyData.Key.UnicodeChar\r
1784 ));\r
1785 \r
bcecde14 1786 KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;\r
1787 KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;\r
1788 //\r
1789 // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then \r
1790 // Int 16 depend KB buffer and some key bits in BDA to translate the scancode to ASCII code, and return both the scancode and ASCII \r
1791 // code to Int 16 caller. This translation process works well if the Int 9 could response user input in time. But in Tiano enviorment, the Int 9 \r
1792 // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when \r
1793 // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit \r
1794 // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode \r
1795 // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers \r
1796 // performance, like USB.\r
1797 //\r
1798 // 1. If CTRL or ALT release code is missed, all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In \r
1799 // this case, the KB input seems fail to work, and user input is blocked. To solve the problem, we can help to clear the CTRL or ALT flag in BDA \r
1800 // after every Int 16 finish. Thus persist to press CTRL or ALT has same effection as only press one time. It is Ok, since user not often use the \r
1801 // CTRL and ALT.\r
1802 //\r
1803 // 2. If SHIFT release code is missed, all later lowercase input will become capital. This is ugly, but not block user input. If user press the lost \r
1804 // SHIFT again, the lowercase will come back to normal. Since user often use the SHIFT, it is not reasonable to help to clear the SHIFT flag in BDA,\r
1805 // which will let persist to press SHIFT has same effection as only press one time. \r
1806 //\r
1807 //0040h:0017h - KEYBOARD - STATUS FLAGS 1\r
1808 // 7 INSert active\r
1809 // 6 Caps Lock active\r
1810 // 5 Num Lock active\r
1811 // 4 Scroll Lock active\r
1812 // 3 either Alt pressed\r
1813 // 2 either Ctrl pressed\r
1814 // 1 Left Shift pressed\r
1815 // 0 Right Shift pressed\r
1816\r
1817\r
1818 //\r
1819 // Clear the CTRL and ALT BDA flag\r
1820 //\r
1821 KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1\r
1822 KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2\r
1823\r
f6c014fb 1824 DEBUG_CODE (\r
1825 {\r
1826 if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {\r
1827 DEBUG ((EFI_D_INFO, "[KBD]Caps Lock Key is pressed.\n"));\r
1828 }\r
1829 if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {\r
1830 DEBUG ((EFI_D_INFO, "[KBD]Num Lock Key is pressed.\n"));\r
1831 }\r
1832 if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {\r
1833 DEBUG ((EFI_D_INFO, "[KBD]Scroll Lock Key is pressed.\n"));\r
1834 } \r
1835 if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {\r
1836 if ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) {\r
1837 DEBUG ((EFI_D_INFO, "[KBD]Left Alt Key is pressed.\n"));\r
1838 } else {\r
1839 DEBUG ((EFI_D_INFO, "[KBD]Right Alt Key is pressed.\n"));\r
1840 }\r
1841 } \r
1842 if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {\r
1843 if ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) {\r
1844 DEBUG ((EFI_D_INFO, "[KBD]Left Ctrl Key is pressed.\n"));\r
1845 } else {\r
1846 DEBUG ((EFI_D_INFO, "[KBD]Right Ctrl Key is pressed.\n"));\r
1847 }\r
1848 } \r
1849 if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {\r
1850 DEBUG ((EFI_D_INFO, "[KBD]Left Shift Key is pressed.\n"));\r
1851 }\r
1852 if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {\r
1853 DEBUG ((EFI_D_INFO, "[KBD]Right Shift Key is pressed.\n"));\r
1854 }\r
1855 }\r
1856 );\r
1857\r
bcecde14 1858 //\r
1859 // Record toggle state\r
1860 //\r
1861 if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {\r
1862 KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;\r
1863 }\r
1864 if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {\r
1865 KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;\r
1866 }\r
1867 if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {\r
1868 KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;\r
1869 }\r
1870 //\r
1871 // Record shift state\r
1872 // BUGBUG: Need add Menu key and Left/Right Logo key state in the future\r
1873 // \r
1874 if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {\r
1875 KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) ? EFI_LEFT_ALT_PRESSED : EFI_RIGHT_ALT_PRESSED;\r
1876 } \r
1877 if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {\r
1878 KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) ? EFI_LEFT_CONTROL_PRESSED : EFI_RIGHT_CONTROL_PRESSED;\r
1879 } \r
1880 if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {\r
1881 KeyData.KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;\r
1882 }\r
1883 if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {\r
1884 KeyData.KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;\r
1885 }\r
1886\r
1887 //\r
1888 // Clear left alt and left ctrl BDA flag\r
1889 //\r
1890 KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);\r
1891 *((UINT8 *) (UINTN) 0x418) = KbFlag2;\r
1892 KbFlag1 &= ~0x0C; \r
1893 *((UINT8 *) (UINTN) 0x417) = KbFlag1; \r
1894\r
1895 \r
1896 //\r
1897 // Output EFI input key and shift/toggle state\r
1898 //\r
1899 if (KeyData.Key.UnicodeChar == CHAR_NULL || KeyData.Key.UnicodeChar == CHAR_SCANCODE || KeyData.Key.UnicodeChar == CHAR_ESC) {\r
1900 KeyData.Key.ScanCode = ConvertToEFIScanCode (KeyData.Key.UnicodeChar, KeyData.Key.ScanCode);\r
1901 KeyData.Key.UnicodeChar = CHAR_NULL;\r
1902 } else {\r
1903 KeyData.Key.ScanCode = SCAN_NULL;\r
1904 }\r
1905\r
1906 //\r
1907 // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.\r
1908 //\r
1909 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
1910 if (KeyData.Key.UnicodeChar >= 1 && KeyData.Key.UnicodeChar <= 26) {\r
1911 if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ==\r
1912 ((KeyData.KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0)\r
1913 ) {\r
1914 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'a' - 1);\r
1915 } else {\r
1916 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'A' - 1);\r
1917 }\r
1918 }\r
1919 }\r
1920\r
f6c014fb 1921 DEBUG ((\r
1922 EFI_D_INFO,\r
1923 "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",\r
1924 KeyData.Key.ScanCode,\r
1925 KeyData.Key.UnicodeChar\r
1926 ));\r
1927\r
bcecde14 1928 //\r
1929 // Need not return associated shift state if a class of printable characters that\r
1930 // are normally adjusted by shift modifiers.\r
1931 // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.\r
1932 //\r
1933 if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') ||\r
1934 (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z')\r
1935 ) {\r
f6c014fb 1936 DEBUG ((EFI_D_INFO, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n"));\r
bcecde14 1937 KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);\r
1938 }\r
1939\r
1940 //\r
1941 // Invoke notification functions if exist\r
1942 //\r
1943 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
1944 CurrentNotify = CR (\r
1945 Link, \r
1946 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
1947 NotifyEntry, \r
1948 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
1949 );\r
1950 if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) { \r
1951 CurrentNotify->KeyNotificationFn (&KeyData);\r
1952 }\r
1953 }\r
1954\r
1955 //\r
1956 // Convert the Ctrl+[a-z] to Ctrl+[1-26]\r
1957 //\r
1958 if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {\r
1959 if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {\r
1960 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'a' + 1);\r
1961 } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {\r
1962 KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'A' + 1);\r
1963 }\r
1964 }\r
1965 Enqueue (&BiosKeyboardPrivate->Queue, &KeyData);\r
1966 //\r
1967 // Leave critical section and return\r
1968 //\r
1969 gBS->RestoreTPL (OldTpl);\r
1970\r
1971 return ; \r
1972}\r
1973\r
1974/**\r
1975 Free keyboard notify list.\r
1976\r
1977 @param ListHead The list head\r
1978\r
1979 @retval EFI_SUCCESS Free the notify list successfully\r
1980 @retval EFI_INVALID_PARAMETER ListHead is invalid.\r
1981\r
1982**/\r
1983EFI_STATUS\r
1984BiosKeyboardFreeNotifyList (\r
1985 IN OUT LIST_ENTRY *ListHead\r
1986 )\r
1987{\r
1988 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;\r
1989\r
1990 if (ListHead == NULL) {\r
1991 return EFI_INVALID_PARAMETER;\r
1992 }\r
1993 while (!IsListEmpty (ListHead)) {\r
1994 NotifyNode = CR (\r
1995 ListHead->ForwardLink, \r
1996 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
1997 NotifyEntry, \r
1998 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
1999 );\r
2000 RemoveEntryList (ListHead->ForwardLink);\r
2001 gBS->FreePool (NotifyNode);\r
2002 }\r
2003\r
2004 return EFI_SUCCESS;\r
2005}\r
2006\r
2007/**\r
2008 Check if key is registered.\r
2009\r
2010 @param RegsiteredData A pointer to a buffer that is filled in with the keystroke \r
2011 state data for the key that was registered.\r
2012 @param InputData A pointer to a buffer that is filled in with the keystroke \r
2013 state data for the key that was pressed.\r
2014\r
2015 @retval TRUE Key be pressed matches a registered key.\r
2016 @retval FLASE Match failed. \r
2017 \r
2018**/\r
2019BOOLEAN\r
2020IsKeyRegistered (\r
2021 IN EFI_KEY_DATA *RegsiteredData,\r
2022 IN EFI_KEY_DATA *InputData\r
2023 )\r
2024{\r
2025 ASSERT (RegsiteredData != NULL && InputData != NULL);\r
2026 \r
2027 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||\r
2028 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {\r
2029 return FALSE; \r
2030 } \r
2031 \r
2032 //\r
2033 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.\r
2034 //\r
2035 if (RegsiteredData->KeyState.KeyShiftState != 0 &&\r
2036 RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {\r
2037 return FALSE; \r
2038 } \r
2039 if (RegsiteredData->KeyState.KeyToggleState != 0 &&\r
2040 RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {\r
2041 return FALSE; \r
2042 } \r
2043 \r
2044 return TRUE;\r
2045\r
2046}\r
2047\r
2048/**\r
2049 Waiting on the keyboard event, if there's any key pressed by the user, signal the event\r
2050\r
2051 @param Event The event that be siganlled when any key has been stroked.\r
2052 @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.\r
2053 \r
2054**/\r
2055VOID\r
2056EFIAPI\r
2057BiosKeyboardWaitForKeyEx (\r
2058 IN EFI_EVENT Event,\r
2059 IN VOID *Context\r
2060 )\r
2061{ \r
2062 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
2063 \r
2064 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context); \r
2065 BiosKeyboardWaitForKey (Event, &BiosKeyboardPrivate->SimpleTextIn);\r
2066\r
2067}\r
2068\r
2069/**\r
2070 Reset the input device and optionaly run diagnostics\r
2071 \r
2072 @param This Protocol instance pointer.\r
2073 @param ExtendedVerification Driver may perform diagnostics on reset.\r
2074\r
2075 @retval EFI_SUCCESS The device was reset.\r
2076 @retval EFI_DEVICE_ERROR The device is not functioning properly and could \r
2077 not be reset.\r
2078\r
2079**/\r
2080EFI_STATUS\r
2081EFIAPI\r
2082BiosKeyboardResetEx (\r
2083 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
2084 IN BOOLEAN ExtendedVerification\r
2085 )\r
2086{\r
2087 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
2088 EFI_STATUS Status;\r
2089 EFI_TPL OldTpl;\r
2090 \r
2091 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This); \r
2092\r
2093 Status = BiosKeyboardPrivate->SimpleTextIn.Reset (\r
2094 &BiosKeyboardPrivate->SimpleTextIn, \r
2095 ExtendedVerification\r
2096 );\r
2097 if (EFI_ERROR (Status)) {\r
2098 return EFI_DEVICE_ERROR;\r
2099 }\r
2100\r
2101 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
2102\r
2103 gBS->RestoreTPL (OldTpl);\r
2104 \r
2105 return EFI_SUCCESS;\r
2106\r
2107}\r
2108\r
2109/**\r
2110 Reads the next keystroke from the input device. The WaitForKey Event can \r
2111 be used to test for existance of a keystroke via WaitForEvent () call.\r
2112\r
2113 @param This Protocol instance pointer.\r
2114 @param KeyData A pointer to a buffer that is filled in with the keystroke \r
2115 state data for the key that was pressed.\r
2116 \r
2117 @retval EFI_SUCCESS The keystroke information was returned.\r
2118 @retval EFI_NOT_READY There was no keystroke data availiable.\r
2119 @retval EFI_DEVICE_ERROR The keystroke information was not returned due to \r
2120 hardware errors.\r
2121 @retval EFI_INVALID_PARAMETER KeyData is NULL. \r
2122 \r
2123**/\r
2124EFI_STATUS\r
2125EFIAPI\r
2126BiosKeyboardReadKeyStrokeEx (\r
2127 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
2128 OUT EFI_KEY_DATA *KeyData\r
2129 )\r
2130{\r
2131 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
2132\r
2133 if (KeyData == NULL) {\r
2134 return EFI_INVALID_PARAMETER;\r
2135 }\r
2136 \r
2137 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
2138\r
2139 return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, KeyData);\r
2140 \r
2141}\r
2142\r
2143/**\r
2144 Set certain state for the input device.\r
2145\r
2146 @param This Protocol instance pointer.\r
2147 @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the \r
2148 state for the input device.\r
2149\r
2150 @retval EFI_SUCCESS The device state was set successfully.\r
2151 @retval EFI_DEVICE_ERROR The device is not functioning correctly and could \r
2152 not have the setting adjusted.\r
2153 @retval EFI_UNSUPPORTED The device does not have the ability to set its state.\r
2154 @retval EFI_INVALID_PARAMETER KeyToggleState is NULL. \r
2155\r
2156**/ \r
2157EFI_STATUS\r
2158EFIAPI\r
2159BiosKeyboardSetState (\r
2160 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
2161 IN EFI_KEY_TOGGLE_STATE *KeyToggleState\r
2162 )\r
2163{\r
2164 EFI_STATUS Status;\r
2165 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
2166 EFI_TPL OldTpl;\r
2167 EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;\r
2168 UINT8 Command;\r
2169\r
2170 if (KeyToggleState == NULL) {\r
2171 return EFI_INVALID_PARAMETER;\r
2172 }\r
2173\r
5829afe3 2174 //\r
2175 // Thunk keyboard driver doesn't support partial keystroke.\r
2176 //\r
2177 if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID ||\r
2178 (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED\r
2179 ) {\r
bcecde14 2180 return EFI_UNSUPPORTED;\r
2181 }\r
2182\r
2183 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
2184 //\r
2185 // See if the Legacy BIOS Protocol is available\r
2186 //\r
2187 Status = gBS->LocateProtocol (\r
2188 &gEfiLegacyBiosProtocolGuid,\r
2189 NULL,\r
2190 (VOID **) &LegacyBios\r
2191 );\r
2192\r
2193 ASSERT_EFI_ERROR (Status);\r
2194 //\r
2195 // Enter critical section\r
2196 //\r
2197 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
2198\r
2199 Command = 0;\r
2200 if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {\r
2201 Command |= 4;\r
2202 }\r
2203 if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {\r
2204 Command |= 2;\r
2205 }\r
2206 if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {\r
2207 Command |= 1;\r
2208 }\r
2209\r
2210 Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);\r
2211 if (EFI_ERROR (Status)) {\r
2212 return EFI_DEVICE_ERROR;\r
2213 } \r
2214 Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);\r
2215 if (EFI_ERROR (Status)) {\r
2216 return EFI_DEVICE_ERROR;\r
2217 }\r
2218 Status = KeyboardWrite (BiosKeyboardPrivate, Command);\r
2219 if (EFI_ERROR (Status)) {\r
2220 return EFI_DEVICE_ERROR;\r
2221 } \r
2222 //\r
2223 // Call Legacy BIOS Protocol to set whatever is necessary\r
2224 //\r
2225 LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);\r
2226\r
2227 Status = EFI_SUCCESS;\r
2228\r
2229 //\r
2230 // Leave critical section and return\r
2231 //\r
2232 gBS->RestoreTPL (OldTpl);\r
2233\r
2234 return Status;\r
2235\r
2236}\r
2237\r
2238/**\r
2239 Register a notification function for a particular keystroke for the input device.\r
2240\r
2241 @param This Protocol instance pointer.\r
2242 @param KeyData A pointer to a buffer that is filled in with the keystroke \r
2243 information data for the key that was pressed.\r
2244 @param KeyNotificationFunction Points to the function to be called when the key \r
2245 sequence is typed specified by KeyData. \r
2246 @param NotifyHandle Points to the unique handle assigned to the registered notification. \r
2247\r
2248 \r
2249 @retval EFI_SUCCESS The notification function was registered successfully.\r
2250 @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.\r
2251 @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.\r
2252 \r
2253**/ \r
2254EFI_STATUS\r
2255EFIAPI\r
2256BiosKeyboardRegisterKeyNotify (\r
2257 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
2258 IN EFI_KEY_DATA *KeyData,\r
2259 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,\r
2260 OUT EFI_HANDLE *NotifyHandle\r
2261 )\r
2262{\r
2263 EFI_STATUS Status;\r
2264 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
2265 EFI_TPL OldTpl;\r
2266 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;\r
2267 LIST_ENTRY *Link;\r
2268 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify; \r
2269\r
2270 if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {\r
2271 return EFI_INVALID_PARAMETER;\r
2272 }\r
2273\r
2274 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
2275\r
2276 //\r
2277 // Enter critical section\r
2278 //\r
2279 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);\r
2280\r
2281 //\r
2282 // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.\r
2283 //\r
2284 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
2285 CurrentNotify = CR (\r
2286 Link, \r
2287 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
2288 NotifyEntry, \r
2289 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
2290 );\r
2291 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) { \r
2292 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {\r
2293 *NotifyHandle = CurrentNotify->NotifyHandle; \r
2294 Status = EFI_SUCCESS;\r
2295 goto Exit;\r
2296 }\r
2297 } \r
2298 }\r
2299\r
2300 //\r
2301 // Allocate resource to save the notification function\r
2302 //\r
2303 \r
2304 NewNotify = (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY));\r
2305 if (NewNotify == NULL) {\r
2306 Status = EFI_OUT_OF_RESOURCES;\r
2307 goto Exit;\r
2308 }\r
2309\r
2310 NewNotify->Signature = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;\r
2311 NewNotify->KeyNotificationFn = KeyNotificationFunction;\r
2312 NewNotify->NotifyHandle = (EFI_HANDLE) NewNotify;\r
2313 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));\r
2314 InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);\r
2315\r
2316 *NotifyHandle = NewNotify->NotifyHandle; \r
2317 Status = EFI_SUCCESS;\r
2318 \r
2319Exit:\r
2320 //\r
2321 // Leave critical section and return\r
2322 //\r
2323 gBS->RestoreTPL (OldTpl);\r
2324 return Status; \r
2325}\r
2326\r
2327/**\r
2328 Remove a registered notification function from a particular keystroke.\r
2329\r
2330 @param This Protocol instance pointer. \r
2331 @param NotificationHandle The handle of the notification function being unregistered.\r
2332 \r
2333 @retval EFI_SUCCESS The notification function was unregistered successfully.\r
2334 @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.\r
2335 \r
2336**/ \r
2337EFI_STATUS\r
2338EFIAPI\r
2339BiosKeyboardUnregisterKeyNotify (\r
2340 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,\r
2341 IN EFI_HANDLE NotificationHandle\r
2342 )\r
2343{\r
2344 EFI_STATUS Status;\r
2345 BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;\r
2346 EFI_TPL OldTpl;\r
2347 LIST_ENTRY *Link;\r
2348 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;\r
2349\r
2350 //\r
2351 // Check incoming notification handle\r
2352 //\r
2353 if (NotificationHandle == NULL) {\r
2354 return EFI_INVALID_PARAMETER;\r
2355 }\r
2356\r
2357 if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {\r
2358 return EFI_INVALID_PARAMETER;\r
2359 } \r
2360 \r
2361 BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);\r
2362 \r
2363 //\r
2364 // Enter critical section\r
2365 //\r
2366 OldTpl = gBS->RaiseTPL (TPL_NOTIFY); \r
2367\r
2368 for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {\r
2369 CurrentNotify = CR (\r
2370 Link, \r
2371 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY, \r
2372 NotifyEntry, \r
2373 BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE\r
2374 ); \r
2375 if (CurrentNotify->NotifyHandle == NotificationHandle) {\r
2376 //\r
2377 // Remove the notification function from NotifyList and free resources\r
2378 //\r
2379 RemoveEntryList (&CurrentNotify->NotifyEntry); \r
2380\r
2381 Status = EFI_SUCCESS;\r
2382 goto Exit;\r
2383 }\r
2384 }\r
2385 \r
2386 //\r
2387 // Can not find the specified Notification Handle\r
2388 //\r
2389 Status = EFI_INVALID_PARAMETER;\r
2390\r
2391Exit:\r
2392 //\r
2393 // Leave critical section and return\r
2394 //\r
2395 gBS->RestoreTPL (OldTpl);\r
2396 return Status;\r
2397}\r
2398\r
2399/**\r
2400 The user Entry Point for module BiosKeyboard. The user code starts with this function.\r
2401\r
2402 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
2403 @param[in] SystemTable A pointer to the EFI System Table.\r
2404\r
2405 @retval EFI_SUCCESS The entry point is executed successfully.\r
2406 @retval other Some error occurs when executing this entry point.\r
2407\r
2408**/\r
2409EFI_STATUS\r
2410EFIAPI\r
2411InitializeBiosKeyboard(\r
2412 IN EFI_HANDLE ImageHandle,\r
2413 IN EFI_SYSTEM_TABLE *SystemTable\r
2414 )\r
2415{\r
2416 EFI_STATUS Status;\r
2417\r
2418 //\r
2419 // Install driver model protocol(s).\r
2420 //\r
2421 Status = EfiLibInstallDriverBindingComponentName2 (\r
2422 ImageHandle,\r
2423 SystemTable,\r
2424 &gBiosKeyboardDriverBinding,\r
2425 ImageHandle,\r
2426 &gBiosKeyboardComponentName,\r
2427 &gBiosKeyboardComponentName2\r
2428 );\r
2429 ASSERT_EFI_ERROR (Status);\r
2430\r
2431 return Status;\r
2432}\r