├── .gitignore ├── examples ├── rust-logo │ ├── rust-logo.bmp │ └── main.rs ├── sierpinski │ └── main.rs ├── mandelbrot │ └── main.rs └── starfield │ └── main.rs ├── LICENSE ├── README.md ├── Cargo.toml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /examples/rust-logo/rust-logo.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Roysten/rust-framebuffer/HEAD/examples/rust-logo/rust-logo.bmp -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 2 | Version 2, December 2004 3 | 4 | Copyright (C) 2004 Sam Hocevar 5 | 6 | Everyone is permitted to copy and distribute verbatim or modified 7 | copies of this license document, and changing it is allowed as long 8 | as the name is changed. 9 | 10 | DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE 11 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 12 | 13 | 0. You just DO WHAT THE FUCK YOU WANT TO. 14 | 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # rust-framebuffer 2 | Basic framebuffer abstraction for Rust. 3 | 4 | To be able to use this library, you have to add yourself to the `video` group: 5 | ```console 6 | $ sudo usermod -aG video "$USER" 7 | ``` 8 | 9 | An example can be found in the examples directory. Use the following command to compile and run: 10 | ```console 11 | $ cargo run --release --example rust-logo 12 | ``` 13 | 14 | Make sure to check out the starfield example as well! 15 | 16 | Basic documentation is available: http://roysten.github.io/rust-framebuffer/target/doc/framebuffer/. 17 | The documentation is a bit sparse, but I hope the examples can make up for that. 18 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "framebuffer" 3 | version = "0.3.1" 4 | authors = ["Roy van der Vegt "] 5 | edition = "2018" 6 | description = """ 7 | Basic framebuffer abstraction. Handles the necessary ioctls and mmaps the framebuffer device. 8 | """ 9 | keywords = ["framebuffer", "fb"] 10 | documentation = "http://roysten.github.io/rust-framebuffer/target/doc/framebuffer/" 11 | repository = "https://github.com/roysten/rust-framebuffer" 12 | license = "WTFPL" 13 | [lib] 14 | name = "framebuffer" 15 | path = "src/lib.rs" 16 | 17 | [dependencies] 18 | libc = "0.2" 19 | memmap = "0.7" 20 | errno = "0.2.7" 21 | 22 | [[example]] 23 | name = "rust-logo" 24 | path = "examples/rust-logo/main.rs" 25 | 26 | [[example]] 27 | name = "starfield" 28 | path = "examples/starfield/main.rs" 29 | 30 | [[example]] 31 | name = "mandelbrot" 32 | path = "examples/mandelbrot/main.rs" 33 | 34 | [[example]] 35 | name = "sierpinski" 36 | path = "examples/sierpinski/main.rs" 37 | 38 | [dev_dependencies] 39 | bmp = "0.1.4" 40 | rand = "0.8" 41 | -------------------------------------------------------------------------------- /examples/rust-logo/main.rs: -------------------------------------------------------------------------------- 1 | extern crate bmp; 2 | extern crate framebuffer; 3 | 4 | use framebuffer::{Framebuffer, KdMode}; 5 | 6 | fn main() { 7 | let mut framebuffer = Framebuffer::new("/dev/fb0").unwrap(); 8 | 9 | let w = framebuffer.var_screen_info.xres; 10 | let h = framebuffer.var_screen_info.yres; 11 | let line_length = framebuffer.fix_screen_info.line_length; 12 | let bytespp = framebuffer.var_screen_info.bits_per_pixel / 8; 13 | 14 | let mut frame = vec![0u8; (line_length * h) as usize]; 15 | let img = bmp::open("examples/rust-logo/rust-logo.bmp").unwrap(); 16 | 17 | //Disable text mode in current tty 18 | let _ = Framebuffer::set_kd_mode(KdMode::Graphics).unwrap(); 19 | 20 | for offset in 0..w - img.get_width() { 21 | for (x, y) in img.coordinates() { 22 | let px = img.get_pixel(x, y); 23 | let start_index = (y * line_length + (offset + x) * bytespp) as usize; 24 | frame[start_index] = px.b; 25 | frame[start_index + 1] = px.g; 26 | frame[start_index + 2] = px.r; 27 | } 28 | 29 | let _ = framebuffer.write_frame(&frame); 30 | } 31 | 32 | //Reenable text mode in current tty 33 | let _ = Framebuffer::set_kd_mode(KdMode::Text).unwrap(); 34 | } 35 | -------------------------------------------------------------------------------- /examples/sierpinski/main.rs: -------------------------------------------------------------------------------- 1 | extern crate framebuffer; 2 | 3 | use framebuffer::{Framebuffer, KdMode}; 4 | 5 | fn main() { 6 | let mut framebuffer = Framebuffer::new("/dev/fb0").unwrap(); 7 | 8 | let w = framebuffer.var_screen_info.xres as usize; 9 | let h = framebuffer.var_screen_info.yres as usize; 10 | let line_length = framebuffer.fix_screen_info.line_length as usize; 11 | let bytespp = (framebuffer.var_screen_info.bits_per_pixel / 8) as usize; 12 | 13 | let mut frame = vec![0u8; line_length * h]; 14 | 15 | let _ = Framebuffer::set_kd_mode(KdMode::Graphics).unwrap(); 16 | 17 | let half_line = w * bytespp / 2; 18 | frame[half_line] = 255; 19 | frame[half_line + 1] = 255; 20 | frame[half_line + 2] = 255; 21 | 22 | for y in 1..h { 23 | for x in 0..w { 24 | let curr_index = y * line_length + x * bytespp; 25 | let prev_index = curr_index - line_length; 26 | 27 | let val_a = if x == 0 { 28 | 0 29 | } else { 30 | frame[prev_index - bytespp] 31 | }; 32 | let val_b = if x == w - 1 { 33 | 0 34 | } else { 35 | frame[prev_index + bytespp] 36 | }; 37 | 38 | let val = if val_a > 0 { 255 } else { 0 } ^ if val_b > 0 { 255 } else { 0 }; 39 | 40 | frame[curr_index] = val; 41 | frame[curr_index + 1] = val; 42 | frame[curr_index + 2] = val; 43 | } 44 | } 45 | 46 | let _ = framebuffer.write_frame(&frame); 47 | let _ = std::io::stdin().read_line(&mut String::new()); 48 | let _ = Framebuffer::set_kd_mode(KdMode::Text).unwrap(); 49 | } 50 | -------------------------------------------------------------------------------- /examples/mandelbrot/main.rs: -------------------------------------------------------------------------------- 1 | extern crate framebuffer; 2 | 3 | use framebuffer::{Framebuffer, KdMode}; 4 | 5 | //Algorithm copied from: 6 | //https://en.wikipedia.org/wiki/Mandelbrot_set 7 | fn main() { 8 | let mut framebuffer = Framebuffer::new("/dev/fb0").unwrap(); 9 | 10 | let w = framebuffer.var_screen_info.xres; 11 | let h = framebuffer.var_screen_info.yres; 12 | let line_length = framebuffer.fix_screen_info.line_length; 13 | let bytespp = framebuffer.var_screen_info.bits_per_pixel / 8; 14 | 15 | let mut frame = vec![0u8; (line_length * h) as usize]; 16 | 17 | let _ = Framebuffer::set_kd_mode(KdMode::Graphics).unwrap(); 18 | 19 | for (r, line) in frame.chunks_mut(line_length as usize).enumerate() { 20 | for (c, p) in line.chunks_mut(bytespp as usize).enumerate() { 21 | let x0 = (c as f32 / w as f32) * 3.5 - 2.5; 22 | let y0 = (r as f32 / h as f32) * 2.0 - 1.0; 23 | 24 | let mut it = 0; 25 | let max_it = 200; 26 | 27 | let mut x = 0.0; 28 | let mut y = 0.0; 29 | 30 | while x * x + y * y < 4.0 && it < max_it { 31 | let xtemp = x * x - y * y + x0; 32 | y = 2.0 * x * y + y0; 33 | x = xtemp; 34 | it += 1; 35 | } 36 | 37 | p[0] = (125.0 * (it as f32 / max_it as f32)) as u8; 38 | p[1] = (255.0 * (it as f32 / max_it as f32)) as u8; 39 | p[2] = (75.0 * (it as f32 / max_it as f32)) as u8; 40 | } 41 | } 42 | 43 | let _ = framebuffer.write_frame(&frame); 44 | 45 | std::io::stdin().read_line(&mut String::new()).unwrap(); 46 | let _ = Framebuffer::set_kd_mode(KdMode::Text).unwrap(); 47 | } 48 | -------------------------------------------------------------------------------- /examples/starfield/main.rs: -------------------------------------------------------------------------------- 1 | extern crate framebuffer; 2 | extern crate rand; 3 | 4 | use framebuffer::Framebuffer; 5 | use rand::Rng; 6 | 7 | const STAR_SPEED: f32 = 1.003; 8 | const STAR_GROWTH: f32 = 1.002; 9 | const STAR_COUNT: usize = 40; 10 | 11 | struct Starfield { 12 | stars: [Star; STAR_COUNT], 13 | } 14 | 15 | impl Starfield { 16 | fn new(framebuffer: &Framebuffer) -> Starfield { 17 | let w = framebuffer.var_screen_info.xres as usize; 18 | let h = framebuffer.var_screen_info.yres as usize; 19 | 20 | let mut stars = [Star { 21 | a: 0.0, 22 | b: 0.0, 23 | x: 0.0, 24 | size: 0.0, 25 | color: (255, 255, 255), 26 | }; STAR_COUNT]; 27 | for star in stars.iter_mut() { 28 | *star = Star::new_rand(w, h); 29 | } 30 | Starfield { stars: stars } 31 | } 32 | 33 | fn tick(&mut self, framebuffer: &Framebuffer, frame: &mut [u8]) { 34 | let w = framebuffer.var_screen_info.xres as usize; 35 | let h = framebuffer.var_screen_info.yres as usize; 36 | 37 | for star in self.stars.iter_mut() { 38 | Starfield::draw_star(&star, framebuffer, frame, (0, 0, 0)); 39 | star.tick(w, h); 40 | Starfield::draw_star(&star, framebuffer, frame, star.color); 41 | } 42 | } 43 | 44 | fn draw_star(star_data: &Star, framebuffer: &Framebuffer, frame: &mut [u8], color: (u8, u8, u8)) { 45 | let w = framebuffer.var_screen_info.xres as usize; 46 | let h = framebuffer.var_screen_info.yres as usize; 47 | 48 | let line_length = framebuffer.fix_screen_info.line_length as usize; 49 | let bytespp = framebuffer.var_screen_info.bits_per_pixel as usize / 8; 50 | 51 | macro_rules! coords_to_index { 52 | ($x:expr, $y:expr) => { 53 | $y * line_length + $x * bytespp 54 | }; 55 | } 56 | 57 | let pos = star_data.get_pos(w, h); 58 | 59 | let dim = star_data.size as usize; 60 | for i in 0..dim { 61 | for j in 0..dim { 62 | if pos.0 + i < w && pos.1 + j < h { 63 | frame[coords_to_index!(pos.0 + i, pos.1 + j)] = color.0; 64 | frame[coords_to_index!(pos.0 + i, pos.1 + j) + 1] = color.1; 65 | frame[coords_to_index!(pos.0 + i, pos.1 + j) + 2] = color.2; 66 | } 67 | } 68 | } 69 | } 70 | } 71 | 72 | #[derive(Clone, Copy)] 73 | struct Star { 74 | color: (u8, u8, u8), 75 | a: f32, 76 | b: f32, 77 | x: f32, 78 | size: f32, 79 | } 80 | 81 | impl Star { 82 | fn new_rand(w: usize, h: usize) -> Star { 83 | let mut star = Star { 84 | a: 0.0, 85 | x: 0.0, 86 | b: 0.0, 87 | size: 0.0, 88 | color: (0, 0, 0), 89 | }; 90 | star.init(w, h); 91 | star 92 | } 93 | 94 | fn init(&mut self, w: usize, h: usize) { 95 | let wh = w as f32 / 4.0; 96 | let hh = h as f32 / 4.0; 97 | 98 | let mut rng = rand::thread_rng(); 99 | self.x = rng.gen_range(-wh..wh); 100 | self.b = rng.gen_range(-hh..hh); 101 | if self.x != 0.0 { 102 | self.a = self.b / self.x; 103 | } 104 | self.size = rng.gen_range(1.0..1.001); 105 | self.color.0 = rng.gen_range(128..255); 106 | self.color.1 = rng.gen_range(128..255); 107 | self.color.2 = rng.gen_range(128..255); 108 | } 109 | 110 | fn get_pos(&self, w: usize, h: usize) -> (usize, usize) { 111 | let x_coord = (self.x + w as f32 / 2.0) as usize; 112 | let y_coord = (self.a * self.x + self.b + h as f32 / 2.0) as usize; //y = ax + b 113 | (x_coord, y_coord) 114 | } 115 | 116 | fn tick(&mut self, w: usize, h: usize) { 117 | let pos = self.get_pos(w, h); 118 | if pos.0 >= w || pos.1 >= h || pos.0 == 0 || pos.1 == 0 { 119 | self.init(w, h); 120 | } 121 | 122 | self.x *= STAR_SPEED; 123 | self.size *= STAR_GROWTH; 124 | } 125 | } 126 | 127 | fn main() { 128 | let mut framebuffer = Framebuffer::new("/dev/fb0").unwrap(); 129 | 130 | let _w = framebuffer.var_screen_info.xres_virtual; 131 | let h = framebuffer.var_screen_info.yres_virtual; 132 | let line_length = framebuffer.fix_screen_info.line_length; 133 | let mut frame = vec![0u8; (line_length * h) as usize]; 134 | 135 | let mut starfield = Starfield::new(&framebuffer); 136 | 137 | //Disable text mode in current tty 138 | //let _ = Framebuffer::set_kd_mode(KdMode::Graphics).unwrap(); 139 | 140 | loop { 141 | starfield.tick(&framebuffer, &mut frame); 142 | let _ = framebuffer.write_frame(&frame); 143 | } 144 | 145 | //Reenable text mode in current tty 146 | //let _ = Framebuffer::set_kd_mode(KdMode::Text).unwrap(); 147 | } 148 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | //!Simple linux framebuffer abstraction. 2 | //!Examples can be found [here](https://github.com/Roysten/rust-framebuffer/tree/master/examples). 3 | 4 | extern crate libc; 5 | extern crate memmap; 6 | 7 | use libc::ioctl; 8 | 9 | use std::fmt; 10 | use std::fs::{File, OpenOptions}; 11 | use std::os::unix::io::AsRawFd; 12 | use std::path::Path; 13 | 14 | use errno::errno; 15 | use memmap::{MmapMut, MmapOptions}; 16 | 17 | const FBIOGET_VSCREENINFO: libc::c_ulong = 0x4600; 18 | const FBIOPUT_VSCREENINFO: libc::c_ulong = 0x4601; 19 | const FBIOGET_FSCREENINFO: libc::c_ulong = 0x4602; 20 | const FBIOPAN_DISPLAY: libc::c_ulong = 0x4606; 21 | 22 | const KDSETMODE: libc::c_ulong = 0x4B3A; 23 | const KD_TEXT: libc::c_ulong = 0x00; 24 | const KD_GRAPHICS: libc::c_ulong = 0x01; 25 | 26 | ///Bitfield which is a part of VarScreeninfo. 27 | #[repr(C)] 28 | #[derive(Clone, Debug)] 29 | pub struct Bitfield { 30 | pub offset: u32, 31 | pub length: u32, 32 | pub msb_right: u32, 33 | } 34 | 35 | ///Struct as defined in /usr/include/linux/fb.h 36 | #[repr(C)] 37 | #[derive(Clone, Debug)] 38 | pub struct VarScreeninfo { 39 | pub xres: u32, 40 | pub yres: u32, 41 | pub xres_virtual: u32, 42 | pub yres_virtual: u32, 43 | pub xoffset: u32, 44 | pub yoffset: u32, 45 | pub bits_per_pixel: u32, 46 | pub grayscale: u32, 47 | pub red: Bitfield, 48 | pub green: Bitfield, 49 | pub blue: Bitfield, 50 | pub transp: Bitfield, 51 | pub nonstd: u32, 52 | pub activate: u32, 53 | pub height: u32, 54 | pub width: u32, 55 | pub accel_flags: u32, 56 | pub pixclock: u32, 57 | pub left_margin: u32, 58 | pub right_margin: u32, 59 | pub upper_margin: u32, 60 | pub lower_margin: u32, 61 | pub hsync_len: u32, 62 | pub vsync_len: u32, 63 | pub sync: u32, 64 | pub vmode: u32, 65 | pub rotate: u32, 66 | pub colorspace: u32, 67 | pub reserved: [u32; 4], 68 | } 69 | 70 | ///Struct as defined in /usr/include/linux/fb.h Note: type is a keyword in Rust and therefore has been 71 | ///changed to fb_type. 72 | #[repr(C)] 73 | #[derive(Clone, Debug)] 74 | pub struct FixScreeninfo { 75 | pub id: [u8; 16], 76 | pub smem_start: usize, 77 | pub smem_len: u32, 78 | pub fb_type: u32, 79 | pub type_aux: u32, 80 | pub visual: u32, 81 | pub xpanstep: u16, 82 | pub ypanstep: u16, 83 | pub ywrapstep: u16, 84 | pub line_length: u32, 85 | pub mmio_start: usize, 86 | pub mmio_len: u32, 87 | pub accel: u32, 88 | pub capabilities: u16, 89 | pub reserved: [u16; 2], 90 | } 91 | 92 | impl ::std::default::Default for Bitfield { 93 | fn default() -> Self { 94 | unsafe { ::std::mem::zeroed() } 95 | } 96 | } 97 | 98 | impl ::std::default::Default for VarScreeninfo { 99 | fn default() -> Self { 100 | unsafe { ::std::mem::zeroed() } 101 | } 102 | } 103 | 104 | impl ::std::default::Default for FixScreeninfo { 105 | fn default() -> Self { 106 | unsafe { ::std::mem::zeroed() } 107 | } 108 | } 109 | 110 | ///Enum that can be used to set the current KdMode. 111 | pub enum KdMode { 112 | Graphics = KD_GRAPHICS as isize, 113 | Text = KD_TEXT as isize, 114 | } 115 | 116 | ///Kind of errors that can occur when dealing with the Framebuffer. 117 | #[derive(Debug)] 118 | pub enum FramebufferErrorKind { 119 | IoctlFailed, 120 | IoError, 121 | } 122 | 123 | #[derive(Debug)] 124 | pub struct FramebufferError { 125 | pub kind: FramebufferErrorKind, 126 | pub details: String, 127 | } 128 | 129 | impl FramebufferError { 130 | fn new(kind: FramebufferErrorKind, details: &str) -> FramebufferError { 131 | FramebufferError { 132 | kind, 133 | details: String::from(details), 134 | } 135 | } 136 | } 137 | 138 | impl std::error::Error for FramebufferError { 139 | fn description(&self) -> &str { 140 | &self.details 141 | } 142 | } 143 | 144 | impl fmt::Display for FramebufferError { 145 | fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 146 | write!(fmt, "{}", self.details) 147 | } 148 | } 149 | 150 | impl std::convert::From for FramebufferError { 151 | fn from(err: std::io::Error) -> FramebufferError { 152 | FramebufferError::new(FramebufferErrorKind::IoError, &err.to_string()) 153 | } 154 | } 155 | 156 | ///Struct that should be used to work with the framebuffer. Direct usage of `frame` should not be 157 | ///necessary. 158 | #[derive(Debug)] 159 | pub struct Framebuffer { 160 | pub device: File, 161 | pub frame: MmapMut, 162 | pub var_screen_info: VarScreeninfo, 163 | pub fix_screen_info: FixScreeninfo, 164 | } 165 | 166 | impl Framebuffer { 167 | pub fn new>(path_to_device: P) -> Result { 168 | let device = OpenOptions::new() 169 | .read(true) 170 | .write(true) 171 | .open(path_to_device)?; 172 | 173 | let var_screen_info = Framebuffer::get_var_screeninfo(&device)?; 174 | let fix_screen_info = Framebuffer::get_fix_screeninfo(&device)?; 175 | 176 | let frame_length = (fix_screen_info.line_length * var_screen_info.yres_virtual) as usize; 177 | let frame = unsafe { MmapOptions::new().len(frame_length).map_mut(&device) }; 178 | match frame { 179 | Ok(frame_result) => Ok(Framebuffer { 180 | device, 181 | frame: frame_result, 182 | var_screen_info, 183 | fix_screen_info, 184 | }), 185 | Err(_) => Err(FramebufferError::new( 186 | FramebufferErrorKind::IoError, 187 | &format!("Failed to map memory (offset: {} len: {})", 0, frame_length), 188 | )), 189 | } 190 | } 191 | 192 | ///Writes a frame to the Framebuffer. 193 | pub fn write_frame(&mut self, frame: &[u8]) { 194 | self.frame[..].copy_from_slice(&frame[..]); 195 | } 196 | 197 | ///Reads a frame from the framebuffer. 198 | pub fn read_frame(&self) -> &[u8] { 199 | &self.frame[..] 200 | } 201 | 202 | ///Creates a FixScreeninfo struct and fills it using ioctl. 203 | pub fn get_fix_screeninfo(device: &File) -> Result { 204 | let mut info: FixScreeninfo = Default::default(); 205 | let result = unsafe { ioctl(device.as_raw_fd(), FBIOGET_FSCREENINFO as _, &mut info) }; 206 | match result { 207 | -1 => Err(FramebufferError::new( 208 | FramebufferErrorKind::IoctlFailed, 209 | &format!("Ioctl returned -1: {}", errno()), 210 | )), 211 | _ => Ok(info), 212 | } 213 | } 214 | 215 | ///Creates a VarScreeninfo struct and fills it using ioctl. 216 | pub fn get_var_screeninfo(device: &File) -> Result { 217 | let mut info: VarScreeninfo = Default::default(); 218 | let result = unsafe { ioctl(device.as_raw_fd(), FBIOGET_VSCREENINFO as _, &mut info) }; 219 | match result { 220 | -1 => Err(FramebufferError::new( 221 | FramebufferErrorKind::IoctlFailed, 222 | &format!("Ioctl returned -1: {}", errno()), 223 | )), 224 | _ => Ok(info), 225 | } 226 | } 227 | 228 | pub fn put_var_screeninfo( 229 | device: &File, 230 | screeninfo: &VarScreeninfo, 231 | ) -> Result { 232 | match unsafe { ioctl(device.as_raw_fd(), FBIOPUT_VSCREENINFO as _, screeninfo) } { 233 | -1 => Err(FramebufferError::new( 234 | FramebufferErrorKind::IoctlFailed, 235 | &format!("Ioctl returned -1: {}", errno()), 236 | )), 237 | ret => Ok(ret), 238 | } 239 | } 240 | 241 | pub fn pan_display( 242 | device: &File, 243 | screeninfo: &VarScreeninfo, 244 | ) -> Result { 245 | match unsafe { ioctl(device.as_raw_fd(), FBIOPAN_DISPLAY as _, screeninfo) } { 246 | -1 => Err(FramebufferError::new( 247 | FramebufferErrorKind::IoctlFailed, 248 | &format!("Ioctl returned -1: {}", errno()), 249 | )), 250 | ret => Ok(ret), 251 | } 252 | } 253 | 254 | ///Sets the tty graphics mode. Make sure to change it back to KdMode::Text after the program is 255 | ///done! 256 | pub fn set_kd_mode(kd_mode: KdMode) -> Result { 257 | match unsafe { ioctl(0, KDSETMODE as _, kd_mode) } { 258 | -1 => Err(FramebufferError::new( 259 | FramebufferErrorKind::IoctlFailed, 260 | &format!("Ioctl returned -1: {}", errno()), 261 | )), 262 | ret => Ok(ret), 263 | } 264 | } 265 | 266 | /// Allows setting tty mode from non-terminal session by explicitly specifying device name 267 | pub fn set_kd_mode_ex>( 268 | path_to_device: P, 269 | kd_mode: KdMode, 270 | ) -> Result { 271 | let device = OpenOptions::new() 272 | .read(true) 273 | .write(true) 274 | .open(path_to_device)?; 275 | 276 | match unsafe { ioctl(device.as_raw_fd(), KDSETMODE as _, kd_mode) } { 277 | -1 => Err(FramebufferError::new( 278 | FramebufferErrorKind::IoctlFailed, 279 | &format!("Ioctl returned -1: {}", errno()), 280 | )), 281 | ret => Ok(ret), 282 | } 283 | } 284 | } 285 | --------------------------------------------------------------------------------