make getty work

Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
Anhad Singh
2023-07-07 16:51:27 +10:00
parent 2cfd62d194
commit 5c4e7b36fa
10 changed files with 375 additions and 111 deletions
+25
View File
@@ -0,0 +1,25 @@
use std::fs::File;
use std::io::{Error, Read};
pub struct Handle(File);
impl Handle {
pub fn new<S: Into<String>>(device_name: S) -> Result<Self, Error> {
let path = format!("input:handle/{}", device_name.into());
Ok(Self(File::open(path)?))
}
// The return value is the display identifier. It will be used to uniquely
// identify the display on activation events.
pub fn register(&mut self) -> Result<usize, Error> {
Ok(dbg!(self.0.read(&mut [])?))
}
}
#[repr(packed)]
pub struct Damage {
pub x: i32,
pub y: i32,
pub width: i32,
pub height: i32,
}
+106 -10
View File
@@ -15,10 +15,11 @@ use std::collections::BTreeMap;
use std::fs::File;
use std::io::{Read, Write};
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
use orbclient::{Event, EventOption};
use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL};
#[derive(Debug)]
enum Handle {
Producer,
Consumer {
@@ -26,6 +27,7 @@ enum Handle {
pending: Vec<u8>,
notified: bool,
},
Device(Arc<String>),
}
impl Handle {
@@ -36,27 +38,46 @@ impl Handle {
struct InputScheme {
handles: BTreeMap<usize, Handle>,
next_id: AtomicUsize,
next_vt_id: AtomicUsize,
vts: BTreeMap<usize, Arc<String>>,
super_key: bool,
active_vt: Option<(Arc<String>, File)>,
}
impl InputScheme {
pub fn new() -> Self {
Self {
next_id: AtomicUsize::new(0),
next_vt_id: AtomicUsize::new(1),
handles: BTreeMap::new(),
vts: BTreeMap::new(),
super_key: false,
active_vt: None,
}
}
}
impl SchemeMut for InputScheme {
fn open(&mut self, path: &str, _flags: usize, _uid: u32, _gid: u32) -> syscall::Result<usize> {
let handle_ty = match path {
let mut path_parts = path.split('/');
let command = path_parts.next().ok_or(SysError::new(EINVAL))?;
let handle_ty = match command {
"producer" => Handle::Producer,
"consumer" => Handle::Consumer {
events: EventFlags::empty(),
pending: Vec::new(),
notified: false,
},
"handle" => {
let value = path_parts.next().ok_or(SysError::new(EINVAL))?;
Handle::Device(Arc::new(value.to_string()))
}
_ => unreachable!("inputd: invalid path {path}"),
};
@@ -72,17 +93,24 @@ impl SchemeMut for InputScheme {
fn read(&mut self, id: usize, buf: &mut [u8]) -> syscall::Result<usize> {
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
if let Handle::Consumer { pending, .. } = handle {
let copy = core::cmp::min(pending.len(), buf.len());
match handle {
Handle::Consumer { pending, .. } => {
let copy = core::cmp::min(pending.len(), buf.len());
for (i, byte) in pending.drain(..copy).enumerate() {
buf[i] = byte;
for (i, byte) in pending.drain(..copy).enumerate() {
buf[i] = byte;
}
Ok(copy)
}
Ok(copy)
} else {
// A producer cannot read from the channel.
unreachable!()
Handle::Device(device) => {
let vt = self.next_vt_id.fetch_add(1, Ordering::SeqCst);
self.vts.insert(vt, device.clone());
Ok(vt)
}
_ => unreachable!(),
}
}
@@ -91,6 +119,74 @@ impl SchemeMut for InputScheme {
return Ok(1);
}
let events = unsafe {
core::slice::from_raw_parts(
buf.as_ptr() as *const Event,
buf.len() / core::mem::size_of::<Event>(),
)
};
for event in events.iter() {
let mut new_active_opt = None;
match event.to_option() {
EventOption::Key(key_event) => match key_event.scancode {
f @ 0x3B..=0x44 if self.super_key => {
// F1 through F10
new_active_opt = Some((f - 0x3A) as usize);
}
0x57 if self.super_key => {
// F11
new_active_opt = Some(11);
}
0x58 if self.super_key => {
// F12
new_active_opt = Some(12);
}
0x5B => {
// Super
self.super_key = key_event.pressed;
}
_ => (),
},
_ => continue,
}
if let Some(new_active) = new_active_opt {
if let Some(vt) = self.vts.get(&new_active) {
// Result: display/virtio-gpu:3/acvtivate
let activate = format!("display/{vt}:{new_active}/activate");
log::info!("inputd: switching to VT #{new_active} ({activate})");
let file = File::open(&activate).unwrap();
// Drop the old active VT first.
//
// TODO(andypython): This can be drastically improved by introducting something
// like ioctl() to the display scheme.
for (vt, device) in self.vts.iter() {
if vt == &new_active {
continue;
}
let deactivate = format!("display/{device}:{}/deactivate", vt);
let _ = File::open(&deactivate);
if device.contains("virtio") {
break;
}
}
self.active_vt = Some((vt.clone(), file));
} else {
log::warn!("inputd: switch to non-existent VT #{new_active} was requested");
}
}
}
let handle = self.handles.get_mut(&id).ok_or(SysError::new(EINVAL))?;
assert!(handle.is_producer());