From c7ebd8c35cfbf2de62a6ac058d98c26becb83390 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 22 Dec 2021 15:25:36 +0100 Subject: lib: rework led flags as composite type Split the underlying led bits handling into KbLeds and employ this to construct both KbLedState and KbLedFlags, preserving their distinctness. This also finally implements the handling of the default states from the higher order bits of KD*KBLED. --- src/lib.rs | 237 +++++++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 207 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 01f0187..aee486d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ fn cvt_r(f: &mut dyn FnMut() -> T) -> io::Result /** Wrappers for ``ioctl_console(2)`` functionality. */ pub mod ioctl { - use super::{cvt_r, KbLedFlags, KbLedState, Palette}; + use super::{cvt_r, KbLedFlags, KbLedState, KbLeds, Palette}; use libc::ioctl; use std::{io::Result, os::unix::io::AsRawFd}; @@ -58,8 +58,11 @@ pub mod ioctl pub const KB_101: libc::c_char = 0x0002; pub const KDGETLED: libc::c_ulong = 0x4b31; pub const KDSETLED: libc::c_ulong = 0x4b32; + pub const KDGKBLED: libc::c_ulong = 0x4B64; pub const KDSKBLED: libc::c_ulong = 0x4B65; + pub const KD_KBLED_STATE_MASK: libc::c_ulong = 0x07; + pub const KD_KBLED_DEFAULT_MASK: libc::c_ulong = 0x70; pub fn pio_cmap(fd: &F, pal: &Palette) -> Result<()> { @@ -113,7 +116,7 @@ pub mod ioctl }) .map(|_| ())?; - Ok(KbLedState::from(leds)) + Ok(KbLedState(KbLeds::from(leds))) } /** If ``state`` is ``None`` it is taken to mean “revert to normal” as per @@ -167,12 +170,13 @@ pub mod ioctl }) .map(|_| ())?; - Ok(KbLedFlags::from(flags)) + KbLedFlags::try_from(flags as u8) } pub fn kdskbled(fd: &F, flags: KbLedFlags) -> Result<()> { - let flags = libc::c_ulong::from(flags); + let default = libc::c_ulong::from(flags.default); + let flags = libc::c_ulong::from(flags.flags) | (default << 4); cvt_r(&mut || { unsafe { @@ -200,16 +204,12 @@ pub mod ioctl } } -/** Base type which the LED state and flags are aliases of. */ #[derive(Clone, Copy, Debug)] -pub struct KbLeds(u8); - -pub type KbLedFlags = KbLeds; -pub type KbLedState = KbLeds; +struct KbLeds(u8); impl KbLeds { - pub fn new(cap: bool, num: bool, scr: bool) -> Self + fn new(cap: bool, num: bool, scr: bool) -> Self { let mut state = 0u8; @@ -220,46 +220,33 @@ impl KbLeds Self(state) } - #[inline] - pub fn get(con: &Console) -> io::Result { ioctl::kdgetled(con) } - - #[inline] - pub fn set(&self, con: &Console) -> io::Result<()> - { - ioctl::kdsetled(con, Some(*self)) - } - - #[inline] - pub fn revert(con: &Console) -> io::Result<()> - { - ioctl::kdsetled(con, None) - } + fn off() -> Self { Self(0) } #[inline] - pub fn cap(&self) -> bool { (self.0 & 0x4) != 0 } + fn cap(&self) -> bool { (self.0 & 0x4) != 0 } #[inline] - pub fn num(&self) -> bool { (self.0 & 0x2) != 0 } + fn num(&self) -> bool { (self.0 & 0x2) != 0 } #[inline] - pub fn scr(&self) -> bool { (self.0 & 0x1) != 0 } + fn scr(&self) -> bool { (self.0 & 0x1) != 0 } #[inline] - pub fn set_cap(&mut self, set: bool) + fn set_cap(&mut self, set: bool) { let bit = (set as u8) << 2; self.0 = (self.0 & !bit) | bit; } #[inline] - pub fn set_num(&mut self, set: bool) + fn set_num(&mut self, set: bool) { let bit = (set as u8) << 1; self.0 = (self.0 & !bit) | bit; } #[inline] - pub fn set_scr(&mut self, set: bool) + fn set_scr(&mut self, set: bool) { let bit = set as u8; self.0 = (self.0 & !bit) | bit; @@ -340,6 +327,196 @@ mod kb_led_state } } +#[derive(Copy, Clone, Debug)] +pub struct KbLedState(KbLeds); + +impl KbLedState +{ + pub fn new(cap: bool, num: bool, scr: bool) -> Self + { + Self(KbLeds::new(cap, num, scr)) + } + + #[inline] + pub fn get(con: &Console) -> io::Result { ioctl::kdgetled(con) } + + #[inline] + pub fn set(&self, con: &Console) -> io::Result<()> + { + ioctl::kdsetled(con, Some(*self)) + } + + #[inline] + pub fn revert(con: &Console) -> io::Result<()> + { + ioctl::kdsetled(con, None) + } + + #[inline] + pub fn cap(&self) -> bool { self.0.cap() } + + #[inline] + pub fn num(&self) -> bool { self.0.num() } + + #[inline] + pub fn scr(&self) -> bool { self.0.scr() } + + #[inline] + pub fn set_cap(&mut self, set: bool) { self.0.set_cap(set) } + + #[inline] + pub fn set_num(&mut self, set: bool) { self.0.set_num(set) } + + #[inline] + pub fn set_scr(&mut self, set: bool) { self.0.set_scr(set) } +} + +impl fmt::Display for KbLedState +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + write!(f, "{}", self.0) + } +} + +impl From for KbLedState +{ + fn from(leds: libc::c_char) -> Self { Self(KbLeds(leds as u8)) } +} + +impl From for libc::c_ulong +{ + fn from(state: KbLedState) -> Self { state.0 .0 as libc::c_ulong } +} + +impl From for u8 +{ + fn from(state: KbLedState) -> Self { state.0 .0 } +} + +impl TryFrom for KbLedState +{ + type Error = io::Error; + + fn try_from(val: u8) -> io::Result + { + Ok(Self(KbLeds::try_from(val)?)) + } +} + +#[derive(Copy, Clone, Debug)] +pub struct KbLedFlags +{ + flags: KbLeds, + default: KbLeds, +} + +impl KbLedFlags +{ + pub fn new_flags(cap: bool, num: bool, scr: bool) -> Self + { + let flags = KbLeds::new(cap, num, scr); + let default = KbLeds::off(); + Self { flags, default } + } + + pub fn new( + fcap: bool, + fnum: bool, + fscr: bool, + dcap: bool, + dnum: bool, + dscr: bool, + ) -> Self + { + let flags = KbLeds::new(fcap, fnum, fscr); + let default = KbLeds::new(dcap, dnum, dscr); + Self { flags, default } + } + + #[inline] + pub fn get(con: &Console) -> io::Result { ioctl::kdgkbled(con) } + + #[inline] + pub fn set(&self, con: &Console) -> io::Result<()> + { + ioctl::kdskbled(con, *self) + } + + #[inline] + pub fn cap(&self) -> bool { self.flags.cap() } + + #[inline] + pub fn num(&self) -> bool { self.flags.num() } + + #[inline] + pub fn scr(&self) -> bool { self.flags.scr() } + + #[inline] + pub fn default_cap(&self) -> bool { self.default.cap() } + + #[inline] + pub fn default_num(&self) -> bool { self.default.num() } + + #[inline] + pub fn default_scr(&self) -> bool { self.default.scr() } + + #[inline] + pub fn set_cap(&mut self, set: bool) { self.flags.set_cap(set) } + + #[inline] + pub fn set_num(&mut self, set: bool) { self.flags.set_num(set) } + + #[inline] + pub fn set_scr(&mut self, set: bool) { self.flags.set_scr(set) } + + #[inline] + pub fn set_default_cap(&mut self, set: bool) { self.default.set_cap(set) } + + #[inline] + pub fn set_default_num(&mut self, set: bool) { self.default.set_num(set) } + + #[inline] + pub fn set_default_scr(&mut self, set: bool) { self.default.set_scr(set) } +} + +impl From for u8 +{ + fn from(state: KbLedFlags) -> Self + { + state.flags.0 | (state.default.0 << 0x4) + } +} + +impl TryFrom for KbLedFlags +{ + type Error = io::Error; + + /** From the manpage: + + The low order three bits (mask 0x7) get the current flag state, + and the low order bits of the next nibble (mask 0x70) get the + default flag state. + */ + fn try_from(val: u8) -> io::Result + { + let flags = val & (ioctl::KD_KBLED_STATE_MASK as u8); + let default = val & (ioctl::KD_KBLED_DEFAULT_MASK as u8) >> 4; + let flags = KbLeds::try_from(flags)?; + let default = KbLeds::try_from(default)?; + + Ok(Self { flags, default }) + } +} + +impl fmt::Display for KbLedFlags +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result + { + write!(f, "[flags: {}; default: {}]", self.flags, self.default) + } +} + #[derive(Debug)] pub struct Fd(libc::c_int); -- cgit v1.2.3