From 55789cb1580c682a085e2ce57835f324665f18d1 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg@phi-gamma.net>
Date: Sun, 12 Dec 2021 21:52:11 +0100
Subject: lib: add ioctl wrappers for KDGKBLED / KDSKBLED
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Reusing the same definitions as we have for KD{G,S}ETLED
as they’re practically the same.
---
 src/lib.rs | 154 ++++++++++++++++++++++++++++++++++++++++++++-----------------
 1 file changed, 111 insertions(+), 43 deletions(-)

diff --git a/src/lib.rs b/src/lib.rs
index 6a932d8..75595cd 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -46,28 +46,20 @@ fn cvt_r<T: IsMinusOne>(f: &mut dyn FnMut() -> T) -> io::Result<T>
 /** Wrappers for ``ioctl_console(2)`` functionality. */
 pub mod ioctl
 {
-    use super::{cvt_r, KbLedState, Palette};
+    use super::{cvt_r, KbLedFlags, KbLedState, Palette};
     use libc::ioctl;
     use std::{io::Result, os::unix::io::AsRawFd};
 
     /* XXX: can we get these into ``libc``? */
-    pub const KDGKBTYPE: libc::c_ulong = 0x4b33; /* kd.h */
-    pub const GIO_CMAP: libc::c_ulong = 0x00004B70; /* kd.h */
-    pub const PIO_CMAP: libc::c_ulong = 0x00004B71; /* kd.h */
-    pub const KB_101: libc::c_char = 0x0002; /* kd.h */
-    pub const KDGETLED: libc::c_ulong = 0x4b31; /* kd.h */
-    pub const KDSETLED: libc::c_ulong = 0x4b32; /* kd.h */
-
-    pub fn kdgkbtype<F: AsRawFd>(fd: &F) -> Result<libc::c_char>
-    {
-        let mut kb: libc::c_char = 0;
-
-        let _ = cvt_r(&mut || unsafe {
-            ioctl(fd.as_raw_fd(), KDGKBTYPE, &mut kb as *mut _)
-        })?;
-
-        Ok(kb)
-    }
+    /* kd.h */
+    pub const KDGKBTYPE: libc::c_ulong = 0x4b33;
+    pub const GIO_CMAP: libc::c_ulong = 0x00004B70;
+    pub const PIO_CMAP: libc::c_ulong = 0x00004B71;
+    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 fn pio_cmap<F: AsRawFd>(fd: &F, pal: &Palette) -> Result<()>
     {
@@ -133,14 +125,13 @@ pub mod ioctl
             order bit is set, the LEDs revert to normal: displaying the state
             of the keyboard functions of caps lock, num lock, and scroll lock.
     */
-
     pub fn kdsetled<F: AsRawFd>(fd: &F, state: Option<KbLedState>)
         -> Result<()>
     {
-        let leds: libc::c_char = if let Some(state) = state {
+        let leds: libc::c_ulong = if let Some(state) = state {
             state.into()
         } else {
-            libc::c_char::MAX
+            libc::c_ulong::MAX
         };
 
         cvt_r(&mut || {
@@ -148,7 +139,7 @@ pub mod ioctl
                 ioctl(
                     fd.as_raw_fd(),
                     KDSETLED,
-                    std::mem::transmute::<&libc::c_char, *const libc::c_void>(
+                    std::mem::transmute::<&libc::c_ulong, *const libc::c_void>(
                         &leds,
                     ),
                 )
@@ -158,12 +149,65 @@ pub mod ioctl
 
         Ok(())
     }
+
+    pub fn kdgkbled<F: AsRawFd>(fd: &F) -> Result<KbLedFlags>
+    {
+        let mut flags: libc::c_char = 0;
+
+        cvt_r(&mut || {
+            unsafe {
+                ioctl(
+                    fd.as_raw_fd(),
+                    KDGKBLED,
+                    std::mem::transmute::<&mut libc::c_char, *mut libc::c_void>(
+                        &mut flags,
+                    ),
+                )
+            }
+        })
+        .map(|_| ())?;
+
+        Ok(KbLedFlags::from(flags))
+    }
+
+    pub fn kdskbled<F: AsRawFd>(fd: &F, flags: KbLedFlags) -> Result<()>
+    {
+        let flags = libc::c_ulong::from(flags);
+
+        cvt_r(&mut || {
+            unsafe {
+                ioctl(
+                    fd.as_raw_fd(),
+                    KDSKBLED,
+                    std::mem::transmute::<&libc::c_ulong, *const libc::c_void>(
+                        &flags,
+                    ),
+                )
+            }
+        })
+        .map(|_| ())
+    }
+
+    pub fn kdgkbtype<F: AsRawFd>(fd: &F) -> Result<libc::c_char>
+    {
+        let mut kb: libc::c_char = 0;
+
+        let _ = cvt_r(&mut || unsafe {
+            ioctl(fd.as_raw_fd(), KDGKBTYPE, &mut kb as *mut _)
+        })?;
+
+        Ok(kb)
+    }
 }
 
+/** Base type which the LED state and flags are aliases of. */
 #[derive(Clone, Copy, Debug)]
-pub struct KbLedState(u8);
+pub struct KbLeds(u8);
+
+pub type KbLedFlags = KbLeds;
+pub type KbLedState = KbLeds;
 
-impl KbLedState
+impl KbLeds
 {
     pub fn new(cap: bool, num: bool, scr: bool) -> Self
     {
@@ -222,7 +266,7 @@ impl KbLedState
     }
 }
 
-impl fmt::Display for KbLedState
+impl fmt::Display for KbLeds
 {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result
     {
@@ -236,7 +280,7 @@ impl fmt::Display for KbLedState
     }
 }
 
-impl From<libc::c_char> for KbLedState
+impl From<libc::c_char> for KbLeds
 {
     fn from(leds: libc::c_char) -> Self
     {
@@ -244,17 +288,17 @@ impl From<libc::c_char> for KbLedState
     }
 }
 
-impl From<KbLedState> for libc::c_char
+impl From<KbLeds> for libc::c_ulong
 {
-    fn from(state: KbLedState) -> Self { state.0 as libc::c_char }
+    fn from(state: KbLeds) -> Self { state.0 as libc::c_ulong }
 }
 
-impl From<KbLedState> for u8
+impl From<KbLeds> for u8
 {
-    fn from(state: KbLedState) -> Self { state.0 }
+    fn from(state: KbLeds) -> Self { state.0 }
 }
 
-impl TryFrom<u8> for KbLedState
+impl TryFrom<u8> for KbLeds
 {
     type Error = io::Error;
 
@@ -277,25 +321,49 @@ impl TryFrom<u8> for KbLedState
 #[cfg(test)]
 mod kb_led_state
 {
-    use super::KbLedState;
+    use super::KbLeds;
 
     #[test]
     fn create()
     {
-        assert_eq!(0u8, KbLedState::new(false, false, false).into());
-        assert_eq!(1u8, KbLedState::new(false, false, true).into());
-        assert_eq!(2u8, KbLedState::new(false, true, false).into());
-        assert_eq!(4u8, KbLedState::new(true, false, false).into());
-        assert_eq!(6u8, KbLedState::new(true, true, false).into());
-
-        assert_eq!(0u8, KbLedState::from(0u8 as libc::c_char).into());
-        assert_eq!(1u8, KbLedState::from(1u8 as libc::c_char).into());
-        assert_eq!(2u8, KbLedState::from(2u8 as libc::c_char).into());
-        assert_eq!(4u8, KbLedState::from(4u8 as libc::c_char).into());
-        assert_eq!(6u8, KbLedState::from(6u8 as libc::c_char).into());
+        assert_eq!(0u8, KbLeds::new(false, false, false).into());
+        assert_eq!(1u8, KbLeds::new(false, false, true).into());
+        assert_eq!(2u8, KbLeds::new(false, true, false).into());
+        assert_eq!(4u8, KbLeds::new(true, false, false).into());
+        assert_eq!(6u8, KbLeds::new(true, true, false).into());
+
+        assert_eq!(0u8, KbLeds::from(0u8 as libc::c_char).into());
+        assert_eq!(1u8, KbLeds::from(1u8 as libc::c_char).into());
+        assert_eq!(2u8, KbLeds::from(2u8 as libc::c_char).into());
+        assert_eq!(4u8, KbLeds::from(4u8 as libc::c_char).into());
+        assert_eq!(6u8, KbLeds::from(6u8 as libc::c_char).into());
     }
 }
 
+//#[derive(Clone, Copy, Debug)]
+//pub struct KbLedFlags(u8);
+
+//impl KbLedFlags {
+//pub fn new(cap: bool, num: bool, scr: bool) -> Self
+//{
+//let mut flags = 0u8;
+
+//flags |= (cap as u8) << 2;
+//flags |= (num as u8) << 1;
+//flags |= scr as u8;
+
+//Self(flags)
+//}
+//}
+
+//impl From<libc::c_char> for KbLedFlags
+//{
+//fn from(flags: libc::c_char) -> Self
+//{
+//Self::new(flags & 0x4 != 0, flags & 0x2 != 0, flags & 0x1 != 0)
+//}
+//}
+
 #[derive(Debug)]
 pub struct Fd(libc::c_int);
 
-- 
cgit v1.2.3