mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-25 00:50:22 +00:00
Kernel: Add a framebuffer driver for 3Dfx Voodoo 3
A bit old but a relatively uncomplicated device capable of outputting 1920x1080 video with 32-bit color. Tested with a Voodoo 3 3000 16MB PCI card. Resolution switching from DisplaySettings also works. If the requested mode contains timing information, it is used directly. Otherwise, display timing values are selected from the EDID. First the detailed timings are checked, and then standard and established timings for which there is a matching DMT mode. The driver does not (yet) read the actual EDID, so the generic EDID in DisplayConnector now includes a set of common display modes to make this work. The driver should also be compatible with the Voodoo Banshee, 4 and 5 but I don't have these cards to test this with. The PCI IDs of these cards are included as a commented line in case someone wants to give it a try.
This commit is contained in:
parent
77441079dd
commit
8388fe51b5
Notes:
sideshowbarker
2024-07-17 00:37:23 +09:00
Author: https://github.com/edwinr Commit: https://github.com/SerenityOS/serenity/commit/8388fe51b5 Pull-request: https://github.com/SerenityOS/serenity/pull/20753 Reviewed-by: https://github.com/ADKaster Reviewed-by: https://github.com/Hendiadyoin1 Reviewed-by: https://github.com/gmta ✅ Reviewed-by: https://github.com/supercomputer7
11 changed files with 805 additions and 4 deletions
|
@ -17,6 +17,7 @@ enum VendorID {
|
|||
QEMUOld = 0x1234,
|
||||
VirtualBox = 0x80ee,
|
||||
VMWare = 0x15ad,
|
||||
Tdfx = 0x121a,
|
||||
};
|
||||
|
||||
enum DeviceID {
|
||||
|
|
|
@ -83,6 +83,8 @@ set(KERNEL_SOURCES
|
|||
Devices/Generic/RandomDevice.cpp
|
||||
Devices/Generic/SelfTTYDevice.cpp
|
||||
Devices/Generic/ZeroDevice.cpp
|
||||
Devices/GPU/3dfx/GraphicsAdapter.cpp
|
||||
Devices/GPU/3dfx/VoodooDisplayConnector.cpp
|
||||
Devices/GPU/Bochs/GraphicsAdapter.cpp
|
||||
Devices/GPU/Bochs/QEMUDisplayConnector.cpp
|
||||
Devices/GPU/Console/BootFramebufferConsole.cpp
|
||||
|
|
|
@ -299,6 +299,10 @@
|
|||
#cmakedefine01 TCP_SOCKET_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef TDFX_DEBUG
|
||||
#cmakedefine01 TDFX_DEBUG
|
||||
#endif
|
||||
|
||||
#ifndef THREAD_DEBUG
|
||||
#cmakedefine01 THREAD_DEBUG
|
||||
#endif
|
||||
|
|
209
Kernel/Devices/GPU/3dfx/Definitions.h
Normal file
209
Kernel/Devices/GPU/3dfx/Definitions.h
Normal file
|
@ -0,0 +1,209 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Edwin Rijkee <edwin@virtualparadise.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Array.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
namespace Kernel::VoodooGraphics {
|
||||
|
||||
enum class VGAPort : u16 {
|
||||
AttributeController = 0x3c0,
|
||||
MiscOutputWrite = 0x3c2,
|
||||
SequencerIndex = 0x3c4,
|
||||
SequencerData = 0x3c5,
|
||||
MiscOutputRead = 0x3cc,
|
||||
GraphicsControllerIndex = 0x3ce,
|
||||
GraphicsControllerData = 0x3cf,
|
||||
CrtcIndex = 0x3d4,
|
||||
CrtcData = 0x3d5,
|
||||
InputStatus1 = 0x3da,
|
||||
};
|
||||
|
||||
enum CRTCHorizontalBlankingEndFlags : u8 {
|
||||
CompatibilityRead = 1 << 7
|
||||
};
|
||||
|
||||
enum CRTCVerticalSyncEndFlags : u8 {
|
||||
EnableVertInt = 1 << 5,
|
||||
CRTCRegsWriteProt = 1 << 7
|
||||
};
|
||||
|
||||
enum CRTCModeControlFlags : u8 {
|
||||
ByteWordMode = 1 << 6,
|
||||
TimingEnable = 1 << 7
|
||||
};
|
||||
|
||||
enum GraphicsControllerMiscellaneousFlags : u8 {
|
||||
MemoryMapEGAVGAExtended = 1 << 2,
|
||||
};
|
||||
|
||||
enum AttributeControllerModeFlags : u8 {
|
||||
GraphicsMode = 1 << 0,
|
||||
PixelWidth = 1 << 6,
|
||||
};
|
||||
|
||||
enum SequencerResetFlags : u8 {
|
||||
AsynchronousReset = 1 << 0,
|
||||
SynchronousReset = 1 << 1,
|
||||
};
|
||||
|
||||
enum SequencerClockingModeFlags : u8 {
|
||||
DotClock8 = 1 << 0,
|
||||
};
|
||||
|
||||
enum MiscellaneousOutputFlags : u8 {
|
||||
CRTCAddressColor = 1 << 0,
|
||||
ClockSelectPLL = 0b1100,
|
||||
VerticalSyncPositive = 1 << 7,
|
||||
HorizontalSyncPositive = 1 << 6,
|
||||
};
|
||||
|
||||
enum DacModeFlags : u32 {
|
||||
DacMode2x = 1 << 0,
|
||||
};
|
||||
|
||||
enum VgaInit0Flags : u32 {
|
||||
FIFODepth8Bit = 1 << 2,
|
||||
EnableVgaExtensions = 1 << 6,
|
||||
WakeUpSelect3C3 = 1 << 8,
|
||||
EnableAltReadback = 1 << 10,
|
||||
ExtendedShiftOut = 1 << 12,
|
||||
};
|
||||
|
||||
enum VidProcCfgFlags : u32 {
|
||||
VideoProcessorEnable = 1 << 0,
|
||||
DesktopSurfaceEnable = 1 << 7,
|
||||
DesktopCLUTBypass = 1 << 10,
|
||||
DesktopPixelFormat32Bit = 0b11 << 18,
|
||||
TwoXMode = 1 << 26,
|
||||
};
|
||||
|
||||
struct PLLSettings {
|
||||
static i32 const reference_frequency_in_khz = 14318;
|
||||
i32 m = 0;
|
||||
i32 n = 0;
|
||||
i32 k = 0;
|
||||
|
||||
int frequency_in_khz() const
|
||||
{
|
||||
return (reference_frequency_in_khz * (n + 2) / (m + 2)) >> k;
|
||||
}
|
||||
|
||||
u32 register_value() const
|
||||
{
|
||||
return (n << 8) | (m << 2) | k;
|
||||
}
|
||||
};
|
||||
|
||||
// CRT Controller Registers
|
||||
struct CRRegisters {
|
||||
u8 horizontal_total; // CR0
|
||||
u8 horizontal_display_enable_end; // CR1
|
||||
u8 horizontal_blanking_start; // CR2
|
||||
u8 horizontal_blanking_end; // CR3
|
||||
u8 horizontal_sync_start; // CR4
|
||||
u8 horizontal_sync_end; // CR5
|
||||
u8 vertical_total; // CR6
|
||||
u8 overflow; // CR7
|
||||
u8 reserved_0; // CR8
|
||||
u8 maximum_scan_line; // CR9
|
||||
u8 reserved_1[6];
|
||||
u8 vertical_sync_start; // CR10
|
||||
u8 vertical_sync_end; // CR11
|
||||
u8 vertical_display_enable_end; // CR12
|
||||
u8 reserved_2[2];
|
||||
u8 vertical_blanking_start; // CR15
|
||||
u8 vertical_blanking_end; // CR16
|
||||
u8 mode_control; // CR17
|
||||
u8 reserved_3[2];
|
||||
u8 horizontal_extensions; // CR1A
|
||||
u8 vertical_extensions; // CR1B
|
||||
};
|
||||
|
||||
// Graphics Controller Registers
|
||||
struct GRRegisters {
|
||||
u8 reserved_0[6];
|
||||
u8 graphics_controller_miscellaneous; // GR6
|
||||
u8 reserved_1[2];
|
||||
};
|
||||
|
||||
// Attribute Controller Registers
|
||||
struct ARRegisters {
|
||||
u8 reserved_0[15];
|
||||
u8 attribute_controller_mode; // AR10
|
||||
u8 reserved_1[5];
|
||||
};
|
||||
|
||||
// Sequencer Registers
|
||||
struct SRRegisters {
|
||||
u8 sequencer_reset; // SR0
|
||||
u8 sequencer_clocking_mode; // SR1
|
||||
u8 reserved[3];
|
||||
};
|
||||
|
||||
struct ModeRegisters {
|
||||
u32 vid_screen_size = 0;
|
||||
u32 vid_desktop_overlay_stride = 0;
|
||||
u8 misc_out_reg = 0;
|
||||
u32 vga_init0 = 0;
|
||||
u32 vid_proc_cfg = 0;
|
||||
u32 dac_mode = 0;
|
||||
u32 pll_ctrl0 = 0;
|
||||
|
||||
union {
|
||||
Array<u8, 0x1c> cr_data = { 0 };
|
||||
CRRegisters cr;
|
||||
};
|
||||
|
||||
union {
|
||||
Array<u8, 0x09> gr_data = { 0 };
|
||||
GRRegisters gr;
|
||||
};
|
||||
|
||||
union {
|
||||
Array<u8, 0x15> ar_data = { 0 };
|
||||
ARRegisters ar;
|
||||
};
|
||||
|
||||
union {
|
||||
Array<u8, 0x05> sr_data = { 0 };
|
||||
SRRegisters sr;
|
||||
};
|
||||
};
|
||||
|
||||
static_assert(sizeof(ModeRegisters::cr_data) == sizeof(ModeRegisters::cr));
|
||||
static_assert(sizeof(ModeRegisters::gr_data) == sizeof(ModeRegisters::gr));
|
||||
static_assert(sizeof(ModeRegisters::ar_data) == sizeof(ModeRegisters::ar));
|
||||
|
||||
struct [[gnu::packed]] RegisterMap {
|
||||
u32 status;
|
||||
u32 reserved_0[9];
|
||||
u32 vga_init0;
|
||||
u32 reserved_1[5];
|
||||
u32 pll_ctrl0;
|
||||
u32 reserved_2[2];
|
||||
u32 dac_mode;
|
||||
u32 reserved_3[3];
|
||||
|
||||
u32 vid_proc_cfg;
|
||||
u32 reserved_4[14];
|
||||
u32 vid_screen_size;
|
||||
u32 reserved_5[18];
|
||||
u32 vid_desktop_start_addr;
|
||||
u32 vid_desktop_overlay_stride;
|
||||
};
|
||||
|
||||
static_assert(__builtin_offsetof(RegisterMap, status) == 0);
|
||||
static_assert(__builtin_offsetof(RegisterMap, vga_init0) == 0x28);
|
||||
static_assert(__builtin_offsetof(RegisterMap, pll_ctrl0) == 0x40);
|
||||
static_assert(__builtin_offsetof(RegisterMap, dac_mode) == 0x4c);
|
||||
static_assert(__builtin_offsetof(RegisterMap, vid_proc_cfg) == 0x5c);
|
||||
static_assert(__builtin_offsetof(RegisterMap, vid_screen_size) == 0x98);
|
||||
static_assert(__builtin_offsetof(RegisterMap, vid_desktop_start_addr) == 0xe4);
|
||||
static_assert(__builtin_offsetof(RegisterMap, vid_desktop_overlay_stride) == 0xe8);
|
||||
}
|
70
Kernel/Devices/GPU/3dfx/GraphicsAdapter.cpp
Normal file
70
Kernel/Devices/GPU/3dfx/GraphicsAdapter.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Edwin Rijkee <edwin@virtualparadise.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Bus/PCI/IDs.h>
|
||||
#include <Kernel/Devices/GPU/3dfx/Definitions.h>
|
||||
#include <Kernel/Devices/GPU/3dfx/GraphicsAdapter.h>
|
||||
#include <Kernel/Devices/GPU/3dfx/VoodooDisplayConnector.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
static constexpr u16 supported_models[] {
|
||||
// 0x0003, // Banshee (untested)
|
||||
0x0005, // Voodoo 3
|
||||
// 0x0009 // Voodoo 4 / Voodoo 5 (untested)
|
||||
};
|
||||
|
||||
static bool is_supported_model(u16 device_id)
|
||||
{
|
||||
for (auto& id : supported_models) {
|
||||
if (id == device_id)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT ErrorOr<bool> VoodooGraphicsAdapter::probe(PCI::DeviceIdentifier const& pci_device_identifier)
|
||||
{
|
||||
PCI::HardwareID id = pci_device_identifier.hardware_id();
|
||||
return id.vendor_id == PCI::VendorID::Tdfx && is_supported_model(id.device_id);
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT ErrorOr<NonnullLockRefPtr<GenericGraphicsAdapter>> VoodooGraphicsAdapter::create(PCI::DeviceIdentifier const& pci_device_identifier)
|
||||
{
|
||||
auto adapter = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) VoodooGraphicsAdapter(pci_device_identifier)));
|
||||
MUST(adapter->initialize_adapter(pci_device_identifier));
|
||||
return adapter;
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT VoodooGraphicsAdapter::VoodooGraphicsAdapter(PCI::DeviceIdentifier const& device_identifier)
|
||||
: PCI::Device(const_cast<PCI::DeviceIdentifier&>(device_identifier))
|
||||
{
|
||||
}
|
||||
|
||||
UNMAP_AFTER_INIT ErrorOr<void> VoodooGraphicsAdapter::initialize_adapter(PCI::DeviceIdentifier const& pci_device_identifier)
|
||||
{
|
||||
PCI::enable_io_space(device_identifier());
|
||||
PCI::enable_memory_space(device_identifier());
|
||||
|
||||
auto mmio_addr = PhysicalAddress(PCI::get_BAR0(pci_device_identifier) & PCI::bar_address_mask);
|
||||
auto mmio_size = PCI::get_BAR_space_size(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR0);
|
||||
dbgln_if(TDFX_DEBUG, "3dfx mmio addr {} size {}", mmio_addr, mmio_size);
|
||||
auto mmio_mapping = TRY(Memory::map_typed<VoodooGraphics::RegisterMap volatile>(mmio_addr, mmio_size, Memory::Region::Access::Read | Memory::Region::Access::Write));
|
||||
|
||||
auto vmem_addr = PhysicalAddress(PCI::get_BAR1(pci_device_identifier) & PCI::bar_address_mask);
|
||||
auto vmem_size = PCI::get_BAR_space_size(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR1);
|
||||
dbgln_if(TDFX_DEBUG, "3dfx vmem addr {} size {}", vmem_addr, vmem_size);
|
||||
|
||||
auto io_window = TRY(IOWindow::create_for_pci_device_bar(pci_device_identifier, PCI::HeaderType0BaseRegister::BAR2));
|
||||
|
||||
m_display_connector = VoodooGraphics::VoodooDisplayConnector::must_create(vmem_addr, vmem_size, move(mmio_mapping), move(io_window));
|
||||
TRY(m_display_connector->set_safe_mode_setting());
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
}
|
32
Kernel/Devices/GPU/3dfx/GraphicsAdapter.h
Normal file
32
Kernel/Devices/GPU/3dfx/GraphicsAdapter.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Edwin Rijkee <edwin@virtualparadise.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <Kernel/Bus/PCI/Device.h>
|
||||
#include <Kernel/Devices/GPU/Console/GenericFramebufferConsole.h>
|
||||
#include <Kernel/Devices/GPU/GenericGraphicsAdapter.h>
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
class VoodooGraphicsAdapter final : public GenericGraphicsAdapter
|
||||
, public PCI::Device {
|
||||
|
||||
public:
|
||||
static ErrorOr<bool> probe(PCI::DeviceIdentifier const&);
|
||||
static ErrorOr<NonnullLockRefPtr<GenericGraphicsAdapter>> create(PCI::DeviceIdentifier const&);
|
||||
virtual ~VoodooGraphicsAdapter() = default;
|
||||
virtual StringView device_name() const override { return "VoodooGraphicsAdapter"sv; }
|
||||
|
||||
private:
|
||||
ErrorOr<void> initialize_adapter(PCI::DeviceIdentifier const&);
|
||||
|
||||
explicit VoodooGraphicsAdapter(PCI::DeviceIdentifier const&);
|
||||
|
||||
LockRefPtr<DisplayConnector> m_display_connector;
|
||||
};
|
||||
}
|
416
Kernel/Devices/GPU/3dfx/VoodooDisplayConnector.cpp
Normal file
416
Kernel/Devices/GPU/3dfx/VoodooDisplayConnector.cpp
Normal file
|
@ -0,0 +1,416 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Edwin Rijkee <edwin@virtualparadise.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#include <Kernel/Devices/GPU/3dfx/VoodooDisplayConnector.h>
|
||||
#include <Kernel/Devices/GPU/Console/ContiguousFramebufferConsole.h>
|
||||
#include <Kernel/Devices/GPU/Management.h>
|
||||
#include <Kernel/Time/TimeManagement.h>
|
||||
|
||||
namespace Kernel::VoodooGraphics {
|
||||
|
||||
NonnullLockRefPtr<VoodooDisplayConnector> VoodooDisplayConnector::must_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, Memory::TypedMapping<RegisterMap volatile> registers_mapping, NonnullOwnPtr<IOWindow> io_window)
|
||||
{
|
||||
auto device_or_error = DeviceManagement::try_create_device<VoodooDisplayConnector>(framebuffer_address, framebuffer_resource_size, move(registers_mapping), move(io_window));
|
||||
VERIFY(!device_or_error.is_error());
|
||||
auto connector = device_or_error.release_value();
|
||||
MUST(connector->create_attached_framebuffer_console());
|
||||
MUST(connector->fetch_and_initialize_edid());
|
||||
return connector;
|
||||
}
|
||||
|
||||
ErrorOr<void> VoodooDisplayConnector::fetch_and_initialize_edid()
|
||||
{
|
||||
// TODO: actually fetch the EDID.
|
||||
return initialize_edid_for_generic_monitor({});
|
||||
}
|
||||
|
||||
ErrorOr<void> VoodooDisplayConnector::create_attached_framebuffer_console()
|
||||
{
|
||||
m_framebuffer_console = Graphics::ContiguousFramebufferConsole::initialize(m_framebuffer_address.value(), 1024, 768, 1024 * sizeof(u32));
|
||||
GraphicsManagement::the().set_console(*m_framebuffer_console);
|
||||
return {};
|
||||
}
|
||||
|
||||
VoodooDisplayConnector::VoodooDisplayConnector(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, Memory::TypedMapping<RegisterMap volatile> registers_mapping, NonnullOwnPtr<IOWindow> io_window)
|
||||
: DisplayConnector(framebuffer_address, framebuffer_resource_size, true)
|
||||
, m_registers(move(registers_mapping))
|
||||
, m_io_window(move(io_window))
|
||||
{
|
||||
}
|
||||
|
||||
ErrorOr<IterationDecision> VoodooDisplayConnector::for_each_dmt_timing_in_edid(Function<IterationDecision(EDID::DMT::MonitorTiming const&)> callback) const
|
||||
{
|
||||
IterationDecision iteration_decision = TRY(m_edid_parser->for_each_standard_timing([&](auto& standard_timing) {
|
||||
auto timing = EDID::DMT::find_timing_by_dmt_id(standard_timing.dmt_id());
|
||||
if (!timing) {
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
return callback(*timing);
|
||||
}));
|
||||
|
||||
if (iteration_decision == IterationDecision::Break) {
|
||||
return iteration_decision;
|
||||
}
|
||||
|
||||
iteration_decision = TRY(m_edid_parser->for_each_established_timing([&](auto& established_timing) {
|
||||
auto timing = EDID::DMT::find_timing_by_dmt_id(established_timing.dmt_id());
|
||||
if (!timing) {
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
return callback(*timing);
|
||||
}));
|
||||
|
||||
return iteration_decision;
|
||||
}
|
||||
|
||||
auto VoodooDisplayConnector::find_suitable_mode(ModeSetting const& requested_mode) const -> ErrorOr<ModeSetting>
|
||||
{
|
||||
u32 width = requested_mode.horizontal_active;
|
||||
u32 height = requested_mode.vertical_active;
|
||||
ModeSetting result = requested_mode;
|
||||
|
||||
if (requested_mode.horizontal_stride == 0) {
|
||||
result.horizontal_stride = sizeof(u32) * width;
|
||||
}
|
||||
|
||||
if (requested_mode.pixel_clock_in_khz != 0) {
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: Requested mode {}x{} includes timing information", width, height);
|
||||
return result;
|
||||
}
|
||||
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: Looking for suitable mode with resolution {}x{}", width, height);
|
||||
|
||||
IterationDecision iteration_decision = TRY(m_edid_parser->for_each_detailed_timing([&](auto& timing, unsigned) {
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: Considering detailed timing {}x{} @ {}", timing.horizontal_addressable_pixels(), timing.vertical_addressable_lines(), timing.refresh_rate());
|
||||
|
||||
if (timing.is_interlaced() || timing.horizontal_addressable_pixels() != width || timing.vertical_addressable_lines() != height) {
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
result.pixel_clock_in_khz = timing.pixel_clock_khz();
|
||||
result.horizontal_front_porch_pixels = timing.horizontal_front_porch_pixels();
|
||||
result.horizontal_sync_time_pixels = timing.horizontal_sync_pulse_width_pixels();
|
||||
result.horizontal_blank_pixels = timing.horizontal_blanking_pixels();
|
||||
result.vertical_front_porch_lines = timing.vertical_front_porch_lines();
|
||||
result.vertical_sync_time_lines = timing.vertical_sync_pulse_width_lines();
|
||||
result.vertical_blank_lines = timing.vertical_blanking_lines();
|
||||
return IterationDecision::Break;
|
||||
}));
|
||||
|
||||
if (iteration_decision == IterationDecision::Break) {
|
||||
return result;
|
||||
}
|
||||
|
||||
iteration_decision = TRY(for_each_dmt_timing_in_edid([&](auto& timing) {
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: Considering DMT timing {}x{} @ {}", timing.horizontal_pixels, timing.vertical_lines, timing.vertical_frequency_hz());
|
||||
|
||||
if (timing.scan_type != EDID::DMT::MonitorTiming::ScanType::NonInterlaced || timing.horizontal_pixels != width || timing.vertical_lines != height) {
|
||||
return IterationDecision::Continue;
|
||||
}
|
||||
|
||||
result.pixel_clock_in_khz = timing.pixel_clock_khz;
|
||||
result.horizontal_front_porch_pixels = timing.horizontal_front_porch_pixels;
|
||||
result.horizontal_sync_time_pixels = timing.horizontal_sync_time_pixels;
|
||||
result.horizontal_blank_pixels = timing.horizontal_blank_pixels;
|
||||
result.vertical_front_porch_lines = timing.vertical_front_porch_lines;
|
||||
result.vertical_sync_time_lines = timing.vertical_sync_time_lines;
|
||||
result.vertical_blank_lines = timing.vertical_blank_lines;
|
||||
return IterationDecision::Break;
|
||||
}));
|
||||
|
||||
if (iteration_decision == IterationDecision::Break) {
|
||||
return result;
|
||||
}
|
||||
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: No timing information available for display mode {}x{}", width, height);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
ErrorOr<void>
|
||||
VoodooDisplayConnector::set_mode_setting(ModeSetting const& requested_mode_setting)
|
||||
{
|
||||
SpinlockLocker locker(m_modeset_lock);
|
||||
VERIFY(m_framebuffer_console);
|
||||
|
||||
ModeSetting mode_setting = TRY(find_suitable_mode(requested_mode_setting));
|
||||
dbgln_if(TDFX_DEBUG, "VoodooDisplayConnector resolution registers set to - {}x{}", mode_setting.horizontal_active, mode_setting.vertical_active);
|
||||
|
||||
auto regs = TRY(prepare_mode_switch(mode_setting));
|
||||
TRY(perform_mode_switch(regs));
|
||||
|
||||
m_framebuffer_console->set_resolution(mode_setting.horizontal_active, mode_setting.vertical_active, mode_setting.horizontal_stride);
|
||||
m_current_mode_setting = mode_setting;
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> VoodooDisplayConnector::set_y_offset(size_t)
|
||||
{
|
||||
return ENOTIMPL;
|
||||
}
|
||||
|
||||
ErrorOr<void> VoodooDisplayConnector::set_safe_mode_setting()
|
||||
{
|
||||
DisplayConnector::ModeSetting safe_mode_set {
|
||||
.horizontal_stride = 1024 * sizeof(u32),
|
||||
.pixel_clock_in_khz = 65000,
|
||||
.horizontal_active = 1024,
|
||||
.horizontal_front_porch_pixels = 24,
|
||||
.horizontal_sync_time_pixels = 136,
|
||||
.horizontal_blank_pixels = 320,
|
||||
.vertical_active = 768,
|
||||
.vertical_front_porch_lines = 3,
|
||||
.vertical_sync_time_lines = 6,
|
||||
.vertical_blank_lines = 38,
|
||||
.horizontal_offset = 0,
|
||||
.vertical_offset = 0,
|
||||
};
|
||||
return set_mode_setting(safe_mode_set);
|
||||
}
|
||||
|
||||
ErrorOr<void> VoodooDisplayConnector::unblank()
|
||||
{
|
||||
return ENOTIMPL;
|
||||
}
|
||||
|
||||
ErrorOr<void> VoodooDisplayConnector::flush_first_surface()
|
||||
{
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
void VoodooDisplayConnector::enable_console()
|
||||
{
|
||||
VERIFY(m_control_lock.is_locked());
|
||||
VERIFY(m_framebuffer_console);
|
||||
m_framebuffer_console->enable();
|
||||
}
|
||||
|
||||
void VoodooDisplayConnector::disable_console()
|
||||
{
|
||||
VERIFY(m_control_lock.is_locked());
|
||||
VERIFY(m_framebuffer_console);
|
||||
m_framebuffer_console->disable();
|
||||
}
|
||||
|
||||
u8 VoodooDisplayConnector::read_vga(VGAPort port)
|
||||
{
|
||||
return m_io_window->read8(static_cast<u16>(port) - 0x300);
|
||||
}
|
||||
|
||||
u8 VoodooDisplayConnector::read_vga_indexed(VGAPort index_port, VGAPort data_port, u8 index)
|
||||
{
|
||||
m_io_window->write8(static_cast<u16>(index_port) - 0x300, index);
|
||||
return m_io_window->read8(static_cast<u16>(data_port) - 0x300);
|
||||
}
|
||||
|
||||
void VoodooDisplayConnector::write_vga(VGAPort port, u8 value)
|
||||
{
|
||||
m_io_window->write8(static_cast<u16>(port) - 0x300, value - 0x300);
|
||||
}
|
||||
|
||||
void VoodooDisplayConnector::write_vga_indexed(VGAPort index_port, VGAPort data_port, u8 index, u8 value)
|
||||
{
|
||||
m_io_window->write8(static_cast<u16>(index_port) - 0x300, index);
|
||||
m_io_window->write8(static_cast<u16>(data_port) - 0x300, value);
|
||||
}
|
||||
|
||||
ErrorOr<void> VoodooDisplayConnector::wait_for_fifo_space(u32 entries)
|
||||
{
|
||||
VERIFY(entries < 32);
|
||||
|
||||
auto deadline = TimeManagement::the().monotonic_time() + Duration::from_seconds(1);
|
||||
do {
|
||||
if ((m_registers->status & 0x1f) >= entries) {
|
||||
return {};
|
||||
}
|
||||
(void)Thread::current()->sleep(Duration::from_milliseconds(1));
|
||||
} while (TimeManagement::the().monotonic_time() < deadline);
|
||||
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: timed out waiting for fifo space");
|
||||
return EIO;
|
||||
}
|
||||
|
||||
PLLSettings VoodooDisplayConnector::calculate_pll(i32 desired_frequency_in_khz)
|
||||
{
|
||||
VoodooGraphics::PLLSettings current;
|
||||
VoodooGraphics::PLLSettings best;
|
||||
i32 best_difference;
|
||||
|
||||
best_difference = desired_frequency_in_khz;
|
||||
|
||||
for (current.m = 0; current.m < 64; current.m++) {
|
||||
for (current.n = 0; current.n < 256; current.n++) {
|
||||
for (current.k = 0; current.k < 4; current.k++) {
|
||||
auto frequency_in_khz = current.frequency_in_khz();
|
||||
|
||||
auto error = AK::abs(frequency_in_khz - desired_frequency_in_khz);
|
||||
if (error < best_difference) {
|
||||
best_difference = error;
|
||||
best = current;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return best;
|
||||
}
|
||||
|
||||
ErrorOr<ModeRegisters> VoodooDisplayConnector::prepare_mode_switch(ModeSetting const& mode_setting)
|
||||
{
|
||||
u32 width = mode_setting.horizontal_active;
|
||||
u32 height = mode_setting.vertical_active;
|
||||
|
||||
ModeRegisters regs;
|
||||
|
||||
regs.vga_init0 = EnableVgaExtensions | WakeUpSelect3C3 | EnableAltReadback | FIFODepth8Bit | ExtendedShiftOut;
|
||||
regs.vid_proc_cfg |= VideoProcessorEnable | DesktopSurfaceEnable | DesktopPixelFormat32Bit | DesktopCLUTBypass;
|
||||
|
||||
// We only want to touch the 2X flag of the DAC Mode register, the other flags are preserved
|
||||
regs.dac_mode = m_registers->dac_mode & ~DacMode2x;
|
||||
|
||||
u32 const max_pixel_clock_in_khz = 270000;
|
||||
if (mode_setting.pixel_clock_in_khz > max_pixel_clock_in_khz) {
|
||||
return ENOTSUP;
|
||||
}
|
||||
|
||||
u32 horizontal_divisor = 8;
|
||||
if (mode_setting.pixel_clock_in_khz > max_pixel_clock_in_khz / 2) {
|
||||
horizontal_divisor = 16;
|
||||
regs.dac_mode |= DacMode2x;
|
||||
regs.vid_proc_cfg |= TwoXMode;
|
||||
}
|
||||
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: Calculating best PLL settings for pixel clock {} KHz", mode_setting.pixel_clock_in_khz);
|
||||
auto pll = calculate_pll(mode_setting.pixel_clock_in_khz);
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: Best matching PLL settings: m={}, n={}, k={}. Frequency: {} KHz", pll.m, pll.n, pll.k, pll.frequency_in_khz());
|
||||
regs.pll_ctrl0 = pll.register_value();
|
||||
regs.vid_screen_size = width | (height << 12);
|
||||
regs.vid_desktop_overlay_stride = mode_setting.horizontal_stride;
|
||||
regs.misc_out_reg = ClockSelectPLL | CRTCAddressColor;
|
||||
if (height < 768) {
|
||||
regs.misc_out_reg |= VerticalSyncPositive | HorizontalSyncPositive;
|
||||
}
|
||||
|
||||
u32 hor_total = mode_setting.horizontal_total() / horizontal_divisor - 5;
|
||||
u32 hor_disp_en_end = width / horizontal_divisor - 1;
|
||||
u32 hor_sync_start = mode_setting.horizontal_sync_start() / horizontal_divisor;
|
||||
u32 hor_sync_end = (mode_setting.horizontal_sync_end() / horizontal_divisor) & 0x1f;
|
||||
u32 hor_blank_start = hor_disp_en_end;
|
||||
u32 hor_blank_end = hor_total & 0x7f;
|
||||
|
||||
u32 vert_total = mode_setting.vertical_total() - 2;
|
||||
u32 vert_disp_en_end = height - 1;
|
||||
u32 vert_sync_start = mode_setting.vertical_sync_start();
|
||||
u32 vert_sync_end = mode_setting.vertical_sync_end() & 0xf;
|
||||
u32 vert_blank_start = mode_setting.vertical_blanking_start() - 1;
|
||||
u32 vert_blank_end = (mode_setting.vertical_total() - 1) & 0xff;
|
||||
|
||||
if (hor_total > 0x1ff || // 9-bit field
|
||||
hor_disp_en_end > 0x1ff || // 9-bit field
|
||||
hor_sync_start > 0x1ff || // 9-bit field
|
||||
hor_sync_end > 0x1f || // 5-bit field
|
||||
hor_blank_start > 0x1ff || // 9-bit field
|
||||
hor_blank_end > 0x7f || // 7-bit field
|
||||
vert_total > 0x7ff || // 11-bit field
|
||||
vert_disp_en_end > 0x7ff || // 11-bit field
|
||||
vert_sync_start > 0x7ff || // 11-bit field
|
||||
vert_sync_end > 0x0f || // 4-bit field
|
||||
vert_blank_start > 0x7ff || // 11-bit field
|
||||
vert_blank_end > 0xff // 8-bit field
|
||||
) {
|
||||
dbgln_if(TDFX_DEBUG, "3dfx: One of the timing values is too large to fit in its register");
|
||||
return EOVERFLOW;
|
||||
}
|
||||
|
||||
// CRT Controller Registers
|
||||
regs.cr.horizontal_total = hor_total; // bit 0-7 of hor_total
|
||||
regs.cr.horizontal_display_enable_end = hor_disp_en_end; // bit 0-7 of hor_disp_en_end
|
||||
regs.cr.horizontal_blanking_start = hor_blank_start; // bit 0-7 of hor_blank_start
|
||||
regs.cr.horizontal_blanking_end = (hor_blank_end & 0x1f) // bit 0-4 of hor_blank_end
|
||||
| CompatibilityRead;
|
||||
regs.cr.horizontal_sync_start = hor_sync_start; // bit 0-7 of hor_sync_start
|
||||
regs.cr.horizontal_sync_end = ((hor_sync_end & 0x1f) // bit 0-4 of hor_sync_end
|
||||
| ((hor_blank_end & 0x20) << 2)); // bit 5 of hor_blank_end
|
||||
regs.cr.vertical_total = vert_total; // bit 0-7 of vert_total
|
||||
regs.cr.overflow = (((vert_total & 0x100) >> 8) // bit 8 of vert_total
|
||||
| ((vert_disp_en_end & 0x100) >> 7) // bit 8 of vert_disp_en_end
|
||||
| ((vert_sync_start & 0x100) >> 6) // bit 8 of vert_sync_start
|
||||
| ((vert_blank_start & 0x100) >> 5) // bit 8 of vert_blank_start
|
||||
| ((vert_total & 0x200) >> 4) // bit 9 of vert_disp_en_end
|
||||
| ((vert_disp_en_end & 0x200) >> 3) // bit 9 of vert_disp_en_end
|
||||
| ((vert_sync_start & 0x200) >> 2)); // bit 9 of vert_sync_start
|
||||
regs.cr.maximum_scan_line = ((vert_blank_start & 0x200) >> 4); // bit 9 of vert_blank_start
|
||||
regs.cr.vertical_sync_start = vert_sync_start; // bit 0-7 of vert_sync_start
|
||||
regs.cr.vertical_sync_end = (vert_sync_end & 0x0f) // bit 0-3 of vert_sync_end
|
||||
| EnableVertInt;
|
||||
regs.cr.vertical_display_enable_end = vert_disp_en_end; // bit 0-7 of vert_disp_en_end
|
||||
regs.cr.vertical_blanking_start = vert_blank_start; // bit 0-7 of vert_blank_start
|
||||
regs.cr.vertical_blanking_end = vert_blank_end; // bit 0-7 of vert_blank_end
|
||||
regs.cr.mode_control = TimingEnable | ByteWordMode;
|
||||
regs.cr.horizontal_extensions = (hor_total & 0x100) >> 8 // bit 8 of hor_total
|
||||
| (hor_disp_en_end & 0x100) >> 6 // bit 8 of hor_disp_en_end
|
||||
| (hor_blank_start & 0x100) >> 4 // bit 8 of hor_blank_start
|
||||
| (hor_blank_end & 0x40) >> 1 // bit 6 of hor_blank_end
|
||||
| (hor_sync_start & 0x100) >> 2 // bit 8 of hor_sync_start
|
||||
| (hor_sync_end & 0x20) << 2; // bit 5 of hor_sync_end
|
||||
regs.cr.vertical_extensions = (vert_total & 0x400) >> 10 // bit 10 of vert_total
|
||||
| (vert_disp_en_end & 0x400) >> 8 // bit 10 of vert_disp_en_endx
|
||||
| (vert_blank_start & 0x400) >> 6 // bit 10 of vert_blank_start
|
||||
| (vert_blank_end & 0x400) >> 4 // bit 10 of vert_blank_end
|
||||
| (vert_sync_start & 0x400) >> 4; // bit 10 of vert_sync_start
|
||||
// Graphics Controller Registers
|
||||
regs.gr.graphics_controller_miscellaneous = MemoryMapEGAVGAExtended;
|
||||
|
||||
// Attribute Controller Registers
|
||||
regs.ar.attribute_controller_mode = GraphicsMode | PixelWidth;
|
||||
|
||||
// Sequencer Registers
|
||||
regs.sr.sequencer_reset = AsynchronousReset | SynchronousReset;
|
||||
regs.sr.sequencer_clocking_mode = DotClock8;
|
||||
|
||||
return regs;
|
||||
}
|
||||
|
||||
ErrorOr<void> VoodooDisplayConnector::perform_mode_switch(ModeRegisters const& regs)
|
||||
{
|
||||
TRY(wait_for_fifo_space(2));
|
||||
m_registers->vid_proc_cfg = 0;
|
||||
m_registers->pll_ctrl0 = regs.pll_ctrl0;
|
||||
|
||||
write_vga(VGAPort::MiscOutputWrite, regs.misc_out_reg);
|
||||
for (u8 i = 0; i < regs.sr_data.size(); i++) {
|
||||
write_vga_indexed(VGAPort::SequencerIndex, VGAPort::SequencerData, i, regs.sr_data[i]);
|
||||
}
|
||||
|
||||
// first unprotect CR0 - CR7
|
||||
write_vga_indexed(VGAPort::CrtcIndex, VGAPort::CrtcData, 0x11, read_vga_indexed(VGAPort::CrtcIndex, VGAPort::CrtcData, 0x11) & ~CRTCRegsWriteProt);
|
||||
for (u8 i = 0; i < regs.cr_data.size(); i++) {
|
||||
write_vga_indexed(VGAPort::CrtcIndex, VGAPort::CrtcData, i, regs.cr_data[i]);
|
||||
}
|
||||
|
||||
for (u8 i = 0; i < regs.gr_data.size(); i++) {
|
||||
write_vga_indexed(VGAPort::GraphicsControllerIndex, VGAPort::GraphicsControllerData, i, regs.gr_data[i]);
|
||||
}
|
||||
|
||||
// The AttributeController IO port flips between the index and the data register on every write.
|
||||
// Reading InputStatus1 has the side effect of resetting this, this way we know it is in the state we expect
|
||||
read_vga(VGAPort::InputStatus1);
|
||||
for (u8 i = 0; i < regs.ar_data.size(); i++) {
|
||||
write_vga_indexed(VGAPort::AttributeController, VGAPort::AttributeController, i, regs.ar_data[i]);
|
||||
}
|
||||
|
||||
TRY(wait_for_fifo_space(6));
|
||||
m_registers->vga_init0 = regs.vga_init0;
|
||||
m_registers->dac_mode = regs.dac_mode;
|
||||
m_registers->vid_desktop_overlay_stride = regs.vid_desktop_overlay_stride;
|
||||
m_registers->vid_screen_size = regs.vid_screen_size;
|
||||
m_registers->vid_desktop_start_addr = 0;
|
||||
m_registers->vid_proc_cfg = regs.vid_proc_cfg;
|
||||
|
||||
return {};
|
||||
}
|
||||
}
|
59
Kernel/Devices/GPU/3dfx/VoodooDisplayConnector.h
Normal file
59
Kernel/Devices/GPU/3dfx/VoodooDisplayConnector.h
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Edwin Rijkee <edwin@virtualparadise.org>
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-2-Clause
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Kernel/Devices/DeviceManagement.h>
|
||||
#include <Kernel/Devices/GPU/3dfx/Definitions.h>
|
||||
#include <Kernel/Devices/GPU/Console/GenericFramebufferConsole.h>
|
||||
#include <Kernel/Devices/GPU/DisplayConnector.h>
|
||||
#include <Kernel/Library/IOWindow.h>
|
||||
#include <Kernel/Memory/TypedMapping.h>
|
||||
|
||||
namespace Kernel::VoodooGraphics {
|
||||
|
||||
class VoodooDisplayConnector final
|
||||
: public DisplayConnector {
|
||||
friend class VoodooGraphicsAdapter;
|
||||
friend class Kernel::DeviceManagement;
|
||||
|
||||
public:
|
||||
static NonnullLockRefPtr<VoodooDisplayConnector> must_create(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, Memory::TypedMapping<RegisterMap volatile>, NonnullOwnPtr<IOWindow> io_window);
|
||||
|
||||
private:
|
||||
ErrorOr<void> fetch_and_initialize_edid();
|
||||
ErrorOr<void> create_attached_framebuffer_console();
|
||||
VoodooDisplayConnector(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, Memory::TypedMapping<RegisterMap volatile>, NonnullOwnPtr<IOWindow> io_window);
|
||||
|
||||
virtual bool mutable_mode_setting_capable() const override final { return false; }
|
||||
virtual bool double_framebuffering_capable() const override { return false; }
|
||||
virtual ErrorOr<void> set_mode_setting(ModeSetting const&) override;
|
||||
virtual ErrorOr<void> set_y_offset(size_t y) override;
|
||||
virtual ErrorOr<void> set_safe_mode_setting() override final;
|
||||
virtual ErrorOr<void> unblank() override;
|
||||
virtual bool partial_flush_support() const override final { return false; }
|
||||
virtual bool flush_support() const override final { return false; }
|
||||
virtual bool refresh_rate_support() const override final { return false; }
|
||||
virtual ErrorOr<void> flush_first_surface() override final;
|
||||
virtual void enable_console() override final;
|
||||
virtual void disable_console() override final;
|
||||
|
||||
ErrorOr<IterationDecision> for_each_dmt_timing_in_edid(Function<IterationDecision(EDID::DMT::MonitorTiming const&)>) const;
|
||||
ErrorOr<ModeSetting> find_suitable_mode(ModeSetting const& requested_mode) const;
|
||||
u8 read_vga(VGAPort port);
|
||||
u8 read_vga_indexed(VGAPort index_port, VGAPort data_port, u8 index);
|
||||
void write_vga(VGAPort port, u8 value);
|
||||
void write_vga_indexed(VGAPort index_port, VGAPort data_port, u8 index, u8 value);
|
||||
ErrorOr<void> wait_for_fifo_space(u32 minimum_entries);
|
||||
static PLLSettings calculate_pll(i32 desired_frequency_in_khz);
|
||||
ErrorOr<ModeRegisters> prepare_mode_switch(ModeSetting const& mode_setting);
|
||||
ErrorOr<void> perform_mode_switch(ModeRegisters const& regs);
|
||||
|
||||
LockRefPtr<Graphics::GenericFramebufferConsole> m_framebuffer_console;
|
||||
Memory::TypedMapping<RegisterMap volatile> m_registers;
|
||||
NonnullOwnPtr<IOWindow> m_io_window;
|
||||
};
|
||||
}
|
|
@ -197,10 +197,15 @@ ErrorOr<void> DisplayConnector::initialize_edid_for_generic_monitor(Optional<Arr
|
|||
/* colour space, preferred timing mode) */
|
||||
0xEE, 0x91, 0xA3, 0x54, 0x4C, 0x99, 0x26, 0x0F, 0x50, 0x54,
|
||||
/* chromaticity for standard colour space. */
|
||||
0x00, 0x00, 0x00, /* no default timings */
|
||||
0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
|
||||
0x01, 0x01,
|
||||
0x01, 0x01, 0x01, 0x01, /* no standard timings */
|
||||
0x21, 0x08, 0x00, /* default timings: 640x480@60, 800x600@60, 1024x768@60 */
|
||||
0xd1, 0xc0, /* standard timing 1920x1080 @ 60 Hz */
|
||||
0xb3, 0x00, /* standard timing 1680x1050 @ 60 Hz */
|
||||
0xa9, 0xc0, /* standard timing 1600x900 @ 60 Hz */
|
||||
0x95, 0x00, /* standard timing 1440x900 @ 60 Hz */
|
||||
0x8b, 0xc0, /* standard timing 1360x768 @ 60 Hz */
|
||||
0x81, 0x80, /* standard timing 1280x1024 @ 60 Hz */
|
||||
0x81, 0x40, /* standard timing 1280x960 @ 60 Hz */
|
||||
0x81, 0xc0, /* standard timing 1280x720 @ 60 Hz */
|
||||
0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x06, 0x00, 0x02, 0x02,
|
||||
0x02, 0x02,
|
||||
/* descriptor block 1 goes below */
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <Kernel/Boot/Multiboot.h>
|
||||
#include <Kernel/Bus/PCI/API.h>
|
||||
#include <Kernel/Bus/PCI/IDs.h>
|
||||
#include <Kernel/Devices/GPU/3dfx/GraphicsAdapter.h>
|
||||
#include <Kernel/Devices/GPU/Bochs/GraphicsAdapter.h>
|
||||
#include <Kernel/Devices/GPU/Console/BootFramebufferConsole.h>
|
||||
#include <Kernel/Devices/GPU/Intel/NativeGraphicsAdapter.h>
|
||||
|
@ -130,6 +131,7 @@ static constexpr PCIGraphicsDriverInitializer s_initializers[] = {
|
|||
{ BochsGraphicsAdapter::probe, BochsGraphicsAdapter::create },
|
||||
{ VirtIOGraphicsAdapter::probe, VirtIOGraphicsAdapter::create },
|
||||
{ VMWareGraphicsAdapter::probe, VMWareGraphicsAdapter::create },
|
||||
{ VoodooGraphicsAdapter::probe, VoodooGraphicsAdapter::create },
|
||||
};
|
||||
|
||||
UNMAP_AFTER_INIT ErrorOr<void> GraphicsManagement::determine_and_initialize_graphics_device(PCI::DeviceIdentifier const& device_identifier)
|
||||
|
|
|
@ -178,6 +178,7 @@ set(SYSTEM_MENU_DEBUG ON)
|
|||
set(SYSTEMSERVER_DEBUG ON)
|
||||
set(TCP_DEBUG ON)
|
||||
set(TCP_SOCKET_DEBUG ON)
|
||||
set(TDFX_DEBUG ON)
|
||||
set(TERMCAP_DEBUG ON)
|
||||
set(TERMINAL_DEBUG ON)
|
||||
set(TEXTEDITOR_DEBUG ON)
|
||||
|
|
Loading…
Reference in a new issue