Skip to content

Commit 73e0562

Browse files
authored
Merge pull request #44 from wedsonaf/miscdev
Add support for registering misc devices
2 parents b3dee61 + 586e37d commit 73e0562

File tree

4 files changed

+97
-0
lines changed

4 files changed

+97
-0
lines changed

drivers/char/rust_example/src/lib.rs

+17
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@
33
#![no_std]
44
#![feature(global_asm)]
55

6+
extern crate alloc;
7+
8+
use alloc::boxed::Box;
9+
use core::pin::Pin;
610
use kernel::prelude::*;
11+
use kernel::{cstr, file_operations::FileOperations, miscdev};
712

813
module! {
914
type: RustExample,
@@ -25,8 +30,18 @@ module! {
2530
},
2631
}
2732

33+
struct RustFile;
34+
35+
impl FileOperations for RustFile {
36+
fn open() -> KernelResult<Self> {
37+
println!("rust file was opened!");
38+
Ok(Self)
39+
}
40+
}
41+
2842
struct RustExample {
2943
message: String,
44+
_dev: Pin<Box<miscdev::Registration>>,
3045
}
3146

3247
impl KernelModule for RustExample {
@@ -36,8 +51,10 @@ impl KernelModule for RustExample {
3651
println!("Parameters:");
3752
println!(" my_bool: {}", my_bool.read());
3853
println!(" my_i32: {}", my_i32.read());
54+
3955
Ok(RustExample {
4056
message: "on the heap!".to_owned(),
57+
_dev: miscdev::Registration::new_pinned::<RustFile>(cstr!("rust_miscdev"), None)?,
4158
})
4259
}
4360
}

rust/kernel/src/bindings_helper.h

+1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <linux/sysctl.h>
99
#include <linux/uaccess.h>
1010
#include <linux/version.h>
11+
#include <linux/miscdevice.h>
1112

1213
// bindgen gets confused at certain things
1314
const gfp_t BINDINGS_GFP_KERNEL = GFP_KERNEL;

rust/kernel/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ pub mod c_types;
2525
pub mod chrdev;
2626
mod error;
2727
pub mod file_operations;
28+
pub mod miscdev;
2829
pub mod prelude;
2930
pub mod printk;
3031
pub mod random;

rust/kernel/src/miscdev.rs

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
3+
use crate::error::{Error, KernelResult};
4+
use crate::file_operations::{FileOperations, FileOperationsVtable};
5+
use crate::{bindings, c_types, CStr};
6+
use alloc::boxed::Box;
7+
use core::marker::PhantomPinned;
8+
use core::pin::Pin;
9+
10+
/// A registration of a misc device.
11+
pub struct Registration {
12+
mdev: Option<bindings::miscdevice>,
13+
_pin: PhantomPinned,
14+
}
15+
16+
impl Registration {
17+
/// Initialises a new registration but does not register it yet. It is allowed to move.
18+
pub fn new() -> Self {
19+
Self {
20+
mdev: None,
21+
_pin: PhantomPinned,
22+
}
23+
}
24+
25+
/// Registers a new misc device. On success, it returns a pinned heap-allocated representation
26+
/// of the registration.
27+
pub fn new_pinned<T: FileOperations>(
28+
name: CStr<'static>,
29+
minor: Option<i32>,
30+
) -> KernelResult<Pin<Box<Self>>> {
31+
let mut r = crate::try_alloc_pinned(Self::new())?;
32+
r.as_mut().register::<T>(name, minor)?;
33+
Ok(r)
34+
}
35+
36+
/// Attempts to actually register the misc device with the rest of the kernel. It must be
37+
/// pinned because the memory block that represents the registration is self-referential. If a
38+
/// minor is not given, the kernel allocates a new one if possible.
39+
pub fn register<T: FileOperations>(
40+
self: Pin<&mut Self>,
41+
name: CStr<'static>,
42+
minor: Option<i32>,
43+
) -> KernelResult<()> {
44+
// SAFETY: we must ensure that we never move out of `this`.
45+
let this = unsafe { self.get_unchecked_mut() };
46+
if this.mdev.is_some() {
47+
// Already registered.
48+
return Err(Error::EINVAL);
49+
}
50+
51+
this.mdev = Some(bindings::miscdevice::default());
52+
let dev = this.mdev.as_mut().unwrap();
53+
dev.fops = &FileOperationsVtable::<T>::VTABLE;
54+
dev.name = name.as_ptr() as *const c_types::c_char;
55+
dev.minor = minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32);
56+
let ret = unsafe { bindings::misc_register(dev) };
57+
if ret < 0 {
58+
this.mdev = None;
59+
return Err(Error::from_kernel_errno(ret));
60+
}
61+
Ok(())
62+
}
63+
}
64+
65+
// SAFETY: The only method is `register`, which requires a (pinned) mutable `Registration`, so it
66+
// is safe to pass `&Registration` to multiple threads because it offers no interior mutability.
67+
unsafe impl Sync for Registration {}
68+
69+
impl Drop for Registration {
70+
/// Removes the registration from the kernel if it has completed successfully before.
71+
fn drop(&mut self) {
72+
if let Some(ref mut dev) = self.mdev {
73+
unsafe {
74+
bindings::misc_deregister(dev);
75+
}
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)