VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/VirtioKeyboardDxe/VirtioKeyboard.c@ 108794

Last change on this file since 108794 was 108794, checked in by vboxsync, 2 weeks ago

Devices/EFI/FirmwareNew: Merge edk2-stable202502 from the vendor branch and make it build for the important platforms, bugref:4643

  • Property svn:eol-style set to native
File size: 39.3 KB
Line 
1/** @file
2
3 This driver produces EFI_SIMPLE_TEXT_INPUT_PROTOCOL for virtarm devices.
4
5 Copyright (C) 2024, Red Hat, Inc.
6
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9**/
10
11#include <Library/BaseMemoryLib.h>
12#include <Library/DebugLib.h>
13#include <Library/MemoryAllocationLib.h>
14#include <Library/UefiBootServicesTableLib.h>
15#include <Library/UefiLib.h>
16#include <Library/VirtioLib.h>
17
18#include <VirtioKeyboard.h>
19#include <VirtioKeyCodes.h>
20
21// -----------------------------------------------------------------------------
22// Return buffer pointer out of the ring buffer
23STATIC
24VOID *
25BufferPtr (
26 IN VIRTIO_KBD_RING *Ring,
27 IN UINT32 BufferNr
28 )
29{
30 return Ring->Buffers + Ring->BufferSize * BufferNr;
31}
32
33// -----------------------------------------------------------------------------
34// Return buffer physical address out of the ring buffer
35STATIC
36EFI_PHYSICAL_ADDRESS
37BufferAddr (
38 IN VIRTIO_KBD_RING *Ring,
39 IN UINT32 BufferNr
40 )
41{
42 return Ring->DeviceAddress + Ring->BufferSize * BufferNr;
43}
44
45// Return next buffer from ring
46STATIC
47UINT32
48BufferNext (
49 IN VIRTIO_KBD_RING *Ring
50 )
51{
52 return Ring->Indices.NextDescIdx % Ring->Ring.QueueSize;
53}
54
55// -----------------------------------------------------------------------------
56// Push the buffer to the device
57EFI_STATUS
58EFIAPI
59VirtioKeyboardRingSendBuffer (
60 IN OUT VIRTIO_KBD_DEV *Dev,
61 IN UINT16 Index,
62 IN VOID *Data,
63 IN UINT32 DataSize,
64 IN BOOLEAN Notify
65 )
66{
67 VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
68 UINT32 BufferNr = BufferNext (Ring);
69 UINT16 Idx = *Ring->Ring.Avail.Idx;
70 UINT16 Flags = 0;
71
72 ASSERT (DataSize <= Ring->BufferSize);
73
74 if (Data) {
75 /* driver -> device */
76 CopyMem (BufferPtr (Ring, BufferNr), Data, DataSize);
77 } else {
78 /* device -> driver */
79 Flags |= VRING_DESC_F_WRITE;
80 }
81
82 VirtioAppendDesc (
83 &Ring->Ring,
84 BufferAddr (Ring, BufferNr),
85 DataSize,
86 Flags,
87 &Ring->Indices
88 );
89
90 Ring->Ring.Avail.Ring[Idx % Ring->Ring.QueueSize] =
91 Ring->Indices.HeadDescIdx % Ring->Ring.QueueSize;
92 Ring->Indices.HeadDescIdx = Ring->Indices.NextDescIdx;
93 Idx++;
94
95 // Force compiler to not optimize this code
96 MemoryFence ();
97 *Ring->Ring.Avail.Idx = Idx;
98 MemoryFence ();
99
100 if (Notify) {
101 Dev->VirtIo->SetQueueNotify (Dev->VirtIo, Index);
102 }
103
104 return EFI_SUCCESS;
105}
106
107// -----------------------------------------------------------------------------
108// Look for buffer ready to be processed
109BOOLEAN
110EFIAPI
111VirtioKeyboardRingHasBuffer (
112 IN OUT VIRTIO_KBD_DEV *Dev,
113 IN UINT16 Index
114 )
115{
116 VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
117 UINT16 UsedIdx = *Ring->Ring.Used.Idx;
118
119 if (!Ring->Ready) {
120 return FALSE;
121 }
122
123 if (Ring->LastUsedIdx == UsedIdx) {
124 return FALSE;
125 }
126
127 return TRUE;
128}
129
130// -----------------------------------------------------------------------------
131// Get data from buffer which is marked as ready from device
132BOOLEAN
133EFIAPI
134VirtioKeyboardRingGetBuffer (
135 IN OUT VIRTIO_KBD_DEV *Dev,
136 IN UINT16 Index,
137 OUT VOID *Data,
138 OUT UINT32 *DataSize
139 )
140{
141 VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
142 UINT16 UsedIdx = *Ring->Ring.Used.Idx;
143 volatile VRING_USED_ELEM *UsedElem;
144
145 if (!Ring->Ready) {
146 return FALSE;
147 }
148
149 if (Ring->LastUsedIdx == UsedIdx) {
150 return FALSE;
151 }
152
153 UsedElem = Ring->Ring.Used.UsedElem + (Ring->LastUsedIdx % Ring->Ring.QueueSize);
154
155 if (UsedElem->Len > Ring->BufferSize) {
156 DEBUG ((DEBUG_ERROR, "%a:%d: %d: invalid length\n", __func__, __LINE__, Index));
157 UsedElem->Len = 0;
158 }
159
160 if (Data && DataSize) {
161 CopyMem (Data, BufferPtr (Ring, UsedElem->Id), UsedElem->Len);
162 *DataSize = UsedElem->Len;
163 }
164
165 if (Index % 2 == 0) {
166 /* RX - re-queue buffer */
167 VirtioKeyboardRingSendBuffer (Dev, Index, NULL, Ring->BufferSize, FALSE);
168 }
169
170 Ring->LastUsedIdx++;
171 return TRUE;
172}
173
174// -----------------------------------------------------------------------------
175// Initialize ring buffer
176EFI_STATUS
177EFIAPI
178VirtioKeyboardInitRing (
179 IN OUT VIRTIO_KBD_DEV *Dev,
180 IN UINT16 Index,
181 IN UINT32 BufferSize
182 )
183{
184 VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
185 EFI_STATUS Status;
186 UINT16 QueueSize;
187 UINT64 RingBaseShift;
188
189 //
190 // step 4b -- allocate request virtqueue
191 //
192 Status = Dev->VirtIo->SetQueueSel (Dev->VirtIo, Index);
193 if (EFI_ERROR (Status)) {
194 goto Failed;
195 }
196
197 Status = Dev->VirtIo->GetQueueNumMax (Dev->VirtIo, &QueueSize);
198 if (EFI_ERROR (Status)) {
199 goto Failed;
200 }
201
202 //
203 // VirtioKeyboard uses one descriptor
204 //
205 if (QueueSize < 1) {
206 Status = EFI_UNSUPPORTED;
207 goto Failed;
208 }
209
210 Status = VirtioRingInit (Dev->VirtIo, QueueSize, &Ring->Ring);
211 if (EFI_ERROR (Status)) {
212 goto Failed;
213 }
214
215 //
216 // If anything fails from here on, we must release the ring resources.
217 //
218 Status = VirtioRingMap (
219 Dev->VirtIo,
220 &Ring->Ring,
221 &RingBaseShift,
222 &Ring->RingMap
223 );
224 if (EFI_ERROR (Status)) {
225 goto ReleaseQueue;
226 }
227
228 //
229 // Additional steps for MMIO: align the queue appropriately, and set the
230 // size. If anything fails from here on, we must unmap the ring resources.
231 //
232 Status = Dev->VirtIo->SetQueueNum (Dev->VirtIo, QueueSize);
233 if (EFI_ERROR (Status)) {
234 goto UnmapQueue;
235 }
236
237 Status = Dev->VirtIo->SetQueueAlign (Dev->VirtIo, EFI_PAGE_SIZE);
238 if (EFI_ERROR (Status)) {
239 goto UnmapQueue;
240 }
241
242 //
243 // step 4c -- Report GPFN (guest-physical frame number) of queue.
244 //
245 Status = Dev->VirtIo->SetQueueAddress (
246 Dev->VirtIo,
247 &Ring->Ring,
248 RingBaseShift
249 );
250 if (EFI_ERROR (Status)) {
251 goto UnmapQueue;
252 }
253
254 Ring->BufferCount = QueueSize;
255 Ring->BufferSize = BufferSize;
256 Ring->BufferPages = EFI_SIZE_TO_PAGES (Ring->BufferCount * Ring->BufferSize);
257
258 Status = Dev->VirtIo->AllocateSharedPages (Dev->VirtIo, Ring->BufferPages, (VOID **)&Ring->Buffers);
259 if (EFI_ERROR (Status)) {
260 goto UnmapQueue;
261 }
262
263 Status = VirtioMapAllBytesInSharedBuffer (
264 Dev->VirtIo,
265 VirtioOperationBusMasterCommonBuffer,
266 Ring->Buffers,
267 EFI_PAGES_TO_SIZE (Ring->BufferPages),
268 &Ring->DeviceAddress,
269 &Ring->BufferMap
270 );
271 if (EFI_ERROR (Status)) {
272 goto ReleasePages;
273 }
274
275 VirtioPrepare (&Ring->Ring, &Ring->Indices);
276 Ring->Ready = TRUE;
277
278 return EFI_SUCCESS;
279
280ReleasePages:
281 Dev->VirtIo->FreeSharedPages (
282 Dev->VirtIo,
283 Ring->BufferPages,
284 Ring->Buffers
285 );
286 Ring->Buffers = NULL;
287
288UnmapQueue:
289 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->RingMap);
290 Ring->RingMap = NULL;
291
292ReleaseQueue:
293 VirtioRingUninit (Dev->VirtIo, &Ring->Ring);
294
295Failed:
296 return Status;
297}
298
299// -----------------------------------------------------------------------------
300// Deinitialize ring buffer
301VOID
302EFIAPI
303VirtioKeyboardUninitRing (
304 IN OUT VIRTIO_KBD_DEV *Dev,
305 IN UINT16 Index
306 )
307{
308 VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
309
310 if (Ring->BufferMap) {
311 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->BufferMap);
312 Ring->BufferMap = NULL;
313 }
314
315 if (Ring->Buffers) {
316 Dev->VirtIo->FreeSharedPages (
317 Dev->VirtIo,
318 Ring->BufferPages,
319 Ring->Buffers
320 );
321 Ring->Buffers = NULL;
322 }
323
324 if (!Ring->RingMap) {
325 Dev->VirtIo->UnmapSharedBuffer (Dev->VirtIo, Ring->RingMap);
326 Ring->RingMap = NULL;
327 }
328
329 if (Ring->Ring.Base) {
330 VirtioRingUninit (Dev->VirtIo, &Ring->Ring);
331 }
332
333 ZeroMem (Ring, sizeof (*Ring));
334}
335
336// -----------------------------------------------------------------------------
337// Deinitialize all rings allocated in driver
338STATIC
339VOID
340EFIAPI
341VirtioKeyboardUninitAllRings (
342 IN OUT VIRTIO_KBD_DEV *Dev
343 )
344{
345 UINT16 Index;
346
347 for (Index = 0; Index < KEYBOARD_MAX_RINGS; Index++) {
348 VirtioKeyboardUninitRing (Dev, Index);
349 }
350}
351
352// -----------------------------------------------------------------------------
353// Mark all buffers as ready to write and push to device
354VOID
355EFIAPI
356VirtioKeyboardRingFillRx (
357 IN OUT VIRTIO_KBD_DEV *Dev,
358 IN UINT16 Index
359 )
360{
361 VIRTIO_KBD_RING *Ring = Dev->Rings + Index;
362 UINT32 BufferNr;
363
364 for (BufferNr = 0; BufferNr < Ring->BufferCount; BufferNr++) {
365 VirtioKeyboardRingSendBuffer (Dev, Index, NULL, Ring->BufferSize, FALSE);
366 }
367
368 Dev->VirtIo->SetQueueNotify (Dev->VirtIo, Index);
369}
370
371// Forward declaration of module Uninit function
372STATIC
373VOID
374EFIAPI
375VirtioKeyboardUninit (
376 IN OUT VIRTIO_KBD_DEV *Dev
377 );
378
379// Forward declaration of module Init function
380STATIC
381EFI_STATUS
382EFIAPI
383VirtioKeyboardInit (
384 IN OUT VIRTIO_KBD_DEV *Dev
385 );
386
387// -----------------------------------------------------------------------------
388// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
389EFI_STATUS
390EFIAPI
391VirtioKeyboardSimpleTextInputReset (
392 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
393 IN BOOLEAN ExtendedVerification
394 )
395{
396 VIRTIO_KBD_DEV *Dev;
397
398 Dev = VIRTIO_KEYBOARD_FROM_THIS (This);
399 VirtioKeyboardUninit (Dev);
400 VirtioKeyboardInit (Dev);
401
402 return EFI_SUCCESS;
403}
404
405// -----------------------------------------------------------------------------
406// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
407EFI_STATUS
408EFIAPI
409VirtioKeyboardSimpleTextInputReadKeyStroke (
410 IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
411 OUT EFI_INPUT_KEY *Key
412 )
413{
414 VIRTIO_KBD_DEV *Dev;
415 EFI_TPL OldTpl;
416
417 if (Key == NULL) {
418 return EFI_INVALID_PARAMETER;
419 }
420
421 Dev = VIRTIO_KEYBOARD_FROM_THIS (This);
422
423 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
424 if (Dev->KeyReady) {
425 // Get last key from the buffer
426 *Key = Dev->LastKey;
427
428 // Mark key as consumed
429 Dev->KeyReady = FALSE;
430
431 gBS->RestoreTPL (OldTpl);
432 return EFI_SUCCESS;
433 }
434
435 gBS->RestoreTPL (OldTpl);
436
437 return EFI_NOT_READY;
438}
439
440// -----------------------------------------------------------------------------
441// Function converting VirtIO key codes to UEFI key codes
442STATIC
443VOID
444EFIAPI
445VirtioKeyboardConvertKeyCode (
446 IN OUT VIRTIO_KBD_DEV *Dev,
447 IN UINT16 Code,
448 OUT EFI_INPUT_KEY *Key
449 )
450{
451 // Key mapping in between Linux and UEFI
452 // https://github.com/torvalds/linux/blob/master/include/uapi/linux/input-event-codes.h
453 // https://dox.ipxe.org/SimpleTextIn_8h_source.html#l00048
454 // https://uefi.org/specs/UEFI/2.10/Apx_B_Console.html
455
456 static const UINT16 Map[] = {
457 [KEY_1] = '1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
458 [KEY_MINUS] = '-', '=',
459 [KEY_Q] = 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p',
460 [KEY_LEFTBRACE] = '[', ']',
461 [KEY_A] = 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l',
462 [KEY_SEMICOLON] = ';', '\'', '`',
463 [KEY_BACKSLASH] = '\\',
464 [KEY_Z] = 'z', 'x', 'c', 'v', 'b', 'n', 'm',
465 [KEY_COMMA] = ',', '.', '/',
466 [KEY_SPACE] = ' ',
467 [MAX_KEYBOARD_CODE] = 0x00
468 };
469
470 static const UINT16 MapShift[] = {
471 [KEY_1] = '!', '@', '#', '$', '%', '^', '&', '*', '(', ')',
472 [KEY_MINUS] = '_', '+',
473 [KEY_Q] = 'Q', 'W', 'E', 'R', 'T', 'Y', 'U', 'I', 'O', 'P',
474 [KEY_LEFTBRACE] = '{', '}',
475 [KEY_A] = 'A', 'S', 'D', 'F', 'G', 'H', 'J', 'K', 'L',
476 [KEY_SEMICOLON] = ':', '\"', '~',
477 [KEY_BACKSLASH] = '|',
478 [KEY_Z] = 'Z', 'X', 'C', 'V', 'B', 'N', 'M',
479 [KEY_COMMA] = '<', '>', '?',
480 [KEY_SPACE] = ' ',
481 [MAX_KEYBOARD_CODE] = 0x00
482 };
483
484 // Set default readings
485 Key->ScanCode = SCAN_NULL;
486 Key->UnicodeChar = CHAR_NULL;
487
488 // Check if key code is not out of the keyboard mapping boundaries
489 if (Code >= MAX_KEYBOARD_CODE) {
490 DEBUG ((DEBUG_INFO, "%a: Key code out of range \n", __func__));
491 return;
492 }
493
494 // Handle F1 - F10 keys
495 if ((Code >= KEY_F1) && (Code <= KEY_F10)) {
496 Key->ScanCode = SCAN_F1 + (Code - KEY_F1);
497 return;
498 }
499
500 switch (Code) {
501 case KEY_PAGEUP:
502 Key->ScanCode = SCAN_PAGE_UP;
503 break;
504
505 case KEY_PAGEDOWN:
506 Key->ScanCode = SCAN_PAGE_DOWN;
507 break;
508
509 case KEY_HOME:
510 Key->ScanCode = SCAN_HOME;
511 break;
512
513 case KEY_END:
514 Key->ScanCode = SCAN_END;
515 break;
516
517 case KEY_DELETE:
518 Key->ScanCode = SCAN_DELETE;
519 break;
520
521 case KEY_INSERT:
522 Key->ScanCode = SCAN_INSERT;
523 break;
524
525 case KEY_UP:
526 Key->ScanCode = SCAN_UP;
527 break;
528
529 case KEY_LEFT:
530 Key->ScanCode = SCAN_LEFT;
531 break;
532
533 case KEY_RIGHT:
534 Key->ScanCode = SCAN_RIGHT;
535 break;
536
537 case KEY_DOWN:
538 Key->ScanCode = SCAN_DOWN;
539 break;
540
541 case KEY_BACKSPACE:
542 Key->UnicodeChar = CHAR_BACKSPACE;
543 break;
544
545 case KEY_TAB:
546 Key->UnicodeChar = CHAR_TAB;
547 break;
548
549 case KEY_ENTER:
550 // Key->UnicodeChar = CHAR_LINEFEED;
551 Key->UnicodeChar = CHAR_CARRIAGE_RETURN;
552 break;
553
554 case KEY_ESC:
555 Key->ScanCode = SCAN_ESC;
556 break;
557
558 default:
559 if (Dev->KeyActive[KEY_LEFTSHIFT] || Dev->KeyActive[KEY_RIGHTSHIFT]) {
560 Key->ScanCode = MapShift[Code];
561 Key->UnicodeChar = MapShift[Code];
562 } else {
563 Key->ScanCode = Map[Code];
564 Key->UnicodeChar = Map[Code];
565 }
566
567 if (Dev->KeyActive[KEY_LEFTCTRL] || Dev->KeyActive[KEY_RIGHTCTRL]) {
568 // Convert Ctrl+[a-z] and Ctrl+[A-Z] into [1-26] ASCII table entries
569 Key->UnicodeChar &= 0x1F;
570 }
571
572 break;
573 }
574}
575
576// -----------------------------------------------------------------------------
577// Main function processing virtio keyboard events
578STATIC
579VOID
580EFIAPI
581VirtioKeyboardGetDeviceData (
582 IN OUT VIRTIO_KBD_DEV *Dev
583 )
584{
585 BOOLEAN HasData;
586 UINT8 Data[KEYBOARD_RX_BUFSIZE + 1];
587 UINT32 DataSize;
588 VIRTIO_KBD_EVENT Event;
589 EFI_TPL OldTpl;
590
591 for ( ; ; ) {
592 HasData = VirtioKeyboardRingGetBuffer (Dev, 0, Data, &DataSize);
593
594 // Exit if no new data
595 if (!HasData) {
596 return;
597 }
598
599 if (DataSize < sizeof (Event)) {
600 continue;
601 }
602
603 // Clearing last character is not needed as it will be overwritten anyway
604 // Dev->LastKey.ScanCode = SCAN_NULL;
605 // Dev->LastKey.UnicodeChar = CHAR_NULL;
606
607 CopyMem (&Event, Data, sizeof (Event));
608
609 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
610 switch (Event.Type) {
611 case EV_SYN:
612 // Sync event received
613 break;
614
615 case EV_KEY:
616 // Key press event received
617 // DEBUG ((DEBUG_INFO, "%a: ---------------------- \nType: %x Code: %x Value: %x\n",
618 // __func__, Event.Type, Event.Code, Event.Value));
619
620 if (Event.Value == KEY_PRESSED) {
621 // Key pressed event received
622 Dev->KeyActive[(UINT8)Event.Code] = TRUE;
623
624 // Evaluate key
625 VirtioKeyboardConvertKeyCode (Dev, Event.Code, &Dev->LastKey);
626
627 // Flag that printable character is ready to be send
628 Dev->KeyReady = TRUE;
629 } else {
630 // Key released event received
631 Dev->KeyActive[(UINT8)Event.Code] = FALSE;
632 }
633
634 break;
635
636 default:
637 DEBUG ((DEBUG_INFO, "%a: Unhandled VirtIo event\n", __func__));
638 break;
639 }
640
641 gBS->RestoreTPL (OldTpl);
642 }
643}
644
645// -----------------------------------------------------------------------------
646// Callback hook for timer interrupt
647STATIC
648VOID
649EFIAPI
650VirtioKeyboardTimer (
651 IN EFI_EVENT Event,
652 IN VOID *Context
653 )
654{
655 VIRTIO_KBD_DEV *Dev = Context;
656
657 VirtioKeyboardGetDeviceData (Dev);
658}
659
660// -----------------------------------------------------------------------------
661// EFI_SIMPLE_TEXT_INPUT_PROTOCOL API
662VOID
663EFIAPI
664VirtioKeyboardWaitForKey (
665 IN EFI_EVENT Event,
666 IN VOID *Context
667 )
668{
669 VIRTIO_KBD_DEV *Dev = VIRTIO_KEYBOARD_FROM_THIS (Context);
670
671 //
672 // Stall 1ms to give a chance to let other driver interrupt this routine
673 // for their timer event.
674 // e.g. UI setup or Shell, other drivers which are driven by timer event
675 // will have a bad performance during this period,
676 // e.g. usb keyboard driver.
677 // Add a stall period can greatly increate other driver performance during
678 // the WaitForKey is recursivly invoked. 1ms delay will make little impact
679 // to the thunk keyboard driver, and user can not feel the delay at all when
680 // input.
681 gBS->Stall (1000);
682
683 // Use TimerEvent callback function to check whether there's any key pressed
684 VirtioKeyboardTimer (NULL, Dev);
685
686 // If there is a new key ready - send signal
687 if (Dev->KeyReady) {
688 gBS->SignalEvent (Event);
689 }
690}
691
692/// -----------------------------------------------------------------------------
693// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
694EFI_STATUS
695EFIAPI
696VirtioKeyboardResetEx (
697 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
698 IN BOOLEAN ExtendedVerification
699 )
700{
701 VIRTIO_KBD_DEV *Dev;
702 EFI_STATUS Status;
703 EFI_TPL OldTpl;
704
705 Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (This);
706
707 // Call the reset function from SIMPLE_TEXT_INPUT protocol
708 Status = Dev->Txt.Reset (
709 &Dev->Txt,
710 ExtendedVerification
711 );
712
713 if (EFI_ERROR (Status)) {
714 return EFI_DEVICE_ERROR;
715 }
716
717 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
718 gBS->RestoreTPL (OldTpl);
719
720 return EFI_SUCCESS;
721}
722
723// -----------------------------------------------------------------------------
724// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
725EFI_STATUS
726EFIAPI
727VirtioKeyboardReadKeyStrokeEx (
728 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
729 OUT EFI_KEY_DATA *KeyData
730 )
731{
732 VIRTIO_KBD_DEV *Dev;
733 EFI_STATUS Status;
734 EFI_INPUT_KEY Key;
735 EFI_KEY_STATE KeyState;
736
737 if (KeyData == NULL) {
738 return EFI_INVALID_PARAMETER;
739 }
740
741 Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (This);
742
743 // Get the last pressed key
744 Status = Dev->Txt.ReadKeyStroke (&Dev->Txt, &Key);
745 if (EFI_ERROR (Status)) {
746 return EFI_DEVICE_ERROR;
747 }
748
749 // Add key state informations
750 KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
751 KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
752
753 // Shift key modifier
754 if (Dev->KeyActive[KEY_LEFTSHIFT]) {
755 KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
756 }
757
758 if (Dev->KeyActive[KEY_RIGHTSHIFT]) {
759 KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
760 }
761
762 // Ctrl key modifier
763 if (Dev->KeyActive[KEY_LEFTCTRL]) {
764 KeyState.KeyShiftState |= EFI_LEFT_CONTROL_PRESSED;
765 }
766
767 if (Dev->KeyActive[KEY_RIGHTCTRL]) {
768 KeyState.KeyShiftState |= EFI_RIGHT_CONTROL_PRESSED;
769 }
770
771 // ALt key modifier
772 if (Dev->KeyActive[KEY_LEFTALT]) {
773 KeyState.KeyShiftState |= EFI_LEFT_ALT_PRESSED;
774 }
775
776 if (Dev->KeyActive[KEY_RIGHTALT]) {
777 KeyState.KeyShiftState |= EFI_RIGHT_ALT_PRESSED;
778 }
779
780 // Return value only when there is no failure
781 KeyData->Key = Key;
782 KeyData->KeyState = KeyState;
783
784 return EFI_SUCCESS;
785}
786
787// -----------------------------------------------------------------------------
788// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
789VOID
790EFIAPI
791VirtioKeyboardWaitForKeyEx (
792 IN EFI_EVENT Event,
793 IN VOID *Context
794 )
795{
796 VIRTIO_KBD_DEV *Dev;
797
798 Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (Context);
799 VirtioKeyboardWaitForKey (Event, &Dev->Txt);
800}
801
802// -----------------------------------------------------------------------------
803// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
804EFI_STATUS
805EFIAPI
806VirtioKeyboardSetState (
807 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
808 IN EFI_KEY_TOGGLE_STATE *KeyToggleState
809 )
810{
811 if (KeyToggleState == NULL) {
812 return EFI_INVALID_PARAMETER;
813 }
814
815 return EFI_SUCCESS;
816}
817
818BOOLEAN
819IsKeyRegistered (
820 IN EFI_KEY_DATA *RegsiteredData,
821 IN EFI_KEY_DATA *InputData
822 )
823
824{
825 ASSERT (RegsiteredData != NULL && InputData != NULL);
826
827 if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
828 (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar))
829 {
830 return FALSE;
831 }
832
833 //
834 // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means
835 // these state could be ignored.
836 //
837 if ((RegsiteredData->KeyState.KeyShiftState != 0) &&
838 (RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState))
839 {
840 return FALSE;
841 }
842
843 if ((RegsiteredData->KeyState.KeyToggleState != 0) &&
844 (RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState))
845 {
846 return FALSE;
847 }
848
849 return TRUE;
850}
851
852// -----------------------------------------------------------------------------
853// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
854EFI_STATUS
855EFIAPI
856VirtioKeyboardRegisterKeyNotify (
857 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
858 IN EFI_KEY_DATA *KeyData,
859 IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
860 OUT VOID **NotifyHandle
861 )
862{
863 EFI_STATUS Status;
864 VIRTIO_KBD_DEV *Dev;
865 EFI_TPL OldTpl;
866 LIST_ENTRY *Link;
867 VIRTIO_KBD_IN_EX_NOTIFY *NewNotify;
868 VIRTIO_KBD_IN_EX_NOTIFY *CurrentNotify;
869
870 if ((KeyData == NULL) ||
871 (NotifyHandle == NULL) ||
872 (KeyNotificationFunction == NULL))
873 {
874 return EFI_INVALID_PARAMETER;
875 }
876
877 Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (This);
878
879 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
880
881 // Check if the (KeyData, NotificationFunction) pair is already registered.
882 for (Link = Dev->NotifyList.ForwardLink;
883 Link != &Dev->NotifyList;
884 Link = Link->ForwardLink)
885 {
886 CurrentNotify = CR (
887 Link,
888 VIRTIO_KBD_IN_EX_NOTIFY,
889 NotifyEntry,
890 VIRTIO_KBD_SIG
891 );
892 if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
893 if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
894 *NotifyHandle = CurrentNotify;
895 Status = EFI_SUCCESS;
896 goto Exit;
897 }
898 }
899 }
900
901 NewNotify = (VIRTIO_KBD_IN_EX_NOTIFY *)AllocateZeroPool (sizeof (VIRTIO_KBD_IN_EX_NOTIFY));
902 if (NewNotify == NULL) {
903 Status = EFI_OUT_OF_RESOURCES;
904 goto Exit;
905 }
906
907 NewNotify->Signature = VIRTIO_KBD_SIG;
908 NewNotify->KeyNotificationFn = KeyNotificationFunction;
909 CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
910 InsertTailList (&Dev->NotifyList, &NewNotify->NotifyEntry);
911
912 *NotifyHandle = NewNotify;
913 Status = EFI_SUCCESS;
914
915Exit:
916 gBS->RestoreTPL (OldTpl);
917
918 return Status;
919}
920
921// -----------------------------------------------------------------------------
922// EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL API
923EFI_STATUS
924EFIAPI
925VirtioKeyboardUnregisterKeyNotify (
926 IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
927 IN VOID *NotificationHandle
928 )
929{
930 EFI_STATUS Status;
931 VIRTIO_KBD_DEV *Dev;
932 EFI_TPL OldTpl;
933 LIST_ENTRY *Link;
934 VIRTIO_KBD_IN_EX_NOTIFY *CurrentNotify;
935
936 if (NotificationHandle == NULL) {
937 return EFI_INVALID_PARAMETER;
938 }
939
940 if (((VIRTIO_KBD_IN_EX_NOTIFY *)NotificationHandle)->Signature != VIRTIO_KBD_SIG) {
941 return EFI_INVALID_PARAMETER;
942 }
943
944 Dev = VIRTIO_KEYBOARD_EX_FROM_THIS (This);
945
946 OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
947
948 for (Link = Dev->NotifyList.ForwardLink;
949 Link != &Dev->NotifyList;
950 Link = Link->ForwardLink)
951 {
952 CurrentNotify = CR (
953 Link,
954 VIRTIO_KBD_IN_EX_NOTIFY,
955 NotifyEntry,
956 VIRTIO_KBD_SIG
957 );
958 if (CurrentNotify == NotificationHandle) {
959 RemoveEntryList (&CurrentNotify->NotifyEntry);
960
961 Status = EFI_SUCCESS;
962 goto Exit;
963 }
964 }
965
966 // Notification has not been found
967 Status = EFI_INVALID_PARAMETER;
968
969Exit:
970 gBS->RestoreTPL (OldTpl);
971
972 return Status;
973}
974
975// -----------------------------------------------------------------------------
976// Driver init
977STATIC
978EFI_STATUS
979EFIAPI
980VirtioKeyboardInit (
981 IN OUT VIRTIO_KBD_DEV *Dev
982 )
983{
984 UINT8 NextDevStat;
985 EFI_STATUS Status;
986 UINT64 Features;
987
988 //
989 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
990 //
991 NextDevStat = 0; // step 1 -- reset device
992 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
993 if (EFI_ERROR (Status)) {
994 goto Failed;
995 }
996
997 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
998 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
999 if (EFI_ERROR (Status)) {
1000 goto Failed;
1001 }
1002
1003 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
1004 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
1005 if (EFI_ERROR (Status)) {
1006 goto Failed;
1007 }
1008
1009 //
1010 // Set Page Size - MMIO VirtIo Specific
1011 //
1012 Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
1013 if (EFI_ERROR (Status)) {
1014 goto Failed;
1015 }
1016
1017 //
1018 // step 4a -- retrieve and validate features
1019 //
1020 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
1021 if (EFI_ERROR (Status)) {
1022 goto Failed;
1023 }
1024
1025 Features &= VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM;
1026
1027 //
1028 // In virtio-1.0, feature negotiation is expected to complete before queue
1029 // discovery, and the device can also reject the selected set of features.
1030 //
1031 if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
1032 Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
1033 if (EFI_ERROR (Status)) {
1034 goto Failed;
1035 }
1036 }
1037
1038 Status = VirtioKeyboardInitRing (Dev, 0, KEYBOARD_RX_BUFSIZE);
1039 if (EFI_ERROR (Status)) {
1040 goto Failed;
1041 }
1042
1043 //
1044 // step 5 -- Report understood features and guest-tuneables.
1045 //
1046 if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
1047 Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
1048 Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
1049 if (EFI_ERROR (Status)) {
1050 goto Failed;
1051 }
1052 }
1053
1054 //
1055 // step 6 -- initialization complete
1056 //
1057 NextDevStat |= VSTAT_DRIVER_OK;
1058 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
1059 if (EFI_ERROR (Status)) {
1060 goto Failed;
1061 }
1062
1063 //
1064 // populate the exported interface's attributes
1065 //
1066
1067 // struct _EFI_SIMPLE_TEXT_INPUT_PROTOCOL {
1068 // EFI_INPUT_RESET Reset;
1069 // EFI_INPUT_READ_KEY ReadKeyStroke;
1070 // EFI_EVENT WaitForKey;
1071 // };
1072 Dev->Txt.Reset = (EFI_INPUT_RESET)VirtioKeyboardSimpleTextInputReset;
1073 Dev->Txt.ReadKeyStroke = VirtioKeyboardSimpleTextInputReadKeyStroke;
1074 Dev->Txt.WaitForKey = (EFI_EVENT)VirtioKeyboardWaitForKey;
1075
1076 // struct _EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL {
1077 // EFI_INPUT_RESET_EX Reset;
1078 // EFI_INPUT_READ_KEY_EX ReadKeyStrokeEx;
1079 // EFI_EVENT WaitForKeyEx;
1080 // EFI_SET_STATE SetState;
1081 // EFI_REGISTER_KEYSTROKE_NOTIFY RegisterKeyNotify;
1082 // EFI_UNREGISTER_KEYSTROKE_NOTIFY UnregisterKeyNotify;
1083 // }
1084 Dev->TxtEx.Reset = (EFI_INPUT_RESET_EX)VirtioKeyboardResetEx;
1085 Dev->TxtEx.ReadKeyStrokeEx = VirtioKeyboardReadKeyStrokeEx;
1086 Dev->TxtEx.SetState = VirtioKeyboardSetState;
1087 Dev->TxtEx.RegisterKeyNotify = VirtioKeyboardRegisterKeyNotify;
1088 Dev->TxtEx.UnregisterKeyNotify = VirtioKeyboardUnregisterKeyNotify;
1089 InitializeListHead (&Dev->NotifyList);
1090
1091 //
1092 // Setup the WaitForKey event
1093 //
1094 Status = gBS->CreateEvent (
1095 EVT_NOTIFY_WAIT,
1096 TPL_NOTIFY,
1097 VirtioKeyboardWaitForKey,
1098 &(Dev->Txt),
1099 &((Dev->Txt).WaitForKey)
1100 );
1101 if (EFI_ERROR (Status)) {
1102 goto Failed;
1103 }
1104
1105 //
1106 // Setup the WaitForKeyEx event
1107 //
1108 Status = gBS->CreateEvent (
1109 EVT_NOTIFY_WAIT,
1110 TPL_NOTIFY,
1111 VirtioKeyboardWaitForKeyEx,
1112 &(Dev->TxtEx),
1113 &((Dev->TxtEx).WaitForKeyEx)
1114 );
1115 if (EFI_ERROR (Status)) {
1116 goto Failed;
1117 }
1118
1119 VirtioKeyboardRingFillRx (Dev, 0);
1120
1121 //
1122 // Event for reading key in time intervals
1123 //
1124 Status = gBS->CreateEvent (
1125 EVT_TIMER | EVT_NOTIFY_SIGNAL,
1126 TPL_NOTIFY,
1127 VirtioKeyboardTimer,
1128 Dev,
1129 &Dev->KeyReadTimer
1130 );
1131 if (EFI_ERROR (Status)) {
1132 goto Failed;
1133 }
1134
1135 Status = gBS->SetTimer (
1136 Dev->KeyReadTimer,
1137 TimerPeriodic,
1138 EFI_TIMER_PERIOD_MILLISECONDS (KEYBOARD_PROBE_TIME_MS)
1139 );
1140 if (EFI_ERROR (Status)) {
1141 goto Failed;
1142 }
1143
1144 return EFI_SUCCESS;
1145
1146Failed:
1147 VirtioKeyboardUninitAllRings (Dev);
1148 // VirtualKeyboardFreeNotifyList (&VirtualKeyboardPrivate->NotifyList);
1149
1150 //
1151 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
1152 // Status. VirtIo access failure here should not mask the original error.
1153 //
1154 NextDevStat |= VSTAT_FAILED;
1155 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
1156
1157 return Status; // reached only via Failed above
1158}
1159
1160// -----------------------------------------------------------------------------
1161// Deinitialize driver
1162STATIC
1163VOID
1164EFIAPI
1165VirtioKeyboardUninit (
1166 IN OUT VIRTIO_KBD_DEV *Dev
1167 )
1168{
1169 gBS->CloseEvent (Dev->KeyReadTimer);
1170 //
1171 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
1172 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
1173 // the old comms area.
1174 //
1175 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1176
1177 VirtioKeyboardUninitAllRings (Dev);
1178}
1179
1180// -----------------------------------------------------------------------------
1181// Handle device exit before switch to boot
1182STATIC
1183VOID
1184EFIAPI
1185VirtioKeyboardExitBoot (
1186 IN EFI_EVENT Event,
1187 IN VOID *Context
1188 )
1189{
1190 VIRTIO_KBD_DEV *Dev;
1191
1192 DEBUG ((DEBUG_INFO, "%a: Context=0x%p\n", __func__, Context));
1193 //
1194 // Reset the device. This causes the hypervisor to forget about the virtio
1195 // ring.
1196 //
1197 // We allocated said ring in EfiBootServicesData type memory, and code
1198 // executing after ExitBootServices() is permitted to overwrite it.
1199 //
1200 Dev = Context;
1201 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
1202}
1203
1204// -----------------------------------------------------------------------------
1205// Binding validation function
1206STATIC
1207EFI_STATUS
1208EFIAPI
1209VirtioKeyboardBindingSupported (
1210 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1211 IN EFI_HANDLE DeviceHandle,
1212 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1213 )
1214{
1215 EFI_STATUS Status;
1216 VIRTIO_DEVICE_PROTOCOL *VirtIo;
1217
1218 //
1219 // Attempt to open the device with the VirtIo set of interfaces. On success,
1220 // the protocol is "instantiated" for the VirtIo device. Covers duplicate
1221 // open attempts (EFI_ALREADY_STARTED).
1222 //
1223 Status = gBS->OpenProtocol (
1224 DeviceHandle, // candidate device
1225 &gVirtioDeviceProtocolGuid, // for generic VirtIo access
1226 (VOID **)&VirtIo, // handle to instantiate
1227 This->DriverBindingHandle, // requestor driver identity
1228 DeviceHandle, // ControllerHandle, according to
1229 // the UEFI Driver Model
1230 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
1231 // the device; to be released
1232 );
1233 if (EFI_ERROR (Status)) {
1234 if (Status != EFI_UNSUPPORTED) {
1235 DEBUG ((DEBUG_INFO, "%a:%d: %r\n", __func__, __LINE__, Status));
1236 }
1237
1238 return Status;
1239 }
1240
1241 DEBUG ((DEBUG_INFO, "%a:%d: 0x%x\n", __func__, __LINE__, VirtIo->SubSystemDeviceId));
1242 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_INPUT) {
1243 Status = EFI_UNSUPPORTED;
1244 }
1245
1246 //
1247 // We needed VirtIo access only transitorily, to see whether we support the
1248 // device or not.
1249 //
1250 gBS->CloseProtocol (
1251 DeviceHandle,
1252 &gVirtioDeviceProtocolGuid,
1253 This->DriverBindingHandle,
1254 DeviceHandle
1255 );
1256 return Status;
1257}
1258
1259// -----------------------------------------------------------------------------
1260// Driver binding function API
1261STATIC
1262EFI_STATUS
1263EFIAPI
1264VirtioKeyboardBindingStart (
1265 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1266 IN EFI_HANDLE DeviceHandle,
1267 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
1268 )
1269{
1270 VIRTIO_KBD_DEV *Dev;
1271 EFI_STATUS Status;
1272
1273 Dev = (VIRTIO_KBD_DEV *)AllocateZeroPool (sizeof *Dev);
1274 if (Dev == NULL) {
1275 return EFI_OUT_OF_RESOURCES;
1276 }
1277
1278 Status = gBS->OpenProtocol (
1279 DeviceHandle,
1280 &gVirtioDeviceProtocolGuid,
1281 (VOID **)&Dev->VirtIo,
1282 This->DriverBindingHandle,
1283 DeviceHandle,
1284 EFI_OPEN_PROTOCOL_BY_DRIVER
1285 );
1286 if (EFI_ERROR (Status)) {
1287 goto FreeVirtioKbd;
1288 }
1289
1290 //
1291 // VirtIo access granted, configure virtio keyboard device.
1292 //
1293 Status = VirtioKeyboardInit (Dev);
1294 if (EFI_ERROR (Status)) {
1295 goto CloseVirtIo;
1296 }
1297
1298 Status = gBS->CreateEvent (
1299 EVT_SIGNAL_EXIT_BOOT_SERVICES,
1300 TPL_CALLBACK,
1301 &VirtioKeyboardExitBoot,
1302 Dev,
1303 &Dev->ExitBoot
1304 );
1305 if (EFI_ERROR (Status)) {
1306 goto UninitDev;
1307 }
1308
1309 //
1310 // Setup complete, attempt to export the driver instance's EFI_SIMPLE_TEXT_INPUT_PROTOCOL
1311 // interface.
1312 //
1313 Dev->Signature = VIRTIO_KBD_SIG;
1314 Status = gBS->InstallMultipleProtocolInterfaces (
1315 &DeviceHandle,
1316 &gEfiSimpleTextInProtocolGuid,
1317 &Dev->Txt,
1318 &gEfiSimpleTextInputExProtocolGuid,
1319 &Dev->TxtEx,
1320 NULL
1321 );
1322 if (EFI_ERROR (Status)) {
1323 goto CloseExitBoot;
1324 }
1325
1326 return EFI_SUCCESS;
1327
1328CloseExitBoot:
1329 gBS->CloseEvent (Dev->ExitBoot);
1330
1331UninitDev:
1332 VirtioKeyboardUninit (Dev);
1333
1334CloseVirtIo:
1335 gBS->CloseProtocol (
1336 DeviceHandle,
1337 &gVirtioDeviceProtocolGuid,
1338 This->DriverBindingHandle,
1339 DeviceHandle
1340 );
1341
1342FreeVirtioKbd:
1343 FreePool (Dev);
1344
1345 return Status;
1346}
1347
1348// -----------------------------------------------------------------------------
1349// Driver unbinding function API
1350STATIC
1351EFI_STATUS
1352EFIAPI
1353VirtioKeyboardBindingStop (
1354 IN EFI_DRIVER_BINDING_PROTOCOL *This,
1355 IN EFI_HANDLE DeviceHandle,
1356 IN UINTN NumberOfChildren,
1357 IN EFI_HANDLE *ChildHandleBuffer
1358 )
1359{
1360 EFI_STATUS Status;
1361 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *Txt;
1362 VIRTIO_KBD_DEV *Dev;
1363
1364 Status = gBS->OpenProtocol (
1365 DeviceHandle, // candidate device
1366 &gEfiSimpleTextInProtocolGuid, // retrieve the RNG iface
1367 (VOID **)&Txt, // target pointer
1368 This->DriverBindingHandle, // requestor driver ident.
1369 DeviceHandle, // lookup req. for dev.
1370 EFI_OPEN_PROTOCOL_GET_PROTOCOL // lookup only, no new ref.
1371 );
1372 if (EFI_ERROR (Status)) {
1373 return Status;
1374 }
1375
1376 Dev = VIRTIO_KEYBOARD_FROM_THIS (Txt);
1377
1378 //
1379 // Handle Stop() requests for in-use driver instances gracefully.
1380 //
1381 Status = gBS->UninstallMultipleProtocolInterfaces (
1382 &DeviceHandle,
1383 &gEfiSimpleTextInProtocolGuid,
1384 &Dev->Txt,
1385 &gEfiSimpleTextInputExProtocolGuid,
1386 &Dev->TxtEx,
1387 NULL
1388 );
1389 if (EFI_ERROR (Status)) {
1390 return Status;
1391 }
1392
1393 gBS->CloseEvent (Dev->ExitBoot);
1394
1395 VirtioKeyboardUninit (Dev);
1396
1397 gBS->CloseProtocol (
1398 DeviceHandle,
1399 &gVirtioDeviceProtocolGuid,
1400 This->DriverBindingHandle,
1401 DeviceHandle
1402 );
1403
1404 FreePool (Dev);
1405
1406 return EFI_SUCCESS;
1407}
1408
1409// -----------------------------------------------------------------------------
1410// Forward declaration of global variable
1411STATIC
1412EFI_COMPONENT_NAME_PROTOCOL gComponentName;
1413
1414// -----------------------------------------------------------------------------
1415// Driver name to be displayed
1416STATIC
1417EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
1418 { "eng;en", L"Virtio Keyboard Driver" },
1419 { NULL, NULL }
1420};
1421
1422// -----------------------------------------------------------------------------
1423// Driver name lookup function
1424STATIC
1425EFI_STATUS
1426EFIAPI
1427VirtioKeyboardGetDriverName (
1428 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1429 IN CHAR8 *Language,
1430 OUT CHAR16 **DriverName
1431 )
1432{
1433 return LookupUnicodeString2 (
1434 Language,
1435 This->SupportedLanguages,
1436 mDriverNameTable,
1437 DriverName,
1438 (BOOLEAN)(This == &gComponentName) // Iso639Language
1439 );
1440}
1441
1442// -----------------------------------------------------------------------------
1443// Device name to be displayed
1444STATIC
1445EFI_UNICODE_STRING_TABLE mDeviceNameTable[] = {
1446 { "eng;en", L"RHEL virtio virtual keyboard BOB (Basic Operation Board)" },
1447 { NULL, NULL }
1448};
1449
1450// -----------------------------------------------------------------------------
1451STATIC
1452EFI_COMPONENT_NAME_PROTOCOL gDeviceName;
1453
1454// -----------------------------------------------------------------------------
1455STATIC
1456EFI_STATUS
1457EFIAPI
1458VirtioKeyboardGetDeviceName (
1459 IN EFI_COMPONENT_NAME_PROTOCOL *This,
1460 IN EFI_HANDLE DeviceHandle,
1461 IN EFI_HANDLE ChildHandle,
1462 IN CHAR8 *Language,
1463 OUT CHAR16 **ControllerName
1464 )
1465{
1466 return LookupUnicodeString2 (
1467 Language,
1468 This->SupportedLanguages,
1469 mDeviceNameTable,
1470 ControllerName,
1471 (BOOLEAN)(This == &gDeviceName) // Iso639Language
1472 );
1473}
1474
1475// -----------------------------------------------------------------------------
1476// General driver UEFI interface for showing driver name
1477STATIC
1478EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
1479 &VirtioKeyboardGetDriverName,
1480 &VirtioKeyboardGetDeviceName,
1481 "eng" // SupportedLanguages, ISO 639-2 language codes
1482};
1483
1484// -----------------------------------------------------------------------------
1485// General driver UEFI interface for showing driver name
1486STATIC
1487EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
1488 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioKeyboardGetDriverName,
1489 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioKeyboardGetDeviceName,
1490 "en" // SupportedLanguages, RFC 4646 language codes
1491};
1492
1493// -----------------------------------------------------------------------------
1494// General driver UEFI interface for loading / unloading driver
1495STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
1496 &VirtioKeyboardBindingSupported,
1497 &VirtioKeyboardBindingStart,
1498 &VirtioKeyboardBindingStop,
1499 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
1500 NULL, // ImageHandle, to be overwritten by
1501 // EfiLibInstallDriverBindingComponentName2() in VirtioKeyboardEntryPoint()
1502 NULL // DriverBindingHandle, ditto
1503};
1504
1505// -----------------------------------------------------------------------------
1506// Driver entry point set in INF file, registers all driver functions into UEFI
1507EFI_STATUS
1508EFIAPI
1509VirtioKeyboardEntryPoint (
1510 IN EFI_HANDLE ImageHandle,
1511 IN EFI_SYSTEM_TABLE *SystemTable
1512 )
1513{
1514 DEBUG ((DEBUG_INFO, "Virtio keyboard has been loaded.......................\n"));
1515 return EfiLibInstallDriverBindingComponentName2 (
1516 ImageHandle,
1517 SystemTable,
1518 &gDriverBinding,
1519 ImageHandle,
1520 &gComponentName,
1521 &gComponentName2
1522 );
1523}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette