os/vfs/impls/
char_dev_file.rs1use crate::device::Driver;
2use crate::sync::SpinLock;
3use crate::uapi::ioctl::Termios;
4use crate::vfs::dev::{major, minor};
5use crate::vfs::devno::{chrdev_major, get_chrdev_driver, misc_minor};
6use crate::vfs::{Dentry, File, FsError, Inode, InodeMetadata, OpenFlags, SeekWhence};
7use alloc::sync::Arc;
8
9pub struct CharDeviceFile {
11 pub dentry: Arc<Dentry>,
13
14 pub inode: Arc<dyn Inode>,
16
17 dev: u64,
19
20 driver: Option<Arc<dyn Driver>>,
22
23 pub flags: OpenFlags,
25
26 offset: SpinLock<usize>,
28
29 termios: SpinLock<Termios>,
31
32 winsize: SpinLock<crate::uapi::ioctl::WinSize>,
34}
35
36impl CharDeviceFile {
37 pub fn new(dentry: Arc<Dentry>, flags: OpenFlags) -> Result<Self, FsError> {
47 let inode = dentry.inode.clone();
48 let metadata = inode.metadata()?;
49 let dev = metadata.rdev;
50
51 let driver = get_chrdev_driver(dev);
54
55 let maj = major(dev);
57 if driver.is_none() && maj != chrdev_major::MEM {
58 return Err(FsError::NoDevice);
60 }
61
62 Ok(Self {
63 dentry,
64 inode,
65 dev,
66 driver,
67 flags,
68 offset: SpinLock::new(0),
69 termios: SpinLock::new(Termios::default()),
70 winsize: SpinLock::new(crate::uapi::ioctl::WinSize {
71 ws_row: 24,
72 ws_col: 80,
73 ws_xpixel: 0,
74 ws_ypixel: 0,
75 }),
76 })
77 }
78
79 fn mem_device_read(&self, buf: &mut [u8]) -> Result<usize, FsError> {
81 let min = minor(self.dev);
82 match min {
83 3 => {
84 Ok(0)
86 }
87 5 => {
88 buf.fill(0);
90 Ok(buf.len())
91 }
92 8 | 9 => {
93 use crate::arch::timer::get_ticks;
95 let mut seed = get_ticks() as u32;
96 for byte in buf.iter_mut() {
97 seed = seed.wrapping_mul(1103515245).wrapping_add(12345);
99 *byte = (seed >> 16) as u8;
100 }
101 Ok(buf.len())
102 }
103 _ => Err(FsError::NoDevice),
104 }
105 }
106
107 fn mem_device_write(&self, buf: &[u8]) -> Result<usize, FsError> {
109 let min = minor(self.dev);
110 match min {
111 3 | 5 => {
112 Ok(buf.len())
114 }
115 _ => Err(FsError::NoDevice),
116 }
117 }
118}
119
120impl File for CharDeviceFile {
121 fn readable(&self) -> bool {
122 self.flags.readable()
123 }
124
125 fn writable(&self) -> bool {
126 self.flags.writable()
127 }
128
129 fn read(&self, buf: &mut [u8]) -> Result<usize, FsError> {
130 if !self.readable() {
131 return Err(FsError::PermissionDenied);
132 }
133
134 let maj = major(self.dev);
135
136 if maj == chrdev_major::MEM {
138 return self.mem_device_read(buf);
139 }
140
141 if let Some(ref driver) = self.driver {
143 if let Some(serial) = driver.as_serial() {
144 let is_nonblock = self.flags.contains(OpenFlags::O_NONBLOCK);
145
146 if is_nonblock {
147 if let Some(byte) = serial.try_read() {
149 buf[0] = byte;
150 let mut count = 1;
151 while count < buf.len() {
153 if let Some(b) = serial.try_read() {
154 buf[count] = b;
155 count += 1;
156 } else {
157 break;
158 }
159 }
160 Ok(count)
161 } else {
162 Err(FsError::WouldBlock)
163 }
164 } else {
165 buf[0] = serial.read();
167 let mut count = 1;
168 while count < buf.len() {
170 if let Some(b) = serial.try_read() {
171 buf[count] = b;
172 count += 1;
173 } else {
174 break;
175 }
176 }
177 Ok(count)
178 }
179 } else {
180 Err(FsError::NotSupported)
181 }
182 } else {
183 Err(FsError::NoDevice)
184 }
185 }
186
187 fn write(&self, buf: &[u8]) -> Result<usize, FsError> {
188 if !self.writable() {
189 return Err(FsError::PermissionDenied);
190 }
191
192 let maj = major(self.dev);
193
194 if maj == chrdev_major::MEM {
196 return self.mem_device_write(buf);
197 }
198
199 if let Some(ref driver) = self.driver {
201 if let Some(serial) = driver.as_serial() {
202 serial.write(buf);
203 Ok(buf.len())
204 } else {
205 Err(FsError::NotSupported)
206 }
207 } else {
208 Err(FsError::NoDevice)
209 }
210 }
211
212 fn metadata(&self) -> Result<InodeMetadata, FsError> {
213 self.inode.metadata()
214 }
215
216 fn lseek(&self, offset: isize, whence: SeekWhence) -> Result<usize, FsError> {
217 Err(FsError::NotSupported)
220 }
221
222 fn offset(&self) -> usize {
223 *self.offset.lock()
224 }
225
226 fn flags(&self) -> OpenFlags {
227 self.flags.clone()
228 }
229
230 fn inode(&self) -> Result<Arc<dyn Inode>, FsError> {
231 Ok(self.inode.clone())
232 }
233
234 fn dentry(&self) -> Result<Arc<Dentry>, FsError> {
235 Ok(self.dentry.clone())
236 }
237
238 fn ioctl(&self, request: u32, arg: usize) -> Result<isize, FsError> {
239 use crate::arch::trap::SumGuard;
240 use crate::uapi::errno::{EINVAL, ENOTTY};
241 use crate::uapi::ioctl::*;
242
243 let maj = major(self.dev);
244
245 match maj {
247 chrdev_major::CONSOLE => {
248 self.console_ioctl(request, arg)
250 }
251 chrdev_major::MISC => {
252 self.misc_ioctl(request, arg)
254 }
255 _ => Err(FsError::NotSupported),
256 }
257 }
258 fn as_any(&self) -> &dyn core::any::Any {
259 self
260 }
261}
262
263impl CharDeviceFile {
264 fn console_ioctl(&self, request: u32, arg: usize) -> Result<isize, FsError> {
266 use crate::arch::trap::SumGuard;
267 use crate::uapi::errno::{EINVAL, ENOTTY};
268 use crate::uapi::ioctl::*;
269
270 match request {
271 TCGETS => {
272 if arg == 0 {
273 return Ok(-EINVAL as isize);
274 }
275
276 unsafe {
277 let _guard = SumGuard::new();
278 let termios_ptr = arg as *mut Termios;
279 if termios_ptr.is_null() {
280 return Ok(-EINVAL as isize);
281 }
282
283 core::ptr::write_bytes(
285 termios_ptr as *mut u8,
286 0,
287 core::mem::size_of::<Termios>(),
288 );
289
290 let termios = *self.termios.lock();
292 core::ptr::write_volatile(termios_ptr, termios);
293 }
294 Ok(0)
295 }
296
297 TCSETS | TCSETSW | TCSETSF => {
298 if arg == 0 {
299 return Ok(-EINVAL as isize);
300 }
301
302 {
303 let _guard = SumGuard::new();
304 let termios_ptr = arg as *const Termios;
305 if termios_ptr.is_null() {
306 return Ok(-EINVAL as isize);
307 }
308
309 unsafe {
310 let new_termios = core::ptr::read_volatile(termios_ptr);
312 *self.termios.lock() = new_termios;
313 }
314 }
315 Ok(0)
316 }
317
318 TIOCGWINSZ => {
319 if arg == 0 {
320 return Ok(-EINVAL as isize);
321 }
322
323 unsafe {
324 let _guard = SumGuard::new();
325 let winsize_ptr = arg as *mut crate::uapi::ioctl::WinSize;
326 if winsize_ptr.is_null() {
327 return Ok(-EINVAL as isize);
328 }
329
330 core::ptr::write_bytes(
332 winsize_ptr as *mut u8,
333 0,
334 core::mem::size_of::<crate::uapi::ioctl::WinSize>(),
335 );
336
337 let winsize = *self.winsize.lock();
339 core::ptr::write_volatile(winsize_ptr, winsize);
340 }
341 Ok(0)
342 }
343
344 TIOCSWINSZ => {
345 if arg == 0 {
346 return Ok(-EINVAL as isize);
347 }
348
349 {
350 let _guard = SumGuard::new();
351 let winsize_ptr = arg as *const crate::uapi::ioctl::WinSize;
352 if winsize_ptr.is_null() {
353 return Ok(-EINVAL as isize);
354 }
355
356 unsafe {
357 let new_winsize = core::ptr::read_volatile(winsize_ptr);
359 *self.winsize.lock() = new_winsize;
360 }
361 }
362 Ok(0)
363 }
364
365 _ => Ok(-ENOTTY as isize),
367 }
368 }
369
370 fn misc_ioctl(&self, request: u32, arg: usize) -> Result<isize, FsError> {
372 use crate::arch::trap::SumGuard;
373 use crate::uapi::errno::EINVAL;
374 use crate::uapi::ioctl::*;
375 use crate::vfs::dev::minor;
376
377 let min = minor(self.dev);
378
379 if min == misc_minor::RTC {
381 match request {
382 RTC_RD_TIME => {
383 if arg == 0 {
384 return Ok(-EINVAL as isize);
385 }
386
387 if let Some(ref driver) = self.driver {
389 if let Some(rtc) = driver.as_rtc() {
390 let dt = rtc.read_datetime();
391
392 unsafe {
393 let _guard = SumGuard::new();
394 let rtc_time_ptr = arg as *mut RtcTime;
395 if rtc_time_ptr.is_null() {
396 return Ok(-EINVAL as isize);
397 }
398
399 core::ptr::write_bytes(
401 rtc_time_ptr as *mut u8,
402 0,
403 core::mem::size_of::<RtcTime>(),
404 );
405
406 let rtc_time = RtcTime {
408 tm_sec: dt.second as i32,
409 tm_min: dt.minute as i32,
410 tm_hour: dt.hour as i32,
411 tm_mday: dt.day as i32,
412 tm_mon: (dt.month - 1) as i32, tm_year: (dt.year - 1900) as i32,
414 tm_wday: 0, tm_yday: 0, tm_isdst: 0,
417 };
418
419 core::ptr::write_volatile(rtc_time_ptr, rtc_time);
420 }
421 return Ok(0);
422 }
423 }
424 Err(FsError::NoDevice)
425 }
426 _ => Err(FsError::NotSupported),
427 }
428 } else {
429 Err(FsError::NotSupported)
430 }
431 }
432}