VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/FirmwareNew/OvmfPkg/VirtioSerialDxe/VirtioSerial.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: 20.1 KB
Line 
1/** @file
2
3 Driver for virtio-serial devices.
4
5 The virtio serial device also known as virtio console device because
6 initially it had only support for a single tty, intended to be used
7 as console. Support for multiple streams and named data ports has
8 been added later on.
9
10 https://docs.oasis-open.org/virtio/virtio/v1.2/cs01/virtio-v1.2-cs01.html#x1-2900003
11
12 SPDX-License-Identifier: BSD-2-Clause-Patent
13
14**/
15
16#include <Library/BaseMemoryLib.h>
17#include <Library/DebugLib.h>
18#include <Library/DevicePathLib.h>
19#include <Library/MemoryAllocationLib.h>
20#include <Library/UefiBootServicesTableLib.h>
21#include <Library/UefiLib.h>
22#include <Library/VirtioLib.h>
23
24#include "VirtioSerial.h"
25
26STATIC LIST_ENTRY mVirtioSerialList;
27
28STATIC CONST CHAR8 *EventNames[] = {
29 [VIRTIO_SERIAL_DEVICE_READY] = "device-ready",
30 [VIRTIO_SERIAL_DEVICE_ADD] = "device-add",
31 [VIRTIO_SERIAL_DEVICE_REMOVE] = "device-remove",
32 [VIRTIO_SERIAL_PORT_READY] = "port-ready",
33 [VIRTIO_SERIAL_CONSOLE_PORT] = "console-port",
34 [VIRTIO_SERIAL_RESIZE] = "resize",
35 [VIRTIO_SERIAL_PORT_OPEN] = "port-open",
36 [VIRTIO_SERIAL_PORT_NAME] = "port-name",
37};
38
39VOID
40EFIAPI
41LogDevicePath (
42 UINT32 Level,
43 const CHAR8 *Func,
44 CHAR16 *Note,
45 EFI_DEVICE_PATH_PROTOCOL *DevicePath
46 )
47{
48 CHAR16 *Str;
49
50 Str = ConvertDevicePathToText (DevicePath, FALSE, FALSE);
51 if (!Str) {
52 DEBUG ((DEBUG_INFO, "ConvertDevicePathToText failed\n"));
53 return;
54 }
55
56 DEBUG ((Level, "%a: %s%s%s\n", Func, Note ? Note : L"", Note ? L": " : L"", Str));
57 FreePool (Str);
58}
59
60EFI_STATUS
61EFIAPI
62VirtioSerialTxControl (
63 IN OUT VIRTIO_SERIAL_DEV *Dev,
64 IN UINT32 Id,
65 IN UINT16 Event,
66 IN UINT16 Value
67 )
68{
69 VIRTIO_SERIAL_CONTROL Control;
70
71 Control.Id = Id;
72 Control.Event = Event;
73 Control.Value = Value;
74
75 DEBUG ((
76 DEBUG_INFO,
77 "%a:%d: >>> event %a, port-id %d, value %d\n",
78 __func__,
79 __LINE__,
80 EventNames[Control.Event],
81 Control.Id,
82 Control.Value
83 ));
84
85 VirtioSerialRingClearTx (Dev, VIRTIO_SERIAL_Q_TX_CTRL);
86 return VirtioSerialRingSendBuffer (Dev, VIRTIO_SERIAL_Q_TX_CTRL, &Control, sizeof (Control), TRUE);
87}
88
89STATIC
90VOID
91EFIAPI
92VirtioSerialRxControl (
93 IN OUT VIRTIO_SERIAL_DEV *Dev
94 )
95{
96 UINT8 Data[CTRL_RX_BUFSIZE+1];
97 UINT32 DataSize;
98 VIRTIO_SERIAL_CONTROL Control;
99 EFI_STATUS Status;
100 BOOLEAN HasData;
101 UINT16 Ready;
102
103 for ( ; ;) {
104 HasData = VirtioSerialRingGetBuffer (Dev, VIRTIO_SERIAL_Q_RX_CTRL, Data, &DataSize);
105 if (!HasData) {
106 return;
107 }
108
109 if (DataSize < sizeof (Control)) {
110 DEBUG ((
111 DEBUG_ERROR,
112 "%a:%d: length mismatch: %d != %d\n",
113 __func__,
114 __LINE__,
115 DataSize,
116 sizeof (Control)
117 ));
118 continue;
119 }
120
121 CopyMem (&Control, Data, sizeof (Control));
122
123 if (Control.Event < ARRAY_SIZE (EventNames)) {
124 DEBUG ((
125 DEBUG_INFO,
126 "%a:%d: <<< event %a, port-id %d, value %d\n",
127 __func__,
128 __LINE__,
129 EventNames[Control.Event],
130 Control.Id,
131 Control.Value
132 ));
133 } else {
134 DEBUG ((
135 DEBUG_ERROR,
136 "%a:%d: unknown event: %d\n",
137 __func__,
138 __LINE__,
139 Control.Event
140 ));
141 }
142
143 switch (Control.Event) {
144 case VIRTIO_SERIAL_DEVICE_ADD:
145 if (Control.Id < MAX_PORTS) {
146 Status = VirtioSerialPortAdd (Dev, Control.Id);
147 Ready = (Status == EFI_SUCCESS) ? 1 : 0;
148 } else {
149 Ready = 0;
150 }
151
152 VirtioSerialTxControl (Dev, Control.Id, VIRTIO_SERIAL_PORT_READY, Ready);
153 if (Ready) {
154 Dev->NumPorts++;
155 }
156
157 break;
158 case VIRTIO_SERIAL_DEVICE_REMOVE:
159 if (Control.Id < MAX_PORTS) {
160 VirtioSerialPortRemove (Dev, Control.Id);
161 }
162
163 break;
164 case VIRTIO_SERIAL_CONSOLE_PORT:
165 if (Control.Id < MAX_PORTS) {
166 VirtioSerialPortSetConsole (Dev, Control.Id);
167 Dev->NumConsoles++;
168 VirtioSerialPortSetDeviceOpen (Dev, Control.Id, 1);
169 }
170
171 break;
172 case VIRTIO_SERIAL_PORT_NAME:
173 if (Control.Id < MAX_PORTS) {
174 Data[DataSize] = 0;
175 VirtioSerialPortSetName (Dev, Control.Id, Data + sizeof (Control));
176 Dev->NumNamedPorts++;
177 }
178
179 break;
180 case VIRTIO_SERIAL_PORT_OPEN:
181 if (Control.Id < MAX_PORTS) {
182 VirtioSerialPortSetDeviceOpen (Dev, Control.Id, Control.Value);
183 }
184
185 break;
186 default:
187 break;
188 }
189 }
190}
191
192STATIC
193VOID
194EFIAPI
195VirtioSerialTimer (
196 IN EFI_EVENT Event,
197 IN VOID *Context
198 )
199{
200 VIRTIO_SERIAL_DEV *Dev = Context;
201
202 VirtioSerialRxControl (Dev);
203}
204
205STATIC
206VOID
207EFIAPI
208VirtioSerialUninitAllRings (
209 IN OUT VIRTIO_SERIAL_DEV *Dev
210 )
211{
212 UINT16 Index;
213
214 for (Index = 0; Index < MAX_RINGS; Index++) {
215 VirtioSerialUninitRing (Dev, Index);
216 }
217}
218
219STATIC
220EFI_STATUS
221EFIAPI
222VirtioSerialInit (
223 IN OUT VIRTIO_SERIAL_DEV *Dev
224 )
225{
226 UINT8 NextDevStat;
227 EFI_STATUS Status;
228 UINT64 Features;
229 UINTN Retries;
230
231 //
232 // Execute virtio-0.9.5, 2.2.1 Device Initialization Sequence.
233 //
234 NextDevStat = 0; // step 1 -- reset device
235 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
236 if (EFI_ERROR (Status)) {
237 goto Failed;
238 }
239
240 NextDevStat |= VSTAT_ACK; // step 2 -- acknowledge device presence
241 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
242 if (EFI_ERROR (Status)) {
243 goto Failed;
244 }
245
246 NextDevStat |= VSTAT_DRIVER; // step 3 -- we know how to drive it
247 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
248 if (EFI_ERROR (Status)) {
249 goto Failed;
250 }
251
252 //
253 // Set Page Size - MMIO VirtIo Specific
254 //
255 Status = Dev->VirtIo->SetPageSize (Dev->VirtIo, EFI_PAGE_SIZE);
256 if (EFI_ERROR (Status)) {
257 goto Failed;
258 }
259
260 //
261 // step 4a -- retrieve and validate features
262 //
263 Status = Dev->VirtIo->GetDeviceFeatures (Dev->VirtIo, &Features);
264 if (EFI_ERROR (Status)) {
265 goto Failed;
266 }
267
268 Features &= (VIRTIO_F_VERSION_1 |
269 VIRTIO_F_IOMMU_PLATFORM |
270 VIRTIO_SERIAL_F_MULTIPORT);
271
272 //
273 // In virtio-1.0, feature negotiation is expected to complete before queue
274 // discovery, and the device can also reject the selected set of features.
275 //
276 if (Dev->VirtIo->Revision >= VIRTIO_SPEC_REVISION (1, 0, 0)) {
277 Status = Virtio10WriteFeatures (Dev->VirtIo, Features, &NextDevStat);
278 if (EFI_ERROR (Status)) {
279 goto Failed;
280 }
281 }
282
283 DEBUG ((
284 DEBUG_INFO,
285 "%a:%d: features ok:%a%a%a\n",
286 __func__,
287 __LINE__,
288 (Features & VIRTIO_F_VERSION_1) ? " v1.0" : "",
289 (Features & VIRTIO_F_IOMMU_PLATFORM) ? " iommu" : "",
290 (Features & VIRTIO_SERIAL_F_MULTIPORT) ? " multiport" : ""
291 ));
292
293 if (Features & VIRTIO_SERIAL_F_MULTIPORT) {
294 Dev->VirtIo->ReadDevice (
295 Dev->VirtIo,
296 OFFSET_OF (VIRTIO_SERIAL_CONFIG, MaxPorts),
297 sizeof (Dev->Config.MaxPorts),
298 sizeof (Dev->Config.MaxPorts),
299 &Dev->Config.MaxPorts
300 );
301 DEBUG ((
302 DEBUG_INFO,
303 "%a:%d: max device ports: %d\n",
304 __func__,
305 __LINE__,
306 Dev->Config.MaxPorts
307 ));
308 }
309
310 Status = VirtioSerialInitRing (Dev, VIRTIO_SERIAL_Q_RX_CTRL, CTRL_RX_BUFSIZE);
311 if (EFI_ERROR (Status)) {
312 goto Failed;
313 }
314
315 Status = VirtioSerialInitRing (Dev, VIRTIO_SERIAL_Q_TX_CTRL, CTRL_TX_BUFSIZE);
316 if (EFI_ERROR (Status)) {
317 goto Failed;
318 }
319
320 //
321 // step 5 -- Report understood features and guest-tuneables.
322 //
323 if (Dev->VirtIo->Revision < VIRTIO_SPEC_REVISION (1, 0, 0)) {
324 Features &= ~(UINT64)(VIRTIO_F_VERSION_1 | VIRTIO_F_IOMMU_PLATFORM);
325 Status = Dev->VirtIo->SetGuestFeatures (Dev->VirtIo, Features);
326 if (EFI_ERROR (Status)) {
327 goto Failed;
328 }
329 }
330
331 //
332 // step 6 -- initialization complete
333 //
334 NextDevStat |= VSTAT_DRIVER_OK;
335 Status = Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
336 if (EFI_ERROR (Status)) {
337 goto Failed;
338 }
339
340 VirtioSerialRingFillRx (Dev, VIRTIO_SERIAL_Q_RX_CTRL);
341 VirtioSerialTxControl (Dev, 0, VIRTIO_SERIAL_DEVICE_READY, 1);
342 for (Retries = 0; Retries < 100; Retries++) {
343 gBS->Stall (1000);
344 VirtioSerialRxControl (Dev);
345 if (Dev->NumPorts && (Dev->NumConsoles + Dev->NumNamedPorts == Dev->NumPorts)) {
346 // port discovery complete
347 break;
348 }
349 }
350
351 Status = gBS->CreateEvent (
352 EVT_TIMER | EVT_NOTIFY_SIGNAL,
353 TPL_NOTIFY,
354 VirtioSerialTimer,
355 Dev,
356 &Dev->Timer
357 );
358 if (EFI_ERROR (Status)) {
359 goto Failed;
360 }
361
362 Status = gBS->SetTimer (
363 Dev->Timer,
364 TimerPeriodic,
365 EFI_TIMER_PERIOD_MILLISECONDS (10)
366 );
367 if (EFI_ERROR (Status)) {
368 goto Failed;
369 }
370
371 DEBUG ((
372 DEBUG_INFO,
373 "%a:%d: OK, %d consoles, %d named ports\n",
374 __func__,
375 __LINE__,
376 Dev->NumConsoles,
377 Dev->NumNamedPorts
378 ));
379 return EFI_SUCCESS;
380
381Failed:
382 VirtioSerialUninitAllRings (Dev);
383
384 //
385 // Notify the host about our failure to setup: virtio-0.9.5, 2.2.2.1 Device
386 // Status. VirtIo access failure here should not mask the original error.
387 //
388 NextDevStat |= VSTAT_FAILED;
389 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, NextDevStat);
390
391 DEBUG ((DEBUG_INFO, "%a:%d: ERROR: %r\n", __func__, __LINE__, Status));
392 return Status; // reached only via Failed above
393}
394
395STATIC
396VOID
397EFIAPI
398VirtioSerialUninit (
399 IN OUT VIRTIO_SERIAL_DEV *Dev
400 )
401{
402 UINT32 PortId;
403
404 gBS->CloseEvent (Dev->Timer);
405
406 //
407 // Reset the virtual device -- see virtio-0.9.5, 2.2.2.1 Device Status. When
408 // VIRTIO_CFG_WRITE() returns, the host will have learned to stay away from
409 // the old comms area.
410 //
411 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
412
413 for (PortId = 0; PortId < MAX_PORTS; PortId++) {
414 VirtioSerialPortRemove (Dev, PortId);
415 }
416
417 VirtioSerialUninitAllRings (Dev);
418}
419
420//
421// Event notification function enqueued by ExitBootServices().
422//
423
424STATIC
425VOID
426EFIAPI
427VirtioSerialExitBoot (
428 IN EFI_EVENT Event,
429 IN VOID *Context
430 )
431{
432 VIRTIO_SERIAL_DEV *Dev;
433
434 DEBUG ((DEBUG_INFO, "%a: Context=0x%p\n", __func__, Context));
435 //
436 // Reset the device. This causes the hypervisor to forget about the virtio
437 // ring.
438 //
439 // We allocated said ring in EfiBootServicesData type memory, and code
440 // executing after ExitBootServices() is permitted to overwrite it.
441 //
442 Dev = Context;
443 Dev->VirtIo->SetDeviceStatus (Dev->VirtIo, 0);
444}
445
446STATIC
447VIRTIO_SERIAL_DEV *
448VirtioSerialFind (
449 EFI_HANDLE DeviceHandle
450 )
451{
452 VIRTIO_SERIAL_DEV *Dev;
453 LIST_ENTRY *Entry;
454
455 BASE_LIST_FOR_EACH (Entry, &mVirtioSerialList) {
456 Dev = CR (Entry, VIRTIO_SERIAL_DEV, Link, VIRTIO_SERIAL_SIG);
457 if (DeviceHandle == Dev->DeviceHandle) {
458 return Dev;
459 }
460 }
461 return NULL;
462}
463
464//
465// Probe, start and stop functions of this driver, called by the DXE core for
466// specific devices.
467//
468// The following specifications document these interfaces:
469// - Driver Writer's Guide for UEFI 2.3.1 v1.01, 9 Driver Binding Protocol
470// - UEFI Spec 2.3.1 + Errata C, 10.1 EFI Driver Binding Protocol
471//
472// The implementation follows:
473// - Driver Writer's Guide for UEFI 2.3.1 v1.01
474// - 5.1.3.4 OpenProtocol() and CloseProtocol()
475// - UEFI Spec 2.3.1 + Errata C
476// - 6.3 Protocol Handler Services
477//
478
479STATIC
480EFI_STATUS
481EFIAPI
482VirtioSerialDriverBindingSupported (
483 IN EFI_DRIVER_BINDING_PROTOCOL *This,
484 IN EFI_HANDLE DeviceHandle,
485 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
486 )
487{
488 EFI_STATUS Status;
489 VIRTIO_DEVICE_PROTOCOL *VirtIo;
490
491 //
492 // Attempt to open the device with the VirtIo set of interfaces. On success,
493 // the protocol is "instantiated" for the VirtIo device. Covers duplicate
494 // open attempts (EFI_ALREADY_STARTED).
495 //
496 Status = gBS->OpenProtocol (
497 DeviceHandle, // candidate device
498 &gVirtioDeviceProtocolGuid, // for generic VirtIo access
499 (VOID **)&VirtIo, // handle to instantiate
500 This->DriverBindingHandle, // requestor driver identity
501 DeviceHandle, // ControllerHandle, according to
502 // the UEFI Driver Model
503 EFI_OPEN_PROTOCOL_BY_DRIVER // get exclusive VirtIo access to
504 // the device; to be released
505 );
506 if (EFI_ERROR (Status)) {
507 return Status;
508 }
509
510 if (VirtIo->SubSystemDeviceId != VIRTIO_SUBSYSTEM_CONSOLE) {
511 Status = EFI_UNSUPPORTED;
512 }
513
514 //
515 // We needed VirtIo access only transitorily, to see whether we support the
516 // device or not.
517 //
518 gBS->CloseProtocol (
519 DeviceHandle,
520 &gVirtioDeviceProtocolGuid,
521 This->DriverBindingHandle,
522 DeviceHandle
523 );
524 return Status;
525}
526
527STATIC
528EFI_STATUS
529EFIAPI
530VirtioSerialDriverBindingStart (
531 IN EFI_DRIVER_BINDING_PROTOCOL *This,
532 IN EFI_HANDLE DeviceHandle,
533 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
534 )
535{
536 VIRTIO_SERIAL_DEV *Dev;
537 EFI_STATUS Status;
538
539 Dev = (VIRTIO_SERIAL_DEV *)AllocateZeroPool (sizeof *Dev);
540 if (Dev == NULL) {
541 return EFI_OUT_OF_RESOURCES;
542 }
543
544 Status = gBS->OpenProtocol (
545 DeviceHandle,
546 &gEfiDevicePathProtocolGuid,
547 (VOID **)&Dev->DevicePath,
548 This->DriverBindingHandle,
549 DeviceHandle,
550 EFI_OPEN_PROTOCOL_GET_PROTOCOL
551 );
552 if (EFI_ERROR (Status)) {
553 goto FreeVirtioSerial;
554 }
555
556 Status = gBS->OpenProtocol (
557 DeviceHandle,
558 &gVirtioDeviceProtocolGuid,
559 (VOID **)&Dev->VirtIo,
560 This->DriverBindingHandle,
561 DeviceHandle,
562 EFI_OPEN_PROTOCOL_BY_DRIVER
563 );
564 if (EFI_ERROR (Status)) {
565 goto FreeVirtioSerial;
566 }
567
568 LogDevicePath (DEBUG_INFO, __func__, L"Dev", Dev->DevicePath);
569
570 //
571 // VirtIo access granted, configure virtio-serial device.
572 //
573 Dev->Signature = VIRTIO_SERIAL_SIG;
574 Dev->DriverBindingHandle = This->DriverBindingHandle;
575 Dev->DeviceHandle = DeviceHandle;
576 Status = VirtioSerialInit (Dev);
577 if (EFI_ERROR (Status)) {
578 goto CloseVirtIo;
579 }
580
581 Status = gBS->CreateEvent (
582 EVT_SIGNAL_EXIT_BOOT_SERVICES,
583 TPL_CALLBACK,
584 &VirtioSerialExitBoot,
585 Dev,
586 &Dev->ExitBoot
587 );
588 if (EFI_ERROR (Status)) {
589 goto UninitDev;
590 }
591
592 InsertTailList (&mVirtioSerialList, &(Dev->Link));
593 return EFI_SUCCESS;
594
595UninitDev:
596 VirtioSerialUninit (Dev);
597
598CloseVirtIo:
599 gBS->CloseProtocol (
600 DeviceHandle,
601 &gVirtioDeviceProtocolGuid,
602 This->DriverBindingHandle,
603 DeviceHandle
604 );
605
606FreeVirtioSerial:
607 FreePool (Dev);
608
609 return Status;
610}
611
612STATIC
613EFI_STATUS
614EFIAPI
615VirtioSerialDriverBindingStop (
616 IN EFI_DRIVER_BINDING_PROTOCOL *This,
617 IN EFI_HANDLE DeviceHandle,
618 IN UINTN NumberOfChildren,
619 IN EFI_HANDLE *ChildHandleBuffer
620 )
621{
622 VIRTIO_SERIAL_DEV *Dev;
623 UINT32 PortId;
624 UINT32 Child;
625
626 Dev = VirtioSerialFind (DeviceHandle);
627 if (!Dev) {
628 return EFI_SUCCESS;
629 }
630
631 if (NumberOfChildren) {
632 for (Child = 0; Child < NumberOfChildren; Child++) {
633 DEBUG ((DEBUG_INFO, "%a:%d: child handle 0x%x\n", __func__, __LINE__, ChildHandleBuffer[Child]));
634 for (PortId = 0; PortId < MAX_PORTS; PortId++) {
635 if (Dev->Ports[PortId].Ready &&
636 Dev->Ports[PortId].SerialIo &&
637 (Dev->Ports[PortId].SerialIo->DeviceHandle == ChildHandleBuffer[Child]))
638 {
639 VirtioSerialPortRemove (Dev, PortId);
640 }
641 }
642 }
643
644 return EFI_SUCCESS;
645 }
646
647 DEBUG ((DEBUG_INFO, "%a:%d: controller handle 0x%x\n", __func__, __LINE__, DeviceHandle));
648
649 gBS->CloseEvent (Dev->ExitBoot);
650
651 VirtioSerialUninit (Dev);
652
653 gBS->CloseProtocol (
654 DeviceHandle,
655 &gVirtioDeviceProtocolGuid,
656 This->DriverBindingHandle,
657 DeviceHandle
658 );
659
660 RemoveEntryList (&(Dev->Link));
661 ZeroMem (Dev, sizeof (*Dev));
662 FreePool (Dev);
663
664 return EFI_SUCCESS;
665}
666
667//
668// The static object that groups the Supported() (ie. probe), Start() and
669// Stop() functions of the driver together. Refer to UEFI Spec 2.3.1 + Errata
670// C, 10.1 EFI Driver Binding Protocol.
671//
672STATIC EFI_DRIVER_BINDING_PROTOCOL gDriverBinding = {
673 &VirtioSerialDriverBindingSupported,
674 &VirtioSerialDriverBindingStart,
675 &VirtioSerialDriverBindingStop,
676 0x10, // Version, must be in [0x10 .. 0xFFFFFFEF] for IHV-developed drivers
677 NULL, // ImageHandle, to be overwritten by
678 // EfiLibInstallDriverBindingComponentName2() in VirtioSerialEntryPoint()
679 NULL // DriverBindingHandle, ditto
680};
681
682//
683// The purpose of the following scaffolding (EFI_COMPONENT_NAME_PROTOCOL and
684// EFI_COMPONENT_NAME2_PROTOCOL implementation) is to format the driver's name
685// in English, for display on standard console devices. This is recommended for
686// UEFI drivers that follow the UEFI Driver Model. Refer to the Driver Writer's
687// Guide for UEFI 2.3.1 v1.01, 11 UEFI Driver and Controller Names.
688//
689
690STATIC
691EFI_UNICODE_STRING_TABLE mDriverNameTable[] = {
692 { "eng;en", L"Virtio Serial Driver" },
693 { NULL, NULL }
694};
695
696STATIC
697EFI_UNICODE_STRING_TABLE mDeviceNameTable[] = {
698 { "eng;en", L"Virtio Serial Device" },
699 { NULL, NULL }
700};
701
702STATIC
703EFI_UNICODE_STRING_TABLE mPortNameTable[] = {
704 { "eng;en", L"Virtio Serial Port" },
705 { NULL, NULL }
706};
707
708STATIC
709EFI_COMPONENT_NAME_PROTOCOL gComponentName;
710
711STATIC
712EFI_STATUS
713EFIAPI
714VirtioSerialGetDriverName (
715 IN EFI_COMPONENT_NAME_PROTOCOL *This,
716 IN CHAR8 *Language,
717 OUT CHAR16 **DriverName
718 )
719{
720 return LookupUnicodeString2 (
721 Language,
722 This->SupportedLanguages,
723 mDriverNameTable,
724 DriverName,
725 (BOOLEAN)(This == &gComponentName) // Iso639Language
726 );
727}
728
729STATIC
730EFI_STATUS
731EFIAPI
732VirtioSerialGetDeviceName (
733 IN EFI_COMPONENT_NAME_PROTOCOL *This,
734 IN EFI_HANDLE DeviceHandle,
735 IN EFI_HANDLE ChildHandle,
736 IN CHAR8 *Language,
737 OUT CHAR16 **ControllerName
738 )
739{
740 EFI_UNICODE_STRING_TABLE *Table;
741 VIRTIO_SERIAL_DEV *Dev;
742 UINT32 PortId;
743
744 Dev = VirtioSerialFind (DeviceHandle);
745 if (!Dev) {
746 return EFI_UNSUPPORTED;
747 }
748
749 if (ChildHandle) {
750 for (PortId = 0; PortId < MAX_PORTS; PortId++) {
751 if (Dev->Ports[PortId].Ready &&
752 Dev->Ports[PortId].SerialIo &&
753 (Dev->Ports[PortId].SerialIo->DeviceHandle == ChildHandle))
754 {
755 *ControllerName = Dev->Ports[PortId].Name;
756 return EFI_SUCCESS;
757 }
758 }
759
760 Table = mPortNameTable;
761 } else {
762 Table = mDeviceNameTable;
763 }
764
765 return LookupUnicodeString2 (
766 Language,
767 This->SupportedLanguages,
768 Table,
769 ControllerName,
770 (BOOLEAN)(This == &gComponentName)
771 );
772}
773
774STATIC
775EFI_COMPONENT_NAME_PROTOCOL gComponentName = {
776 &VirtioSerialGetDriverName,
777 &VirtioSerialGetDeviceName,
778 "eng" // SupportedLanguages, ISO 639-2 language codes
779};
780
781STATIC
782EFI_COMPONENT_NAME2_PROTOCOL gComponentName2 = {
783 (EFI_COMPONENT_NAME2_GET_DRIVER_NAME)&VirtioSerialGetDriverName,
784 (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME)&VirtioSerialGetDeviceName,
785 "en" // SupportedLanguages, RFC 4646 language codes
786};
787
788//
789// Entry point of this driver.
790//
791EFI_STATUS
792EFIAPI
793VirtioSerialEntryPoint (
794 IN EFI_HANDLE ImageHandle,
795 IN EFI_SYSTEM_TABLE *SystemTable
796 )
797{
798 InitializeListHead (&mVirtioSerialList);
799 return EfiLibInstallDriverBindingComponentName2 (
800 ImageHandle,
801 SystemTable,
802 &gDriverBinding,
803 ImageHandle,
804 &gComponentName,
805 &gComponentName2
806 );
807}
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