Merge branch 'ps2-keymap-config' into 'master'
Add ps2 scheme to make the keymap configurable See merge request redox-os/drivers!293
This commit is contained in:
Generated
+1
@@ -1022,6 +1022,7 @@ dependencies = [
|
||||
"log",
|
||||
"orbclient",
|
||||
"redox-daemon",
|
||||
"redox-scheme 0.6.2",
|
||||
"redox_event",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
@@ -36,7 +36,9 @@ impl Backend for DeviceTreeBackend {
|
||||
|
||||
fn probe(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
let dt = fdt::Fdt::new(&self.dtb).map_err(|err| format!("failed to parse dtb: {}", err))?;
|
||||
let root = dt.find_node("/").ok_or_else(|| format!("failed to find root node"))?;
|
||||
let root = dt
|
||||
.find_node("/")
|
||||
.ok_or_else(|| format!("failed to find root node"))?;
|
||||
Self::dump(&root, 0);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ orbclient = "0.3.27"
|
||||
redox_event = "0.4.1"
|
||||
redox_syscall = "0.5.10"
|
||||
redox-daemon = "0.1"
|
||||
redox-scheme = "0.6.2"
|
||||
libredox = "0.1.3"
|
||||
|
||||
common = { path = "../../common" }
|
||||
|
||||
+72
-14
@@ -13,11 +13,15 @@ use common::acquire_port_io_rights;
|
||||
use event::{user_data, EventQueue};
|
||||
use inputd::ProducerHandle;
|
||||
use log::info;
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
use syscall::{EAGAIN, EWOULDBLOCK};
|
||||
|
||||
use crate::scheme::Ps2Scheme;
|
||||
use crate::state::Ps2d;
|
||||
|
||||
mod controller;
|
||||
mod keymap;
|
||||
mod scheme;
|
||||
mod state;
|
||||
mod vm;
|
||||
|
||||
@@ -32,18 +36,11 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
|
||||
acquire_port_io_rights().expect("ps2d: failed to get I/O permission");
|
||||
|
||||
let (keymap, keymap_name): (fn(u8, bool) -> char, &str) = match env::args().skip(1).next() {
|
||||
Some(k) => match k.to_lowercase().as_ref() {
|
||||
"dvorak" => (keymap::dvorak::get_char, "dvorak"),
|
||||
"us" => (keymap::us::get_char, "us"),
|
||||
"gb" => (keymap::gb::get_char, "gb"),
|
||||
"azerty" => (keymap::azerty::get_char, "azerty"),
|
||||
"bepo" => (keymap::bepo::get_char, "bepo"),
|
||||
"it" => (keymap::it::get_char, "it"),
|
||||
&_ => (keymap::us::get_char, "us"),
|
||||
},
|
||||
None => (keymap::us::get_char, "us"),
|
||||
};
|
||||
let (mut keymap, mut keymap_name): (fn(u8, bool) -> char, &str) =
|
||||
match env::args().skip(1).next() {
|
||||
Some(k) => get_keymap_from_str(&k),
|
||||
None => (keymap::us::get_char, "us"),
|
||||
};
|
||||
|
||||
info!("ps2d: using keymap '{}'", keymap_name);
|
||||
|
||||
@@ -53,6 +50,7 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
enum Source {
|
||||
Keyboard,
|
||||
Mouse,
|
||||
Scheme,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,14 +87,29 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let mut ps2d = Ps2d::new(input, keymap);
|
||||
|
||||
let scheme_file = Socket::nonblock("ps2").expect("ps2d: failed to create ps2 scheme");
|
||||
|
||||
let mut scheme_handle = Ps2Scheme::new(
|
||||
keymap_name.to_owned(),
|
||||
vec!["dvorak", "us", "gb", "azerty", "bepo", "it"],
|
||||
);
|
||||
|
||||
event_queue
|
||||
.subscribe(
|
||||
scheme_file.inner().raw(),
|
||||
Source::Scheme,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("ps2d: failed to enter null namespace");
|
||||
|
||||
daemon
|
||||
.ready()
|
||||
.expect("ps2d: failed to mark daemon as ready");
|
||||
|
||||
let mut ps2d = Ps2d::new(input, keymap);
|
||||
|
||||
let mut data = [0; 256];
|
||||
for event in event_queue.map(|e| e.expect("ps2d: failed to get next event").user_data) {
|
||||
// There are some gotchas with ps/2 controllers that require this weird
|
||||
@@ -111,6 +124,39 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
let (file, keyboard) = match event {
|
||||
Source::Keyboard => (&mut key_file, true),
|
||||
Source::Mouse => (&mut mouse_file, false),
|
||||
Source::Scheme => {
|
||||
loop {
|
||||
let request = match scheme_file.next_request(SignalBehavior::Interrupt) {
|
||||
Ok(Some(request)) => request,
|
||||
Ok(None) => {
|
||||
// Scheme likely got unmounted
|
||||
std::process::exit(0);
|
||||
}
|
||||
Err(err) if err.errno == EWOULDBLOCK || err.errno == EAGAIN => break,
|
||||
Err(err) => panic!("ps2: failed to read scheme: {:?}", err),
|
||||
};
|
||||
|
||||
match request.kind() {
|
||||
RequestKind::Call(call) => {
|
||||
let response = call.handle_sync(&mut scheme_handle);
|
||||
|
||||
scheme_file
|
||||
.write_response(response, SignalBehavior::Restart)
|
||||
.expect("ps2: failed to write next scheme response");
|
||||
}
|
||||
RequestKind::OnClose { id: _ } => {}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
if keymap_name != &scheme_handle.keymap {
|
||||
(keymap, keymap_name) = get_keymap_from_str(&scheme_handle.keymap);
|
||||
info!("ps2d: updating to new keymap '{:?}'", keymap_name);
|
||||
ps2d.update_keymap(keymap);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
};
|
||||
|
||||
loop {
|
||||
@@ -128,6 +174,18 @@ fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
||||
process::exit(0);
|
||||
}
|
||||
|
||||
fn get_keymap_from_str(k: &str) -> (fn(u8, bool) -> char, &'static str) {
|
||||
match k.to_lowercase().as_ref() {
|
||||
"dvorak" => (keymap::dvorak::get_char, "dvorak"),
|
||||
"us" => (keymap::us::get_char, "us"),
|
||||
"gb" => (keymap::gb::get_char, "gb"),
|
||||
"azerty" => (keymap::azerty::get_char, "azerty"),
|
||||
"bepo" => (keymap::bepo::get_char, "bepo"),
|
||||
"it" => (keymap::it::get_char, "it"),
|
||||
&_ => (keymap::us::get_char, "us"),
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
redox_daemon::Daemon::new(daemon).expect("ps2d: failed to create daemon");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,145 @@
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use std::convert::TryFrom;
|
||||
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{
|
||||
Error, Result, EACCES, EINVAL, EMFILE, ENOENT, ENOTDIR, MODE_DIR, MODE_FILE, O_WRONLY,
|
||||
};
|
||||
|
||||
pub struct Ps2Scheme {
|
||||
pub keymap: String,
|
||||
pub keymap_list: String,
|
||||
}
|
||||
|
||||
impl Ps2Scheme {
|
||||
pub fn new(keymap: String, keymap_list: Vec<&str>) -> Ps2Scheme {
|
||||
let scheme = Ps2Scheme {
|
||||
keymap,
|
||||
keymap_list: keymap_list.join("\n"),
|
||||
};
|
||||
scheme
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeSync for Ps2Scheme {
|
||||
fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
let path = path_str.trim_start_matches('/');
|
||||
if flags & O_WRONLY != 0 {
|
||||
if ctx.uid != 0 || ctx.gid != 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
} else if path != "keymap" {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
|
||||
match path {
|
||||
"" => Ok(OpenResult::ThisScheme {
|
||||
number: 0,
|
||||
flags: NewFdFlags::empty(),
|
||||
}),
|
||||
"keymap" => Ok(OpenResult::ThisScheme {
|
||||
number: 1,
|
||||
flags: NewFdFlags::POSITIONED,
|
||||
}),
|
||||
"keymap_list" => Ok(OpenResult::ThisScheme {
|
||||
number: 2,
|
||||
flags: NewFdFlags::POSITIONED,
|
||||
}),
|
||||
_ => Err(Error::new(ENOENT)),
|
||||
}
|
||||
}
|
||||
fn getdents<'buf>(
|
||||
&mut self,
|
||||
id: usize,
|
||||
mut buf: DirentBuf<&'buf mut [u8]>,
|
||||
opaque_offset: u64,
|
||||
) -> Result<DirentBuf<&'buf mut [u8]>> {
|
||||
if id != 0 {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
}
|
||||
let Ok(offset) = usize::try_from(opaque_offset) else {
|
||||
return Ok(buf);
|
||||
};
|
||||
for (this_idx, name) in ["keymap", "keymap_list"].iter().enumerate().skip(offset) {
|
||||
buf.entry(DirEntry {
|
||||
inode: this_idx as u64,
|
||||
next_opaque_id: this_idx as u64 + 1,
|
||||
kind: DirentKind::Regular,
|
||||
name,
|
||||
})?;
|
||||
}
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
fn fstat(&mut self, id: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> {
|
||||
stat.st_size = 0;
|
||||
stat.st_mode = match id {
|
||||
0 => 0o555 | MODE_DIR,
|
||||
1 => 0o644 | MODE_FILE,
|
||||
2 => 0o444 | MODE_FILE,
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
};
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fpath(&mut self, _id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let path = b"/scheme/ps2";
|
||||
|
||||
let mut i = 0;
|
||||
while i < buf.len() && i < path.len() {
|
||||
buf[i] = path[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(i)
|
||||
}
|
||||
|
||||
fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read(
|
||||
&mut self,
|
||||
id: usize,
|
||||
buf: &mut [u8],
|
||||
offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
if offset != 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let value = match id {
|
||||
1 => self.keymap.as_bytes(),
|
||||
2 => self.keymap_list.as_bytes(),
|
||||
_ => {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
};
|
||||
|
||||
if buf.len() + 2 < value.len() {
|
||||
return Err(Error::new(EMFILE));
|
||||
}
|
||||
buf[..value.len()].copy_from_slice(value);
|
||||
buf[value.len()] = b'\n';
|
||||
buf[value.len() + 1] = b'\0';
|
||||
Ok(value.len() + 2)
|
||||
}
|
||||
|
||||
fn write(
|
||||
&mut self,
|
||||
id: usize,
|
||||
buf: &[u8],
|
||||
offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
if offset != 0 || id != 1 {
|
||||
return Ok(0);
|
||||
}
|
||||
let new_keymap = String::from_utf8(buf.to_vec()).map_err(|_| Error::new(EINVAL))?;
|
||||
self.keymap = new_keymap.trim().to_string();
|
||||
Ok(buf.len())
|
||||
}
|
||||
}
|
||||
@@ -67,6 +67,10 @@ impl<F: Fn(u8, bool) -> char> Ps2d<F> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_keymap(&mut self, keymap: F) {
|
||||
self.get_char = keymap;
|
||||
}
|
||||
|
||||
pub fn irq(&mut self) {
|
||||
while let Some((keyboard, data)) = self.ps2.next() {
|
||||
self.handle(keyboard, data);
|
||||
|
||||
+1
-1
@@ -205,7 +205,7 @@ impl SchemeSync for InputScheme {
|
||||
"control" => Handle::Control,
|
||||
|
||||
_ => {
|
||||
log::error!("inputd: invalid path {path}");
|
||||
log::error!("inputd: invalid path '{path}'");
|
||||
return Err(SysError::new(EINVAL));
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user