Merge branch 'drm6' into 'drm'
Move drm ioctl (de)serialization into a new redox-ioctl crate See merge request redox-os/relibc!810
This commit is contained in:
Generated
+9
-1
@@ -417,6 +417,14 @@ dependencies = [
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-ioctl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"drm-sys",
|
||||
"redox_syscall",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-path"
|
||||
version = "0.3.1"
|
||||
@@ -465,7 +473,6 @@ dependencies = [
|
||||
"chrono",
|
||||
"chrono-tz",
|
||||
"dlmalloc",
|
||||
"drm-sys",
|
||||
"generic-rt",
|
||||
"libc",
|
||||
"libm",
|
||||
@@ -478,6 +485,7 @@ dependencies = [
|
||||
"rand",
|
||||
"rand_jitter",
|
||||
"rand_xorshift",
|
||||
"redox-ioctl",
|
||||
"redox-path",
|
||||
"redox-rt",
|
||||
"redox_event",
|
||||
|
||||
+1
-1
@@ -62,13 +62,13 @@ features = ["c_api"]
|
||||
sc = "0.2.7"
|
||||
|
||||
[target.'cfg(target_os = "redox")'.dependencies]
|
||||
drm-sys = "0.8.0"
|
||||
redox_syscall = "0.5.13"
|
||||
redox-rt = { path = "redox-rt" }
|
||||
redox-path = "0.3"
|
||||
redox_event = { git = "https://gitlab.redox-os.org/redox-os/event.git", default-features = false, features = [
|
||||
"redox_syscall",
|
||||
] }
|
||||
redox-ioctl = { path = "redox-ioctl" }
|
||||
|
||||
[features]
|
||||
default = ["check_against_libc_crate"]
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "redox-ioctl"
|
||||
authors = ["bjorn3 <bjorn3_gh@protonmail.com>"]
|
||||
version = "0.1.0"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
description = "Ioctl definitions and (de)serialization for Redox"
|
||||
|
||||
[dependencies]
|
||||
drm-sys = "0.8.0"
|
||||
redox_syscall = "0.5.8"
|
||||
|
||||
[features]
|
||||
@@ -0,0 +1,172 @@
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
cmp,
|
||||
ffi::{c_char, c_int},
|
||||
iter, mem, slice,
|
||||
};
|
||||
|
||||
pub use drm_sys::{
|
||||
__kernel_size_t, drm_get_cap, drm_mode_card_res, drm_mode_crtc, drm_mode_fb_cmd,
|
||||
drm_mode_fb_cmd2, drm_mode_get_connector, drm_mode_get_encoder, drm_mode_get_plane,
|
||||
drm_mode_get_plane_res, drm_mode_modeinfo, drm_mode_obj_get_properties, drm_set_client_cap,
|
||||
drm_version,
|
||||
};
|
||||
|
||||
pub const VERSION: u64 = 0;
|
||||
define_ioctl_data! {
|
||||
struct drm_version, DrmVersion {
|
||||
version_major: c_int,
|
||||
version_minor: c_int,
|
||||
version_patchlevel: c_int,
|
||||
name_len: __kernel_size_t,
|
||||
name: *mut c_char [array<c_char, name_len>],
|
||||
date_len: __kernel_size_t,
|
||||
date: *mut c_char [array<c_char, date_len>],
|
||||
desc_len: __kernel_size_t,
|
||||
desc: *mut c_char [array<c_char, desc_len>],
|
||||
}
|
||||
}
|
||||
|
||||
pub const GET_CAP: u64 = 0x0C;
|
||||
pub use drm_sys::DRM_CAP_DUMB_BUFFER;
|
||||
define_ioctl_data! {
|
||||
struct drm_get_cap, DrmGetCap {
|
||||
capability: u64,
|
||||
value: u64,
|
||||
}
|
||||
}
|
||||
|
||||
pub const SET_CLIENT_CAP: u64 = 0x0D;
|
||||
pub use drm_sys::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT;
|
||||
define_ioctl_data! {
|
||||
struct drm_set_client_cap, DrmSetClientCap {
|
||||
capability: u64,
|
||||
value: u64,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_CARD_RES: u64 = 0xA0;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_card_res, DrmModeCardRes {
|
||||
fb_id_ptr: u64 [array<u32, count_fbs>],
|
||||
crtc_id_ptr: u64 [array<u32, count_crtcs>],
|
||||
connector_id_ptr: u64 [array<u32, count_connectors>],
|
||||
encoder_id_ptr: u64 [array<u32, count_encoders>],
|
||||
count_fbs: u32,
|
||||
count_crtcs: u32,
|
||||
count_connectors: u32,
|
||||
count_encoders: u32,
|
||||
min_width: u32,
|
||||
max_width: u32,
|
||||
min_height: u32,
|
||||
max_height: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_CRTC: u64 = 0xA1;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_crtc, DrmModeCrtc {
|
||||
set_connectors_ptr: u64,
|
||||
count_connectors: u32,
|
||||
crtc_id: u32,
|
||||
fb_id: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
gamma_size: u32,
|
||||
mode_valid: u32,
|
||||
mode: drm_mode_modeinfo,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_ENCODER: u64 = 0xA6;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_get_encoder, DrmModeGetEncoder {
|
||||
encoder_id: u32,
|
||||
encoder_type: u32,
|
||||
crtc_id: u32,
|
||||
possible_crtcs: u32,
|
||||
possible_clones: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_CONNECTOR: u64 = 0xA7;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_get_connector, DrmModeGetConnector {
|
||||
encoders_ptr: u64 [array<u32, count_encoders>],
|
||||
modes_ptr: u64 [array<drm_mode_modeinfo, count_modes>],
|
||||
props_ptr: u64 [array<u32, count_props>],
|
||||
prop_values_ptr: u64 [array<u64, count_props>],
|
||||
count_modes: u32,
|
||||
count_props: u32,
|
||||
count_encoders: u32,
|
||||
encoder_id: u32,
|
||||
connector_id: u32,
|
||||
connector_type: u32,
|
||||
connector_type_id: u32,
|
||||
connection: u32,
|
||||
mm_width: u32,
|
||||
mm_height: u32,
|
||||
subpixel: u32,
|
||||
pad: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_FB: u64 = 0xAD;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_fb_cmd, DrmModeFbCmd {
|
||||
fb_id: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
pitch: u32,
|
||||
bpp: u32,
|
||||
depth: u32,
|
||||
handle: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_PLANE_RES: u64 = 0xB5;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_get_plane_res, DrmModeGetPlaneRes {
|
||||
plane_id_ptr: u64 [array<u32, count_planes>],
|
||||
count_planes: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_PLANE: u64 = 0xB6;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_get_plane, DrmModeGetPlane {
|
||||
plane_id: u32,
|
||||
crtc_id: u32,
|
||||
fb_id: u32,
|
||||
possible_crtcs: u32,
|
||||
gamma_size: u32,
|
||||
count_format_types: u32,
|
||||
format_type_ptr: u64 [array<u32, count_format_types>],
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_OBJ_GET_PROPERTIES: u64 = 0xB9;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_obj_get_properties, DrmModeObjGetProperties {
|
||||
props_ptr: u64 [array<u32, count_props>],
|
||||
prop_values_ptr: u64 [array<u64, count_props>],
|
||||
count_props: u32,
|
||||
obj_id: u32,
|
||||
obj_type: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_FB2: u64 = 0xCE;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_fb_cmd2, DrmModeFbCmd2 {
|
||||
fb_id: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
pixel_format: u32,
|
||||
flags: u32,
|
||||
handles: [u32; 4],
|
||||
pitches: [u32; 4],
|
||||
offsets: [u32; 4],
|
||||
modifier: [u64; 4],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,169 @@
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub trait IoctlData {
|
||||
unsafe fn write(&self) -> Vec<u8>;
|
||||
unsafe fn read_from(&mut self, buf: &[u8]);
|
||||
}
|
||||
|
||||
macro_rules! define_ioctl_data {
|
||||
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||
$($rest:tt)*
|
||||
}) => {
|
||||
define_ioctl_data!(
|
||||
struct $ioctl_ty, $mem_ty { $($rest)* } => (), (), ()
|
||||
);
|
||||
};
|
||||
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||
$field:ident: $ty:ty,
|
||||
$($rest:tt)*
|
||||
} =>
|
||||
($($ioctl_fields:tt)*),
|
||||
($($counted_fields:tt)*),
|
||||
($($noncounted_fields:tt)*)
|
||||
) => {
|
||||
define_ioctl_data!(
|
||||
struct $ioctl_ty, $mem_ty { $($rest)* } =>
|
||||
($($ioctl_fields)* $field: $ty,),
|
||||
($($counted_fields)*),
|
||||
($($noncounted_fields)* $field: $ty,)
|
||||
);
|
||||
};
|
||||
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||
$field:ident: $ty:ty [array<$el:ty, $counted_by:ident>],
|
||||
$($rest:tt)*
|
||||
} =>
|
||||
($($ioctl_fields:tt)*),
|
||||
($($counted_fields:tt)*),
|
||||
($($noncounted_fields:tt)*)
|
||||
) => {
|
||||
define_ioctl_data!(
|
||||
struct $ioctl_ty, $mem_ty { $($rest)* } =>
|
||||
($($ioctl_fields)* $field: $ty,),
|
||||
($($counted_fields)* $field: $ty [array<$el, $counted_by>],),
|
||||
($($noncounted_fields)*)
|
||||
);
|
||||
};
|
||||
(struct $ioctl_ty:ident, $mem_ty:ident {} =>
|
||||
($($ioctl_field:ident: $ioctl_field_ty:ty,)*),
|
||||
($($counted_field:ident: $counted_ty:ty [array<$el:ty, $counted_by:ident>],)*),
|
||||
($($noncounted_field:ident: $noncounted_ty:ty,)*)
|
||||
) => {
|
||||
// FIXME check ioctl_ty doesn't have padding
|
||||
const _: $ioctl_ty = $ioctl_ty {
|
||||
$($ioctl_field: unsafe { mem::zeroed::<$ioctl_field_ty>() },)*
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ${concat(__, $mem_ty, Noncounted)} {
|
||||
$($noncounted_field: $noncounted_ty,)*
|
||||
}
|
||||
|
||||
pub struct $mem_ty<'a> {
|
||||
noncounted_fields: &'a mut ${concat(__, $mem_ty, Noncounted)},
|
||||
$($counted_field: &'a mut [$el],)*
|
||||
}
|
||||
|
||||
impl $crate::ioctl_data::IoctlData for $ioctl_ty {
|
||||
unsafe fn write(&self) -> Vec<u8> {
|
||||
let noncounted_fields = ${concat(__, $mem_ty, Noncounted)} {
|
||||
$($noncounted_field: self.$noncounted_field,)*
|
||||
};
|
||||
// FIXME use Vec::with_capacity
|
||||
let mut data = Vec::<u8>::new();
|
||||
data.extend_from_slice(&unsafe {
|
||||
mem::transmute::<
|
||||
${concat(__, $mem_ty, Noncounted)},
|
||||
[u8; size_of::<${concat(__, $mem_ty, Noncounted)}>()],
|
||||
>(noncounted_fields)
|
||||
});
|
||||
$(
|
||||
let size = self.$counted_by as usize * size_of::<$el>();
|
||||
if self.$counted_field as usize != 0 {
|
||||
let $counted_field = unsafe {
|
||||
slice::from_raw_parts(self.$counted_field as *const u8, size)
|
||||
};
|
||||
data.extend_from_slice(&$counted_field);
|
||||
} else {
|
||||
data.extend(iter::repeat(0u8).take(size));
|
||||
};
|
||||
|
||||
)*
|
||||
data
|
||||
}
|
||||
|
||||
unsafe fn read_from(&mut self, mut buf: &[u8]) {
|
||||
// FIXME be robust against malicious scheme implementations by returning an error
|
||||
// when the buf is the wrong size
|
||||
let noncounted_fields = buf.split_off(..size_of::<${concat(__, $mem_ty, Noncounted)}>()).unwrap();
|
||||
|
||||
$(
|
||||
let size = self.$counted_by as usize * size_of::<$el>();
|
||||
let $counted_field = buf.split_off(..size).unwrap();
|
||||
if self.$counted_field as usize != 0 {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self.$counted_field as *mut u8, size).copy_from_slice($counted_field);
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
assert!(buf.is_empty());
|
||||
|
||||
let noncounted_fields = unsafe { &*(noncounted_fields as *const _ as *const ${concat(__, $mem_ty, Noncounted)}) };
|
||||
$(self.$noncounted_field = noncounted_fields.$noncounted_field;)*
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $mem_ty<'a> {
|
||||
pub fn with(
|
||||
mut buf: &'a mut [u8],
|
||||
f: impl FnOnce($mem_ty<'a>) -> syscall::Result<usize>,
|
||||
) -> syscall::Result<usize> {
|
||||
let noncounted_fields = buf.split_off_mut(..size_of::<${concat(__, $mem_ty, Noncounted)}>())
|
||||
.ok_or(syscall::Error::new(syscall::EINVAL))?;
|
||||
let noncounted_fields = unsafe { &mut *(noncounted_fields as *mut _ as *mut ${concat(__, $mem_ty, Noncounted)}) };
|
||||
|
||||
$(
|
||||
let $counted_field = buf.split_off_mut(..noncounted_fields.$counted_by as usize * size_of::<$el>())
|
||||
.ok_or(syscall::Error::new(syscall::EINVAL))?;
|
||||
let $counted_field = unsafe {
|
||||
slice::from_raw_parts_mut($counted_field as *mut _ as *mut $el, noncounted_fields.$counted_by as usize)
|
||||
};
|
||||
)*
|
||||
|
||||
if !buf.is_empty() {
|
||||
return Err(syscall::Error::new(syscall::EINVAL));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ok( f($mem_ty {
|
||||
noncounted_fields,
|
||||
$($counted_field,)*
|
||||
})?)
|
||||
}
|
||||
|
||||
$(
|
||||
pub fn $noncounted_field(&self) -> $noncounted_ty {
|
||||
self.noncounted_fields.$noncounted_field
|
||||
}
|
||||
|
||||
/// Should not be called for fields used as array length
|
||||
pub fn ${concat(set_, $noncounted_field)}(&mut self, data: $noncounted_ty) {
|
||||
self.noncounted_fields.$noncounted_field = data;
|
||||
}
|
||||
)*
|
||||
|
||||
$(
|
||||
pub fn $counted_field(&self) -> &[$el] {
|
||||
self.$counted_field
|
||||
}
|
||||
|
||||
pub fn ${concat(set_, $counted_field)}(&mut self, data: &[$el]) {
|
||||
let copied_count = cmp::min(data.len(), self.$counted_field.len());
|
||||
self.$counted_field[..copied_count].copy_from_slice(&data[..copied_count]);
|
||||
self.noncounted_fields.$counted_by = data.len() as _;
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#![feature(macro_metavar_expr_concat)]
|
||||
#![no_std]
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
#[macro_use]
|
||||
mod ioctl_data;
|
||||
pub use ioctl_data::IoctlData;
|
||||
|
||||
pub mod drm;
|
||||
@@ -1,10 +1,6 @@
|
||||
use alloc::vec::Vec;
|
||||
use core::{mem, slice};
|
||||
use drm_sys::{
|
||||
drm_get_cap, drm_mode_card_res, drm_mode_crtc, drm_mode_fb_cmd, drm_mode_fb_cmd2,
|
||||
drm_mode_get_connector, drm_mode_get_encoder, drm_mode_get_plane, drm_mode_get_plane_res,
|
||||
drm_mode_obj_get_properties, drm_set_client_cap, drm_version,
|
||||
};
|
||||
use core::slice;
|
||||
|
||||
use redox_ioctl::{IoctlData, drm::*};
|
||||
|
||||
use crate::{
|
||||
error::{Errno, Result},
|
||||
@@ -12,7 +8,7 @@ use crate::{
|
||||
platform::types::*,
|
||||
};
|
||||
|
||||
use super::{IoctlBuffer, graphics_ipc as ipc, graphics_ipc::IoctlData};
|
||||
use super::IoctlBuffer;
|
||||
|
||||
const DRM_FORMAT_ARGB8888: u32 = 0x34325241; // 'AR24' fourcc code, for ARGB8888
|
||||
|
||||
@@ -61,7 +57,7 @@ impl Dev {
|
||||
}
|
||||
|
||||
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, mem::size_of::<T>());
|
||||
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,
|
||||
@@ -70,7 +66,7 @@ impl Dev {
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn read_write_ioctl<T: ipc::IoctlData>(
|
||||
unsafe fn read_write_ioctl<T: IoctlData>(
|
||||
&self,
|
||||
mut buf: IoctlBuffer,
|
||||
func: u64,
|
||||
@@ -88,11 +84,7 @@ impl Dev {
|
||||
Ok(res as c_int)
|
||||
}
|
||||
|
||||
unsafe fn write_ioctl<T: ipc::IoctlData>(
|
||||
&self,
|
||||
mut buf: IoctlBuffer,
|
||||
func: u64,
|
||||
) -> Result<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(
|
||||
@@ -103,45 +95,23 @@ impl Dev {
|
||||
)?;
|
||||
Ok(res as c_int)
|
||||
}
|
||||
|
||||
fn display_count(&self) -> Result<usize> {
|
||||
let mut cmd = ipc::DisplayCount { count: 0 };
|
||||
unsafe {
|
||||
self.call(&mut cmd, ipc::DISPLAY_COUNT)?;
|
||||
}
|
||||
Ok(cmd.count)
|
||||
}
|
||||
|
||||
fn display_size(&self, display_id: usize) -> Result<(u32, u32)> {
|
||||
let mut cmd = ipc::DisplaySize {
|
||||
display_id,
|
||||
width: 0,
|
||||
height: 0,
|
||||
};
|
||||
unsafe {
|
||||
self.call(&mut cmd, ipc::DISPLAY_SIZE)?;
|
||||
}
|
||||
Ok((cmd.width, cmd.height))
|
||||
}
|
||||
}
|
||||
|
||||
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, ipc::VERSION),
|
||||
0x0C => dev.read_write_ioctl::<drm_get_cap>(buf, ipc::GET_CAP),
|
||||
0x0D => dev.write_ioctl::<drm_set_client_cap>(buf, ipc::SET_CLIENT_CAP),
|
||||
0xA0 => dev.read_write_ioctl::<drm_mode_card_res>(buf, ipc::MODE_CARD_RES),
|
||||
0xA1 => dev.read_write_ioctl::<drm_mode_crtc>(buf, ipc::MODE_GET_CRTC),
|
||||
0xA6 => dev.read_write_ioctl::<drm_mode_get_encoder>(buf, ipc::MODE_GET_ENCODER),
|
||||
0xA7 => dev.read_write_ioctl::<drm_mode_get_connector>(buf, ipc::MODE_GET_CONNECTOR),
|
||||
0xAD => dev.read_write_ioctl::<drm_mode_fb_cmd>(buf, ipc::MODE_GET_FB),
|
||||
0xB5 => dev.read_write_ioctl::<drm_mode_get_plane_res>(buf, ipc::MODE_GET_PLANE_RES),
|
||||
0xB6 => dev.read_write_ioctl::<drm_mode_get_plane>(buf, ipc::MODE_GET_PLANE),
|
||||
0xB9 => {
|
||||
dev.read_write_ioctl::<drm_mode_obj_get_properties>(buf, ipc::MODE_OBJ_GET_PROPERTIES)
|
||||
}
|
||||
0xCE => dev.read_write_ioctl::<drm_mode_fb_cmd2>(buf, ipc::MODE_GET_FB2),
|
||||
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,392 +0,0 @@
|
||||
// Adapted from graphics-ipc v2 ipc module, cannot use as it needs libstd
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
#[repr(C, packed)]
|
||||
pub struct Damage {
|
||||
pub x: u32,
|
||||
pub y: u32,
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use core::{
|
||||
cmp,
|
||||
ffi::{c_char, c_int},
|
||||
iter, mem, slice,
|
||||
};
|
||||
|
||||
pub trait IoctlData {
|
||||
unsafe fn write(&self) -> Vec<u8>;
|
||||
unsafe fn read_from(&mut self, buf: &[u8]);
|
||||
}
|
||||
|
||||
macro_rules! define_ioctl_data {
|
||||
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||
$($rest:tt)*
|
||||
}) => {
|
||||
define_ioctl_data!(
|
||||
struct $ioctl_ty, $mem_ty { $($rest)* } => (), (), ()
|
||||
);
|
||||
};
|
||||
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||
$field:ident: $ty:ty,
|
||||
$($rest:tt)*
|
||||
} =>
|
||||
($($ioctl_fields:tt)*),
|
||||
($($counted_fields:tt)*),
|
||||
($($noncounted_fields:tt)*)
|
||||
) => {
|
||||
define_ioctl_data!(
|
||||
struct $ioctl_ty, $mem_ty { $($rest)* } =>
|
||||
($($ioctl_fields)* $field: $ty,),
|
||||
($($counted_fields)*),
|
||||
($($noncounted_fields)* $field: $ty,)
|
||||
);
|
||||
};
|
||||
(struct $ioctl_ty:ident, $mem_ty:ident {
|
||||
$field:ident: $ty:ty [array<$el:ty, $counted_by:ident>],
|
||||
$($rest:tt)*
|
||||
} =>
|
||||
($($ioctl_fields:tt)*),
|
||||
($($counted_fields:tt)*),
|
||||
($($noncounted_fields:tt)*)
|
||||
) => {
|
||||
define_ioctl_data!(
|
||||
struct $ioctl_ty, $mem_ty { $($rest)* } =>
|
||||
($($ioctl_fields)* $field: $ty,),
|
||||
($($counted_fields)* $field: $ty [array<$el, $counted_by>],),
|
||||
($($noncounted_fields)*)
|
||||
);
|
||||
};
|
||||
(struct $ioctl_ty:ident, $mem_ty:ident {} =>
|
||||
($($ioctl_field:ident: $ioctl_field_ty:ty,)*),
|
||||
($($counted_field:ident: $counted_ty:ty [array<$el:ty, $counted_by:ident>],)*),
|
||||
($($noncounted_field:ident: $noncounted_ty:ty,)*)
|
||||
) => {
|
||||
pub use drm_sys::$ioctl_ty;
|
||||
|
||||
// FIXME check ioctl_ty doesn't have padding
|
||||
const _: $ioctl_ty = $ioctl_ty {
|
||||
$($ioctl_field: unsafe { mem::zeroed::<$ioctl_field_ty>() },)*
|
||||
};
|
||||
|
||||
#[repr(C)]
|
||||
pub struct ${concat(__, $mem_ty, Noncounted)} {
|
||||
$($noncounted_field: $noncounted_ty,)*
|
||||
}
|
||||
|
||||
pub struct $mem_ty<'a> {
|
||||
noncounted_fields: &'a mut ${concat(__, $mem_ty, Noncounted)},
|
||||
$($counted_field: &'a mut [$el],)*
|
||||
}
|
||||
|
||||
impl IoctlData for $ioctl_ty {
|
||||
unsafe fn write(&self) -> Vec<u8> {
|
||||
let noncounted_fields = ${concat(__, $mem_ty, Noncounted)} {
|
||||
$($noncounted_field: self.$noncounted_field,)*
|
||||
};
|
||||
// FIXME use Vec::with_capacity
|
||||
let mut data = Vec::<u8>::new();
|
||||
data.extend_from_slice(&unsafe {
|
||||
mem::transmute::<
|
||||
${concat(__, $mem_ty, Noncounted)},
|
||||
[u8; size_of::<${concat(__, $mem_ty, Noncounted)}>()],
|
||||
>(noncounted_fields)
|
||||
});
|
||||
$(
|
||||
let size = self.$counted_by as usize * size_of::<$el>();
|
||||
if self.$counted_field as usize != 0 {
|
||||
let $counted_field = unsafe {
|
||||
slice::from_raw_parts(self.$counted_field as *const u8, size)
|
||||
};
|
||||
data.extend_from_slice(&$counted_field);
|
||||
} else {
|
||||
data.extend(iter::repeat(0u8).take(size));
|
||||
};
|
||||
|
||||
)*
|
||||
data
|
||||
}
|
||||
|
||||
unsafe fn read_from(&mut self, mut buf: &[u8]) {
|
||||
// FIXME be robust against malicious scheme implementations by returning an error
|
||||
// when the buf is the wrong size
|
||||
let noncounted_fields = buf.split_off(..size_of::<${concat(__, $mem_ty, Noncounted)}>()).unwrap();
|
||||
|
||||
$(
|
||||
let size = self.$counted_by as usize * size_of::<$el>();
|
||||
let $counted_field = buf.split_off(..size).unwrap();
|
||||
if self.$counted_field as usize != 0 {
|
||||
unsafe {
|
||||
slice::from_raw_parts_mut(self.$counted_field as *mut u8, size).copy_from_slice($counted_field);
|
||||
}
|
||||
}
|
||||
)*
|
||||
|
||||
assert!(buf.is_empty());
|
||||
|
||||
let noncounted_fields = unsafe { &*(noncounted_fields as *const _ as *const ${concat(__, $mem_ty, Noncounted)}) };
|
||||
$(self.$noncounted_field = noncounted_fields.$noncounted_field;)*
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> $mem_ty<'a> {
|
||||
pub fn with(
|
||||
mut buf: &'a mut [u8],
|
||||
f: impl FnOnce($mem_ty<'a>) -> syscall::Result<usize>,
|
||||
) -> syscall::Result<usize> {
|
||||
let noncounted_fields = buf.split_off_mut(..size_of::<${concat(__, $mem_ty, Noncounted)}>())
|
||||
.ok_or(syscall::Error::new(syscall::EINVAL))?;
|
||||
let noncounted_fields = unsafe { &mut *(noncounted_fields as *mut _ as *mut ${concat(__, $mem_ty, Noncounted)}) };
|
||||
|
||||
$(
|
||||
let $counted_field = buf.split_off_mut(..noncounted_fields.$counted_by as usize * size_of::<$el>())
|
||||
.ok_or(syscall::Error::new(syscall::EINVAL))?;
|
||||
let $counted_field = unsafe {
|
||||
slice::from_raw_parts_mut($counted_field as *mut _ as *mut $el, noncounted_fields.$counted_by as usize)
|
||||
};
|
||||
)*
|
||||
|
||||
if !buf.is_empty() {
|
||||
return Err(syscall::Error::new(syscall::EINVAL));
|
||||
}
|
||||
|
||||
|
||||
|
||||
Ok( f($mem_ty {
|
||||
noncounted_fields,
|
||||
$($counted_field,)*
|
||||
})?)
|
||||
}
|
||||
|
||||
$(
|
||||
pub fn $noncounted_field(&self) -> $noncounted_ty {
|
||||
self.noncounted_fields.$noncounted_field
|
||||
}
|
||||
|
||||
/// Should not be called for fields used as array length
|
||||
pub fn ${concat(set_, $noncounted_field)}(&mut self, data: $noncounted_ty) {
|
||||
self.noncounted_fields.$noncounted_field = data;
|
||||
}
|
||||
)*
|
||||
|
||||
$(
|
||||
pub fn $counted_field(&self) -> &[$el] {
|
||||
self.$counted_field
|
||||
}
|
||||
|
||||
pub fn ${concat(set_, $counted_field)}(&mut self, data: &[$el]) {
|
||||
let copied_count = cmp::min(data.len(), self.$counted_field.len());
|
||||
self.$counted_field[..copied_count].copy_from_slice(&data[..copied_count]);
|
||||
self.noncounted_fields.$counted_by = data.len() as _;
|
||||
}
|
||||
)*
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub const VERSION: u64 = 0;
|
||||
define_ioctl_data! {
|
||||
struct drm_version, DrmVersion {
|
||||
version_major: c_int,
|
||||
version_minor: c_int,
|
||||
version_patchlevel: c_int,
|
||||
name_len: drm_sys::__kernel_size_t,
|
||||
name: *mut c_char [array<c_char, name_len>],
|
||||
date_len: drm_sys::__kernel_size_t,
|
||||
date: *mut c_char [array<c_char, date_len>],
|
||||
desc_len: drm_sys::__kernel_size_t,
|
||||
desc: *mut c_char [array<c_char, desc_len>],
|
||||
}
|
||||
}
|
||||
|
||||
pub const GET_CAP: u64 = 0x0C;
|
||||
pub use drm_sys::DRM_CAP_DUMB_BUFFER;
|
||||
define_ioctl_data! {
|
||||
struct drm_get_cap, DrmGetCap {
|
||||
capability: u64,
|
||||
value: u64,
|
||||
}
|
||||
}
|
||||
|
||||
pub const SET_CLIENT_CAP: u64 = 0x0D;
|
||||
pub use drm_sys::DRM_CLIENT_CAP_CURSOR_PLANE_HOTSPOT;
|
||||
define_ioctl_data! {
|
||||
struct drm_set_client_cap, DrmSetClientCap {
|
||||
capability: u64,
|
||||
value: u64,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_CARD_RES: u64 = 0xA0;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_card_res, DrmModeCardRes {
|
||||
fb_id_ptr: u64 [array<u32, count_fbs>],
|
||||
crtc_id_ptr: u64 [array<u32, count_crtcs>],
|
||||
connector_id_ptr: u64 [array<u32, count_connectors>],
|
||||
encoder_id_ptr: u64 [array<u32, count_encoders>],
|
||||
count_fbs: u32,
|
||||
count_crtcs: u32,
|
||||
count_connectors: u32,
|
||||
count_encoders: u32,
|
||||
min_width: u32,
|
||||
max_width: u32,
|
||||
min_height: u32,
|
||||
max_height: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_CRTC: u64 = 0xA1;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_crtc, DrmModeCrtc {
|
||||
set_connectors_ptr: u64,
|
||||
count_connectors: u32,
|
||||
crtc_id: u32,
|
||||
fb_id: u32,
|
||||
x: u32,
|
||||
y: u32,
|
||||
gamma_size: u32,
|
||||
mode_valid: u32,
|
||||
mode: drm_sys::drm_mode_modeinfo,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_ENCODER: u64 = 0xA6;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_get_encoder, DrmModeGetEncoder {
|
||||
encoder_id: u32,
|
||||
encoder_type: u32,
|
||||
crtc_id: u32,
|
||||
possible_crtcs: u32,
|
||||
possible_clones: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_CONNECTOR: u64 = 0xA7;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_get_connector, DrmModeGetConnector {
|
||||
encoders_ptr: u64 [array<u32, count_encoders>],
|
||||
modes_ptr: u64 [array<drm_sys::drm_mode_modeinfo, count_modes>],
|
||||
props_ptr: u64 [array<u32, count_props>],
|
||||
prop_values_ptr: u64 [array<u64, count_props>],
|
||||
count_modes: u32,
|
||||
count_props: u32,
|
||||
count_encoders: u32,
|
||||
encoder_id: u32,
|
||||
connector_id: u32,
|
||||
connector_type: u32,
|
||||
connector_type_id: u32,
|
||||
connection: u32,
|
||||
mm_width: u32,
|
||||
mm_height: u32,
|
||||
subpixel: u32,
|
||||
pad: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_FB: u64 = 0xAD;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_fb_cmd, DrmModeFbCmd {
|
||||
fb_id: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
pitch: u32,
|
||||
bpp: u32,
|
||||
depth: u32,
|
||||
handle: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_PLANE_RES: u64 = 0xB5;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_get_plane_res, DrmModeGetPlaneRes {
|
||||
plane_id_ptr: u64 [array<u32, count_planes>],
|
||||
count_planes: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_PLANE: u64 = 0xB6;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_get_plane, DrmModeGetPlane {
|
||||
plane_id: u32,
|
||||
crtc_id: u32,
|
||||
fb_id: u32,
|
||||
possible_crtcs: u32,
|
||||
gamma_size: u32,
|
||||
count_format_types: u32,
|
||||
format_type_ptr: u64 [array<u32, count_format_types>],
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_OBJ_GET_PROPERTIES: u64 = 0xB9;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_obj_get_properties, DrmModeObjGetProperties {
|
||||
props_ptr: u64 [array<u32, count_props>],
|
||||
prop_values_ptr: u64 [array<u64, count_props>],
|
||||
count_props: u32,
|
||||
obj_id: u32,
|
||||
obj_type: u32,
|
||||
}
|
||||
}
|
||||
|
||||
pub const MODE_GET_FB2: u64 = 0xCE;
|
||||
define_ioctl_data! {
|
||||
struct drm_mode_fb_cmd2, DrmModeFbCmd2 {
|
||||
fb_id: u32,
|
||||
width: u32,
|
||||
height: u32,
|
||||
pixel_format: u32,
|
||||
flags: u32,
|
||||
handles: [u32; 4],
|
||||
pitches: [u32; 4],
|
||||
offsets: [u32; 4],
|
||||
modifier: [u64; 4],
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME replace these with proper drm interfaces
|
||||
pub const DISPLAY_COUNT: u64 = 1;
|
||||
#[repr(C, packed)]
|
||||
pub struct DisplayCount {
|
||||
pub count: usize,
|
||||
}
|
||||
|
||||
pub const DISPLAY_SIZE: u64 = 2;
|
||||
#[repr(C, packed)]
|
||||
pub struct DisplaySize {
|
||||
pub display_id: usize,
|
||||
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
}
|
||||
|
||||
pub const CREATE_DUMB_FRAMEBUFFER: u64 = 3;
|
||||
#[repr(C, packed)]
|
||||
pub struct CreateDumbFramebuffer {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
|
||||
pub fb_id: usize,
|
||||
}
|
||||
|
||||
pub const DUMB_FRAMEBUFFER_MAP_OFFSET: u64 = 4;
|
||||
#[repr(C, packed)]
|
||||
pub struct DumbFramebufferMapOffset {
|
||||
pub fb_id: usize,
|
||||
|
||||
pub offset: usize,
|
||||
}
|
||||
|
||||
pub const DESTROY_DUMB_FRAMEBUFFER: u64 = 5;
|
||||
#[repr(C, packed)]
|
||||
pub struct DestroyDumbFramebuffer {
|
||||
pub fb_id: usize,
|
||||
}
|
||||
|
||||
pub const UPDATE_PLANE: u64 = 6;
|
||||
#[repr(C, packed)]
|
||||
pub struct UpdatePlane {
|
||||
pub display_id: usize,
|
||||
pub fb_id: usize,
|
||||
pub damage: Damage,
|
||||
}
|
||||
@@ -14,7 +14,6 @@ use crate::{
|
||||
use super::winsize;
|
||||
|
||||
mod drm;
|
||||
mod graphics_ipc;
|
||||
|
||||
pub const TCGETS: c_ulong = 0x5401;
|
||||
pub const TCSETS: c_ulong = 0x5402;
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
#![feature(c_variadic)]
|
||||
#![feature(core_intrinsics)]
|
||||
#![feature(macro_derive)]
|
||||
#![feature(macro_metavar_expr_concat)]
|
||||
#![feature(maybe_uninit_slice)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(linkage)]
|
||||
|
||||
Reference in New Issue
Block a user