Merge branch 'drm' into 'master'
Implement DRM ioctls for Redox See merge request redox-os/relibc!801
This commit is contained in:
@@ -27,12 +27,14 @@ impl winsize {
|
||||
}
|
||||
}
|
||||
|
||||
pub use self::sys::*;
|
||||
#[cfg(target_os = "linux")]
|
||||
pub use self::linux::*;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[path = "linux.rs"]
|
||||
pub mod sys;
|
||||
pub mod linux;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
#[path = "redox.rs"]
|
||||
pub mod sys;
|
||||
pub use self::redox::*;
|
||||
|
||||
#[cfg(target_os = "redox")]
|
||||
pub mod redox;
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
use core::slice;
|
||||
|
||||
use redox_ioctl::{IoctlData, drm::*};
|
||||
|
||||
use crate::{
|
||||
error::{Errno, Result},
|
||||
header::errno::EINVAL,
|
||||
platform::types::*,
|
||||
};
|
||||
|
||||
use super::IoctlBuffer;
|
||||
|
||||
const DRM_FORMAT_ARGB8888: u32 = 0x34325241; // 'AR24' fourcc code, for ARGB8888
|
||||
|
||||
fn id_index(id: u32) -> u32 {
|
||||
id & 0xFF
|
||||
}
|
||||
|
||||
fn conn_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 8)
|
||||
}
|
||||
|
||||
fn crtc_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 9)
|
||||
}
|
||||
|
||||
fn enc_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 10)
|
||||
}
|
||||
|
||||
fn fb_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 11)
|
||||
}
|
||||
|
||||
fn fb_handle_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 12)
|
||||
}
|
||||
|
||||
fn plane_id(i: u32) -> u32 {
|
||||
id_index(i) | (1 << 13)
|
||||
}
|
||||
|
||||
unsafe fn copy_array<T: Copy>(src: &[T], dst_ptr: *mut T, dst_len: usize) -> usize {
|
||||
let dst = slice::from_raw_parts_mut(dst_ptr, dst_len);
|
||||
dst.copy_from_slice(&src[..src.len().min(dst_len)]);
|
||||
src.len()
|
||||
}
|
||||
|
||||
struct Dev {
|
||||
fd: c_int,
|
||||
}
|
||||
|
||||
impl Dev {
|
||||
fn new(fd: c_int) -> Result<Self> {
|
||||
//TODO: check display scheme using fpath?
|
||||
Ok(Self { fd })
|
||||
}
|
||||
|
||||
unsafe fn call<T>(&self, payload: &mut T, func: u64) -> syscall::Result<usize> {
|
||||
let bytes = slice::from_raw_parts_mut(payload as *mut T as *mut u8, size_of::<T>());
|
||||
redox_rt::sys::sys_call(
|
||||
self.fd as usize,
|
||||
bytes,
|
||||
syscall::CallFlags::empty(),
|
||||
&[func],
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn read_write_ioctl<T: IoctlData>(
|
||||
&self,
|
||||
mut buf: IoctlBuffer,
|
||||
func: u64,
|
||||
) -> Result<c_int> {
|
||||
let mut data = buf.read::<T>()?;
|
||||
let mut wire = data.write();
|
||||
let res = redox_rt::sys::sys_call(
|
||||
self.fd as usize,
|
||||
&mut wire,
|
||||
syscall::CallFlags::empty(),
|
||||
&[func],
|
||||
)?;
|
||||
data.read_from(&wire);
|
||||
buf.write(data)?;
|
||||
Ok(res as c_int)
|
||||
}
|
||||
|
||||
unsafe fn write_ioctl<T: IoctlData>(&self, mut buf: IoctlBuffer, func: u64) -> Result<c_int> {
|
||||
let mut data = buf.read::<T>()?;
|
||||
let mut wire = data.write();
|
||||
let res = redox_rt::sys::sys_call(
|
||||
self.fd as usize,
|
||||
&mut wire,
|
||||
syscall::CallFlags::empty(),
|
||||
&[func],
|
||||
)?;
|
||||
Ok(res as c_int)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) unsafe fn ioctl(fd: c_int, func: u8, buf: IoctlBuffer) -> Result<c_int> {
|
||||
let dev = Dev::new(fd)?;
|
||||
match func {
|
||||
0x00 => dev.read_write_ioctl::<drm_version>(buf, VERSION),
|
||||
0x0C => dev.read_write_ioctl::<drm_get_cap>(buf, GET_CAP),
|
||||
0x0D => dev.write_ioctl::<drm_set_client_cap>(buf, SET_CLIENT_CAP),
|
||||
0xA0 => dev.read_write_ioctl::<drm_mode_card_res>(buf, MODE_CARD_RES),
|
||||
0xA1 => dev.read_write_ioctl::<drm_mode_crtc>(buf, MODE_GET_CRTC),
|
||||
0xA6 => dev.read_write_ioctl::<drm_mode_get_encoder>(buf, MODE_GET_ENCODER),
|
||||
0xA7 => dev.read_write_ioctl::<drm_mode_get_connector>(buf, MODE_GET_CONNECTOR),
|
||||
0xAD => dev.read_write_ioctl::<drm_mode_fb_cmd>(buf, MODE_GET_FB),
|
||||
0xB5 => dev.read_write_ioctl::<drm_mode_get_plane_res>(buf, MODE_GET_PLANE_RES),
|
||||
0xB6 => dev.read_write_ioctl::<drm_mode_get_plane>(buf, MODE_GET_PLANE),
|
||||
0xB9 => dev.read_write_ioctl::<drm_mode_obj_get_properties>(buf, MODE_OBJ_GET_PROPERTIES),
|
||||
0xCE => dev.read_write_ioctl::<drm_mode_fb_cmd2>(buf, MODE_GET_FB2),
|
||||
_ => {
|
||||
eprintln!("unimplemented DRM ioctl({}, 0x{:02x}, {:?})", fd, func, buf);
|
||||
Err(Errno(EINVAL))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
use core::{mem, slice};
|
||||
use core::{mem, ptr, slice};
|
||||
use redox_rt::proc::FdGuard;
|
||||
use syscall;
|
||||
|
||||
@@ -13,6 +13,8 @@ use crate::{
|
||||
|
||||
use super::winsize;
|
||||
|
||||
mod drm;
|
||||
|
||||
pub const TCGETS: c_ulong = 0x5401;
|
||||
pub const TCSETS: c_ulong = 0x5402;
|
||||
pub const TCSETSW: c_ulong = 0x5403;
|
||||
@@ -61,6 +63,47 @@ fn dup_write<T>(fd: c_int, name: &str, t: &T) -> Result<usize> {
|
||||
Ok(bytes / size)
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum IoctlBuffer {
|
||||
None,
|
||||
Read(*mut c_void, usize), // read (write to userspace)
|
||||
Write(*const c_void, usize), // write (read from userspace)
|
||||
ReadWrite(*mut c_void, usize),
|
||||
}
|
||||
|
||||
impl IoctlBuffer {
|
||||
unsafe fn read<T>(&self) -> Result<T> {
|
||||
let (ptr, size) = match *self {
|
||||
Self::Write(ptr, size) => (ptr, size),
|
||||
Self::ReadWrite(ptr, size) => (ptr as *const c_void, size),
|
||||
_ => {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
};
|
||||
if size == mem::size_of::<T>() {
|
||||
let value = unsafe { ptr::read(ptr as *const T) };
|
||||
Ok(value)
|
||||
} else {
|
||||
Err(Errno(EINVAL))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn write<T>(&mut self, value: T) -> Result<()> {
|
||||
let (ptr, size) = match *self {
|
||||
Self::Read(ptr, size) | Self::ReadWrite(ptr, size) => (ptr, size),
|
||||
_ => {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
};
|
||||
if size == mem::size_of::<T>() {
|
||||
unsafe { ptr::write(ptr as *mut T, value) };
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Errno(EINVAL))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Result<c_int> {
|
||||
match request {
|
||||
FIONBIO => {
|
||||
@@ -120,7 +163,25 @@ unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Result<c
|
||||
eprintln!("TODO: ioctl SIOCATMARK");
|
||||
}
|
||||
_ => {
|
||||
return Err(Errno(EINVAL));
|
||||
// See https://docs.kernel.org/userspace-api/ioctl/ioctl-decoding.html for details
|
||||
let dir = (request >> 30) & 0b11;
|
||||
let size = ((request >> 16) & 0x3FFF) as usize;
|
||||
let name = (((request >> 8) & 0xFF) as u8) as char;
|
||||
let func = (request & 0xFF) as u8;
|
||||
match name {
|
||||
'd' => {
|
||||
let buf = match dir {
|
||||
0b10 => IoctlBuffer::Read(out, size),
|
||||
0b01 => IoctlBuffer::Write(out, size),
|
||||
0b11 => IoctlBuffer::ReadWrite(out, size),
|
||||
_ => IoctlBuffer::None,
|
||||
};
|
||||
return drm::ioctl(fd, func, buf);
|
||||
}
|
||||
_ => {
|
||||
return Err(Errno(EINVAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(0)
|
||||
Reference in New Issue
Block a user