cf90f89b42
And use it for a couple of drm interfaces
297 lines
8.3 KiB
Rust
297 lines
8.3 KiB
Rust
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 crate::{
|
|
error::{Errno, Result},
|
|
header::errno::EINVAL,
|
|
platform::types::*,
|
|
};
|
|
|
|
use super::{IoctlBuffer, graphics_ipc as ipc, graphics_ipc::IoctlData};
|
|
|
|
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, mem::size_of::<T>());
|
|
redox_rt::sys::sys_call(
|
|
self.fd as usize,
|
|
bytes,
|
|
syscall::CallFlags::empty(),
|
|
&[func],
|
|
)
|
|
}
|
|
|
|
unsafe fn read_write_ioctl<T: ipc::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: ipc::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)
|
|
}
|
|
|
|
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))
|
|
}
|
|
}
|
|
|
|
unsafe fn mode_card_res(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut res = buf.read::<drm_mode_card_res>()?;
|
|
let count = dev.display_count()?;
|
|
let mut conn_ids = Vec::with_capacity(count);
|
|
let mut crtc_ids = Vec::with_capacity(count);
|
|
let mut enc_ids = Vec::with_capacity(count);
|
|
let mut fb_ids = Vec::with_capacity(count);
|
|
for i in 0..(count as u32) {
|
|
conn_ids.push(conn_id(i));
|
|
crtc_ids.push(crtc_id(i));
|
|
enc_ids.push(enc_id(i));
|
|
fb_ids.push(fb_id(i));
|
|
}
|
|
res.count_fbs = copy_array(&fb_ids, res.fb_id_ptr as *mut u32, res.count_fbs as usize) as u32;
|
|
res.count_crtcs = copy_array(
|
|
&crtc_ids,
|
|
res.crtc_id_ptr as *mut u32,
|
|
res.count_crtcs as usize,
|
|
) as u32;
|
|
res.count_connectors = copy_array(
|
|
&conn_ids,
|
|
res.connector_id_ptr as *mut u32,
|
|
res.count_connectors as usize,
|
|
) as u32;
|
|
res.count_encoders = copy_array(
|
|
&enc_ids,
|
|
res.encoder_id_ptr as *mut u32,
|
|
res.count_encoders as usize,
|
|
) as u32;
|
|
res.min_width = 0;
|
|
res.max_width = 16384;
|
|
res.min_height = 0;
|
|
res.max_height = 16384;
|
|
buf.write(res)?;
|
|
Ok(0)
|
|
}
|
|
|
|
unsafe fn mode_get_crtc(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut crtc = buf.read::<drm_mode_crtc>()?;
|
|
let i = id_index(crtc.crtc_id);
|
|
let (width, height) = dev.display_size(i as usize)?;
|
|
//TOOD: connectors
|
|
crtc.fb_id = fb_id(i);
|
|
crtc.x = 0;
|
|
crtc.y = 0;
|
|
crtc.gamma_size = 0;
|
|
crtc.mode_valid = 0;
|
|
//TODO: mode
|
|
crtc.mode = Default::default();
|
|
buf.write(crtc)?;
|
|
Ok(0)
|
|
}
|
|
|
|
unsafe fn mode_get_encoder(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut enc = buf.read::<drm_mode_get_encoder>()?;
|
|
let i = id_index(enc.encoder_id);
|
|
let (width, height) = dev.display_size(i as usize)?;
|
|
enc.crtc_id = crtc_id(i);
|
|
enc.possible_crtcs = (1 << i);
|
|
enc.possible_clones = (1 << i);
|
|
buf.write(enc)?;
|
|
Ok(0)
|
|
}
|
|
|
|
unsafe fn mode_get_connector(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut conn = buf.read::<drm_mode_get_connector>()?;
|
|
let i = id_index(conn.connector_id);
|
|
let (width, height) = dev.display_size(i as usize)?;
|
|
conn.count_modes = 0;
|
|
conn.count_props = 0;
|
|
conn.count_encoders = copy_array(
|
|
&[enc_id(i)],
|
|
conn.encoders_ptr as *mut u32,
|
|
conn.count_encoders as usize,
|
|
) as u32;
|
|
buf.write(conn)?;
|
|
Ok(0)
|
|
}
|
|
|
|
unsafe fn mode_get_fb(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut fb = buf.read::<drm_mode_fb_cmd>()?;
|
|
let i = id_index(fb.fb_id);
|
|
let (width, height) = dev.display_size(i as usize)?;
|
|
fb.width = width;
|
|
fb.height = height;
|
|
fb.pitch = width * 4; //TODO: stride
|
|
fb.bpp = 32;
|
|
fb.depth = 24;
|
|
fb.handle = fb_handle_id(i);
|
|
buf.write(fb)?;
|
|
Ok(0)
|
|
}
|
|
|
|
unsafe fn mode_get_plane_res(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut res = buf.read::<drm_mode_get_plane_res>()?;
|
|
let count = dev.display_count()?;
|
|
let mut ids = Vec::with_capacity(count);
|
|
for i in 0..(count as u32) {
|
|
ids.push(plane_id(i));
|
|
}
|
|
res.count_planes = copy_array(
|
|
&ids,
|
|
res.plane_id_ptr as *mut u32,
|
|
res.count_planes as usize,
|
|
) as u32;
|
|
buf.write(res)?;
|
|
Ok(0)
|
|
}
|
|
|
|
unsafe fn mode_get_plane(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut plane = buf.read::<drm_mode_get_plane>()?;
|
|
let i = id_index(plane.plane_id);
|
|
let (width, height) = dev.display_size(i as usize)?;
|
|
plane.crtc_id = crtc_id(i);
|
|
plane.fb_id = fb_id(i);
|
|
plane.possible_crtcs = (1 << i);
|
|
plane.count_format_types = copy_array(
|
|
&[DRM_FORMAT_ARGB8888],
|
|
plane.format_type_ptr as *mut u32,
|
|
plane.count_format_types as usize,
|
|
) as u32;
|
|
buf.write(plane)?;
|
|
Ok(0)
|
|
}
|
|
|
|
unsafe fn mode_obj_get_properties(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut props = buf.read::<drm_mode_obj_get_properties>()?;
|
|
//TODO
|
|
props.count_props = 0;
|
|
buf.write(props)?;
|
|
Ok(0)
|
|
}
|
|
|
|
unsafe fn mode_get_fb2(dev: Dev, mut buf: IoctlBuffer) -> Result<c_int> {
|
|
let mut fb = buf.read::<drm_mode_fb_cmd2>()?;
|
|
let i = id_index(fb.fb_id);
|
|
let (width, height) = dev.display_size(i as usize)?;
|
|
fb.width = width;
|
|
fb.height = height;
|
|
fb.pixel_format = DRM_FORMAT_ARGB8888;
|
|
fb.handles[0] = fb_handle_id(i);
|
|
fb.pitches[0] = width * 4;
|
|
fb.offsets[0] = 0;
|
|
fb.modifier[0] = 0;
|
|
buf.write(fb)?;
|
|
Ok(0)
|
|
}
|
|
|
|
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 => mode_card_res(dev, buf),
|
|
0xA1 => mode_get_crtc(dev, buf),
|
|
0xA6 => mode_get_encoder(dev, buf),
|
|
0xA7 => mode_get_connector(dev, buf),
|
|
0xAD => mode_get_fb(dev, buf),
|
|
0xB5 => mode_get_plane_res(dev, buf),
|
|
0xB6 => mode_get_plane(dev, buf),
|
|
0xB9 => mode_obj_get_properties(dev, buf),
|
|
0xCE => mode_get_fb2(dev, buf),
|
|
_ => {
|
|
eprintln!("unimplemented DRM ioctl({}, 0x{:02x}, {:?})", fd, func, buf);
|
|
Err(Errno(EINVAL))
|
|
}
|
|
}
|
|
}
|