| 1 | |
| 2 |
|
| 3 | |
| 4 |
|
| 5 | |
| 6 | |
| 7 | |
| 8 | |
| 9 | |
| 10 | |
| 11 | |
| 12 | |
| 13 | |
| 14 | |
| 15 | |
| 16 | |
| 17 | |
| 18 | |
| 19 | |
| 20 | |
| 21 | |
| 22 | |
| 23 | |
| 24 | |
| 25 | |
| 26 | |
| 27 | |
| 28 | |
| 29 | |
| 30 | |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | |
| 41 | |
| 42 | |
| 43 | |
| 44 | |
| 45 | |
| 46 | |
| 47 | |
| 48 | |
| 49 | |
| 50 | |
| 51 | |
| 52 | |
| 53 | |
| 54 | |
| 55 | |
| 56 | |
| 57 | |
| 58 | |
| 59 | |
| 60 | |
| 61 | |
| 62 | |
| 63 | |
| 64 | |
| 65 | |
| 66 | |
| 67 | |
| 68 | |
| 69 | |
| 70 | |
| 71 | |
| 72 | |
| 73 | |
| 74 | |
| 75 | |
| 76 | |
| 77 | |
| 78 | |
| 79 | |
| 80 | |
| 81 | |
| 82 | |
| 83 | |
| 84 | |
| 85 | |
| 86 | |
| 87 | |
| 88 | |
| 89 | |
| 90 | |
| 91 | |
| 92 | |
| 93 | |
| 94 | |
| 95 | |
| 96 | |
| 97 |
|
| 98 | use kernel::{
|
| 99 | device::Device,
|
| 100 | fs::{
|
| 101 | File,
|
| 102 | Kiocb, |
| 103 | },
|
| 104 | ioctl::{
|
| 105 | _IO,
|
| 106 | _IOC_SIZE,
|
| 107 | _IOR,
|
| 108 | _IOW, |
| 109 | },
|
| 110 | iov::{
|
| 111 | IovIterDest,
|
| 112 | IovIterSource, |
| 113 | },
|
| 114 | miscdevice::{
|
| 115 | MiscDevice,
|
| 116 | MiscDeviceOptions,
|
| 117 | MiscDeviceRegistration, |
| 118 | },
|
| 119 | new_mutex,
|
| 120 | prelude::*,
|
| 121 | sync::{
|
| 122 | aref::ARef,
|
| 123 | Mutex, |
| 124 | },
|
| 125 | uaccess::{
|
| 126 | UserSlice,
|
| 127 | UserSliceReader,
|
| 128 | UserSliceWriter, |
| 129 | },
|
| 130 | };
|
| 131 |
|
| 132 | const RUST_MISC_DEV_HELLO: u32 = _IO('|' as u32, 0x80);
|
| 133 | const RUST_MISC_DEV_GET_VALUE: u32 = _IOR::<i32>('|' as u32, 0x81);
|
| 134 | const RUST_MISC_DEV_SET_VALUE: u32 = _IOW::<i32>('|' as u32, 0x82);
|
| 135 |
|
| 136 | module! {
|
| 137 | type: RustMiscDeviceModule,
|
| 138 | name: "rust_misc_device",
|
| 139 | authors: ["Lee Jones"],
|
| 140 | description: "Rust misc device sample",
|
| 141 | license: "GPL",
|
| 142 | }
|
| 143 |
|
| 144 | #[pin_data]
|
| 145 | struct RustMiscDeviceModule {
|
| 146 | #[pin]
|
| 147 | _miscdev: MiscDeviceRegistration<RustMiscDevice>,
|
| 148 | }
|
| 149 |
|
| 150 | impl kernel::InPlaceModule for RustMiscDeviceModule {
|
| 151 | fn init(_module: &'static ThisModule) -> impl PinInit<Self, Error> {
|
| 152 | pr_info!("Initialising Rust Misc Device Sample\n");
|
| 153 |
|
| 154 | let options = MiscDeviceOptions {
|
| 155 | name: c"rust-misc-device",
|
| 156 | };
|
| 157 |
|
| 158 | try_pin_init!(Self {
|
| 159 | _miscdev <- MiscDeviceRegistration::register(options),
|
| 160 | })
|
| 161 | }
|
| 162 | }
|
| 163 |
|
| 164 | struct Inner {
|
| 165 | value: i32,
|
| 166 | buffer: KVVec<u8>,
|
| 167 | }
|
| 168 |
|
| 169 | #[pin_data(PinnedDrop)]
|
| 170 | struct RustMiscDevice {
|
| 171 | #[pin]
|
| 172 | inner: Mutex<Inner>,
|
| 173 | dev: ARef<Device>,
|
| 174 | }
|
| 175 |
|
| 176 | #[vtable]
|
| 177 | impl MiscDevice for RustMiscDevice {
|
| 178 | type Ptr = Pin<KBox<Self>>;
|
| 179 |
|
| 180 | fn open(_file: &File, misc: &MiscDeviceRegistration<Self>) -> Result<Pin<KBox<Self>>> {
|
| 181 | let dev = ARef::from(misc.device());
|
| 182 |
|
| 183 | dev_info!(dev, "Opening Rust Misc Device Sample\n");
|
| 184 |
|
| 185 | KBox::try_pin_init(
|
| 186 | try_pin_init! {
|
| 187 | RustMiscDevice {
|
| 188 | inner <- new_mutex!(Inner {
|
| 189 | value: 0_i32,
|
| 190 | buffer: KVVec::new(),
|
| 191 | }),
|
| 192 | dev: dev,
|
| 193 | }
|
| 194 | },
|
| 195 | GFP_KERNEL,
|
| 196 | )
|
| 197 | }
|
| 198 |
|
| 199 | fn read_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIterDest<'_>) -> Result<usize> {
|
| 200 | let me = kiocb.file();
|
| 201 | dev_info!(me.dev, "Reading from Rust Misc Device Sample\n");
|
| 202 |
|
| 203 | let inner = me.inner.lock();
|
| 204 | |
| 205 | let read = iov.simple_read_from_buffer(kiocb.ki_pos_mut(), &inner.buffer)?;
|
| 206 |
|
| 207 | Ok(read)
|
| 208 | }
|
| 209 |
|
| 210 | fn write_iter(mut kiocb: Kiocb<'_, Self::Ptr>, iov: &mut IovIterSource<'_>) -> Result<usize> {
|
| 211 | let me = kiocb.file();
|
| 212 | dev_info!(me.dev, "Writing to Rust Misc Device Sample\n");
|
| 213 |
|
| 214 | let mut inner = me.inner.lock();
|
| 215 |
|
| 216 | |
| 217 | inner.buffer.clear();
|
| 218 | let len = iov.copy_from_iter_vec(&mut inner.buffer, GFP_KERNEL)?;
|
| 219 |
|
| 220 | |
| 221 | *kiocb.ki_pos_mut() = 0;
|
| 222 |
|
| 223 | Ok(len)
|
| 224 | }
|
| 225 |
|
| 226 | fn ioctl(me: Pin<&RustMiscDevice>, _file: &File, cmd: u32, arg: usize) -> Result<isize> {
|
| 227 | dev_info!(me.dev, "IOCTLing Rust Misc Device Sample\n");
|
| 228 |
|
| 229 | |
| 230 | let arg = UserPtr::from_addr(arg);
|
| 231 | let size = _IOC_SIZE(cmd);
|
| 232 |
|
| 233 | match cmd {
|
| 234 | RUST_MISC_DEV_GET_VALUE => me.get_value(UserSlice::new(arg, size).writer())?,
|
| 235 | RUST_MISC_DEV_SET_VALUE => me.set_value(UserSlice::new(arg, size).reader())?,
|
| 236 | RUST_MISC_DEV_HELLO => me.hello()?,
|
| 237 | _ => {
|
| 238 | dev_err!(me.dev, "-> IOCTL not recognised: {}\n", cmd);
|
| 239 | return Err(ENOTTY);
|
| 240 | }
|
| 241 | };
|
| 242 |
|
| 243 | Ok(0)
|
| 244 | }
|
| 245 | }
|
| 246 |
|
| 247 | #[pinned_drop]
|
| 248 | impl PinnedDrop for RustMiscDevice {
|
| 249 | fn drop(self: Pin<&mut Self>) {
|
| 250 | dev_info!(self.dev, "Exiting the Rust Misc Device Sample\n");
|
| 251 | }
|
| 252 | }
|
| 253 |
|
| 254 | impl RustMiscDevice {
|
| 255 | fn set_value(&self, mut reader: UserSliceReader) -> Result<isize> {
|
| 256 | let new_value = reader.read::<i32>()?;
|
| 257 | let mut guard = self.inner.lock();
|
| 258 |
|
| 259 | dev_info!(
|
| 260 | self.dev,
|
| 261 | "-> Copying data from userspace (value: {})\n",
|
| 262 | new_value
|
| 263 | );
|
| 264 |
|
| 265 | guard.value = new_value;
|
| 266 | Ok(0)
|
| 267 | }
|
| 268 |
|
| 269 | fn get_value(&self, mut writer: UserSliceWriter) -> Result<isize> {
|
| 270 | let guard = self.inner.lock();
|
| 271 | let value = guard.value;
|
| 272 |
|
| 273 | |
| 274 | drop(guard);
|
| 275 |
|
| 276 | dev_info!(
|
| 277 | self.dev,
|
| 278 | "-> Copying data to userspace (value: {})\n",
|
| 279 | &value
|
| 280 | );
|
| 281 |
|
| 282 | writer.write::<i32>(&value)?;
|
| 283 | Ok(0)
|
| 284 | }
|
| 285 |
|
| 286 | fn hello(&self) -> Result<isize> {
|
| 287 | dev_info!(self.dev, "-> Hello from the Rust Misc Device\n");
|
| 288 |
|
| 289 | Ok(0)
|
| 290 | }
|
| 291 | }
|