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