summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--build.zig73
-rw-r--r--build.zig.zon15
-rwxr-xr-xbuild/build-kernel24
-rwxr-xr-xbuild/run-qemu16
-rw-r--r--eostre/build.zig20
-rw-r--r--eostre/build.zig.zon10
-rw-r--r--flake.nix15
-rw-r--r--src/estd/cursor.zig (renamed from eostre/lib/cursor.zig)0
-rw-r--r--src/estd/parser/common.zig (renamed from eostre/lib/parser/common.zig)0
-rw-r--r--src/estd/parser/context.zig (renamed from eostre/lib/parser/context.zig)0
-rw-r--r--src/estd/parser/root.zig (renamed from eostre/lib/parser/root.zig)0
-rw-r--r--src/estd/root.zig (renamed from eostre/lib/root.zig)0
-rw-r--r--src/init/main.zig21
-rw-r--r--src/screen/cerror.zig272
-rw-r--r--src/screen/drm/card.zig45
-rw-r--r--src/screen/drm/connector.zig156
-rw-r--r--src/screen/drm/request.zig19
-rw-r--r--src/screen/drm/resources.zig76
-rw-r--r--src/screen/main.zig20
-rw-r--r--src/shell/main.zig (renamed from src/main.zig)12
21 files changed, 723 insertions, 72 deletions
diff --git a/.gitignore b/.gitignore
index 6781a58..5da3d0f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
.direnv
.zig-cache
zig-out
+.kernel
diff --git a/build.zig b/build.zig
index 40cae2d..14f17d6 100644
--- a/build.zig
+++ b/build.zig
@@ -1,39 +1,72 @@
const std = @import("std");
+const Program = struct {
+ name: []const u8,
+ qemu: bool,
+};
+
+const programs = [_]Program {
+ .{ .name = "shell", .qemu = false },
+ .{ .name = "screen", .qemu = true },
+};
+
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
- const pkg = b.dependency("eostre", .{
- .target = target,
- .optimize = optimize,
+ const estd = b.createModule(.{
+ .root_source_file = b.path("src/estd/root.zig"),
});
- const exe = b.addExecutable(.{
- .name = "shell",
- .root_source_file = b.path("src/main.zig"),
+ const init_exe = b.addExecutable(.{
+ .name = "init",
+ .root_source_file = b.path("src/init/main.zig"),
.target = target,
- .optimize = optimize
+ .optimize = optimize,
});
+ init_exe.root_module.addImport("estd", estd);
+
+ const test_step = b.step("test", "Run tests");
- const run_exe = b.addRunArtifact(exe);
- const run_step = b.step("run", "Run the application");
- run_step.dependOn(&run_exe.step);
+ inline for (programs) |program| {
+ const path = b.path("src/" ++ program.name ++ "/main.zig");
- exe.root_module.addImport("eostre", pkg.module("eostre"));
+ const exe = b.addExecutable(.{
+ .name = program.name,
+ .root_source_file = path,
+ .target = target,
+ .optimize = optimize
+ });
+ exe.root_module.addImport("estd", estd);
+ b.installArtifact(exe);
- const test_step = b.step("test", "Run unit tests");
+ const run = b.step("run-" ++ program.name, "Run " ++ program.name);
+
+ if (program.qemu) {
+ const run_qemu = b.addSystemCommand(&.{ "./build/run-qemu" });
+ run_qemu.addFileArg(init_exe.getEmittedBin());
+ run_qemu.addFileArg(exe.getEmittedBin());
+ run_qemu.step.dependOn(&exe.step);
+ run_qemu.step.dependOn(&init_exe.step);
+ run.dependOn(&run_qemu.step);
+ } else {
+ const run_artifact = b.addRunArtifact(exe);
+ run.dependOn(&run_artifact.step);
+ }
+
+ const tests = b.addTest(.{
+ .name = program.name,
+ .root_source_file = path,
+ });
+ tests.root_module.addImport("estd", estd);
+ const run_tests = b.addRunArtifact(tests);
+ test_step.dependOn(&run_tests.step);
+ }
const tests = b.addTest(.{
- .name = "shell",
- .root_source_file = b.path("src/main.zig"),
- .target = target,
+ .name = "estd",
+ .root_source_file = b.path("src/estd/root.zig"),
});
- tests.root_module.addImport("eostre", pkg.module("eostre"));
-
const run_tests = b.addRunArtifact(tests);
test_step.dependOn(&run_tests.step);
-
- const lib_tests = b.addRunArtifact(pkg.artifact("eostre"));
- test_step.dependOn(&lib_tests.step);
}
diff --git a/build.zig.zon b/build.zig.zon
deleted file mode 100644
index 311d2b8..0000000
--- a/build.zig.zon
+++ /dev/null
@@ -1,15 +0,0 @@
-.{
- .name = "shell",
- .version = "0.0.0",
- .dependencies = .{
- .eostre = .{
- .path = "./eostre",
- },
- },
-
- .paths = .{
- "src",
- "build.zig",
- "build.zig.zon"
- },
-}
diff --git a/build/build-kernel b/build/build-kernel
new file mode 100755
index 0000000..4265e94
--- /dev/null
+++ b/build/build-kernel
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+VERSION="6.12.11"
+MAJOR_VERSION="$(echo "$VERSION" | sed -E 's/^([0-9]*)\..*$/\1/g')"
+
+SRC_DIR=".kernel"
+URL="https://cdn.kernel.org/pub/linux/kernel/v$MAJOR_VERSION.x/linux-$VERSION.tar.xz"
+
+TARGET_KERNEL="linux-$VERSION/arch/x86_64/boot/bzImage"
+
+mkdir -p "$SRC_DIR"
+cd "$SRC_DIR"
+
+if [ ! -e "linux-$VERSION" ]; then
+ curl "$URL" | tar -J -xvf -
+fi
+
+if [ ! -e "$TARGET_KERNEL" ]; then
+ cd "linux-$VERSION"
+ make defconfig
+ make -j$(nproc)
+fi
+
+echo "$SRC_DIR/$TARGET_KERNEL"
diff --git a/build/run-qemu b/build/run-qemu
new file mode 100755
index 0000000..dbe7895
--- /dev/null
+++ b/build/run-qemu
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+KERNEL_PATH=$(./build/build-kernel)
+
+mkdir -p .kernel/initramfs
+cp "$1" .kernel/initramfs/init
+cp "$2" .kernel/initramfs/process
+printf "./init\n./process\n" | cpio -D .kernel/initramfs/ --quiet -H newc -o | gzip -9 -n > .kernel/initramfs.gz
+
+qemu-system-x86_64 \
+ --cpu host \
+ --enable-kvm \
+ -initrd .kernel/initramfs.gz \
+ -kernel "$KERNEL_PATH" \
+ -append "quiet rdinit=init" \
+ -device virtio-gpu-pci
diff --git a/eostre/build.zig b/eostre/build.zig
deleted file mode 100644
index da302f9..0000000
--- a/eostre/build.zig
+++ /dev/null
@@ -1,20 +0,0 @@
-const std = @import("std");
-
-pub fn build(b: *std.Build) void {
- const target = b.standardTargetOptions(.{});
- const optimize = b.standardOptimizeOption(.{});
-
- _ = b.addModule("eostre", .{
- .root_source_file = b.path("lib/root.zig"),
- .target = target,
- .optimize = optimize,
- });
-
- const tests = b.addTest(.{
- .name = "eostre",
- .root_source_file = b.path("lib/root.zig"),
- .target = target,
- });
-
- b.installArtifact(tests);
-}
diff --git a/eostre/build.zig.zon b/eostre/build.zig.zon
deleted file mode 100644
index 39514b6..0000000
--- a/eostre/build.zig.zon
+++ /dev/null
@@ -1,10 +0,0 @@
-.{
- .name = "eostre",
- .version = "0.0.0",
-
- .paths = .{
- "lib",
- "build.zig",
- "build.zig.zon"
- }
-}
diff --git a/flake.nix b/flake.nix
index 8ffc51e..4158197 100644
--- a/flake.nix
+++ b/flake.nix
@@ -12,7 +12,20 @@
{
devShells.x86_64-linux.default = pkgs.zigStdenv.mkDerivation {
name = "zig-dev-shell";
- buildInputs = [ pkgs.zig ];
+ packages = [ pkgs.libdrm ];
+ buildInputs = [
+ pkgs.zig
+ pkgs.qemu_full
+ pkgs.gnumake
+ pkgs.gcc
+ pkgs.flex
+ pkgs.bison
+ pkgs.elfutils
+ pkgs.openssl
+ pkgs.moreutils
+ pkgs.libdrm
+ pkgs.pkg-config
+ ];
};
};
}
diff --git a/eostre/lib/cursor.zig b/src/estd/cursor.zig
index c0a4a32..c0a4a32 100644
--- a/eostre/lib/cursor.zig
+++ b/src/estd/cursor.zig
diff --git a/eostre/lib/parser/common.zig b/src/estd/parser/common.zig
index 986af58..986af58 100644
--- a/eostre/lib/parser/common.zig
+++ b/src/estd/parser/common.zig
diff --git a/eostre/lib/parser/context.zig b/src/estd/parser/context.zig
index 56fb025..56fb025 100644
--- a/eostre/lib/parser/context.zig
+++ b/src/estd/parser/context.zig
diff --git a/eostre/lib/parser/root.zig b/src/estd/parser/root.zig
index b168a88..b168a88 100644
--- a/eostre/lib/parser/root.zig
+++ b/src/estd/parser/root.zig
diff --git a/eostre/lib/root.zig b/src/estd/root.zig
index 86af090..86af090 100644
--- a/eostre/lib/root.zig
+++ b/src/estd/root.zig
diff --git a/src/init/main.zig b/src/init/main.zig
new file mode 100644
index 0000000..0af43bc
--- /dev/null
+++ b/src/init/main.zig
@@ -0,0 +1,21 @@
+const std = @import("std");
+const os = std.os.linux;
+
+pub fn main() !void {
+ std.debug.print("\u{1b}[1;1H\u{1b}[J", .{});
+ _ = std.os.linux.mount("none", "/dev/", "devtmpfs", 0, 0);
+
+
+ const pid = @as(i32, @intCast(os.fork()));
+
+ if (pid == 0) {
+ _ = os.execve("process", &[_:null]?[*:0]const u8 { "process" }, &[0:null]?[*:0]const u8{});
+
+ return error.ExecFailed;
+ }
+
+ var status: u32 = undefined;
+ _ = os.waitpid(pid, &status, 0);
+
+ while (true) { std.time.sleep(100); }
+}
diff --git a/src/screen/cerror.zig b/src/screen/cerror.zig
new file mode 100644
index 0000000..cd7f6e6
--- /dev/null
+++ b/src/screen/cerror.zig
@@ -0,0 +1,272 @@
+
+pub const CError = error {
+ OperationNotPermitted,
+ NoSuchFileOrDirectory,
+ NoSuchProcess,
+ InterruptedSystemCall,
+ InputOutputError,
+ NoSuchDeviceOrAddress,
+ ArgumentListTooLong,
+ ExecFormatError,
+ BadFileDescriptor,
+ NoChildProcesses,
+ ResourceTemporarilyUnavailable,
+ CannotAllocateMemory,
+ PermissionDenied,
+ BadAddress,
+ BlockDeviceRequired,
+ DeviceOrResourceBusy,
+ FileExists,
+ InvalidCrossDeviceLink,
+ NoSuchDevice,
+ NotADirectory,
+ IsADirectory,
+ InvalidArgument,
+ TooManyOpenFilesInSystem,
+ TooManyOpenFiles,
+ InappropriateIoctlForDevice,
+ TextFileBusy,
+ FileTooLarge,
+ NoSpaceLeftOnDevice,
+ IllegalSeek,
+ ReadOnlyFileSystem,
+ TooManyLinks,
+ BrokenPipe,
+ NumericalArgumentOutOfDomain,
+ NumericalResultOutOfRange,
+ ResourceDeadlockAvoided,
+ FileNameTooLong,
+ NoLocksAvailable,
+ FunctionNotImplemented,
+ DirectoryNotEmpty,
+ TooManyLevelsOfSymbolicLinks,
+ NoMessageOfDesiredType,
+ IdentifierRemoved,
+ ChannelNumberOutOfRange,
+ Level2NotSynchronized,
+ Level3Halted,
+ Level3Reset,
+ LinkNumberOutOfRange,
+ ProtocolDriverNotAttached,
+ NoCSIStructureAvailable,
+ Level2Halted,
+ InvalidExchange,
+ InvalidRequestDescriptor,
+ ExchangeFull,
+ NoAnode,
+ InvalidRequestCode,
+ InvalidSlot,
+ BadFontFileFormat,
+ DeviceNotAStream,
+ NoDataAvailable,
+ TimerExpired,
+ OutOfStreamsResources,
+ MachineIsNotOnTheNetwork,
+ PackageNotInstalled,
+ ObjectIsRemote,
+ LinkHasBeenSevered,
+ AdvertiseError,
+ SrmountError,
+ CommunicationErrorOnSend,
+ ProtocolError,
+ MultihopAttempted,
+ RFSSpecificError,
+ BadMessage,
+ ValueTooLargeForDefinedDataType,
+ NameNotUniqueOnNetwork,
+ FileDescriptorInBadState,
+ RemoteAddressChanged,
+ CanNotAccessANeededSharedLibrary,
+ AccessingACorruptedSharedLibrary,
+ LibSectionInAOutCorrupted,
+ AttemptingToLinkInTooManySharedLibraries,
+ CannotExecASharedLibraryDirectly,
+ InvalidOrIncompleteMultibyteOrWideCharacter,
+ InterruptedSystemCallShouldBeRestarted,
+ StreamsPipeError,
+ TooManyUsers,
+ SocketOperationOnNonSocket,
+ DestinationAddressRequired,
+ MessageTooLong,
+ ProtocolWrongTypeForSocket,
+ ProtocolNotAvailable,
+ ProtocolNotSupported,
+ SocketTypeNotSupported,
+ OperationNotSupported,
+ ProtocolFamilyNotSupported,
+ AddressFamilyNotSupportedByProtocol,
+ AddressAlreadyInUse,
+ CannotAssignRequestedAddress,
+ NetworkIsDown,
+ NetworkIsUnreachable,
+ NetworkDroppedConnectionOnReset,
+ SoftwareCausedConnectionAbort,
+ ConnectionResetByPeer,
+ NoBufferSpaceAvailable,
+ TransportEndpointIsAlreadyConnected,
+ TransportEndpointIsNotConnected,
+ CannotSendAfterTransportEndpointShutdown,
+ TooManyReferences,
+ ConnectionTimedOut,
+ ConnectionRefused,
+ HostIsDown,
+ NoRouteToHost,
+ OperationAlreadyInProgress,
+ OperationNowInProgress,
+ StaleFileHandle,
+ StructureNeedsCleaning,
+ NotAXENIXNamedTypeFile,
+ NoXENIXSemaphoresAvailable,
+ IsANamedTypeFile,
+ RemoteIOError,
+ DiskQuotaExceeded,
+ NoMediumFound,
+ WrongMediumType,
+ OperationCanceled,
+ RequiredKeyNotAvailable,
+ KeyHasExpired,
+ KeyHasBeenRevoked,
+ KeyWasRejectedByService,
+ OwnerDied,
+ StateNotRecoverable,
+ OperationNotPossibleDueToRFKill,
+ MemoryPageHasHardwareError,
+};
+
+pub fn from_usize(errno: usize) CError!void {
+ const n = -@as(isize, @bitCast(errno));
+ return switch (n) {
+ 1 => CError.OperationNotPermitted,
+ 2 => CError.NoSuchFileOrDirectory,
+ 3 => CError.NoSuchProcess,
+ 4 => CError.InterruptedSystemCall,
+ 5 => CError.InputOutputError,
+ 6 => CError.NoSuchDeviceOrAddress,
+ 7 => CError.ArgumentListTooLong,
+ 8 => CError.ExecFormatError,
+ 9 => CError.BadFileDescriptor,
+ 10 => CError.NoChildProcesses,
+ 11 => CError.ResourceTemporarilyUnavailable,
+ 12 => CError.CannotAllocateMemory,
+ 13 => CError.PermissionDenied,
+ 14 => CError.BadAddress,
+ 15 => CError.BlockDeviceRequired,
+ 16 => CError.DeviceOrResourceBusy,
+ 17 => CError.FileExists,
+ 18 => CError.InvalidCrossDeviceLink,
+ 19 => CError.NoSuchDevice,
+ 20 => CError.NotADirectory,
+ 21 => CError.IsADirectory,
+ 22 => CError.InvalidArgument,
+ 23 => CError.TooManyOpenFilesInSystem,
+ 24 => CError.TooManyOpenFiles,
+ 25 => CError.InappropriateIoctlForDevice,
+ 26 => CError.TextFileBusy,
+ 27 => CError.FileTooLarge,
+ 28 => CError.NoSpaceLeftOnDevice,
+ 29 => CError.IllegalSeek,
+ 30 => CError.ReadOnlyFileSystem,
+ 31 => CError.TooManyLinks,
+ 32 => CError.BrokenPipe,
+ 33 => CError.NumericalArgumentOutOfDomain,
+ 34 => CError.NumericalResultOutOfRange,
+ 35 => CError.ResourceDeadlockAvoided,
+ 36 => CError.FileNameTooLong,
+ 37 => CError.NoLocksAvailable,
+ 38 => CError.FunctionNotImplemented,
+ 39 => CError.DirectoryNotEmpty,
+ 40 => CError.TooManyLevelsOfSymbolicLinks,
+ 42 => CError.NoMessageOfDesiredType,
+ 43 => CError.IdentifierRemoved,
+ 44 => CError.ChannelNumberOutOfRange,
+ 45 => CError.Level2NotSynchronized,
+ 46 => CError.Level3Halted,
+ 47 => CError.Level3Reset,
+ 48 => CError.LinkNumberOutOfRange,
+ 49 => CError.ProtocolDriverNotAttached,
+ 50 => CError.NoCSIStructureAvailable,
+ 51 => CError.Level2Halted,
+ 52 => CError.InvalidExchange,
+ 53 => CError.InvalidRequestDescriptor,
+ 54 => CError.ExchangeFull,
+ 55 => CError.NoAnode,
+ 56 => CError.InvalidRequestCode,
+ 57 => CError.InvalidSlot,
+ 59 => CError.BadFontFileFormat,
+ 60 => CError.DeviceNotAStream,
+ 61 => CError.NoDataAvailable,
+ 62 => CError.TimerExpired,
+ 63 => CError.OutOfStreamsResources,
+ 64 => CError.MachineIsNotOnTheNetwork,
+ 65 => CError.PackageNotInstalled,
+ 66 => CError.ObjectIsRemote,
+ 67 => CError.LinkHasBeenSevered,
+ 68 => CError.AdvertiseError,
+ 69 => CError.SrmountError,
+ 70 => CError.CommunicationErrorOnSend,
+ 71 => CError.ProtocolError,
+ 72 => CError.MultihopAttempted,
+ 73 => CError.RFSSpecificError,
+ 74 => CError.BadMessage,
+ 75 => CError.ValueTooLargeForDefinedDataType,
+ 76 => CError.NameNotUniqueOnNetwork,
+ 77 => CError.FileDescriptorInBadState,
+ 78 => CError.RemoteAddressChanged,
+ 79 => CError.CanNotAccessANeededSharedLibrary,
+ 80 => CError.AccessingACorruptedSharedLibrary,
+ 81 => CError.LibSectionInAOutCorrupted,
+ 82 => CError.AttemptingToLinkInTooManySharedLibraries,
+ 83 => CError.CannotExecASharedLibraryDirectly,
+ 84 => CError.InvalidOrIncompleteMultibyteOrWideCharacter,
+ 85 => CError.InterruptedSystemCallShouldBeRestarted,
+ 86 => CError.StreamsPipeError,
+ 87 => CError.TooManyUsers,
+ 88 => CError.SocketOperationOnNonSocket,
+ 89 => CError.DestinationAddressRequired,
+ 90 => CError.MessageTooLong,
+ 91 => CError.ProtocolWrongTypeForSocket,
+ 92 => CError.ProtocolNotAvailable,
+ 93 => CError.ProtocolNotSupported,
+ 94 => CError.SocketTypeNotSupported,
+ 95 => CError.OperationNotSupported,
+ 96 => CError.ProtocolFamilyNotSupported,
+ 97 => CError.AddressFamilyNotSupportedByProtocol,
+ 98 => CError.AddressAlreadyInUse,
+ 99 => CError.CannotAssignRequestedAddress,
+ 100 => CError.NetworkIsDown,
+ 101 => CError.NetworkIsUnreachable,
+ 102 => CError.NetworkDroppedConnectionOnReset,
+ 103 => CError.SoftwareCausedConnectionAbort,
+ 104 => CError.ConnectionResetByPeer,
+ 105 => CError.NoBufferSpaceAvailable,
+ 106 => CError.TransportEndpointIsAlreadyConnected,
+ 107 => CError.TransportEndpointIsNotConnected,
+ 108 => CError.CannotSendAfterTransportEndpointShutdown,
+ 109 => CError.TooManyReferences,
+ 110 => CError.ConnectionTimedOut,
+ 111 => CError.ConnectionRefused,
+ 112 => CError.HostIsDown,
+ 113 => CError.NoRouteToHost,
+ 114 => CError.OperationAlreadyInProgress,
+ 115 => CError.OperationNowInProgress,
+ 116 => CError.StaleFileHandle,
+ 117 => CError.StructureNeedsCleaning,
+ 118 => CError.NotAXENIXNamedTypeFile,
+ 119 => CError.NoXENIXSemaphoresAvailable,
+ 120 => CError.IsANamedTypeFile,
+ 121 => CError.RemoteIOError,
+ 122 => CError.DiskQuotaExceeded,
+ 123 => CError.NoMediumFound,
+ 124 => CError.WrongMediumType,
+ 125 => CError.OperationCanceled,
+ 126 => CError.RequiredKeyNotAvailable,
+ 127 => CError.KeyHasExpired,
+ 128 => CError.KeyHasBeenRevoked,
+ 129 => CError.KeyWasRejectedByService,
+ 130 => CError.OwnerDied,
+ 131 => CError.StateNotRecoverable,
+ 132 => CError.OperationNotPossibleDueToRFKill,
+ 133 => CError.MemoryPageHasHardwareError,
+ else => void{}
+ };
+}
diff --git a/src/screen/drm/card.zig b/src/screen/drm/card.zig
new file mode 100644
index 0000000..67f81f3
--- /dev/null
+++ b/src/screen/drm/card.zig
@@ -0,0 +1,45 @@
+const std = @import("std");
+const os = std.os.linux;
+
+const cerror = @import("../cerror.zig");
+
+const Resources = @import("resources.zig").Resources;
+const Connector = @import("connector.zig").Connector;
+
+
+pub const Card = struct {
+ const Self = @This();
+
+ file: std.fs.File,
+ allocator: std.mem.Allocator,
+
+ pub fn open(name: []const u8, allocator: std.mem.Allocator) !Self {
+ var dri_dir = try std.fs.openDirAbsolute("/dev/dri", .{});
+ defer dri_dir.close();
+
+ return .{
+ .file = try dri_dir.openFile(name, .{
+ .mode = .read_write,
+ .lock_nonblocking = true,
+ }),
+ .allocator = allocator,
+ };
+ }
+
+ pub fn close(self: *Card) void {
+ self.file.close();
+ }
+
+ pub fn is_kms(self: *Card) !bool {
+ const raw_info = Resources.raw_without_ids(self);
+ return raw_info.count_crtcs > 0 and raw_info.count_connectors > 0 and raw_info.count_encoders > 0;
+ }
+
+ pub fn resources(self: *Card) !Resources {
+ return Resources.init(self);
+ }
+
+ pub fn connector(self: *Card, id: u32) !Connector {
+ return Connector.init(self, id);
+ }
+};
diff --git a/src/screen/drm/connector.zig b/src/screen/drm/connector.zig
new file mode 100644
index 0000000..9d7f9ad
--- /dev/null
+++ b/src/screen/drm/connector.zig
@@ -0,0 +1,156 @@
+const std = @import("std");
+const os = std.os.linux;
+const Drm = @import("request.zig").Drm;
+const Card = @import("card.zig").Card;
+
+const RawConnector = extern struct {
+ encoder_ids: ?*u32,
+ modes: ?*ModeInfo,
+ prop_ids: ?*u32,
+ prop_value_ids: ?*u64,
+ count_modes: u32,
+ count_props: u32,
+ count_encoders: u32,
+ encoder_id: u32,
+ connector_id: u32,
+ connector_type: u32,
+ connector_type_id: u32,
+ connection: Connection,
+ mm_width: u32,
+ mm_height: u32,
+ subpixel: u32,
+ pad: u32,
+};
+
+const Connection = enum(u32) {
+ undefined_state = 0,
+ connected = 1,
+ disconnected = 2,
+ unknown = 3,
+};
+
+const ModeInfo = extern struct {
+ const Self = @This();
+ const Flags = packed struct(u32) {
+ phsync: bool,
+ nhsync: bool,
+ pvsync: bool,
+ nvsync: bool,
+ interlace: bool,
+ dblscan: bool,
+ csync: bool,
+ pcsync: bool,
+ ncsync: bool,
+ hskew: bool,
+ bcast: bool,
+ pixmux: bool,
+ dblclk: bool,
+ clkdiv2: bool,
+ _padding: u18,
+ };
+
+ clock: u32,
+ hdisplay: u16,
+ hsync_start: u16,
+ hsync_end: u16,
+ htotal: u16,
+ hskew: u16,
+ vdisplay: u16,
+ vsync_start: u16,
+ vsync_end: u16,
+ vtotal: u16,
+ vscan: u16,
+
+ vrefresh: u32,
+
+ flags: Flags,
+ type: u32,
+ name: [32]u8,
+
+ pub fn frame_rate(self: *const Self) f32 {
+ var rate = (@as(u64, @intCast(self.clock)) * 1000000 / self.htotal + self.vtotal / 2) / self.vtotal;
+
+ if (self.flags.interlace) {
+ rate *= 2;
+ }
+
+ if (self.flags.dblscan) {
+ rate /= 2;
+ }
+
+ if (self.vscan > 1) {
+ rate /= self.vscan;
+ }
+
+ return @as(f32, @floatFromInt(rate)) / 1000.0;
+ }
+};
+
+pub const Connector = struct {
+ const Self = @This();
+
+ card: *Card,
+
+ encoder_ids: []u32,
+ modes: []ModeInfo,
+ prop_ids: []u32,
+ prop_value_ids: []u64,
+ encoder_id: u32,
+ connector_id: u32,
+ connector_type: u32,
+ connector_type_id: u32,
+ connection: Connection,
+ mm_width: u32,
+ mm_height: u32,
+ subpixel: u32,
+ pad: u32,
+
+ pub fn raw_without_ids(card: *Card, id: u32) !RawConnector {
+ var result = std.mem.zeroInit(RawConnector, .{ .connector_id = id });
+ try Drm.get_connector.request(card.file.handle, RawConnector, &result);
+ return result;
+ }
+
+ // NOTE: This function does not take in account
+ // that there might be some hot-plugging going
+ // on. This might have to change in the future.
+ pub fn init(card: *Card, id: u32) !Self {
+ var raw = try Self.raw_without_ids(card, id);
+ const resources = .{
+ .encoder_ids = try card.allocator.alloc(u32, raw.count_encoders),
+ .modes = try card.allocator.alloc(ModeInfo, raw.count_modes),
+ .prop_ids = try card.allocator.alloc(u32, raw.count_props),
+ .prop_value_ids = try card.allocator.alloc(u64, raw.count_props),
+ .encoder_id = raw.encoder_id,
+ .connector_id = raw.connector_id,
+ .connector_type = raw.connector_type,
+ .connector_type_id = raw.connector_type_id,
+ .connection = raw.connection,
+ .mm_width = raw.mm_width,
+ .mm_height = raw.mm_height,
+ .subpixel = raw.subpixel,
+ .pad = raw.pad,
+ .card = card,
+ };
+
+ @memset(resources.encoder_ids, 0);
+ @memset(resources.modes, std.mem.zeroes(ModeInfo));
+ @memset(resources.prop_ids, 0);
+ @memset(resources.prop_value_ids, 0);
+
+ raw.encoder_ids = @ptrCast(resources.encoder_ids);
+ raw.modes = @ptrCast(resources.modes);
+ raw.prop_ids = @ptrCast(resources.prop_ids);
+ raw.prop_value_ids = @ptrCast(resources.prop_value_ids);
+
+ try Drm.get_connector.request(card.file.handle, RawConnector, &raw);
+
+ return resources;
+ }
+
+ pub fn deinit(self: *Self) void {
+ self.card.allocator.free(self.encoder_ids);
+ self.card.allocator.free(self.modes);
+ self.card.allocator.free(self.prop_ids);
+ }
+};
diff --git a/src/screen/drm/request.zig b/src/screen/drm/request.zig
new file mode 100644
index 0000000..bf9701c
--- /dev/null
+++ b/src/screen/drm/request.zig
@@ -0,0 +1,19 @@
+const std = @import("std");
+const os = std.os.linux;
+const cerror = @import("../cerror.zig");
+
+fn ioctl(fd: os.fd_t, request: u32, arg: usize) !void {
+ try cerror.from_usize(os.ioctl(fd, request, arg));
+}
+
+pub const Drm = enum(u8) {
+ const Self = @This();
+
+ get_resources = 0xA0,
+ get_connector = 0xA7,
+
+ pub fn request(self: Self, fd: os.fd_t, T: type, arg: *T) !void {
+ const id = os.IOCTL.IOWR('d', @intFromEnum(self), T);
+ try ioctl(fd, id, @intFromPtr(arg));
+ }
+};
diff --git a/src/screen/drm/resources.zig b/src/screen/drm/resources.zig
new file mode 100644
index 0000000..6128f37
--- /dev/null
+++ b/src/screen/drm/resources.zig
@@ -0,0 +1,76 @@
+const std = @import("std");
+const os = std.os.linux;
+const cerror = @import("../cerror.zig");
+const Card = @import("card.zig").Card;
+const Drm = @import("request.zig").Drm;
+
+const RawResources = extern struct {
+ fb_ids: ?*u32,
+ crtc_ids: ?*u32,
+ connector_ids: ?*u32,
+ encoder_ids: ?*u32,
+ count_fbs: u32,
+ count_crtcs: u32,
+ count_connectors: u32,
+ count_encoders: u32,
+ min_width: u32,
+ max_width: u32,
+ min_height: u32,
+ max_height: u32,
+};
+
+pub const Resources = struct {
+ const Self = @This();
+ const Range = struct { min: u32, max: u32 };
+
+ card: *Card,
+
+ fb_ids: []u32,
+ crtc_ids: []u32,
+ connector_ids: []u32,
+ encoder_ids: []u32,
+ width: Range,
+ height: Range,
+
+ pub fn raw_without_ids(card: *Card) !RawResources {
+ var result = std.mem.zeroes(RawResources);
+ try Drm.get_resources.request(card.file.handle, RawResources, &result);
+ return result;
+ }
+
+ // NOTE: This function does not take in account
+ // that there might be some hot-plugging going
+ // on. This might have to change in the future.
+ pub fn init(card: *Card) !Self {
+ var raw = try Self.raw_without_ids(card);
+ const resources = .{
+ .fb_ids = try card.allocator.alloc(u32, raw.count_fbs),
+ .crtc_ids = try card.allocator.alloc(u32, raw.count_crtcs),
+ .connector_ids = try card.allocator.alloc(u32, raw.count_connectors),
+ .encoder_ids = try card.allocator.alloc(u32, raw.count_encoders),
+ .width = .{ .min = raw.min_width, .max = raw.max_width },
+ .height = .{ .min = raw.min_height, .max = raw.max_height },
+ .card = card,
+ };
+
+ @memset(resources.fb_ids, 0);
+ @memset(resources.crtc_ids, 0);
+ @memset(resources.connector_ids, 0);
+ @memset(resources.encoder_ids, 0);
+
+ raw.fb_ids = @ptrCast(resources.fb_ids);
+ raw.crtc_ids = @ptrCast(resources.crtc_ids);
+ raw.connector_ids = @ptrCast(resources.connector_ids);
+ raw.encoder_ids = @ptrCast(resources.encoder_ids);
+ try Drm.get_resources.request(card.file.handle, RawResources, &raw);
+
+ return resources;
+ }
+
+ pub fn deinit(self: *Self) void {
+ self.card.allocator.free(self.fb_ids);
+ self.card.allocator.free(self.crtc_ids);
+ self.card.allocator.free(self.connector_ids);
+ self.card.allocator.free(self.encoder_ids);
+ }
+};
diff --git a/src/screen/main.zig b/src/screen/main.zig
new file mode 100644
index 0000000..c23e7c5
--- /dev/null
+++ b/src/screen/main.zig
@@ -0,0 +1,20 @@
+const std = @import("std");
+const drm = @import("drm/card.zig");
+
+pub fn main() !void {
+ var gpa = std.heap.GeneralPurposeAllocator(.{}){};
+ const allocator = gpa.allocator();
+
+ var card = try drm.Card.open("card0", allocator);
+ defer card.close();
+
+ var resources = try card.resources();
+ defer resources.deinit();
+
+ var connector = try card.connector(resources.connector_ids[0]);
+ defer connector.deinit();
+
+ for (connector.modes) |mode| {
+ std.debug.print("{d}x{d}@{d}\n", .{mode.hdisplay, mode.vdisplay, mode.frame_rate()});
+ }
+}
diff --git a/src/main.zig b/src/shell/main.zig
index 2144798..337185b 100644
--- a/src/main.zig
+++ b/src/shell/main.zig
@@ -1,10 +1,10 @@
const std = @import("std");
-const eostre = @import("eostre");
-const Cursor = eostre.cursor.Cursor;
-const Parser = eostre.parser.Parser;
-const Context = eostre.parser.Context;
-const Literal = eostre.parser.common.Literal;
-const ParseFn = eostre.parser.ParseFn;
+const estd = @import("estd");
+const Cursor = estd.cursor.Cursor;
+const Parser = estd.parser.Parser;
+const Context = estd.parser.Context;
+const Literal = estd.parser.common.Literal;
+const ParseFn = estd.parser.ParseFn;
const Keyword = enum {
if_statement,