Serenity Operating System
1/*
2 * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#pragma once
8
9#include <AK/Types.h>
10#include <Kernel/API/Ioctl.h>
11#include <Kernel/Devices/CharacterDevice.h>
12#include <Kernel/Memory/SharedFramebufferVMObject.h>
13#include <LibEDID/EDID.h>
14
15namespace Kernel {
16
17class GraphicsManagement;
18class DisplayConnector : public CharacterDevice {
19 friend class GraphicsManagement;
20 friend class DeviceManagement;
21
22public:
23 struct ModeSetting {
24 size_t horizontal_blanking_start() const
25 {
26 return horizontal_active;
27 }
28 size_t horizontal_sync_start() const
29 {
30 return horizontal_active + horizontal_front_porch_pixels;
31 }
32 size_t horizontal_sync_end() const
33 {
34 return horizontal_active + horizontal_front_porch_pixels + horizontal_sync_time_pixels;
35 }
36 size_t horizontal_total() const
37 {
38 return horizontal_active + horizontal_blank_pixels;
39 }
40
41 size_t vertical_blanking_start() const
42 {
43 return vertical_active;
44 }
45 size_t vertical_sync_start() const
46 {
47 return vertical_active + vertical_front_porch_lines;
48 }
49 size_t vertical_sync_end() const
50 {
51 return vertical_active + vertical_front_porch_lines + vertical_sync_time_lines;
52 }
53 size_t vertical_total() const
54 {
55 return vertical_active + vertical_blank_lines;
56 }
57
58 size_t horizontal_stride; // Note: This is commonly known as "pitch"
59 size_t pixel_clock_in_khz;
60
61 size_t horizontal_active;
62 size_t horizontal_front_porch_pixels;
63 size_t horizontal_sync_time_pixels;
64 size_t horizontal_blank_pixels;
65
66 size_t vertical_active;
67 size_t vertical_front_porch_lines;
68 size_t vertical_sync_time_lines;
69 size_t vertical_blank_lines;
70
71 size_t horizontal_offset; // Note: This is commonly known as "x offset"
72 size_t vertical_offset; // Note: This is commonly known as "y offset"
73 };
74
75public:
76 enum class DisplayMode {
77 Graphical,
78 Console,
79 };
80
81public:
82 virtual ~DisplayConnector() = default;
83
84 virtual bool mutable_mode_setting_capable() const = 0;
85 virtual bool double_framebuffering_capable() const = 0;
86 virtual bool flush_support() const = 0;
87 virtual bool partial_flush_support() const = 0;
88 // Note: This can indicate to userland if the underlying hardware requires
89 // a defined refresh rate being supplied when modesetting the screen resolution.
90 // Paravirtualized hardware don't need such setting and can safely ignore this.
91 virtual bool refresh_rate_support() const = 0;
92
93 bool console_mode() const;
94 ErrorOr<ByteBuffer> get_edid() const;
95 virtual ErrorOr<void> set_mode_setting(ModeSetting const&) = 0;
96 virtual ErrorOr<void> set_safe_mode_setting() = 0;
97 ModeSetting current_mode_setting() const;
98 virtual ErrorOr<void> set_y_offset(size_t y) = 0;
99 virtual ErrorOr<void> unblank() = 0;
100
101 void set_display_mode(Badge<GraphicsManagement>, DisplayMode);
102
103 Memory::Region const& framebuffer_region() const { return *m_framebuffer_region; }
104
105protected:
106 void set_edid_bytes(Array<u8, 128> const& edid_bytes, bool might_be_invalid = false);
107
108 DisplayConnector(PhysicalAddress framebuffer_address, size_t framebuffer_resource_size, bool enable_write_combine_optimization);
109 DisplayConnector(size_t framebuffer_resource_size, bool enable_write_combine_optimization);
110 virtual void enable_console() = 0;
111 virtual void disable_console() = 0;
112 virtual ErrorOr<void> flush_first_surface() = 0;
113 virtual ErrorOr<void> flush_rectangle(size_t buffer_index, FBRect const& rect);
114
115 ErrorOr<void> initialize_edid_for_generic_monitor(Optional<Array<u8, 3>> manufacturer_id_string);
116
117 mutable Spinlock<LockRank::None> m_control_lock {};
118 mutable Mutex m_flushing_lock;
119
120 bool m_console_mode { false };
121
122 bool m_vertical_offsetted { false };
123
124 mutable Spinlock<LockRank::None> m_modeset_lock {};
125 ModeSetting m_current_mode_setting {};
126
127 Optional<EDID::Parser> m_edid_parser;
128 EDID::Parser::RawBytes m_edid_bytes {};
129 bool m_edid_valid { false };
130
131 u8* framebuffer_data() { return m_framebuffer_data; }
132
133private:
134 // ^File
135 virtual bool is_seekable() const override { return true; }
136 virtual bool can_read(OpenFileDescription const&, u64) const final override { return true; }
137 virtual bool can_write(OpenFileDescription const&, u64) const final override { return true; }
138 virtual ErrorOr<size_t> read(OpenFileDescription&, u64, UserOrKernelBuffer&, size_t) override final;
139 virtual ErrorOr<size_t> write(OpenFileDescription&, u64, UserOrKernelBuffer const&, size_t) override final;
140 virtual ErrorOr<NonnullLockRefPtr<Memory::VMObject>> vmobject_for_mmap(Process&, Memory::VirtualRange const&, u64&, bool) override final;
141 virtual ErrorOr<void> ioctl(OpenFileDescription&, unsigned request, Userspace<void*> arg) override final;
142 virtual StringView class_name() const override final { return "DisplayConnector"sv; }
143
144 DisplayConnector& operator=(DisplayConnector const&) = delete;
145 DisplayConnector& operator=(DisplayConnector&&) = delete;
146 DisplayConnector(DisplayConnector&&) = delete;
147
148 virtual void will_be_destroyed() override;
149 virtual ErrorOr<void> after_inserting() override;
150
151 ErrorOr<void> allocate_framebuffer_resources(size_t rounded_size);
152
153 ErrorOr<bool> ioctl_requires_ownership(unsigned request) const;
154
155 OwnPtr<Memory::Region> m_framebuffer_region;
156 OwnPtr<Memory::Region> m_fake_writes_framebuffer_region;
157 u8* m_framebuffer_data {};
158
159 bool const m_enable_write_combine_optimization { false };
160 bool const m_framebuffer_at_arbitrary_physical_range { false };
161
162protected:
163 Optional<PhysicalAddress> const m_framebuffer_address;
164 size_t m_framebuffer_resource_size;
165
166private:
167 LockRefPtr<Memory::SharedFramebufferVMObject> m_shared_framebuffer_vmobject;
168
169 LockWeakPtr<Process> m_responsible_process;
170 Spinlock<LockRank::None> m_responsible_process_lock {};
171
172 IntrusiveListNode<DisplayConnector, LockRefPtr<DisplayConnector>> m_list_node;
173};
174}