129 lines
3.7 KiB
Rust
129 lines
3.7 KiB
Rust
#![feature(asm_const)]
|
|
|
|
#[macro_use]
|
|
extern crate bitflags;
|
|
extern crate orbclient;
|
|
extern crate syscall;
|
|
|
|
use std::{env, process};
|
|
use std::fs::{File, OpenOptions};
|
|
use std::io::{Read, Write};
|
|
use std::os::unix::fs::OpenOptionsExt;
|
|
use std::os::unix::io::AsRawFd;
|
|
|
|
use syscall::call::iopl;
|
|
|
|
use crate::state::Ps2d;
|
|
|
|
mod controller;
|
|
mod keymap;
|
|
mod state;
|
|
mod vm;
|
|
|
|
fn daemon(daemon: redox_daemon::Daemon) -> ! {
|
|
unsafe {
|
|
iopl(3).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"),
|
|
};
|
|
|
|
eprintln!("ps2d: using keymap '{}'", keymap_name);
|
|
|
|
let input = OpenOptions::new()
|
|
.write(true)
|
|
.open("display:input")
|
|
.expect("ps2d: failed to open display:input");
|
|
|
|
let mut event_file = OpenOptions::new()
|
|
.read(true)
|
|
.write(true)
|
|
.open("event:")
|
|
.expect("ps2d: failed to open event:");
|
|
|
|
let mut key_file = OpenOptions::new()
|
|
.read(true)
|
|
.write(true)
|
|
.custom_flags(syscall::O_NONBLOCK as i32)
|
|
.open("serio:0")
|
|
.expect("ps2d: failed to open serio:0");
|
|
|
|
event_file.write(&syscall::Event {
|
|
id: key_file.as_raw_fd() as usize,
|
|
flags: syscall::EVENT_READ,
|
|
data: 0
|
|
}).expect("ps2d: failed to event serio:0");
|
|
|
|
let mut mouse_file = OpenOptions::new()
|
|
.read(true)
|
|
.write(true)
|
|
.custom_flags(syscall::O_NONBLOCK as i32)
|
|
.open("serio:1")
|
|
.expect("ps2d: failed to open serio:1");
|
|
|
|
event_file.write(&syscall::Event {
|
|
id: mouse_file.as_raw_fd() as usize,
|
|
flags: syscall::EVENT_READ,
|
|
data: 1
|
|
}).expect("ps2d: failed to event irq:12");
|
|
|
|
syscall::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];
|
|
loop {
|
|
// There are some gotchas with ps/2 controllers that require this weird
|
|
// way of doing things. You read key and mouse data from the same
|
|
// place. There is a status register that may show you which the data
|
|
// came from, but if it is even implemented it can have a race
|
|
// condition causing keyboard data to be read as mouse data.
|
|
//
|
|
// Due to this, we have a kernel driver doing a small amount of work
|
|
// to grab bytes and sort them based on the source
|
|
|
|
let mut event = syscall::Event::default();
|
|
if event_file.read(&mut event).expect("ps2d: failed to read event file") == 0 {
|
|
break;
|
|
}
|
|
|
|
let (file, keyboard) = match event.data {
|
|
0 => (&mut key_file, true),
|
|
1 => (&mut mouse_file, false),
|
|
_ => continue,
|
|
};
|
|
|
|
loop {
|
|
let count = match file.read(&mut data) {
|
|
Ok(0) => break,
|
|
Ok(count) => count,
|
|
Err(_) => break,
|
|
};
|
|
for i in 0..count {
|
|
ps2d.handle(keyboard, data[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
process::exit(0);
|
|
}
|
|
|
|
fn main() {
|
|
redox_daemon::Daemon::new(daemon).expect("ps2d: failed to create daemon");
|
|
}
|