inputd: correctly pass on resize events
Signed-off-by: Anhad Singh <andypython@protonmail.com>
This commit is contained in:
+2
-2
@@ -37,8 +37,8 @@ fn main() {
|
||||
print!("{}", format!(" - BGA {}x{}\n", bga.width(), bga.height()));
|
||||
|
||||
let mut scheme = BgaScheme {
|
||||
bga: bga,
|
||||
display: File::open("display/vesa:input").ok()
|
||||
bga,
|
||||
display: File::open("input:producer").ok()
|
||||
};
|
||||
|
||||
scheme.update_size();
|
||||
|
||||
+89
-18
@@ -1,6 +1,7 @@
|
||||
#![feature(iter_next_chunk)]
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::{Error, Read};
|
||||
use std::mem;
|
||||
|
||||
pub struct Handle(File);
|
||||
|
||||
@@ -19,33 +20,103 @@ impl Handle {
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq)]
|
||||
#[repr(u8)]
|
||||
pub enum CommandTy {
|
||||
enum CmdTy {
|
||||
Unknown = 0,
|
||||
|
||||
Activate,
|
||||
Deactivate,
|
||||
Resize,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
pub struct Command {
|
||||
pub ty: CommandTy,
|
||||
pub value: usize,
|
||||
impl From<u8> for CmdTy {
|
||||
fn from(value: u8) -> Self {
|
||||
match value {
|
||||
1 => CmdTy::Activate,
|
||||
2 => CmdTy::Deactivate,
|
||||
3 => CmdTy::Resize,
|
||||
_ => CmdTy::Unknown,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Command {
|
||||
pub fn new(ty: CommandTy, value: usize) -> Self {
|
||||
Self { ty, value }
|
||||
}
|
||||
pub enum Cmd {
|
||||
// TODO(andypython): #VT should really need to be a `u8`.
|
||||
Activate(usize /* #VT */),
|
||||
Deactivate(usize /* #VT */),
|
||||
Resize {
|
||||
// TODO(andypython): do we really need to pass the VT here?
|
||||
vt: usize,
|
||||
|
||||
/// ## Panics
|
||||
/// This function panics if the buffer is not `sizeof::<Command>()` bytes wide.
|
||||
pub fn parse<'a>(buffer: &'a [u8]) -> &'a Command {
|
||||
assert_eq!(buffer.len(), core::mem::size_of::<Command>());
|
||||
unsafe { &*(buffer.as_ptr() as *const Command) }
|
||||
}
|
||||
width: u32,
|
||||
height: u32,
|
||||
stride: u32,
|
||||
},
|
||||
}
|
||||
|
||||
pub fn into_bytes(self) -> [u8; mem::size_of::<Command>()] {
|
||||
unsafe { core::mem::transmute(self) }
|
||||
impl Cmd {
|
||||
fn ty(&self) -> CmdTy {
|
||||
match self {
|
||||
Cmd::Activate(_) => CmdTy::Activate,
|
||||
Cmd::Deactivate(_) => CmdTy::Deactivate,
|
||||
Cmd::Resize { .. } => CmdTy::Resize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn send_comand(file: &mut File, command: Cmd) -> Result<(), syscall::Error> {
|
||||
use std::os::fd::AsRawFd;
|
||||
|
||||
let mut result = vec![];
|
||||
result.push(command.ty() as u8);
|
||||
|
||||
match command {
|
||||
Cmd::Activate(vt) | Cmd::Deactivate(vt) => result.extend_from_slice(&vt.to_le_bytes()),
|
||||
Cmd::Resize {
|
||||
vt,
|
||||
width,
|
||||
height,
|
||||
stride,
|
||||
} => {
|
||||
result.extend_from_slice(&vt.to_le_bytes());
|
||||
result.extend(width.to_le_bytes());
|
||||
result.extend(height.to_le_bytes());
|
||||
result.extend(stride.to_le_bytes());
|
||||
}
|
||||
};
|
||||
|
||||
let written = syscall::write(file.as_raw_fd() as usize, &result)?;
|
||||
|
||||
// XXX: Ensure all of the data is written.
|
||||
assert_eq!(written, result.len());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn parse_command(buffer: &[u8]) -> Option<Cmd> {
|
||||
const U32_SIZE: usize = core::mem::size_of::<u32>();
|
||||
const USIZE_SIZE: usize = core::mem::size_of::<usize>();
|
||||
|
||||
let mut parser = buffer.iter().cloned();
|
||||
|
||||
let command = CmdTy::from(parser.next()?);
|
||||
let vt = usize::from_le_bytes(parser.next_chunk::<USIZE_SIZE>().ok()?);
|
||||
|
||||
match command {
|
||||
CmdTy::Activate => Some(Cmd::Activate(vt)),
|
||||
CmdTy::Deactivate => Some(Cmd::Deactivate(vt)),
|
||||
CmdTy::Resize => {
|
||||
let width = parser.next_chunk::<U32_SIZE>().ok()?;
|
||||
let height = parser.next_chunk::<U32_SIZE>().ok()?;
|
||||
let stride = parser.next_chunk::<U32_SIZE>().ok()?;
|
||||
|
||||
Some(Cmd::Resize {
|
||||
vt,
|
||||
width: u32::from_le_bytes(width),
|
||||
height: u32::from_le_bytes(height),
|
||||
stride: u32::from_le_bytes(stride),
|
||||
})
|
||||
}
|
||||
|
||||
CmdTy::Unknown => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+23
-13
@@ -13,11 +13,12 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Read, Write};
|
||||
use std::io::{Read, Write};
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
use inputd::{Command, CommandTy};
|
||||
use inputd::Cmd;
|
||||
|
||||
use orbclient::{Event, EventOption};
|
||||
use syscall::{Error as SysError, EventFlags, Packet, SchemeMut, EINVAL};
|
||||
|
||||
@@ -166,15 +167,25 @@ impl SchemeMut for InputScheme {
|
||||
_ => (),
|
||||
},
|
||||
|
||||
EventOption::Resize(resize_event) => {
|
||||
if let Some((_, file, current)) = self.active_vt.as_mut() {
|
||||
inputd::send_comand(
|
||||
file,
|
||||
Cmd::Resize {
|
||||
vt: current.clone(),
|
||||
width: resize_event.width,
|
||||
height: resize_event.height,
|
||||
|
||||
// TODO(andypython): Figure out how to get the stride.
|
||||
stride: resize_event.width,
|
||||
},
|
||||
)?;
|
||||
}
|
||||
}
|
||||
|
||||
_ => continue,
|
||||
}
|
||||
|
||||
let deactivate = |file: &mut File, id: usize| -> io::Result<()> {
|
||||
let command = Command::new(CommandTy::Deactivate, id).into_bytes();
|
||||
file.write(&command)?;
|
||||
Ok(())
|
||||
};
|
||||
|
||||
if let Some(new_active) = new_active_opt {
|
||||
if let Some(vt) = self.vts.get(&new_active).cloned() {
|
||||
if let Some((_, file, current)) = self.active_vt.as_mut() {
|
||||
@@ -183,20 +194,19 @@ impl SchemeMut for InputScheme {
|
||||
continue;
|
||||
}
|
||||
|
||||
deactivate(file, *current).unwrap();
|
||||
inputd::send_comand(file, Cmd::Deactivate(*current))?;
|
||||
} else {
|
||||
let id = self.next_vt_id.load(Ordering::SeqCst) - 1;
|
||||
let mut vt = File::open(self.vts.get_mut(&id).unwrap().as_ref()).unwrap();
|
||||
|
||||
deactivate(&mut vt, id).unwrap();
|
||||
inputd::send_comand(&mut vt, Cmd::Deactivate(id))?;
|
||||
}
|
||||
|
||||
log::info!("inputd: switching to VT #{new_active} (`{vt}`)");
|
||||
|
||||
let mut file = File::open(vt.as_ref()).unwrap();
|
||||
file.write(&Command::new(CommandTy::Activate, new_active).into_bytes())
|
||||
.unwrap();
|
||||
|
||||
inputd::send_comand(&mut file, Cmd::Activate(new_active))?;
|
||||
self.active_vt = Some((vt.clone(), file, new_active));
|
||||
} else {
|
||||
log::warn!("inputd: switch to non-existent VT #{new_active} was requested");
|
||||
@@ -294,7 +304,7 @@ fn deamon(deamon: redox_daemon::Daemon) -> anyhow::Result<()> {
|
||||
last_allocated == *vt
|
||||
};
|
||||
|
||||
// The activate VT is not the same as the VT that the consumer is listening to
|
||||
// The activate VT is not the same as the VT that the consumer is listening to
|
||||
// for events.
|
||||
if !should_notify {
|
||||
continue;
|
||||
|
||||
+1
-1
@@ -208,7 +208,7 @@ fn main() {
|
||||
|
||||
let mut width = 0;
|
||||
let mut height = 0;
|
||||
let mut display_opt = File::open("display/vesa:input").ok();
|
||||
let mut display_opt = File::open("inputd:producer").ok();
|
||||
if let Some(ref display) = display_opt {
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
if let Ok(count) = syscall::fpath(display.as_raw_fd() as usize, &mut buf) {
|
||||
|
||||
+13
-13
@@ -1,8 +1,7 @@
|
||||
use std::collections::BTreeMap;
|
||||
use std::{mem, ptr, slice, str};
|
||||
|
||||
use orbclient::{Event, EventOption};
|
||||
use syscall::{Error, EventFlags, EACCES, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE};
|
||||
use syscall::{Error, EventFlags, EBADF, EINVAL, ENOENT, Map, O_NONBLOCK, Result, SchemeMut, PAGE_SIZE};
|
||||
|
||||
use crate::{
|
||||
display::Display,
|
||||
@@ -37,7 +36,6 @@ pub struct DisplayScheme {
|
||||
pub vts: BTreeMap<VtIndex, BTreeMap<ScreenIndex, Box<dyn Screen>>>,
|
||||
next_id: usize,
|
||||
pub handles: BTreeMap<usize, Handle>,
|
||||
super_key: bool,
|
||||
inputd_handle: inputd::Handle,
|
||||
}
|
||||
|
||||
@@ -74,7 +72,6 @@ impl DisplayScheme {
|
||||
vts,
|
||||
next_id: 0,
|
||||
handles: BTreeMap::new(),
|
||||
super_key: false,
|
||||
inputd_handle
|
||||
}
|
||||
}
|
||||
@@ -306,11 +303,13 @@ impl SchemeMut for DisplayScheme {
|
||||
|
||||
match handle.kind {
|
||||
HandleKind::Input => {
|
||||
let command = inputd::Command::parse(buf);
|
||||
use inputd::Cmd as DisplayCommand;
|
||||
|
||||
let command = inputd::parse_command(buf).unwrap();
|
||||
|
||||
match command.ty {
|
||||
inputd::CommandTy::Activate => {
|
||||
let vt_i = VtIndex(command.value);
|
||||
match command {
|
||||
DisplayCommand::Activate(vt) => {
|
||||
let vt_i = VtIndex(vt);
|
||||
|
||||
if let Some(screens) = self.vts.get_mut(&vt_i) {
|
||||
for (screen_i, screen) in screens.iter_mut() {
|
||||
@@ -323,12 +322,13 @@ impl SchemeMut for DisplayScheme {
|
||||
|
||||
self.active = vt_i;
|
||||
},
|
||||
|
||||
inputd::CommandTy::Deactivate => {
|
||||
// Nothing :)
|
||||
},
|
||||
|
||||
_ => unreachable!()
|
||||
DisplayCommand::Resize { width, height, stride, .. } => {
|
||||
self.resize(width as usize, height as usize, stride as usize);
|
||||
}
|
||||
|
||||
// Nothing to do for deactivate :)
|
||||
DisplayCommand::Deactivate(_) => {},
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
|
||||
@@ -6,4 +6,4 @@ pub mod utils;
|
||||
|
||||
mod probe;
|
||||
|
||||
pub use probe::{probe_device, Device, MSIX_PRIMARY_VECTOR, reinit};
|
||||
pub use probe::{probe_device, reinit, Device, MSIX_PRIMARY_VECTOR};
|
||||
|
||||
@@ -11,7 +11,7 @@ use pcid_interface::*;
|
||||
use syscall::Io;
|
||||
|
||||
use crate::spec::*;
|
||||
use crate::transport::{Error, StandardTransport, Queue};
|
||||
use crate::transport::{Error, Queue, StandardTransport};
|
||||
use crate::utils::{align_down, VolatileCell};
|
||||
|
||||
pub struct Device<'a> {
|
||||
@@ -190,7 +190,12 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result<Device<'a>
|
||||
|
||||
let size = offset + capability.length as usize;
|
||||
|
||||
let addr = common::physmap(aligned_addr, size, common::Prot::RW, common::MemoryType::Uncacheable)? as usize;
|
||||
let addr = common::physmap(
|
||||
aligned_addr,
|
||||
size,
|
||||
common::Prot::RW,
|
||||
common::MemoryType::Uncacheable,
|
||||
)? as usize;
|
||||
|
||||
addr + offset
|
||||
};
|
||||
@@ -262,12 +267,12 @@ pub fn probe_device<'a>(pcid_handle: &mut PcidServerHandle) -> Result<Device<'a>
|
||||
};
|
||||
|
||||
device.transport.reset();
|
||||
reinit(& device)?;
|
||||
reinit(&device)?;
|
||||
|
||||
Ok(device)
|
||||
}
|
||||
|
||||
pub fn reinit<'a>(device: & Device<'a>) -> Result<(), Error> {
|
||||
pub fn reinit<'a>(device: &Device<'a>) -> Result<(), Error> {
|
||||
// XXX: According to the virtio specification v1.2, setting the ACKNOWLEDGE and DRIVER bits
|
||||
// in `device_status` is required to be done in two steps.
|
||||
let mut common = device.transport.common.lock().unwrap();
|
||||
@@ -280,7 +285,5 @@ pub fn reinit<'a>(device: & Device<'a>) -> Result<(), Error> {
|
||||
let old = common.device_status.get();
|
||||
common.device_status.set(old | DeviceStatusFlags::DRIVER);
|
||||
|
||||
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -161,7 +161,7 @@ impl<'a> Queue<'a> {
|
||||
descriptor_stack,
|
||||
used_head: AtomicU16::new(0),
|
||||
sref: sref.clone(),
|
||||
vector
|
||||
vector,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ impl<'a> Queue<'a> {
|
||||
|
||||
// Drain all of the available descriptors.
|
||||
while let Some(_) = self.descriptor_stack.pop() {}
|
||||
|
||||
|
||||
// Refill the descriptor stack.
|
||||
(0..self.descriptor.len() as u16).for_each(|i| self.descriptor_stack.push(i));
|
||||
}
|
||||
@@ -244,9 +244,9 @@ impl<'a> Available<'a> {
|
||||
let size = size.next_multiple_of(syscall::PAGE_SIZE); // align to page size
|
||||
|
||||
let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?;
|
||||
let virt = unsafe {
|
||||
common::physmap(addr, size, common::Prot::RW, common::MemoryType::default())
|
||||
}.map_err(Error::SyscallError)?;
|
||||
let virt =
|
||||
unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) }
|
||||
.map_err(Error::SyscallError)?;
|
||||
|
||||
let ring = unsafe { &mut *(virt as *mut AvailableRing) };
|
||||
|
||||
@@ -312,7 +312,8 @@ impl<'a> Used<'a> {
|
||||
|
||||
let addr = unsafe { syscall::physalloc(size) }.map_err(Error::SyscallError)?;
|
||||
let virt =
|
||||
unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) }.map_err(Error::SyscallError)?;
|
||||
unsafe { common::physmap(addr, size, common::Prot::RW, common::MemoryType::default()) }
|
||||
.map_err(Error::SyscallError)?;
|
||||
|
||||
let ring = unsafe { &mut *(virt as *mut UsedRing) };
|
||||
|
||||
@@ -493,7 +494,14 @@ impl<'a> StandardTransport<'a> {
|
||||
|
||||
log::info!("virtio-core: enabled queue #{queue_index} (size={queue_size})");
|
||||
|
||||
let queue = Queue::new(descriptor, avail, used, notification_bell, queue_index, vector);
|
||||
let queue = Queue::new(
|
||||
descriptor,
|
||||
avail,
|
||||
used,
|
||||
notification_bell,
|
||||
queue_index,
|
||||
vector,
|
||||
);
|
||||
|
||||
let queue_copy = queue.clone();
|
||||
let irq_fd = irq_handle.as_raw_fd();
|
||||
|
||||
@@ -30,7 +30,7 @@ use std::sync::Arc;
|
||||
use pcid_interface::PcidServerHandle;
|
||||
|
||||
use syscall::{Packet, SchemeMut};
|
||||
use virtio_core::transport::{Queue, self};
|
||||
use virtio_core::transport::{self, Queue};
|
||||
use virtio_core::utils::VolatileCell;
|
||||
use virtio_core::MSIX_PRIMARY_VECTOR;
|
||||
|
||||
|
||||
+24
-18
@@ -6,7 +6,7 @@ use std::sync::Arc;
|
||||
use inputd::Damage;
|
||||
|
||||
use common::dma::Dma;
|
||||
use syscall::{Error as SysError, SchemeMut, EINVAL, EAGAIN};
|
||||
use syscall::{Error as SysError, SchemeMut, EAGAIN, EINVAL};
|
||||
|
||||
use virtio_core::spec::{Buffer, ChainBuilder, DescriptorFlags};
|
||||
use virtio_core::transport::{Error, Queue, StandardTransport};
|
||||
@@ -117,8 +117,8 @@ impl<'a> Display<'a> {
|
||||
.next_multiple_of(syscall::PAGE_SIZE);
|
||||
|
||||
let mapped = *self.mapped.get().unwrap();
|
||||
let address = unsafe {syscall::virttophys(mapped)}?;
|
||||
|
||||
let address = unsafe { syscall::virttophys(mapped) }?;
|
||||
|
||||
self.map_screen_with(0, address, fb_size, mapped).await
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@ impl<'a> Display<'a> {
|
||||
let bpp = 32;
|
||||
let fb_size = (self.width as usize * self.height as usize * bpp / 8)
|
||||
.next_multiple_of(syscall::PAGE_SIZE);
|
||||
let address = unsafe { syscall::physalloc(fb_size) }? ;
|
||||
let address = unsafe { syscall::physalloc(fb_size) }?;
|
||||
let mapped = unsafe {
|
||||
common::physmap(
|
||||
address as usize,
|
||||
@@ -147,7 +147,13 @@ impl<'a> Display<'a> {
|
||||
self.map_screen_with(offset, address, fb_size, mapped).await
|
||||
}
|
||||
|
||||
async fn map_screen_with(&self, offset: usize, address: usize, size: usize, mapped: usize) -> Result<usize, Error> {
|
||||
async fn map_screen_with(
|
||||
&self,
|
||||
offset: usize,
|
||||
address: usize,
|
||||
size: usize,
|
||||
mapped: usize,
|
||||
) -> Result<usize, Error> {
|
||||
// Create a host resource using `VIRTIO_GPU_CMD_RESOURCE_CREATE_2D`.
|
||||
let mut request = Dma::new(ResourceCreate2d::default())?;
|
||||
|
||||
@@ -158,10 +164,10 @@ impl<'a> Display<'a> {
|
||||
|
||||
self.send_request(request).await?;
|
||||
|
||||
// Use the allocated framebuffer from tthe guest ram, and attach it as backing
|
||||
// storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`.
|
||||
// Use the allocated framebuffer from tthe guest ram, and attach it as backing
|
||||
// storage to the resource just created, using `VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING`.
|
||||
//
|
||||
// TODO(andypython): Scatter lists are supported, so the framebuffer doesn’t need to be
|
||||
// TODO(andypython): Scatter lists are supported, so the framebuffer doesn’t need to be
|
||||
// contignous in guest physical memory.
|
||||
let entry = Dma::new(MemEntry {
|
||||
address: address as u64,
|
||||
@@ -421,7 +427,7 @@ impl<'a> SchemeMut for Scheme<'a> {
|
||||
Handle::Vt(id) => {
|
||||
let handle = self.vts.get_mut(&id).ok_or(SysError::new(EINVAL))?;
|
||||
|
||||
// The VT is not active and the device is reseted. Ask them to try
|
||||
// The VT is not active and the device is reseted. Ask them to try
|
||||
// again later.
|
||||
if handle.is_reseted.load(Ordering::SeqCst) {
|
||||
return Err(SysError::new(EAGAIN));
|
||||
@@ -442,24 +448,24 @@ impl<'a> SchemeMut for Scheme<'a> {
|
||||
}
|
||||
|
||||
Handle::Input => {
|
||||
let command = inputd::Command::parse(buf);
|
||||
use inputd::Cmd as DisplayCommand;
|
||||
|
||||
match command.ty {
|
||||
inputd::CommandTy::Activate => {
|
||||
let vt = command.value;
|
||||
let command = inputd::parse_command(buf).unwrap();
|
||||
|
||||
match command {
|
||||
DisplayCommand::Activate(vt) => {
|
||||
let display = self.vts.get(&vt).unwrap();
|
||||
futures::executor::block_on(display.init()).unwrap();
|
||||
},
|
||||
|
||||
inputd::CommandTy::Deactivate => {
|
||||
let vt = command.value;
|
||||
}
|
||||
|
||||
DisplayCommand::Deactivate(vt) => {
|
||||
let display = self.vts.get(&vt).ok_or(SysError::new(EINVAL))?;
|
||||
futures::executor::block_on(display.detach()).unwrap();
|
||||
}
|
||||
|
||||
_ => unreachable!(),
|
||||
DisplayCommand::Resize { .. } => {
|
||||
log::warn!("virtio-gpu: resize is not implemented yet")
|
||||
}
|
||||
}
|
||||
|
||||
Ok(buf.len())
|
||||
|
||||
Reference in New Issue
Block a user