From 35b92f2324705db721422fba72c134354e5b2997 Mon Sep 17 00:00:00 2001 From: Jackson Netherwood-Imig Date: Fri, 6 Mar 2026 15:17:51 -0800 Subject: [PATCH] feat: get Device from Card. --- example.zig | 10 ++++++---- src/Card.zig | 20 ++++++++++++++++---- src/Device.zig | 23 +++++++++++------------ src/util.zig | 28 ++++++++++++++++++++++++++++ 4 files changed, 61 insertions(+), 20 deletions(-) create mode 100644 src/util.zig diff --git a/example.zig b/example.zig index 946aaf7..3b1542f 100644 --- a/example.zig +++ b/example.zig @@ -5,13 +5,15 @@ pub fn main(init: std.process.Init) !void { const io = init.io; const gpa = init.gpa; - const device = drm.Device.getFromDevId(io, gpa, drm.makeDev(226, 0), .{}) catch - try drm.Device.getFromDevId(io, gpa, drm.makeDev(226, 1), .{}); + // const device = drm.Device.getFromDevId(io, gpa, drm.makeDev(226, 0), .{}) catch + // try drm.Device.getFromDevId(io, gpa, drm.makeDev(226, 1), .{}); + // const card = try device.openNode(io); + + const card = try drm.Card.openAuto(io, .primary); + const device = try card.getDevice(io, gpa, .{}); std.log.info("Device node path: {s}.", .{device.nodePath()}); - // const card = try drm.Card.openAuto(io); - const card = try device.openNode(io); defer card.close(io); const res = try card.getModesettingResources(gpa); defer res.deinit(gpa); diff --git a/src/Card.zig b/src/Card.zig index 97929b0..88fc856 100644 --- a/src/Card.zig +++ b/src/Card.zig @@ -1,11 +1,12 @@ const std = @import("std"); +const Device = @import("Device.zig"); const drm = @import("drm.zig"); const fmt = @import("format.zig"); const sys = @import("sys.zig"); +const util = @import("util.zig"); const log = std.log.scoped(.drm); - const Card = @This(); handle: std.Io.File, @@ -24,13 +25,15 @@ pub fn open(io: std.Io, path: []const u8) OpenError!Card { pub const OpenAutoError = OpenError || std.Io.Dir.Iterator.Error || error{NoDevicesFound}; -pub fn openAuto(io: std.Io) OpenAutoError!Card { +pub fn openAuto(io: std.Io, target_type: ?drm.Device.NodeType) OpenAutoError!Card { const dir = try std.Io.Dir.openDirAbsolute(io, "/dev/dri", .{ .iterate = true }); defer dir.close(io); var it = dir.iterateAssumeFirstIteration(); - while (try it.next(io)) |entry| if (entry.kind == .character_device) - return Card{ .handle = try dir.openFile(io, entry.name, .{ .mode = .read_write }) }; + while (try it.next(io)) |entry| if (entry.kind == .character_device) { + if (target_type) |t| if (!std.mem.startsWith(u8, entry.name, t.name())) continue; + return Card{ .handle = dir.openFile(io, entry.name, .{ .mode = .read_write }) catch continue }; + }; return error.NoDevicesFound; } @@ -39,6 +42,15 @@ pub fn close(self: Card, io: std.Io) void { self.handle.close(io); } +pub fn getDevId(self: Card) !std.posix.dev_t { + const stat = try util.statFile(self.handle.handle); + return drm.makeDev(stat.rdev_major, stat.rdev_minor); +} + +pub fn getDevice(self: Card, io: std.Io, gpa: std.mem.Allocator, flags: Device.Flags) !Device { + return .getFromDevId(io, gpa, try self.getDevId(), flags); +} + pub fn handleEvents( self: Card, io: std.Io, diff --git a/src/Device.zig b/src/Device.zig index 661718d..053fbf5 100644 --- a/src/Device.zig +++ b/src/Device.zig @@ -4,6 +4,7 @@ const path_max = std.os.linux.PATH_MAX; const Card = @import("Card.zig"); const drm = @import("drm.zig"); const sys = @import("sys.zig"); +const util = @import("util.zig"); const log = std.log.scoped(.drm); const Device = @This(); @@ -183,6 +184,14 @@ pub const NodeType = enum { control, render, pub const max = 3; + + pub fn name(self: NodeType) []const u8 { + return switch (self) { + .primary => drm.primary_minor_name, + .control => drm.control_minor_name, + .render => drm.render_minor_name, + }; + } }; fn processDevice( @@ -202,7 +211,7 @@ fn processDevice( if (node.len + 1 > max_node_length) return error.NodePathTooLong; - const stat = try statx(node); + const stat = try util.statPath(node); const major = stat.rdev_major; const minor = stat.rdev_minor; @@ -375,7 +384,7 @@ fn parseConfigSysfsFile(io: std.Io, major: u32, minor: u32) !PciDeviceInfo { } fn hasRdev(dev: Device, rdev: std.posix.dev_t) bool { - const stat = statx(dev.nodePath()) catch return false; + const stat = util.statPath(dev.nodePath()) catch return false; return drm.makeDev(stat.rdev_major, stat.rdev_minor) == rdev; } @@ -386,13 +395,3 @@ fn getNodeType(name: []const u8) !NodeType { return error.InvalidName; } - -fn statx(path: []const u8) !std.os.linux.Statx { - const posix_path = try std.posix.toPosixPath(path); - var stat_buf: std.os.linux.Statx = undefined; - const rc = std.os.linux.statx(std.os.linux.AT.FDCWD, &posix_path, 0, .{}, &stat_buf); - return switch (std.posix.errno(rc)) { - .SUCCESS => stat_buf, - else => |err| std.posix.unexpectedErrno(err), - }; -} diff --git a/src/util.zig b/src/util.zig new file mode 100644 index 0000000..bfd826c --- /dev/null +++ b/src/util.zig @@ -0,0 +1,28 @@ +const std = @import("std"); + +pub fn statPath(path: []const u8) !std.os.linux.Statx { + const posix_path = try std.posix.toPosixPath(path); + return statxInner(std.os.linux.AT.FDCWD, &posix_path, 0); +} + +pub fn statFile(fd: std.posix.fd_t) !std.os.linux.Statx { + return statxInner(fd, "", std.os.linux.AT.EMPTY_PATH); +} + +fn statxInner(fd: std.posix.fd_t, path: [*:0]const u8, flags: u32) !std.os.linux.Statx { + var stat_buf: std.os.linux.Statx = undefined; + const rc = std.posix.system.statx(fd, path, flags, .{}, &stat_buf); + return switch (std.posix.errno(rc)) { + .SUCCESS => stat_buf, + .ACCES => error.PermissionDenied, + .LOOP => error.SymLinkLoop, + .NAMETOOLONG => error.NameTooLong, + .NOENT => error.FileNotFound, + .NOMEM => error.SystemResources, + .NOTDIR => error.NotADirectory, + .BADF => unreachable, + .FAULT => unreachable, + .INVAL => unreachable, + else => |err| std.posix.unexpectedErrno(err), + }; +}