zig-gpio/src/uapi.zig

254 lines
8.7 KiB
Zig

const std = @import("std");
/// The maximum size of name and label arrays
pub const MAX_NAME_SIZE = 32;
/// Information about a certain GPIO chip
pub const ChipInfo = extern struct {
/// The Linux kernel name of this GPIO chip
name: [MAX_NAME_SIZE]u8,
/// A functional name for this GPIO chip, such as a product
/// number, may be empty (i.e. `label[0] == '\0'`)
label: [MAX_NAME_SIZE]u8,
/// The number of GPIO lines on this chip
lines: u32,
};
/// The maximum number of configuration attributes associated with a line request.
pub const MAX_LINE_NUM_ATTRS = 10;
/// Information about a certain GPIO line
pub const LineInfo = extern struct {
/// The name of this GPIO line, such as the output pin of the line on
/// the chip, a rail or a pin header name on a board, as specified by the
/// GPIO chip, may be empty (i.e. `name[0] == '\0'`)
name: [MAX_NAME_SIZE]u8,
/// a functional name for the consumer of this GPIO line as set
/// by whatever is using it, will be empty if there is no current user,
/// but may also be empty if the consumer doesn't set this up
consumer: [MAX_NAME_SIZE]u8,
/// The local offset on this GPIO chip, fill this in when
/// requesting the line information from the kernel
offset: u32,
/// The number of attributes in `attrs`
num_attrs: u32,
/// Configuration flags for this GPIO line
flags: LineFlags,
/// The configuration attributes associated with the line
attrs: [MAX_LINE_NUM_ATTRS]LineAttribute,
/// Reserved for future use
_padding: [4]u32,
/// Returns the line's name as a slice without any null characters
pub fn nameSlice(self: *const LineInfo) []const u8 {
return std.mem.sliceTo(&self.name, 0);
}
/// Returns the line's consumer as a slice without any null characters
pub fn consumerSlice(self: *const LineInfo) []const u8 {
return std.mem.sliceTo(&self.consumer, 0);
}
};
/// LineAttribute ID values
pub const LineAttributeId = enum(u32) {
/// Indicates that the line attribute contains flags
Flags = 1,
/// Indicates that the line attribute contains output values
OutputValues = 2,
/// Indicates that the line attribute contains a debounce period
Debounce = 3,
};
/// A configurable attribute of a line
pub const LineAttribute = extern struct {
id: LineAttributeId,
_padding: u32 = 0,
data: extern union {
flags: LineFlags,
values: u64,
debounce_period_us: u32,
},
};
/// A configuration attribute
pub const LineConfigAttribute = extern struct {
attr: LineAttribute,
mask: LineValueBitset = .{ .mask = 0 },
};
/// Maximum number of requested lines
pub const MAX_LINES = 64;
/// Information about a request for GPIO lines
pub const LineRequest = extern struct {
offsets: [MAX_LINES]u32,
consumer: [MAX_NAME_SIZE]u8,
config: LineConfig,
num_lines: u32,
event_buffer_size: u32,
_padding: [5]u32 = [5]u32{ 0, 0, 0, 0, 0 },
fd: i32,
};
/// Configuration flags for GPIO lines
pub const LineFlags = packed struct {
/// Line is not available for request
used: bool = false,
/// Line active state is physical low
active_low: bool = false,
/// Line is an input
input: bool = false,
/// Line is an output
output: bool = false,
/// Line detects rising (inactive to active) edges
edge_rising: bool = false,
/// Line detects falling (active to inactive) edges
edge_falling: bool = false,
/// Line is an open drain output
open_drain: bool = false,
/// Line is an open source output
open_source: bool = false,
/// Line has pull-up bias enabled
bias_pull_up: bool = false,
/// Line has pull-down bias enabled
bias_pull_down: bool = false,
/// Line has bias disabled
bias_disabled: bool = false,
/// Line events contain REALTIME timestamps
event_clock_real_time: bool = false,
/// Line events contain timestamps from hardware timestamp engine
event_clock_hte: bool = false,
/// Reserved for future use
_padding: u51 = 0,
};
/// Configuration for GPIO lines
pub const LineConfig = extern struct {
/// Configuration flags for the GPIO lines. This is the default for
/// all requested lines but may be overridden for particular lines
/// using `attrs`.
flags: LineFlags,
/// The number of attributes in `attrs`
num_attrs: u32,
/// Reserved for future use and must be zero-filled
_padding: [5]u32 = [5]u32{ 0, 0, 0, 0, 0 },
/// The configuration attributes associated with the requested lines
attrs: [MAX_LINE_NUM_ATTRS]LineConfigAttribute,
};
/// A bitset representing GPIO line values
pub const LineValueBitset = std.bit_set.IntegerBitSet(MAX_LINES);
/// Values of GPIO lines
pub const LineValues = extern struct {
/// A bitmap containing the value of the lines, set to 1 for active
/// and 0 for inactive.
bits: LineValueBitset = .{ .mask = 0 },
/// A bitmap identifying the lines to get or set, with each bit
/// number corresponding to the index in LineRequest.offsets
mask: LineValueBitset = .{ .mask = 0 },
};
/// `LineInfoChanged.type` values
pub const ChangeType = enum(u32) {
/// Line has been requested
Requested = 1,
/// Line has been released
Released = 2,
/// Line has been reconfigured
Config = 3,
};
/// Information about a change in status of a GPIO line
pub const LineInfoChanged = extern struct {
/// Updated line information
info: LineInfo,
/// Estimate of the time when the status change occurred, in nanoseconds
timestamp_ns: u64,
/// The type of change
type: ChangeType,
/// Reserved for future use
_padding: [5]u32 = [5]u32{ 0, 0, 0, 0, 0 },
};
/// Returns an error based on the given return code
fn handleErrno(ret: usize) !void {
if (ret == 0) return;
return switch (std.posix.errno(ret)) {
.BUSY => error.DeviceIsBusy,
.INVAL => error.InvalidArgument,
.BADF => error.BadFileDescriptor,
.NOTTY => error.InappropriateIOCTLForDevice,
.IO => error.IOError,
.FAULT => unreachable,
else => |err| return std.posix.unexpectedErrno(err),
};
}
/// Executes `GPIO_GET_CHIPINFO_IOCTL` on the given fd and returns the resulting
/// `ChipInfo` value
pub fn getChipInfo(fd: std.posix.fd_t) !ChipInfo {
const req = std.os.linux.IOCTL.IOR(0xB4, 0x01, ChipInfo);
var info = std.mem.zeroes(ChipInfo);
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&info)));
return info;
}
/// Executes `GPIO_V2_GET_LINEINFO_IOCTL` on the given fd and returns the resulting
/// `LineInfo` value
pub fn getLineInfo(fd: std.posix.fd_t, offset: u32) !LineInfo {
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x05, LineInfo);
var info = std.mem.zeroes(LineInfo);
info.offset = offset;
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&info)));
return info;
}
/// Executes `GPIO_V2_GET_LINEINFO_WATCH_IOCTL` on the given fd and returns the resulting
/// `LineInfo` value
pub fn watchLineInfo(fd: std.posix.fd_t, offset: u32) !LineInfo {
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x06, LineInfo);
var info = std.mem.zeroes(LineInfo);
info.offset = offset;
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&info)));
return info;
}
/// Executes `GPIO_GET_LINEINFO_UNWATCH_IOCTL` on the given fd
pub fn unwatchLineInfo(fd: std.posix.fd_t, offset: u32) !void {
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x0C, u32);
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&offset)));
}
/// Executes `GPIO_V2_GET_LINE_IOCTL` on the given fd and returns the resulting
/// line descriptor
pub fn getLine(fd: std.posix.fd_t, lr: LineRequest) !std.posix.fd_t {
const lrp = &lr;
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x07, LineRequest);
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(lrp)));
return lrp.fd;
}
/// Executes `GPIO_V2_LINE_GET_VALUES_IOCTL` on the given fd with the given mask,
/// and returns a bitset representing all the line values.
pub fn getLineValues(fd: std.posix.fd_t, mask: LineValueBitset) !LineValueBitset {
var vals = LineValues{ .mask = mask };
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x0E, LineValues);
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&vals)));
return vals.bits;
}
/// Executes `GPIO_V2_LINE_SET_VALUES_IOCTL` on the given fd
pub fn setLineValues(fd: std.posix.fd_t, lv: LineValues) !void {
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x0F, LineValues);
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&lv)));
}
/// Executes `GPIO_V2_LINE_SET_CONFIG_IOCTL` on the given fd
pub fn setLineConfig(fd: std.posix.fd_t, lc: LineConfig) !void {
const req = std.os.linux.IOCTL.IOWR(0xB4, 0x0D, LineConfig);
try handleErrno(std.os.linux.ioctl(fd, req, @intFromPtr(&lc)));
}