You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

228 lines
6.6 KiB

use alloc::boxed::Box;
use alloc::string::String;
use alloc::sync::Arc;
use alloc::vec;
use core::fmt;
use core::mem::size_of;
use core::mem::transmute_copy;
use core::slice;
use bitflags::*;
use device_tree::util::SliceRead;
use device_tree::Node;
use log::*;
use rcore_memory::paging::PageTable;
use rcore_memory::PAGE_SIZE;
use volatile::Volatile;
use crate::arch::cpu;
use crate::sync::SpinNoIrqLock as Mutex;
use super::super::bus::virtio_mmio::*;
use super::super::{DeviceType, Driver, DRIVERS};
use crate::memory::phys_to_virt;
struct VirtIOInput {
interrupt_parent: u32,
interrupt: u32,
header: &'static mut VirtIOHeader,
// 0 for event, 1 for status
queues: [VirtIOVirtqueue; 2],
x: isize,
y: isize,
}
const VIRTIO_INPUT_CFG_UNSET: u8 = 0x00;
const VIRTIO_INPUT_CFG_ID_NAME: u8 = 0x01;
const VIRTIO_INPUT_CFG_ID_SERIAL: u8 = 0x02;
const VIRTIO_INPUT_CFG_ID_DEVIDS: u8 = 0x03;
const VIRTIO_INPUT_CFG_PROP_BITS: u8 = 0x10;
const VIRTIO_INPUT_CFG_EV_BITS: u8 = 0x11;
const VIRTIO_INPUT_CFG_ABS_INFO: u8 = 0x12;
#[repr(C)]
#[derive(Debug)]
struct VirtIOInputConfig {
select: Volatile<u8>,
subsel: Volatile<u8>,
size: u8,
reversed: [u8; 5],
data: [u8; 32],
}
#[repr(C)]
#[derive(Debug)]
struct VirtIOInputAbsInfo {
min: u32,
max: u32,
fuzz: u32,
flat: u32,
res: u32,
}
#[repr(C)]
#[derive(Debug)]
struct VirtIOInputDevIDs {
bustype: u16,
vendor: u16,
product: u16,
version: u16,
}
#[repr(C)]
#[derive(Clone, Default)]
struct VirtIOInputEvent {
event_type: u16,
code: u16,
value: u32,
}
impl fmt::Display for VirtIOInputEvent {
// linux event codes
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.event_type {
0 => match self.code {
0 => write!(f, "SYN_REPORT"),
_ => write!(f, "Unknown SYN code {}", self.code),
},
2 => match self.code {
0 => write!(f, "REL_X {}", self.value),
1 => write!(f, "REL_Y {}", self.value),
_ => write!(f, "Unknown REL code {}", self.code),
},
_ => write!(f, "Unknown event type {}", self.event_type),
}
}
}
bitflags! {
struct VirtIOInputFeature : u64 {
// device independent
const NOTIFY_ON_EMPTY = 1 << 24; // legacy
const ANY_LAYOUT = 1 << 27; // legacy
const RING_INDIRECT_DESC = 1 << 28;
const RING_EVENT_IDX = 1 << 29;
const UNUSED = 1 << 30; // legacy
const VERSION_1 = 1 << 32; // detect legacy
const ACCESS_PLATFORM = 1 << 33; // since virtio v1.1
const RING_PACKED = 1 << 34; // since virtio v1.1
const IN_ORDER = 1 << 35; // since virtio v1.1
const ORDER_PLATFORM = 1 << 36; // since virtio v1.1
const SR_IOV = 1 << 37; // since virtio v1.1
const NOTIFICATION_DATA = 1 << 38; // since virtio v1.1
}
}
const VIRTIO_QUEUE_EVENT: usize = 0;
const VIRTIO_QUEUE_STATUS: usize = 1;
pub struct VirtIOInputDriver(Mutex<VirtIOInput>);
impl VirtIOInput {
fn try_handle_interrupt(&mut self, _irq: Option<u32>) -> bool {
// for simplicity
if cpu::id() > 0 {
return false;
}
let interrupt = self.header.interrupt_status.read();
if interrupt != 0 {
self.header.interrupt_ack.write(interrupt);
debug!("Got interrupt {:?}", interrupt);
loop {
if let Some((input, output, _, _)) = self.queues[VIRTIO_QUEUE_EVENT].get() {
let event: VirtIOInputEvent = unsafe { transmute_copy(&input[0][0]) };
if event.event_type == 2 && event.code == 0 {
// X
self.x += event.value as isize;
} else if event.event_type == 2 && event.code == 1 {
// X
self.y += event.value as isize;
}
trace!("got {}", event);
self.queues[VIRTIO_QUEUE_EVENT].add(&input, &output, 0);
} else {
break;
}
}
println!("mouse is at x {} y {}", self.x, self.y);
return true;
}
return false;
}
}
impl Driver for VirtIOInputDriver {
fn try_handle_interrupt(&self, irq: Option<u32>) -> bool {
self.0.lock().try_handle_interrupt(irq)
}
fn device_type(&self) -> DeviceType {
DeviceType::Input
}
fn get_id(&self) -> String {
String::from("virtio_input")
}
}
pub fn virtio_input_init(node: &Node) {
let reg = node.prop_raw("reg").unwrap();
let paddr = reg.as_slice().read_be_u64(0).unwrap();
let vaddr = phys_to_virt(paddr as usize);
let header = unsafe { &mut *(vaddr as *mut VirtIOHeader) };
header.status.write(VirtIODeviceStatus::DRIVER.bits());
let device_features_bits = header.read_device_features();
let device_features = VirtIOInputFeature::from_bits_truncate(device_features_bits);
println!("Device features {:?}", device_features);
// negotiate these flags only
let supported_features = VirtIOInputFeature::empty();
let driver_features = (device_features & supported_features).bits();
header.write_driver_features(driver_features);
// read configuration space
let config = unsafe { &mut *((vaddr + VIRTIO_CONFIG_SPACE_OFFSET) as *mut VirtIOInputConfig) };
info!("Config: {:?}", config);
// virtio 4.2.4 Legacy interface
// configure two virtqueues: ingress and egress
header.guest_page_size.write(PAGE_SIZE as u32); // one page
let queue_num = 32;
let queues = [
VirtIOVirtqueue::new(header, VIRTIO_QUEUE_EVENT, queue_num),
VirtIOVirtqueue::new(header, VIRTIO_QUEUE_STATUS, queue_num),
];
let mut driver = VirtIOInput {
interrupt: node.prop_u32("interrupts").unwrap(),
interrupt_parent: node.prop_u32("interrupt-parent").unwrap(),
header,
queues,
x: 0,
y: 0,
};
let buffer = vec![VirtIOInputEvent::default(); queue_num];
let input_buffers: &mut [VirtIOInputEvent] = Box::leak(buffer.into_boxed_slice());
for i in 0..queue_num {
let buffer = unsafe {
slice::from_raw_parts(
(&input_buffers[i]) as *const VirtIOInputEvent as *const u8,
size_of::<VirtIOInputEvent>(),
)
};
driver.queues[VIRTIO_QUEUE_EVENT].add(&[buffer], &[], 0);
}
driver
.header
.status
.write(VirtIODeviceStatus::DRIVER_OK.bits());
let driver = Arc::new(VirtIOInputDriver(Mutex::new(driver)));
DRIVERS.write().push(driver);
}