Skip to content

Commit cf6f772

Browse files
hoshinolinamarcan
authored andcommitted
rust: drm: file: Add File abstraction
A DRM File is the DRM counterpart to a kernel file structure, representing an open DRM file descriptor. Add a Rust abstraction to allow drivers to implement their own File types that implement the DriverFile trait. Signed-off-by: Asahi Lina <lina@asahilina.net>
1 parent f307587 commit cf6f772

4 files changed

Lines changed: 118 additions & 2 deletions

File tree

rust/bindings/bindings_helper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <drm/drm_device.h>
1010
#include <drm/drm_drv.h>
11+
#include <drm/drm_file.h>
1112
#include <drm/drm_ioctl.h>
1213
#include <linux/delay.h>
1314
#include <linux/device.h>

rust/kernel/drm/drv.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,9 @@ pub trait Driver {
138138
/// Should be either `drm::gem::Object<T>` or `drm::gem::shmem::Object<T>`.
139139
type Object: AllocImpl;
140140

141+
/// The type used to represent a DRM File (client)
142+
type File: drm::file::DriverFile;
143+
141144
/// Driver metadata
142145
const INFO: DriverInfo;
143146

@@ -207,8 +210,8 @@ macro_rules! drm_device_register {
207210
impl<T: Driver> Registration<T> {
208211
const VTABLE: bindings::drm_driver = drm_legacy_fields! {
209212
load: None,
210-
open: None, // TODO: File abstraction
211-
postclose: None, // TODO: File abstraction
213+
open: Some(drm::file::open_callback::<T::File>),
214+
postclose: Some(drm::file::postclose_callback::<T::File>),
212215
lastclose: None,
213216
unload: None,
214217
release: None,

rust/kernel/drm/file.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
// SPDX-License-Identifier: GPL-2.0 OR MIT
2+
3+
//! DRM File objects.
4+
//!
5+
//! C header: [`include/linux/drm/drm_file.h`](../../../../include/linux/drm/drm_file.h)
6+
7+
use crate::{bindings, drm, error::Result};
8+
use alloc::boxed::Box;
9+
use core::marker::PhantomData;
10+
use core::pin::Pin;
11+
12+
/// Trait that must be implemented by DRM drivers to represent a DRM File (a client instance).
13+
pub trait DriverFile {
14+
/// The parent `Driver` implementation for this `DriverFile`.
15+
type Driver: drm::drv::Driver;
16+
17+
/// Open a new file (called when a client opens the DRM device).
18+
fn open(device: &drm::device::Device<Self::Driver>) -> Result<Pin<Box<Self>>>;
19+
}
20+
21+
/// An open DRM File.
22+
///
23+
/// # Invariants
24+
/// `raw` is a valid pointer to a `drm_file` struct.
25+
#[repr(transparent)]
26+
pub struct File<T: DriverFile> {
27+
raw: *mut bindings::drm_file,
28+
_p: PhantomData<T>,
29+
}
30+
31+
pub(super) unsafe extern "C" fn open_callback<T: DriverFile>(
32+
raw_dev: *mut bindings::drm_device,
33+
raw_file: *mut bindings::drm_file,
34+
) -> core::ffi::c_int {
35+
let drm = core::mem::ManuallyDrop::new(unsafe { drm::device::Device::from_raw(raw_dev) });
36+
// SAFETY: This reference won't escape this function
37+
let file = unsafe { &mut *raw_file };
38+
39+
let inner = match T::open(&drm) {
40+
Err(e) => {
41+
return e.to_errno();
42+
}
43+
Ok(i) => i,
44+
};
45+
46+
// SAFETY: This pointer is treated as pinned, and the Drop guarantee is upheld below.
47+
file.driver_priv = Box::into_raw(unsafe { Pin::into_inner_unchecked(inner) }) as *mut _;
48+
49+
0
50+
}
51+
52+
pub(super) unsafe extern "C" fn postclose_callback<T: DriverFile>(
53+
_dev: *mut bindings::drm_device,
54+
raw_file: *mut bindings::drm_file,
55+
) {
56+
// SAFETY: This reference won't escape this function
57+
let file = unsafe { &*raw_file };
58+
59+
// Drop the DriverFile
60+
unsafe { Box::from_raw(file.driver_priv as *mut T) };
61+
}
62+
63+
impl<T: DriverFile> File<T> {
64+
// Not intended to be called externally, except via declare_drm_ioctls!()
65+
#[doc(hidden)]
66+
pub unsafe fn from_raw(raw_file: *mut bindings::drm_file) -> File<T> {
67+
File {
68+
raw: raw_file,
69+
_p: PhantomData,
70+
}
71+
}
72+
73+
#[allow(dead_code)]
74+
/// Return the raw pointer to the underlying `drm_file`.
75+
pub(super) fn raw(&self) -> *const bindings::drm_file {
76+
self.raw
77+
}
78+
79+
/// Return an immutable reference to the raw `drm_file` structure.
80+
pub(super) fn file(&self) -> &bindings::drm_file {
81+
unsafe { &*self.raw }
82+
}
83+
84+
/// Return a pinned reference to the driver file structure.
85+
pub fn inner(&self) -> Pin<&T> {
86+
unsafe { Pin::new_unchecked(&*(self.file().driver_priv as *const T)) }
87+
}
88+
}
89+
90+
impl<T: DriverFile> crate::private::Sealed for File<T> {}
91+
92+
/// Generic trait to allow users that don't care about driver specifics to accept any File<T>.
93+
///
94+
/// # Safety
95+
/// Must only be implemented for File<T> and return the pointer, following the normal invariants
96+
/// of that type.
97+
pub unsafe trait GenericFile: crate::private::Sealed {
98+
/// Returns the raw const pointer to the `struct drm_file`
99+
fn raw(&self) -> *const bindings::drm_file;
100+
/// Returns the raw mut pointer to the `struct drm_file`
101+
fn raw_mut(&mut self) -> *mut bindings::drm_file;
102+
}
103+
104+
unsafe impl<T: DriverFile> GenericFile for File<T> {
105+
fn raw(&self) -> *const bindings::drm_file {
106+
self.raw
107+
}
108+
fn raw_mut(&mut self) -> *mut bindings::drm_file {
109+
self.raw
110+
}
111+
}

rust/kernel/drm/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@
44
55
pub mod device;
66
pub mod drv;
7+
pub mod file;
78
pub mod ioctl;

0 commit comments

Comments
 (0)