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