Orbital (#16)
* Port previous ethernet scheme * Add ipd * Fix initfs rebuilds, use QEMU user networking addresses in ipd * Add tcp/udp, netutils, dns, and network config * Add fsync to network driver * Add dns, router, subnet by default * Fix e1000 driver. Make ethernet and IP non-blocking to avoid deadlocks * Add orbital server, WIP * Add futex * Add orbutils and orbital * Update libstd, orbutils, and orbital Move ANSI key encoding to vesad * Add orbital assets * Update orbital * Update to add login manager * Add blocking primitives, block for most things except waitpid, update orbital * Wait in waitpid and IRQ, improvements for other waits * Fevent in root scheme * WIP: Switch to using fevent * Reorganize * Event based e1000d driver * Superuser-only access to some network schemes, display, and disk * Superuser root and irq schemes * Fix orbital
This commit is contained in:
parent
372d44f88c
commit
224c43f761
92 changed files with 3415 additions and 473 deletions
|
@ -4,7 +4,7 @@ version = "0.1.0"
|
|||
|
||||
[dependencies]
|
||||
bitflags = "*"
|
||||
dma = { path = "../dma/" }
|
||||
io = { path = "../io/" }
|
||||
dma = { path = "../../crates/dma/" }
|
||||
io = { path = "../../crates/io/" }
|
||||
spin = "*"
|
||||
syscall = { path = "../../syscall/" }
|
||||
|
|
|
@ -25,6 +25,10 @@ const HBA_SIG_ATAPI: u32 = 0xEB140101;
|
|||
const HBA_SIG_PM: u32 = 0x96690101;
|
||||
const HBA_SIG_SEMB: u32 = 0xC33C0101;
|
||||
|
||||
fn pause() {
|
||||
unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum HbaPortType {
|
||||
None,
|
||||
|
@ -119,7 +123,9 @@ impl HbaPort {
|
|||
cmdfis.counth.write(0);
|
||||
}
|
||||
|
||||
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {}
|
||||
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {
|
||||
pause();
|
||||
}
|
||||
|
||||
self.ci.writef(1 << slot, true);
|
||||
|
||||
|
@ -127,6 +133,7 @@ impl HbaPort {
|
|||
if self.is.readf(HBA_PORT_IS_TFES) {
|
||||
return None;
|
||||
}
|
||||
pause();
|
||||
}
|
||||
|
||||
if self.is.readf(HBA_PORT_IS_TFES) {
|
||||
|
@ -194,7 +201,9 @@ impl HbaPort {
|
|||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
while self.cmd.readf(HBA_PORT_CMD_CR) {}
|
||||
while self.cmd.readf(HBA_PORT_CMD_CR) {
|
||||
pause();
|
||||
}
|
||||
|
||||
self.cmd.writef(HBA_PORT_CMD_FRE, true);
|
||||
self.cmd.writef(HBA_PORT_CMD_ST, true);
|
||||
|
@ -203,7 +212,9 @@ impl HbaPort {
|
|||
pub fn stop(&mut self) {
|
||||
self.cmd.writef(HBA_PORT_CMD_ST, false);
|
||||
|
||||
while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) {}
|
||||
while self.cmd.readf(HBA_PORT_CMD_FR | HBA_PORT_CMD_CR) {
|
||||
pause();
|
||||
}
|
||||
|
||||
self.cmd.writef(HBA_PORT_CMD_FRE, false);
|
||||
}
|
||||
|
@ -267,7 +278,9 @@ impl HbaPort {
|
|||
cmdfis.counth.write((sectors >> 8) as u8);
|
||||
}
|
||||
|
||||
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {}
|
||||
while self.tfd.readf((ATA_DEV_BUSY | ATA_DEV_DRQ) as u32) {
|
||||
pause();
|
||||
}
|
||||
|
||||
self.ci.writef(1 << slot, true);
|
||||
|
||||
|
@ -276,6 +289,7 @@ impl HbaPort {
|
|||
println!("IS_TFES set in CI loop TFS {:X} SERR {:X}", self.tfd.read(), self.serr.read());
|
||||
return Err(Error::new(EIO));
|
||||
}
|
||||
pause();
|
||||
}
|
||||
|
||||
if self.is.readf(HBA_PORT_IS_TFES) {
|
||||
|
@ -312,7 +326,9 @@ pub struct HbaMem {
|
|||
impl HbaMem {
|
||||
pub fn reset(&mut self) {
|
||||
self.ghc.writef(1, true);
|
||||
while self.ghc.readf(1) {}
|
||||
while self.ghc.readf(1) {
|
||||
pause();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -8,10 +8,11 @@ extern crate io;
|
|||
extern crate spin;
|
||||
extern crate syscall;
|
||||
|
||||
use std::{env, thread, usize};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::{env, thread, usize};
|
||||
use syscall::{iopl, physmap, physunmap, MAP_WRITE, Packet, Scheme};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use syscall::{EVENT_READ, MAP_WRITE, Event, Packet, Scheme};
|
||||
|
||||
use scheme::DiskScheme;
|
||||
|
||||
|
@ -29,21 +30,42 @@ fn main() {
|
|||
|
||||
thread::spawn(move || {
|
||||
unsafe {
|
||||
iopl(3).expect("ahcid: failed to get I/O permission");
|
||||
syscall::iopl(3).expect("ahcid: failed to get I/O permission");
|
||||
asm!("cli" :::: "intel", "volatile");
|
||||
}
|
||||
|
||||
let address = unsafe { physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") };
|
||||
let address = unsafe { syscall::physmap(bar, 4096, MAP_WRITE).expect("ahcid: failed to map address") };
|
||||
{
|
||||
let mut socket = File::create(":disk").expect("ahcid: failed to create disk scheme");
|
||||
let socket_fd = socket.as_raw_fd();
|
||||
syscall::fevent(socket_fd, EVENT_READ).expect("ahcid: failed to fevent disk scheme");
|
||||
|
||||
let mut irq_file = File::open(&format!("irq:{}", irq)).expect("ahcid: failed to open irq file");
|
||||
let irq_fd = irq_file.as_raw_fd();
|
||||
syscall::fevent(irq_fd, EVENT_READ).expect("ahcid: failed to fevent irq file");
|
||||
|
||||
let mut event_file = File::open("event:").expect("ahcid: failed to open event file");
|
||||
|
||||
let scheme = DiskScheme::new(ahci::disks(address, irq));
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
socket.read(&mut packet).expect("ahcid: failed to read disk scheme");
|
||||
scheme.handle(&mut packet);
|
||||
socket.write(&mut packet).expect("ahcid: failed to read disk scheme");
|
||||
let mut event = Event::default();
|
||||
event_file.read(&mut event).expect("ahcid: failed to read event file");
|
||||
if event.id == socket_fd {
|
||||
let mut packet = Packet::default();
|
||||
socket.read(&mut packet).expect("ahcid: failed to read disk scheme");
|
||||
scheme.handle(&mut packet);
|
||||
socket.write(&mut packet).expect("ahcid: failed to write disk scheme");
|
||||
} else if event.id == irq_fd {
|
||||
let mut irq = [0; 8];
|
||||
if irq_file.read(&mut irq).expect("ahcid: failed to read irq file") >= irq.len() {
|
||||
println!("IRQ");
|
||||
irq_file.write(&irq).expect("ahcid: failed to write irq file");
|
||||
}
|
||||
} else {
|
||||
println!("Unknown event {}", event.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe { let _ = physunmap(address); }
|
||||
unsafe { let _ = syscall::physunmap(address); }
|
||||
});
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::{cmp, str};
|
|||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use spin::Mutex;
|
||||
use syscall::{Error, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
use syscall::{Error, EACCES, EBADF, EINVAL, ENOENT, Result, Scheme, Stat, MODE_FILE, SEEK_CUR, SEEK_END, SEEK_SET};
|
||||
|
||||
use ahci::disk::Disk;
|
||||
|
||||
|
@ -29,17 +29,21 @@ impl DiskScheme {
|
|||
}
|
||||
|
||||
impl Scheme for DiskScheme {
|
||||
fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
|
||||
let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?;
|
||||
fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||
if uid == 0 {
|
||||
let path_str = str::from_utf8(path).or(Err(Error::new(ENOENT)))?;
|
||||
|
||||
let i = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
|
||||
let i = path_str.parse::<usize>().or(Err(Error::new(ENOENT)))?;
|
||||
|
||||
if let Some(disk) = self.disks.get(i) {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.lock().insert(id, (disk.clone(), 0));
|
||||
Ok(id)
|
||||
if let Some(disk) = self.disks.get(i) {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.lock().insert(id, (disk.clone(), 0));
|
||||
Ok(id)
|
||||
} else {
|
||||
Err(Error::new(ENOENT))
|
||||
}
|
||||
} else {
|
||||
Err(Error::new(ENOENT))
|
||||
Err(Error::new(EACCES))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
[package]
|
||||
name = "dma"
|
||||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
syscall = { path = "../../syscall/" }
|
|
@ -1,80 +0,0 @@
|
|||
#![feature(question_mark)]
|
||||
|
||||
extern crate syscall;
|
||||
|
||||
use std::{mem, ptr};
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use syscall::Result;
|
||||
|
||||
struct PhysBox {
|
||||
address: usize,
|
||||
size: usize
|
||||
}
|
||||
|
||||
impl PhysBox {
|
||||
fn new(size: usize) -> Result<PhysBox> {
|
||||
let address = unsafe { syscall::physalloc(size)? };
|
||||
Ok(PhysBox {
|
||||
address: address,
|
||||
size: size
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for PhysBox {
|
||||
fn drop(&mut self) {
|
||||
let _ = unsafe { syscall::physfree(self.address, self.size) };
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Dma<T> {
|
||||
phys: PhysBox,
|
||||
virt: *mut T
|
||||
}
|
||||
|
||||
impl<T> Dma<T> {
|
||||
pub fn new(value: T) -> Result<Dma<T>> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>())?;
|
||||
let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T;
|
||||
unsafe { ptr::write(virt, value); }
|
||||
Ok(Dma {
|
||||
phys: phys,
|
||||
virt: virt
|
||||
})
|
||||
}
|
||||
|
||||
pub fn zeroed() -> Result<Dma<T>> {
|
||||
let phys = PhysBox::new(mem::size_of::<T>())?;
|
||||
let virt = unsafe { syscall::physmap(phys.address, phys.size, syscall::MAP_WRITE)? } as *mut T;
|
||||
unsafe { ptr::write_bytes(virt as *mut u8, 0, phys.size); }
|
||||
Ok(Dma {
|
||||
phys: phys,
|
||||
virt: virt
|
||||
})
|
||||
}
|
||||
|
||||
pub fn physical(&self) -> usize {
|
||||
self.phys.address
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for Dma<T> {
|
||||
type Target = T;
|
||||
fn deref(&self) -> &T {
|
||||
unsafe { &*self.virt }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> DerefMut for Dma<T> {
|
||||
fn deref_mut(&mut self) -> &mut T {
|
||||
unsafe { &mut *self.virt }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Drop for Dma<T> {
|
||||
fn drop(&mut self) {
|
||||
unsafe { drop(ptr::read(self.virt)); }
|
||||
let _ = unsafe { syscall::physunmap(self.virt as usize) };
|
||||
}
|
||||
}
|
|
@ -4,7 +4,8 @@ version = "0.1.0"
|
|||
|
||||
[dependencies]
|
||||
bitflags = "*"
|
||||
dma = { path = "../dma/" }
|
||||
io = { path = "../io/" }
|
||||
dma = { path = "../../crates/dma/" }
|
||||
event = { path = "../../crates/event/" }
|
||||
io = { path = "../../crates/io/" }
|
||||
spin = "*"
|
||||
syscall = { path = "../../syscall/" }
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::{cmp, mem, ptr, slice};
|
||||
|
||||
use dma::Dma;
|
||||
use syscall::error::Result;
|
||||
use syscall::error::{Error, EACCES, EWOULDBLOCK, Result};
|
||||
use syscall::scheme::Scheme;
|
||||
|
||||
const CTRL: u32 = 0x00;
|
||||
|
@ -96,12 +96,16 @@ pub struct Intel8254x {
|
|||
receive_buffer: [Dma<[u8; 16384]>; 16],
|
||||
receive_ring: Dma<[Rd; 16]>,
|
||||
transmit_buffer: [Dma<[u8; 16384]>; 16],
|
||||
transmit_ring: Dma<[Td; 16]>,
|
||||
transmit_ring: Dma<[Td; 16]>
|
||||
}
|
||||
|
||||
impl Scheme for Intel8254x {
|
||||
fn open(&self, _path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
|
||||
Ok(0)
|
||||
fn open(&self, _path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||
if uid == 0 {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EACCES))
|
||||
}
|
||||
}
|
||||
|
||||
fn dup(&self, id: usize) -> Result<usize> {
|
||||
|
@ -109,7 +113,15 @@ impl Scheme for Intel8254x {
|
|||
}
|
||||
|
||||
fn read(&self, _id: usize, buf: &mut [u8]) -> Result<usize> {
|
||||
for tail in 0..self.receive_ring.len() {
|
||||
let head = unsafe { self.read(RDH) };
|
||||
let mut tail = unsafe { self.read(RDT) };
|
||||
|
||||
tail += 1;
|
||||
if tail >= self.receive_ring.len() as u32 {
|
||||
tail = 0;
|
||||
}
|
||||
|
||||
if tail != head {
|
||||
let rd = unsafe { &mut * (self.receive_ring.as_ptr().offset(tail as isize) as *mut Rd) };
|
||||
if rd.status & RD_DD == RD_DD {
|
||||
rd.status = 0;
|
||||
|
@ -121,11 +133,14 @@ impl Scheme for Intel8254x {
|
|||
buf[i] = data[i];
|
||||
i += 1;
|
||||
}
|
||||
|
||||
unsafe { self.write(RDT, tail) };
|
||||
|
||||
return Ok(i);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
Err(Error::new(EWOULDBLOCK))
|
||||
}
|
||||
|
||||
fn write(&self, _id: usize, buf: &[u8]) -> Result<usize> {
|
||||
|
@ -166,8 +181,12 @@ impl Scheme for Intel8254x {
|
|||
|
||||
return Ok(i);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe { asm!("pause" : : : "memory" : "intel", "volatile"); }
|
||||
}
|
||||
}
|
||||
|
||||
fn fsync(&self, _id: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
|
@ -198,6 +217,11 @@ impl Intel8254x {
|
|||
Ok(module)
|
||||
}
|
||||
|
||||
pub unsafe fn irq(&self) -> bool {
|
||||
let icr = self.read(ICR);
|
||||
icr != 0
|
||||
}
|
||||
|
||||
pub unsafe fn read(&self, register: u32) -> u32 {
|
||||
ptr::read_volatile((self.base + register as usize) as *mut u32)
|
||||
}
|
||||
|
@ -271,8 +295,7 @@ impl Intel8254x {
|
|||
self.write(TDH, 0);
|
||||
self.write(TDT, 0);
|
||||
|
||||
//self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ | IMS_LSC | IMS_TXQE | IMS_TXDW);
|
||||
self.write(IMS, 0);
|
||||
self.write(IMS, IMS_RXT | IMS_RX | IMS_RXDMT | IMS_RXSEQ); // | IMS_LSC | IMS_TXQE | IMS_TXDW
|
||||
|
||||
self.flag(RCTL, RCTL_EN, true);
|
||||
self.flag(RCTL, RCTL_UPE, true);
|
||||
|
|
|
@ -2,13 +2,19 @@
|
|||
#![feature(question_mark)]
|
||||
|
||||
extern crate dma;
|
||||
extern crate event;
|
||||
extern crate syscall;
|
||||
|
||||
use std::cell::RefCell;
|
||||
use std::{env, thread};
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::io::{Read, Write, Result};
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::sync::Arc;
|
||||
|
||||
use syscall::{iopl, physmap, physunmap, Packet, Scheme, MAP_WRITE};
|
||||
use event::EventQueue;
|
||||
use syscall::{Packet, Scheme, MAP_WRITE};
|
||||
use syscall::error::EWOULDBLOCK;
|
||||
|
||||
pub mod device;
|
||||
|
||||
|
@ -23,21 +29,66 @@ fn main() {
|
|||
|
||||
thread::spawn(move || {
|
||||
unsafe {
|
||||
iopl(3).expect("e1000d: failed to get I/O permission");
|
||||
syscall::iopl(3).expect("e1000d: failed to get I/O permission");
|
||||
asm!("cli" :::: "intel", "volatile");
|
||||
}
|
||||
|
||||
let address = unsafe { physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") };
|
||||
let socket = Arc::new(RefCell::new(File::create(":network").expect("e1000d: failed to create network scheme")));
|
||||
|
||||
let address = unsafe { syscall::physmap(bar, 128*1024, MAP_WRITE).expect("e1000d: failed to map address") };
|
||||
{
|
||||
let mut device = unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") };
|
||||
let mut socket = File::create(":network").expect("e1000d: failed to create network scheme");
|
||||
loop {
|
||||
let device = Arc::new(unsafe { device::Intel8254x::new(address, irq).expect("e1000d: failed to allocate device") });
|
||||
|
||||
let mut event_queue = EventQueue::<()>::new().expect("e1000d: failed to create event queue");
|
||||
|
||||
let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));
|
||||
|
||||
let device_irq = device.clone();
|
||||
let socket_irq = socket.clone();
|
||||
let todo_irq = todo.clone();
|
||||
let mut irq_file = File::open(format!("irq:{}", irq)).expect("e1000d: failed to open IRQ file");
|
||||
event_queue.add(irq_file.as_raw_fd(), move |_count: usize| -> Result<Option<()>> {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.read(&mut irq)?;
|
||||
if unsafe { device_irq.irq() } {
|
||||
irq_file.write(&mut irq)?;
|
||||
|
||||
let mut todo = todo_irq.borrow_mut();
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
let a = todo[i].a;
|
||||
device_irq.handle(&mut todo[i]);
|
||||
if todo[i].a == (-EWOULDBLOCK) as usize {
|
||||
todo[i].a = a;
|
||||
i += 1;
|
||||
} else {
|
||||
socket_irq.borrow_mut().write(&mut todo[i])?;
|
||||
todo.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
}).expect("e1000d: failed to catch events on IRQ file");
|
||||
|
||||
let socket_fd = socket.borrow().as_raw_fd();
|
||||
event_queue.add(socket_fd, move |_count: usize| -> Result<Option<()>> {
|
||||
let mut packet = Packet::default();
|
||||
socket.read(&mut packet).expect("e1000d: failed to read network scheme");
|
||||
socket.borrow_mut().read(&mut packet)?;
|
||||
|
||||
let a = packet.a;
|
||||
device.handle(&mut packet);
|
||||
socket.write(&mut packet).expect("e1000d: failed to read network scheme");
|
||||
}
|
||||
if packet.a == (-EWOULDBLOCK) as usize {
|
||||
packet.a = a;
|
||||
todo.borrow_mut().push(packet);
|
||||
} else {
|
||||
socket.borrow_mut().write(&mut packet)?;
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
}).expect("e1000d: failed to catch events on IRQ file");
|
||||
|
||||
event_queue.run().expect("e1000d: failed to handle events");
|
||||
}
|
||||
unsafe { let _ = physunmap(address); }
|
||||
unsafe { let _ = syscall::physunmap(address); }
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
[package]
|
||||
name = "io"
|
||||
version = "0.1.0"
|
|
@ -1,67 +0,0 @@
|
|||
use core::cmp::PartialEq;
|
||||
use core::ops::{BitAnd, BitOr, Not};
|
||||
|
||||
pub trait Io {
|
||||
type Value: Copy + PartialEq + BitAnd<Output = Self::Value> + BitOr<Output = Self::Value> + Not<Output = Self::Value>;
|
||||
|
||||
fn read(&self) -> Self::Value;
|
||||
fn write(&mut self, value: Self::Value);
|
||||
|
||||
#[inline(always)]
|
||||
fn readf(&self, flags: Self::Value) -> bool {
|
||||
(self.read() & flags) as Self::Value == flags
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn writef(&mut self, flags: Self::Value, value: bool) {
|
||||
let tmp: Self::Value = match value {
|
||||
true => self.read() | flags,
|
||||
false => self.read() & !flags,
|
||||
};
|
||||
self.write(tmp);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ReadOnly<I: Io> {
|
||||
inner: I
|
||||
}
|
||||
|
||||
impl<I: Io> ReadOnly<I> {
|
||||
pub const fn new(inner: I) -> ReadOnly<I> {
|
||||
ReadOnly {
|
||||
inner: inner
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn read(&self) -> I::Value {
|
||||
self.inner.read()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn readf(&self, flags: I::Value) -> bool {
|
||||
self.inner.readf(flags)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct WriteOnly<I: Io> {
|
||||
inner: I
|
||||
}
|
||||
|
||||
impl<I: Io> WriteOnly<I> {
|
||||
pub const fn new(inner: I) -> WriteOnly<I> {
|
||||
WriteOnly {
|
||||
inner: inner
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn write(&mut self, value: I::Value) {
|
||||
self.inner.write(value)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn writef(&mut self, flags: I::Value, value: bool) {
|
||||
self.inner.writef(flags, value)
|
||||
}
|
||||
}
|
|
@ -1,14 +0,0 @@
|
|||
//! I/O functions
|
||||
|
||||
#![feature(asm)]
|
||||
#![feature(const_fn)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![no_std]
|
||||
|
||||
pub use self::io::*;
|
||||
pub use self::mmio::*;
|
||||
pub use self::pio::*;
|
||||
|
||||
mod io;
|
||||
mod mmio;
|
||||
mod pio;
|
|
@ -1,31 +0,0 @@
|
|||
use core::intrinsics::{volatile_load, volatile_store};
|
||||
use core::mem::uninitialized;
|
||||
use core::ops::{BitAnd, BitOr, Not};
|
||||
|
||||
use super::io::Io;
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct Mmio<T> {
|
||||
value: T,
|
||||
}
|
||||
|
||||
impl<T> Mmio<T> {
|
||||
/// Create a new Mmio without initializing
|
||||
pub fn new() -> Self {
|
||||
Mmio {
|
||||
value: unsafe { uninitialized() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Io for Mmio<T> where T: Copy + PartialEq + BitAnd<Output = T> + BitOr<Output = T> + Not<Output = T> {
|
||||
type Value = T;
|
||||
|
||||
fn read(&self) -> T {
|
||||
unsafe { volatile_load(&self.value) }
|
||||
}
|
||||
|
||||
fn write(&mut self, value: T) {
|
||||
unsafe { volatile_store(&mut self.value, value) };
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
use core::marker::PhantomData;
|
||||
|
||||
use super::io::Io;
|
||||
|
||||
/// Generic PIO
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Pio<T> {
|
||||
port: u16,
|
||||
value: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> Pio<T> {
|
||||
/// Create a PIO from a given port
|
||||
pub const fn new(port: u16) -> Self {
|
||||
Pio::<T> {
|
||||
port: port,
|
||||
value: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read/Write for byte PIO
|
||||
impl Io for Pio<u8> {
|
||||
type Value = u8;
|
||||
|
||||
/// Read
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u8 {
|
||||
let value: u8;
|
||||
unsafe {
|
||||
asm!("in $0, $1" : "={al}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
/// Write
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u8) {
|
||||
unsafe {
|
||||
asm!("out $1, $0" : : "{al}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read/Write for word PIO
|
||||
impl Io for Pio<u16> {
|
||||
type Value = u16;
|
||||
|
||||
/// Read
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u16 {
|
||||
let value: u16;
|
||||
unsafe {
|
||||
asm!("in $0, $1" : "={ax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
/// Write
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u16) {
|
||||
unsafe {
|
||||
asm!("out $1, $0" : : "{ax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Read/Write for doubleword PIO
|
||||
impl Io for Pio<u32> {
|
||||
type Value = u32;
|
||||
|
||||
/// Read
|
||||
#[inline(always)]
|
||||
fn read(&self) -> u32 {
|
||||
let value: u32;
|
||||
unsafe {
|
||||
asm!("in $0, $1" : "={eax}"(value) : "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
}
|
||||
value
|
||||
}
|
||||
|
||||
/// Write
|
||||
#[inline(always)]
|
||||
fn write(&mut self, value: u32) {
|
||||
unsafe {
|
||||
asm!("out $1, $0" : : "{eax}"(value), "{dx}"(self.port) : "memory" : "intel", "volatile");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,6 @@ version = "0.1.0"
|
|||
|
||||
[dependencies]
|
||||
bitflags = "*"
|
||||
io = { path = "../io/" }
|
||||
spin = "*"
|
||||
io = { path = "../../crates/io/" }
|
||||
orbclient = "0.1"
|
||||
syscall = { path = "../../syscall/" }
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::mem;
|
||||
use std::thread;
|
||||
|
||||
use orbclient::KeyEvent;
|
||||
|
||||
use keymap;
|
||||
|
||||
|
@ -9,7 +10,6 @@ pub fn keyboard() {
|
|||
let mut file = File::open("irq:1").expect("ps2d: failed to open irq:1");
|
||||
let mut input = File::open("display:input").expect("ps2d: failed to open display:input");
|
||||
|
||||
let mut ctrl = false;
|
||||
let mut lshift = false;
|
||||
let mut rshift = false;
|
||||
loop {
|
||||
|
@ -28,71 +28,17 @@ pub fn keyboard() {
|
|||
(data, true)
|
||||
};
|
||||
|
||||
if scancode == 0x1D {
|
||||
ctrl = pressed;
|
||||
} else if scancode == 0x2A {
|
||||
if scancode == 0x2A {
|
||||
lshift = pressed;
|
||||
} else if scancode == 0x36 {
|
||||
rshift = pressed;
|
||||
} else if pressed {
|
||||
match scancode {
|
||||
f @ 0x3B ... 0x44 => { // F1 through F10
|
||||
input.write(&[(f - 0x3B) + 0xF4]).unwrap();
|
||||
},
|
||||
0x57 => { // F11
|
||||
input.write(&[0xFE]).unwrap();
|
||||
},
|
||||
0x58 => { // F12
|
||||
input.write(&[0xFF]).unwrap();
|
||||
},
|
||||
0x47 => { // Home
|
||||
input.write(b"\x1B[H").unwrap();
|
||||
},
|
||||
0x48 => { // Up
|
||||
input.write(b"\x1B[A").unwrap();
|
||||
},
|
||||
0x49 => { // Page up
|
||||
input.write(b"\x1B[5~").unwrap();
|
||||
},
|
||||
0x4B => { // Left
|
||||
input.write(b"\x1B[D").unwrap();
|
||||
},
|
||||
0x4D => { // Right
|
||||
input.write(b"\x1B[C").unwrap();
|
||||
},
|
||||
0x4F => { // End
|
||||
input.write(b"\x1B[F").unwrap();
|
||||
},
|
||||
0x50 => { // Down
|
||||
input.write(b"\x1B[B").unwrap();
|
||||
},
|
||||
0x51 => { // Page down
|
||||
input.write(b"\x1B[6~").unwrap();
|
||||
},
|
||||
0x52 => { // Insert
|
||||
input.write(b"\x1B[2~").unwrap();
|
||||
},
|
||||
0x53 => { // Delete
|
||||
input.write(b"\x1B[3~").unwrap();
|
||||
},
|
||||
_ => {
|
||||
let c = if ctrl {
|
||||
match keymap::get_char(scancode, false) {
|
||||
c @ 'a' ... 'z' => ((c as u8 - b'a') + b'\x01') as char,
|
||||
c => c
|
||||
}
|
||||
} else {
|
||||
keymap::get_char(scancode, lshift || rshift)
|
||||
};
|
||||
|
||||
if c != '\0' {
|
||||
input.write(&[c as u8]).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thread::yield_now();
|
||||
|
||||
input.write(&KeyEvent {
|
||||
character: keymap::get_char(scancode, lshift || rshift),
|
||||
scancode: scancode,
|
||||
pressed: pressed
|
||||
}.to_event()).expect("ps2d: failed to write key event");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#[macro_use]
|
||||
extern crate bitflags;
|
||||
extern crate io;
|
||||
extern crate orbclient;
|
||||
extern crate syscall;
|
||||
|
||||
use std::thread;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::fs::File;
|
||||
use std::io::{Read, Write};
|
||||
use std::mem;
|
||||
use std::thread;
|
||||
|
||||
use orbclient::MouseEvent;
|
||||
|
||||
bitflags! {
|
||||
flags MousePacketFlags: u8 {
|
||||
|
@ -18,6 +19,7 @@ bitflags! {
|
|||
|
||||
pub fn mouse(extra_packet: bool) {
|
||||
let mut file = File::open("irq:12").expect("ps2d: failed to open irq:12");
|
||||
let mut input = File::open("display:input").expect("ps2d: failed to open display:input");
|
||||
|
||||
let mut packets = [0; 4];
|
||||
let mut packet_i = 0;
|
||||
|
@ -40,23 +42,29 @@ pub fn mouse(extra_packet: bool) {
|
|||
packet_i = 0;
|
||||
} else if packet_i >= packets.len() || (!extra_packet && packet_i >= 3) {
|
||||
if ! flags.contains(X_OVERFLOW) && ! flags.contains(Y_OVERFLOW) {
|
||||
let mut dx = packets[1] as isize;
|
||||
let mut dx = packets[1] as i32;
|
||||
if flags.contains(X_SIGN) {
|
||||
dx -= 0x100;
|
||||
}
|
||||
|
||||
let mut dy = packets[2] as isize;
|
||||
let mut dy = -(packets[2] as i32);
|
||||
if flags.contains(Y_SIGN) {
|
||||
dy -= 0x100;
|
||||
dy += 0x100;
|
||||
}
|
||||
|
||||
let extra = if extra_packet {
|
||||
let _extra = if extra_packet {
|
||||
packets[3]
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
print!("ps2d: IRQ {:?}, {}, {}, {}\n", flags, dx, dy, extra);
|
||||
input.write(&MouseEvent {
|
||||
x: dx,
|
||||
y: dy,
|
||||
left_button: flags.contains(LEFT_BUTTON),
|
||||
middle_button: flags.contains(MIDDLE_BUTTON),
|
||||
right_button: flags.contains(RIGHT_BUTTON)
|
||||
}.to_event()).expect("ps2d: failed to write mouse event");
|
||||
} else {
|
||||
println!("ps2d: overflow {:X} {:X} {:X} {:X}", packets[0], packets[1], packets[2], packets[3]);
|
||||
}
|
||||
|
@ -66,8 +74,6 @@ pub fn mouse(extra_packet: bool) {
|
|||
}
|
||||
|
||||
file.write(&irqs).expect("ps2d: failed to write irq:12");
|
||||
} else {
|
||||
thread::yield_now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ name = "vesad"
|
|||
version = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
orbclient = "0.1"
|
||||
ransid = { git = "https://github.com/redox-os/ransid.git", branch = "new_api" }
|
||||
rusttype = { git = "https://github.com/dylanede/rusttype.git", optional = true }
|
||||
syscall = { path = "../../syscall/" }
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#![feature(question_mark)]
|
||||
|
||||
extern crate alloc;
|
||||
extern crate orbclient;
|
||||
extern crate syscall;
|
||||
|
||||
use std::fs::File;
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::BTreeMap;
|
||||
use std::str;
|
||||
use std::{mem, slice, str};
|
||||
|
||||
use syscall::{Result, Error, EBADF, ENOENT, Scheme};
|
||||
use orbclient::{Event, EventOption};
|
||||
use syscall::{Result, Error, EACCES, EBADF, ENOENT, Scheme};
|
||||
|
||||
use display::Display;
|
||||
use screen::TextScreen;
|
||||
use screen::{Screen, GraphicScreen, TextScreen};
|
||||
|
||||
pub struct DisplayScheme {
|
||||
width: usize,
|
||||
height: usize,
|
||||
onscreen: usize,
|
||||
active: Cell<usize>,
|
||||
screens: RefCell<BTreeMap<usize, TextScreen>>
|
||||
screens: RefCell<BTreeMap<usize, Box<Screen>>>
|
||||
}
|
||||
|
||||
impl DisplayScheme {
|
||||
pub fn new(width: usize, height: usize, onscreen: usize) -> DisplayScheme {
|
||||
let mut screens = BTreeMap::new();
|
||||
for i in 1..7 {
|
||||
screens.insert(i, TextScreen::new(Display::new(width, height, onscreen)));
|
||||
}
|
||||
let mut screens: BTreeMap<usize, Box<Screen>> = BTreeMap::new();
|
||||
screens.insert(1, Box::new(TextScreen::new(Display::new(width, height, onscreen))));
|
||||
screens.insert(2, Box::new(GraphicScreen::new(Display::new(width, height, onscreen))));
|
||||
|
||||
DisplayScheme {
|
||||
width: width,
|
||||
|
@ -42,9 +42,13 @@ impl DisplayScheme {
|
|||
}
|
||||
|
||||
impl Scheme for DisplayScheme {
|
||||
fn open(&self, path: &[u8], _flags: usize, _uid: u32, _gid: u32) -> Result<usize> {
|
||||
fn open(&self, path: &[u8], _flags: usize, uid: u32, _gid: u32) -> Result<usize> {
|
||||
if path == b"input" {
|
||||
Ok(0)
|
||||
if uid == 0 {
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EACCES))
|
||||
}
|
||||
} else {
|
||||
let path_str = str::from_utf8(path).unwrap_or("");
|
||||
let id = path_str.parse::<usize>().unwrap_or(0);
|
||||
|
@ -63,9 +67,7 @@ impl Scheme for DisplayScheme {
|
|||
fn fevent(&self, id: usize, flags: usize) -> Result<usize> {
|
||||
let mut screens = self.screens.borrow_mut();
|
||||
if let Some(mut screen) = screens.get_mut(&id) {
|
||||
println!("fevent {:X}", flags);
|
||||
screen.requested = flags;
|
||||
Ok(0)
|
||||
screen.event(flags)
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
|
@ -76,7 +78,7 @@ impl Scheme for DisplayScheme {
|
|||
let path_str = if id == 0 {
|
||||
format!("display:input")
|
||||
} else if let Some(screen) = screens.get(&id) {
|
||||
format!("display:{}/{}/{}", id, screen.console.w, screen.console.h)
|
||||
format!("display:{}/{}/{}", id, screen.width(), screen.height())
|
||||
} else {
|
||||
return Err(Error::new(EBADF));
|
||||
};
|
||||
|
@ -124,11 +126,39 @@ impl Scheme for DisplayScheme {
|
|||
}
|
||||
Ok(1)
|
||||
} else {
|
||||
if let Some(mut screen) = screens.get_mut(&self.active.get()) {
|
||||
screen.input(buf)
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
let events = unsafe { slice::from_raw_parts(buf.as_ptr() as *const Event, buf.len()/mem::size_of::<Event>()) };
|
||||
|
||||
for event in events.iter() {
|
||||
let new_active_opt = if let EventOption::Key(key_event) = event.to_option() {
|
||||
match key_event.scancode {
|
||||
f @ 0x3B ... 0x44 => { // F1 through F10
|
||||
Some((f - 0x3A) as usize)
|
||||
},
|
||||
0x57 => { // F11
|
||||
Some(11)
|
||||
},
|
||||
0x58 => { // F12
|
||||
Some(12)
|
||||
},
|
||||
_ => None
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(new_active) = new_active_opt {
|
||||
if let Some(mut screen) = screens.get_mut(&new_active) {
|
||||
self.active.set(new_active);
|
||||
screen.redraw();
|
||||
}
|
||||
} else {
|
||||
if let Some(mut screen) = screens.get_mut(&self.active.get()) {
|
||||
screen.input(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(events.len() * mem::size_of::<Event>())
|
||||
}
|
||||
} else if let Some(mut screen) = screens.get_mut(&id) {
|
||||
screen.write(buf, id == self.active.get())
|
||||
|
@ -137,6 +167,15 @@ impl Scheme for DisplayScheme {
|
|||
}
|
||||
}
|
||||
|
||||
fn seek(&self, id: usize, pos: usize, whence: usize) -> Result<usize> {
|
||||
let mut screens = self.screens.borrow_mut();
|
||||
if let Some(mut screen) = screens.get_mut(&id) {
|
||||
screen.seek(pos, whence)
|
||||
} else {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
|
||||
fn close(&self, _id: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
|
|
@ -1 +1,118 @@
|
|||
pub struct GraphicScreen;
|
||||
use std::collections::VecDeque;
|
||||
use std::{cmp, mem, slice};
|
||||
|
||||
use orbclient::{Event, EventOption};
|
||||
use syscall::error::*;
|
||||
use syscall::flag::{SEEK_SET, SEEK_CUR, SEEK_END};
|
||||
|
||||
use display::Display;
|
||||
use primitive::fast_copy;
|
||||
use screen::Screen;
|
||||
|
||||
pub struct GraphicScreen {
|
||||
pub display: Display,
|
||||
pub seek: usize,
|
||||
pub mouse_x: i32,
|
||||
pub mouse_y: i32,
|
||||
pub input: VecDeque<Event>,
|
||||
pub requested: usize
|
||||
}
|
||||
|
||||
impl GraphicScreen {
|
||||
pub fn new(display: Display) -> GraphicScreen {
|
||||
GraphicScreen {
|
||||
display: display,
|
||||
seek: 0,
|
||||
mouse_x: 0,
|
||||
mouse_y: 0,
|
||||
input: VecDeque::new(),
|
||||
requested: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Screen for GraphicScreen {
|
||||
fn width(&self) -> usize {
|
||||
self.display.width
|
||||
}
|
||||
|
||||
fn height(&self) -> usize {
|
||||
self.display.height
|
||||
}
|
||||
|
||||
fn event(&mut self, flags: usize) -> Result<usize> {
|
||||
self.requested = flags;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn input(&mut self, event: &Event) {
|
||||
if let EventOption::Mouse(mut mouse_event) = event.to_option() {
|
||||
let x = cmp::max(0, cmp::min(self.display.width as i32, self.mouse_x + mouse_event.x));
|
||||
let y = cmp::max(0, cmp::min(self.display.height as i32, self.mouse_y + mouse_event.y));
|
||||
|
||||
mouse_event.x = x;
|
||||
self.mouse_x = x;
|
||||
mouse_event.y = y;
|
||||
self.mouse_y = y;
|
||||
|
||||
self.input.push_back(mouse_event.to_event());
|
||||
} else {
|
||||
self.input.push_back(*event);
|
||||
}
|
||||
}
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
let mut i = 0;
|
||||
|
||||
let event_buf = unsafe { slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut Event, buf.len()/mem::size_of::<Event>()) };
|
||||
|
||||
while i < event_buf.len() && ! self.input.is_empty() {
|
||||
event_buf[i] = self.input.pop_front().unwrap();
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(i * mem::size_of::<Event>())
|
||||
}
|
||||
|
||||
fn will_block(&self) -> bool {
|
||||
self.input.is_empty()
|
||||
}
|
||||
|
||||
fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
|
||||
let size = cmp::max(0, cmp::min(self.display.offscreen.len() as isize - self.seek as isize, (buf.len()/4) as isize)) as usize;
|
||||
|
||||
if size > 0 {
|
||||
unsafe {
|
||||
fast_copy(self.display.offscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4);
|
||||
if sync {
|
||||
fast_copy(self.display.onscreen.as_mut_ptr().offset(self.seek as isize) as *mut u8, buf.as_ptr(), size * 4);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(size * 4)
|
||||
}
|
||||
|
||||
fn seek(&mut self, pos: usize, whence: usize) -> Result<usize> {
|
||||
let size = self.display.offscreen.len();
|
||||
|
||||
self.seek = match whence {
|
||||
SEEK_SET => cmp::min(size, (pos/4)),
|
||||
SEEK_CUR => cmp::max(0, cmp::min(size as isize, self.seek as isize + (pos/4) as isize)) as usize,
|
||||
SEEK_END => cmp::max(0, cmp::min(size as isize, size as isize + (pos/4) as isize)) as usize,
|
||||
_ => return Err(Error::new(EINVAL))
|
||||
};
|
||||
|
||||
Ok(self.seek * 4)
|
||||
}
|
||||
|
||||
fn sync(&mut self) {
|
||||
self.redraw();
|
||||
}
|
||||
|
||||
fn redraw(&mut self) {
|
||||
let width = self.display.width;
|
||||
let height = self.display.height;
|
||||
self.display.sync(0, 0, width, height);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,30 @@
|
|||
pub use self::graphic::GraphicScreen;
|
||||
pub use self::text::TextScreen;
|
||||
|
||||
use orbclient::Event;
|
||||
use syscall::Result;
|
||||
|
||||
mod graphic;
|
||||
mod text;
|
||||
|
||||
pub enum Screen {
|
||||
Graphic(GraphicScreen),
|
||||
Text(TextScreen)
|
||||
pub trait Screen {
|
||||
fn width(&self) -> usize;
|
||||
|
||||
fn height(&self) -> usize;
|
||||
|
||||
fn event(&mut self, flags: usize) -> Result<usize>;
|
||||
|
||||
fn input(&mut self, event: &Event);
|
||||
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
|
||||
|
||||
fn will_block(&self) -> bool;
|
||||
|
||||
fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize>;
|
||||
|
||||
fn seek(&mut self, pos: usize, whence: usize) -> Result<usize>;
|
||||
|
||||
fn sync(&mut self);
|
||||
|
||||
fn redraw(&mut self);
|
||||
}
|
||||
|
|
|
@ -2,15 +2,17 @@ extern crate ransid;
|
|||
|
||||
use std::collections::{BTreeSet, VecDeque};
|
||||
|
||||
use self::ransid::{Console, Event};
|
||||
use orbclient::{Event, EventOption};
|
||||
use syscall::Result;
|
||||
|
||||
use display::Display;
|
||||
use screen::Screen;
|
||||
|
||||
pub struct TextScreen {
|
||||
pub console: Console,
|
||||
pub console: ransid::Console,
|
||||
pub display: Display,
|
||||
pub changed: BTreeSet<usize>,
|
||||
pub ctrl: bool,
|
||||
pub input: VecDeque<u8>,
|
||||
pub end_of_input: bool,
|
||||
pub cooked: VecDeque<u8>,
|
||||
|
@ -20,17 +22,88 @@ pub struct TextScreen {
|
|||
impl TextScreen {
|
||||
pub fn new(display: Display) -> TextScreen {
|
||||
TextScreen {
|
||||
console: Console::new(display.width/8, display.height/16),
|
||||
console: ransid::Console::new(display.width/8, display.height/16),
|
||||
display: display,
|
||||
changed: BTreeSet::new(),
|
||||
ctrl: false,
|
||||
input: VecDeque::new(),
|
||||
end_of_input: false,
|
||||
cooked: VecDeque::new(),
|
||||
requested: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Screen for TextScreen {
|
||||
fn width(&self) -> usize {
|
||||
self.console.w
|
||||
}
|
||||
|
||||
fn height(&self) -> usize {
|
||||
self.console.h
|
||||
}
|
||||
|
||||
fn event(&mut self, flags: usize) -> Result<usize> {
|
||||
self.requested = flags;
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn input(&mut self, event: &Event) {
|
||||
let mut buf = vec![];
|
||||
|
||||
match event.to_option() {
|
||||
EventOption::Key(key_event) => {
|
||||
if key_event.scancode == 0x1D {
|
||||
self.ctrl = key_event.pressed;
|
||||
} else if key_event.pressed {
|
||||
match key_event.scancode {
|
||||
0x47 => { // Home
|
||||
buf.extend_from_slice(b"\x1B[H");
|
||||
},
|
||||
0x48 => { // Up
|
||||
buf.extend_from_slice(b"\x1B[A");
|
||||
},
|
||||
0x49 => { // Page up
|
||||
buf.extend_from_slice(b"\x1B[5~");
|
||||
},
|
||||
0x4B => { // Left
|
||||
buf.extend_from_slice(b"\x1B[D");
|
||||
},
|
||||
0x4D => { // Right
|
||||
buf.extend_from_slice(b"\x1B[C");
|
||||
},
|
||||
0x4F => { // End
|
||||
buf.extend_from_slice(b"\x1B[F");
|
||||
},
|
||||
0x50 => { // Down
|
||||
buf.extend_from_slice(b"\x1B[B");
|
||||
},
|
||||
0x51 => { // Page down
|
||||
buf.extend_from_slice(b"\x1B[6~");
|
||||
},
|
||||
0x52 => { // Insert
|
||||
buf.extend_from_slice(b"\x1B[2~");
|
||||
},
|
||||
0x53 => { // Delete
|
||||
buf.extend_from_slice(b"\x1B[3~");
|
||||
},
|
||||
_ => {
|
||||
let c = match key_event.character {
|
||||
c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
|
||||
c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
|
||||
c => c
|
||||
};
|
||||
|
||||
if c != '\0' {
|
||||
buf.extend_from_slice(&[c as u8]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
_ => () //TODO: Mouse in terminal
|
||||
}
|
||||
|
||||
pub fn input(&mut self, buf: &[u8]) -> Result<usize> {
|
||||
if self.console.raw_mode {
|
||||
for &b in buf.iter() {
|
||||
self.input.push_back(b);
|
||||
|
@ -40,11 +113,11 @@ impl TextScreen {
|
|||
match b {
|
||||
b'\x03' => {
|
||||
self.end_of_input = true;
|
||||
self.write(b"^C\n", true)?;
|
||||
let _ = self.write(b"^C\n", true);
|
||||
},
|
||||
b'\x08' | b'\x7F' => {
|
||||
if let Some(_c) = self.cooked.pop_back() {
|
||||
self.write(b"\x08", true)?;
|
||||
let _ = self.write(b"\x08", true);
|
||||
}
|
||||
},
|
||||
b'\n' | b'\r' => {
|
||||
|
@ -52,19 +125,18 @@ impl TextScreen {
|
|||
while let Some(c) = self.cooked.pop_front() {
|
||||
self.input.push_back(c);
|
||||
}
|
||||
self.write(b"\n", true)?;
|
||||
let _ = self.write(b"\n", true);
|
||||
},
|
||||
_ => {
|
||||
self.cooked.push_back(b);
|
||||
self.write(&[b], true)?;
|
||||
let _ = self.write(&[b], true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
pub fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
|
||||
let mut i = 0;
|
||||
|
||||
while i < buf.len() && ! self.input.is_empty() {
|
||||
|
@ -79,11 +151,11 @@ impl TextScreen {
|
|||
Ok(i)
|
||||
}
|
||||
|
||||
pub fn will_block(&self) -> bool {
|
||||
fn will_block(&self) -> bool {
|
||||
self.input.is_empty() && ! self.end_of_input
|
||||
}
|
||||
|
||||
pub fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
|
||||
fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
|
||||
if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
|
||||
let x = self.console.x;
|
||||
let y = self.console.y;
|
||||
|
@ -97,17 +169,17 @@ impl TextScreen {
|
|||
let changed = &mut self.changed;
|
||||
self.console.write(buf, |event| {
|
||||
match event {
|
||||
Event::Char { x, y, c, color, bold, .. } => {
|
||||
ransid::Event::Char { x, y, c, color, bold, .. } => {
|
||||
display.char(x * 8, y * 16, c, color.data, bold, false);
|
||||
changed.insert(y);
|
||||
},
|
||||
Event::Rect { x, y, w, h, color } => {
|
||||
ransid::Event::Rect { x, y, w, h, color } => {
|
||||
display.rect(x * 8, y * 16, w * 8, h * 16, color.data);
|
||||
for y2 in y..y + h {
|
||||
changed.insert(y2);
|
||||
}
|
||||
},
|
||||
Event::Scroll { rows, color } => {
|
||||
ransid::Event::Scroll { rows, color } => {
|
||||
display.scroll(rows * 16, color.data);
|
||||
for y in 0..display.height/16 {
|
||||
changed.insert(y);
|
||||
|
@ -132,7 +204,11 @@ impl TextScreen {
|
|||
Ok(buf.len())
|
||||
}
|
||||
|
||||
pub fn sync(&mut self) {
|
||||
fn seek(&mut self, pos: usize, whence: usize) -> Result<usize> {
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn sync(&mut self) {
|
||||
let width = self.display.width;
|
||||
for change in self.changed.iter() {
|
||||
self.display.sync(0, change * 16, width, 16);
|
||||
|
@ -140,7 +216,7 @@ impl TextScreen {
|
|||
self.changed.clear();
|
||||
}
|
||||
|
||||
pub fn redraw(&mut self) {
|
||||
fn redraw(&mut self) {
|
||||
let width = self.display.width;
|
||||
let height = self.display.height;
|
||||
self.display.sync(0, 0, width, height);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue