1 /** @file
2 This driver is a sample implementation of the Graphics Output Protocol for
3 the QEMU (Cirrus Logic 5446) video controller.
4
5 Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
6
7 This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Qemu.h"
18 #include <IndustryStandard/Acpi.h>
19
20 EFI_DRIVER_BINDING_PROTOCOL gQemuVideoDriverBinding = {
21 QemuVideoControllerDriverSupported,
22 QemuVideoControllerDriverStart,
23 QemuVideoControllerDriverStop,
24 0x10,
25 NULL,
26 NULL
27 };
28
29 QEMU_VIDEO_CARD gQemuVideoCardList[] = {
30 {
31 CIRRUS_LOGIC_VENDOR_ID,
32 CIRRUS_LOGIC_5430_DEVICE_ID,
33 QEMU_VIDEO_CIRRUS_5430,
34 L"Cirrus 5430"
35 },{
36 CIRRUS_LOGIC_VENDOR_ID,
37 CIRRUS_LOGIC_5430_ALTERNATE_DEVICE_ID,
38 QEMU_VIDEO_CIRRUS_5430,
39 L"Cirrus 5430"
40 },{
41 CIRRUS_LOGIC_VENDOR_ID,
42 CIRRUS_LOGIC_5446_DEVICE_ID,
43 QEMU_VIDEO_CIRRUS_5446,
44 L"Cirrus 5446"
45 },{
46 0x1234,
47 0x1111,
48 QEMU_VIDEO_BOCHS_MMIO,
49 L"QEMU Standard VGA"
50 },{
51 0x1b36,
52 0x0100,
53 QEMU_VIDEO_BOCHS,
54 L"QEMU QXL VGA"
55 },{
56 0x1af4,
57 0x1050,
58 QEMU_VIDEO_BOCHS_MMIO,
59 L"QEMU VirtIO VGA"
60 },{
61 0 /* end of list */
62 }
63 };
64
65 static QEMU_VIDEO_CARD*
QemuVideoDetect(IN UINT16 VendorId,IN UINT16 DeviceId)66 QemuVideoDetect(
67 IN UINT16 VendorId,
68 IN UINT16 DeviceId
69 )
70 {
71 UINTN Index = 0;
72
73 while (gQemuVideoCardList[Index].VendorId != 0) {
74 if (gQemuVideoCardList[Index].VendorId == VendorId &&
75 gQemuVideoCardList[Index].DeviceId == DeviceId) {
76 return gQemuVideoCardList + Index;
77 }
78 Index++;
79 }
80 return NULL;
81 }
82
83 /**
84 Check if this device is supported.
85
86 @param This The driver binding protocol.
87 @param Controller The controller handle to check.
88 @param RemainingDevicePath The remaining device path.
89
90 @retval EFI_SUCCESS The bus supports this controller.
91 @retval EFI_UNSUPPORTED This device isn't supported.
92
93 **/
94 EFI_STATUS
95 EFIAPI
QemuVideoControllerDriverSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)96 QemuVideoControllerDriverSupported (
97 IN EFI_DRIVER_BINDING_PROTOCOL *This,
98 IN EFI_HANDLE Controller,
99 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
100 )
101 {
102 EFI_STATUS Status;
103 EFI_PCI_IO_PROTOCOL *PciIo;
104 PCI_TYPE00 Pci;
105 QEMU_VIDEO_CARD *Card;
106
107 //
108 // Open the PCI I/O Protocol
109 //
110 Status = gBS->OpenProtocol (
111 Controller,
112 &gEfiPciIoProtocolGuid,
113 (VOID **) &PciIo,
114 This->DriverBindingHandle,
115 Controller,
116 EFI_OPEN_PROTOCOL_BY_DRIVER
117 );
118 if (EFI_ERROR (Status)) {
119 return Status;
120 }
121
122 //
123 // Read the PCI Configuration Header from the PCI Device
124 //
125 Status = PciIo->Pci.Read (
126 PciIo,
127 EfiPciIoWidthUint32,
128 0,
129 sizeof (Pci) / sizeof (UINT32),
130 &Pci
131 );
132 if (EFI_ERROR (Status)) {
133 goto Done;
134 }
135
136 Status = EFI_UNSUPPORTED;
137 if (!IS_PCI_VGA (&Pci)) {
138 goto Done;
139 }
140 Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
141 if (Card != NULL) {
142 DEBUG ((EFI_D_INFO, "QemuVideo: %s detected\n", Card->Name));
143 Status = EFI_SUCCESS;
144 }
145
146 Done:
147 //
148 // Close the PCI I/O Protocol
149 //
150 gBS->CloseProtocol (
151 Controller,
152 &gEfiPciIoProtocolGuid,
153 This->DriverBindingHandle,
154 Controller
155 );
156
157 return Status;
158 }
159
160 /**
161 Start to process the controller.
162
163 @param This The USB bus driver binding instance.
164 @param Controller The controller to check.
165 @param RemainingDevicePath The remaining device patch.
166
167 @retval EFI_SUCCESS The controller is controlled by the usb bus.
168 @retval EFI_ALREADY_STARTED The controller is already controlled by the usb
169 bus.
170 @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
171
172 **/
173 EFI_STATUS
174 EFIAPI
QemuVideoControllerDriverStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath)175 QemuVideoControllerDriverStart (
176 IN EFI_DRIVER_BINDING_PROTOCOL *This,
177 IN EFI_HANDLE Controller,
178 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
179 )
180 {
181 EFI_TPL OldTpl;
182 EFI_STATUS Status;
183 QEMU_VIDEO_PRIVATE_DATA *Private;
184 BOOLEAN IsQxl;
185 EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
186 ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
187 PCI_TYPE00 Pci;
188 QEMU_VIDEO_CARD *Card;
189 EFI_PCI_IO_PROTOCOL *ChildPciIo;
190
191 OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
192
193 //
194 // Allocate Private context data for GOP inteface.
195 //
196 Private = AllocateZeroPool (sizeof (QEMU_VIDEO_PRIVATE_DATA));
197 if (Private == NULL) {
198 Status = EFI_OUT_OF_RESOURCES;
199 goto RestoreTpl;
200 }
201
202 //
203 // Set up context record
204 //
205 Private->Signature = QEMU_VIDEO_PRIVATE_DATA_SIGNATURE;
206
207 //
208 // Open PCI I/O Protocol
209 //
210 Status = gBS->OpenProtocol (
211 Controller,
212 &gEfiPciIoProtocolGuid,
213 (VOID **) &Private->PciIo,
214 This->DriverBindingHandle,
215 Controller,
216 EFI_OPEN_PROTOCOL_BY_DRIVER
217 );
218 if (EFI_ERROR (Status)) {
219 goto FreePrivate;
220 }
221
222 //
223 // Read the PCI Configuration Header from the PCI Device
224 //
225 Status = Private->PciIo->Pci.Read (
226 Private->PciIo,
227 EfiPciIoWidthUint32,
228 0,
229 sizeof (Pci) / sizeof (UINT32),
230 &Pci
231 );
232 if (EFI_ERROR (Status)) {
233 goto ClosePciIo;
234 }
235
236 //
237 // Determine card variant.
238 //
239 Card = QemuVideoDetect(Pci.Hdr.VendorId, Pci.Hdr.DeviceId);
240 if (Card == NULL) {
241 Status = EFI_DEVICE_ERROR;
242 goto ClosePciIo;
243 }
244 Private->Variant = Card->Variant;
245
246 //
247 // IsQxl is based on the detected Card->Variant, which at a later point might
248 // not match Private->Variant.
249 //
250 IsQxl = (BOOLEAN)(Card->Variant == QEMU_VIDEO_BOCHS);
251
252 //
253 // Save original PCI attributes
254 //
255 Status = Private->PciIo->Attributes (
256 Private->PciIo,
257 EfiPciIoAttributeOperationGet,
258 0,
259 &Private->OriginalPciAttributes
260 );
261
262 if (EFI_ERROR (Status)) {
263 goto ClosePciIo;
264 }
265
266 //
267 // Set new PCI attributes
268 //
269 Status = Private->PciIo->Attributes (
270 Private->PciIo,
271 EfiPciIoAttributeOperationEnable,
272 EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | EFI_PCI_IO_ATTRIBUTE_VGA_IO,
273 NULL
274 );
275 if (EFI_ERROR (Status)) {
276 goto ClosePciIo;
277 }
278
279 //
280 // Check whenever the qemu stdvga mmio bar is present (qemu 1.3+).
281 //
282 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
283 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *MmioDesc;
284
285 Status = Private->PciIo->GetBarAttributes (
286 Private->PciIo,
287 PCI_BAR_IDX2,
288 NULL,
289 (VOID**) &MmioDesc
290 );
291 if (EFI_ERROR (Status) ||
292 MmioDesc->ResType != ACPI_ADDRESS_SPACE_TYPE_MEM) {
293 DEBUG ((EFI_D_INFO, "QemuVideo: No mmio bar, fallback to port io\n"));
294 Private->Variant = QEMU_VIDEO_BOCHS;
295 } else {
296 DEBUG ((EFI_D_INFO, "QemuVideo: Using mmio bar @ 0x%lx\n",
297 MmioDesc->AddrRangeMin));
298 }
299
300 if (!EFI_ERROR (Status)) {
301 FreePool (MmioDesc);
302 }
303 }
304
305 //
306 // Check if accessing the bochs interface works.
307 //
308 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
309 Private->Variant == QEMU_VIDEO_BOCHS) {
310 UINT16 BochsId;
311 BochsId = BochsRead(Private, VBE_DISPI_INDEX_ID);
312 if ((BochsId & 0xFFF0) != VBE_DISPI_ID0) {
313 DEBUG ((EFI_D_INFO, "QemuVideo: BochsID mismatch (got 0x%x)\n", BochsId));
314 Status = EFI_DEVICE_ERROR;
315 goto RestoreAttributes;
316 }
317 }
318
319 //
320 // Get ParentDevicePath
321 //
322 Status = gBS->HandleProtocol (
323 Controller,
324 &gEfiDevicePathProtocolGuid,
325 (VOID **) &ParentDevicePath
326 );
327 if (EFI_ERROR (Status)) {
328 goto RestoreAttributes;
329 }
330
331 //
332 // Set Gop Device Path
333 //
334 ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
335 AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
336 AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
337 AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
338 SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
339
340 Private->GopDevicePath = AppendDevicePathNode (
341 ParentDevicePath,
342 (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
343 );
344 if (Private->GopDevicePath == NULL) {
345 Status = EFI_OUT_OF_RESOURCES;
346 goto RestoreAttributes;
347 }
348
349 //
350 // Create new child handle and install the device path protocol on it.
351 //
352 Status = gBS->InstallMultipleProtocolInterfaces (
353 &Private->Handle,
354 &gEfiDevicePathProtocolGuid,
355 Private->GopDevicePath,
356 NULL
357 );
358 if (EFI_ERROR (Status)) {
359 goto FreeGopDevicePath;
360 }
361
362 //
363 // Construct video mode buffer
364 //
365 switch (Private->Variant) {
366 case QEMU_VIDEO_CIRRUS_5430:
367 case QEMU_VIDEO_CIRRUS_5446:
368 Status = QemuVideoCirrusModeSetup (Private);
369 break;
370 case QEMU_VIDEO_BOCHS_MMIO:
371 case QEMU_VIDEO_BOCHS:
372 Status = QemuVideoBochsModeSetup (Private, IsQxl);
373 break;
374 default:
375 ASSERT (FALSE);
376 Status = EFI_DEVICE_ERROR;
377 break;
378 }
379 if (EFI_ERROR (Status)) {
380 goto UninstallGopDevicePath;
381 }
382
383 //
384 // Start the GOP software stack.
385 //
386 Status = QemuVideoGraphicsOutputConstructor (Private);
387 if (EFI_ERROR (Status)) {
388 goto FreeModeData;
389 }
390
391 Status = gBS->InstallMultipleProtocolInterfaces (
392 &Private->Handle,
393 &gEfiGraphicsOutputProtocolGuid,
394 &Private->GraphicsOutput,
395 NULL
396 );
397 if (EFI_ERROR (Status)) {
398 goto DestructQemuVideoGraphics;
399 }
400
401 //
402 // Reference parent handle from child handle.
403 //
404 Status = gBS->OpenProtocol (
405 Controller,
406 &gEfiPciIoProtocolGuid,
407 (VOID **) &ChildPciIo,
408 This->DriverBindingHandle,
409 Private->Handle,
410 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
411 );
412 if (EFI_ERROR (Status)) {
413 goto UninstallGop;
414 }
415
416 #if defined MDE_CPU_IA32 || defined MDE_CPU_X64
417 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO ||
418 Private->Variant == QEMU_VIDEO_BOCHS) {
419 InstallVbeShim (Card->Name, Private->GraphicsOutput.Mode->FrameBufferBase);
420 }
421 #endif
422
423 gBS->RestoreTPL (OldTpl);
424 return EFI_SUCCESS;
425
426 UninstallGop:
427 gBS->UninstallProtocolInterface (Private->Handle,
428 &gEfiGraphicsOutputProtocolGuid, &Private->GraphicsOutput);
429
430 DestructQemuVideoGraphics:
431 QemuVideoGraphicsOutputDestructor (Private);
432
433 FreeModeData:
434 FreePool (Private->ModeData);
435
436 UninstallGopDevicePath:
437 gBS->UninstallProtocolInterface (Private->Handle,
438 &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
439
440 FreeGopDevicePath:
441 FreePool (Private->GopDevicePath);
442
443 RestoreAttributes:
444 Private->PciIo->Attributes (Private->PciIo, EfiPciIoAttributeOperationSet,
445 Private->OriginalPciAttributes, NULL);
446
447 ClosePciIo:
448 gBS->CloseProtocol (Controller, &gEfiPciIoProtocolGuid,
449 This->DriverBindingHandle, Controller);
450
451 FreePrivate:
452 FreePool (Private);
453
454 RestoreTpl:
455 gBS->RestoreTPL (OldTpl);
456
457 return Status;
458 }
459
460 /**
461 Stop this device
462
463 @param This The USB bus driver binding protocol.
464 @param Controller The controller to release.
465 @param NumberOfChildren The number of children of this device that
466 opened the controller BY_CHILD.
467 @param ChildHandleBuffer The array of child handle.
468
469 @retval EFI_SUCCESS The controller or children are stopped.
470 @retval EFI_DEVICE_ERROR Failed to stop the driver.
471
472 **/
473 EFI_STATUS
474 EFIAPI
QemuVideoControllerDriverStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE Controller,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer)475 QemuVideoControllerDriverStop (
476 IN EFI_DRIVER_BINDING_PROTOCOL *This,
477 IN EFI_HANDLE Controller,
478 IN UINTN NumberOfChildren,
479 IN EFI_HANDLE *ChildHandleBuffer
480 )
481 {
482 EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
483
484 EFI_STATUS Status;
485 QEMU_VIDEO_PRIVATE_DATA *Private;
486
487 if (NumberOfChildren == 0) {
488 //
489 // Close the PCI I/O Protocol
490 //
491 gBS->CloseProtocol (
492 Controller,
493 &gEfiPciIoProtocolGuid,
494 This->DriverBindingHandle,
495 Controller
496 );
497 return EFI_SUCCESS;
498 }
499
500 //
501 // free all resources for whose access we need the child handle, because the
502 // child handle is going away
503 //
504 ASSERT (NumberOfChildren == 1);
505 Status = gBS->OpenProtocol (
506 ChildHandleBuffer[0],
507 &gEfiGraphicsOutputProtocolGuid,
508 (VOID **) &GraphicsOutput,
509 This->DriverBindingHandle,
510 Controller,
511 EFI_OPEN_PROTOCOL_GET_PROTOCOL
512 );
513 if (EFI_ERROR (Status)) {
514 return Status;
515 }
516
517 //
518 // Get our private context information
519 //
520 Private = QEMU_VIDEO_PRIVATE_DATA_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
521 ASSERT (Private->Handle == ChildHandleBuffer[0]);
522
523 QemuVideoGraphicsOutputDestructor (Private);
524 //
525 // Remove the GOP protocol interface from the system
526 //
527 Status = gBS->UninstallMultipleProtocolInterfaces (
528 Private->Handle,
529 &gEfiGraphicsOutputProtocolGuid,
530 &Private->GraphicsOutput,
531 NULL
532 );
533
534 if (EFI_ERROR (Status)) {
535 return Status;
536 }
537
538 //
539 // Restore original PCI attributes
540 //
541 Private->PciIo->Attributes (
542 Private->PciIo,
543 EfiPciIoAttributeOperationSet,
544 Private->OriginalPciAttributes,
545 NULL
546 );
547
548 gBS->CloseProtocol (
549 Controller,
550 &gEfiPciIoProtocolGuid,
551 This->DriverBindingHandle,
552 Private->Handle
553 );
554
555 FreePool (Private->ModeData);
556 gBS->UninstallProtocolInterface (Private->Handle,
557 &gEfiDevicePathProtocolGuid, Private->GopDevicePath);
558 FreePool (Private->GopDevicePath);
559
560 //
561 // Free our instance data
562 //
563 gBS->FreePool (Private);
564
565 return EFI_SUCCESS;
566 }
567
568 /**
569 TODO: Add function description
570
571 @param Private TODO: add argument description
572 @param Address TODO: add argument description
573 @param Data TODO: add argument description
574
575 TODO: add return values
576
577 **/
578 VOID
outb(QEMU_VIDEO_PRIVATE_DATA * Private,UINTN Address,UINT8 Data)579 outb (
580 QEMU_VIDEO_PRIVATE_DATA *Private,
581 UINTN Address,
582 UINT8 Data
583 )
584 {
585 Private->PciIo->Io.Write (
586 Private->PciIo,
587 EfiPciIoWidthUint8,
588 EFI_PCI_IO_PASS_THROUGH_BAR,
589 Address,
590 1,
591 &Data
592 );
593 }
594
595 /**
596 TODO: Add function description
597
598 @param Private TODO: add argument description
599 @param Address TODO: add argument description
600 @param Data TODO: add argument description
601
602 TODO: add return values
603
604 **/
605 VOID
outw(QEMU_VIDEO_PRIVATE_DATA * Private,UINTN Address,UINT16 Data)606 outw (
607 QEMU_VIDEO_PRIVATE_DATA *Private,
608 UINTN Address,
609 UINT16 Data
610 )
611 {
612 Private->PciIo->Io.Write (
613 Private->PciIo,
614 EfiPciIoWidthUint16,
615 EFI_PCI_IO_PASS_THROUGH_BAR,
616 Address,
617 1,
618 &Data
619 );
620 }
621
622 /**
623 TODO: Add function description
624
625 @param Private TODO: add argument description
626 @param Address TODO: add argument description
627
628 TODO: add return values
629
630 **/
631 UINT8
inb(QEMU_VIDEO_PRIVATE_DATA * Private,UINTN Address)632 inb (
633 QEMU_VIDEO_PRIVATE_DATA *Private,
634 UINTN Address
635 )
636 {
637 UINT8 Data;
638
639 Private->PciIo->Io.Read (
640 Private->PciIo,
641 EfiPciIoWidthUint8,
642 EFI_PCI_IO_PASS_THROUGH_BAR,
643 Address,
644 1,
645 &Data
646 );
647 return Data;
648 }
649
650 /**
651 TODO: Add function description
652
653 @param Private TODO: add argument description
654 @param Address TODO: add argument description
655
656 TODO: add return values
657
658 **/
659 UINT16
inw(QEMU_VIDEO_PRIVATE_DATA * Private,UINTN Address)660 inw (
661 QEMU_VIDEO_PRIVATE_DATA *Private,
662 UINTN Address
663 )
664 {
665 UINT16 Data;
666
667 Private->PciIo->Io.Read (
668 Private->PciIo,
669 EfiPciIoWidthUint16,
670 EFI_PCI_IO_PASS_THROUGH_BAR,
671 Address,
672 1,
673 &Data
674 );
675 return Data;
676 }
677
678 /**
679 TODO: Add function description
680
681 @param Private TODO: add argument description
682 @param Index TODO: add argument description
683 @param Red TODO: add argument description
684 @param Green TODO: add argument description
685 @param Blue TODO: add argument description
686
687 TODO: add return values
688
689 **/
690 VOID
SetPaletteColor(QEMU_VIDEO_PRIVATE_DATA * Private,UINTN Index,UINT8 Red,UINT8 Green,UINT8 Blue)691 SetPaletteColor (
692 QEMU_VIDEO_PRIVATE_DATA *Private,
693 UINTN Index,
694 UINT8 Red,
695 UINT8 Green,
696 UINT8 Blue
697 )
698 {
699 VgaOutb (Private, PALETTE_INDEX_REGISTER, (UINT8) Index);
700 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Red >> 2));
701 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Green >> 2));
702 VgaOutb (Private, PALETTE_DATA_REGISTER, (UINT8) (Blue >> 2));
703 }
704
705 /**
706 TODO: Add function description
707
708 @param Private TODO: add argument description
709
710 TODO: add return values
711
712 **/
713 VOID
SetDefaultPalette(QEMU_VIDEO_PRIVATE_DATA * Private)714 SetDefaultPalette (
715 QEMU_VIDEO_PRIVATE_DATA *Private
716 )
717 {
718 UINTN Index;
719 UINTN RedIndex;
720 UINTN GreenIndex;
721 UINTN BlueIndex;
722
723 Index = 0;
724 for (RedIndex = 0; RedIndex < 8; RedIndex++) {
725 for (GreenIndex = 0; GreenIndex < 8; GreenIndex++) {
726 for (BlueIndex = 0; BlueIndex < 4; BlueIndex++) {
727 SetPaletteColor (Private, Index, (UINT8) (RedIndex << 5), (UINT8) (GreenIndex << 5), (UINT8) (BlueIndex << 6));
728 Index++;
729 }
730 }
731 }
732 }
733
734 /**
735 TODO: Add function description
736
737 @param Private TODO: add argument description
738
739 TODO: add return values
740
741 **/
742 VOID
ClearScreen(QEMU_VIDEO_PRIVATE_DATA * Private)743 ClearScreen (
744 QEMU_VIDEO_PRIVATE_DATA *Private
745 )
746 {
747 UINT32 Color;
748
749 Color = 0;
750 Private->PciIo->Mem.Write (
751 Private->PciIo,
752 EfiPciIoWidthFillUint32,
753 0,
754 0,
755 0x400000 >> 2,
756 &Color
757 );
758 }
759
760 /**
761 TODO: Add function description
762
763 @param Private TODO: add argument description
764
765 TODO: add return values
766
767 **/
768 VOID
DrawLogo(QEMU_VIDEO_PRIVATE_DATA * Private,UINTN ScreenWidth,UINTN ScreenHeight)769 DrawLogo (
770 QEMU_VIDEO_PRIVATE_DATA *Private,
771 UINTN ScreenWidth,
772 UINTN ScreenHeight
773 )
774 {
775 }
776
777 /**
778 TODO: Add function description
779
780 @param Private TODO: add argument description
781 @param ModeData TODO: add argument description
782
783 TODO: add return values
784
785 **/
786 VOID
InitializeCirrusGraphicsMode(QEMU_VIDEO_PRIVATE_DATA * Private,QEMU_VIDEO_CIRRUS_MODES * ModeData)787 InitializeCirrusGraphicsMode (
788 QEMU_VIDEO_PRIVATE_DATA *Private,
789 QEMU_VIDEO_CIRRUS_MODES *ModeData
790 )
791 {
792 UINT8 Byte;
793 UINTN Index;
794
795 outw (Private, SEQ_ADDRESS_REGISTER, 0x1206);
796 outw (Private, SEQ_ADDRESS_REGISTER, 0x0012);
797
798 for (Index = 0; Index < 15; Index++) {
799 outw (Private, SEQ_ADDRESS_REGISTER, ModeData->SeqSettings[Index]);
800 }
801
802 if (Private->Variant == QEMU_VIDEO_CIRRUS_5430) {
803 outb (Private, SEQ_ADDRESS_REGISTER, 0x0f);
804 Byte = (UINT8) ((inb (Private, SEQ_DATA_REGISTER) & 0xc7) ^ 0x30);
805 outb (Private, SEQ_DATA_REGISTER, Byte);
806 }
807
808 outb (Private, MISC_OUTPUT_REGISTER, ModeData->MiscSetting);
809 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0506);
810 outw (Private, SEQ_ADDRESS_REGISTER, 0x0300);
811 outw (Private, CRTC_ADDRESS_REGISTER, 0x2011);
812
813 for (Index = 0; Index < 28; Index++) {
814 outw (Private, CRTC_ADDRESS_REGISTER, (UINT16) ((ModeData->CrtcSettings[Index] << 8) | Index));
815 }
816
817 for (Index = 0; Index < 9; Index++) {
818 outw (Private, GRAPH_ADDRESS_REGISTER, (UINT16) ((GraphicsController[Index] << 8) | Index));
819 }
820
821 inb (Private, INPUT_STATUS_1_REGISTER);
822
823 for (Index = 0; Index < 21; Index++) {
824 outb (Private, ATT_ADDRESS_REGISTER, (UINT8) Index);
825 outb (Private, ATT_ADDRESS_REGISTER, AttributeController[Index]);
826 }
827
828 outb (Private, ATT_ADDRESS_REGISTER, 0x20);
829
830 outw (Private, GRAPH_ADDRESS_REGISTER, 0x0009);
831 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000a);
832 outw (Private, GRAPH_ADDRESS_REGISTER, 0x000b);
833 outb (Private, DAC_PIXEL_MASK_REGISTER, 0xff);
834
835 SetDefaultPalette (Private);
836 ClearScreen (Private);
837 }
838
839 VOID
BochsWrite(QEMU_VIDEO_PRIVATE_DATA * Private,UINT16 Reg,UINT16 Data)840 BochsWrite (
841 QEMU_VIDEO_PRIVATE_DATA *Private,
842 UINT16 Reg,
843 UINT16 Data
844 )
845 {
846 EFI_STATUS Status;
847
848 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
849 Status = Private->PciIo->Mem.Write (
850 Private->PciIo,
851 EfiPciIoWidthUint16,
852 PCI_BAR_IDX2,
853 0x500 + (Reg << 1),
854 1,
855 &Data
856 );
857 ASSERT_EFI_ERROR (Status);
858 } else {
859 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
860 outw (Private, VBE_DISPI_IOPORT_DATA, Data);
861 }
862 }
863
864 UINT16
BochsRead(QEMU_VIDEO_PRIVATE_DATA * Private,UINT16 Reg)865 BochsRead (
866 QEMU_VIDEO_PRIVATE_DATA *Private,
867 UINT16 Reg
868 )
869 {
870 EFI_STATUS Status;
871 UINT16 Data;
872
873 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
874 Status = Private->PciIo->Mem.Read (
875 Private->PciIo,
876 EfiPciIoWidthUint16,
877 PCI_BAR_IDX2,
878 0x500 + (Reg << 1),
879 1,
880 &Data
881 );
882 ASSERT_EFI_ERROR (Status);
883 } else {
884 outw (Private, VBE_DISPI_IOPORT_INDEX, Reg);
885 Data = inw (Private, VBE_DISPI_IOPORT_DATA);
886 }
887 return Data;
888 }
889
890 VOID
VgaOutb(QEMU_VIDEO_PRIVATE_DATA * Private,UINTN Reg,UINT8 Data)891 VgaOutb (
892 QEMU_VIDEO_PRIVATE_DATA *Private,
893 UINTN Reg,
894 UINT8 Data
895 )
896 {
897 EFI_STATUS Status;
898
899 if (Private->Variant == QEMU_VIDEO_BOCHS_MMIO) {
900 Status = Private->PciIo->Mem.Write (
901 Private->PciIo,
902 EfiPciIoWidthUint8,
903 PCI_BAR_IDX2,
904 0x400 - 0x3c0 + Reg,
905 1,
906 &Data
907 );
908 ASSERT_EFI_ERROR (Status);
909 } else {
910 outb (Private, Reg, Data);
911 }
912 }
913
914 VOID
InitializeBochsGraphicsMode(QEMU_VIDEO_PRIVATE_DATA * Private,QEMU_VIDEO_BOCHS_MODES * ModeData)915 InitializeBochsGraphicsMode (
916 QEMU_VIDEO_PRIVATE_DATA *Private,
917 QEMU_VIDEO_BOCHS_MODES *ModeData
918 )
919 {
920 DEBUG ((EFI_D_INFO, "InitializeBochsGraphicsMode: %dx%d @ %d\n",
921 ModeData->Width, ModeData->Height, ModeData->ColorDepth));
922
923 /* unblank */
924 VgaOutb (Private, ATT_ADDRESS_REGISTER, 0x20);
925
926 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE, 0);
927 BochsWrite (Private, VBE_DISPI_INDEX_BANK, 0);
928 BochsWrite (Private, VBE_DISPI_INDEX_X_OFFSET, 0);
929 BochsWrite (Private, VBE_DISPI_INDEX_Y_OFFSET, 0);
930
931 BochsWrite (Private, VBE_DISPI_INDEX_BPP, (UINT16) ModeData->ColorDepth);
932 BochsWrite (Private, VBE_DISPI_INDEX_XRES, (UINT16) ModeData->Width);
933 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_WIDTH, (UINT16) ModeData->Width);
934 BochsWrite (Private, VBE_DISPI_INDEX_YRES, (UINT16) ModeData->Height);
935 BochsWrite (Private, VBE_DISPI_INDEX_VIRT_HEIGHT, (UINT16) ModeData->Height);
936
937 BochsWrite (Private, VBE_DISPI_INDEX_ENABLE,
938 VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED);
939
940 SetDefaultPalette (Private);
941 ClearScreen (Private);
942 }
943
944 EFI_STATUS
945 EFIAPI
InitializeQemuVideo(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)946 InitializeQemuVideo (
947 IN EFI_HANDLE ImageHandle,
948 IN EFI_SYSTEM_TABLE *SystemTable
949 )
950 {
951 EFI_STATUS Status;
952
953 Status = EfiLibInstallDriverBindingComponentName2 (
954 ImageHandle,
955 SystemTable,
956 &gQemuVideoDriverBinding,
957 ImageHandle,
958 &gQemuVideoComponentName,
959 &gQemuVideoComponentName2
960 );
961 ASSERT_EFI_ERROR (Status);
962
963 //
964 // Install EFI Driver Supported EFI Version Protocol required for
965 // EFI drivers that are on PCI and other plug in cards.
966 //
967 gQemuVideoDriverSupportedEfiVersion.FirmwareVersion = PcdGet32 (PcdDriverSupportedEfiVersion);
968 Status = gBS->InstallMultipleProtocolInterfaces (
969 &ImageHandle,
970 &gEfiDriverSupportedEfiVersionProtocolGuid,
971 &gQemuVideoDriverSupportedEfiVersion,
972 NULL
973 );
974 ASSERT_EFI_ERROR (Status);
975
976 return Status;
977 }
978