kernel/device/char/mod.rs
1use core::any::Any;
2
3use super::Device;
4use crate::object::capability::selectable::{
5 ReadyInterest, ReadySet, SelectWaitOutcome, Selectable,
6};
7use crate::object::capability::{ControlOps, MemoryMappingOps};
8
9extern crate alloc;
10
11/// OS/ABI-agnostic TTY control interface
12///
13/// This trait intentionally avoids Linux/POSIX terms and numbers.
14/// ABI adapters (e.g., abi/linux) should translate their own termios/ioctl
15/// to these neutral controls.
16pub trait TtyControl {
17 /// Enable or disable local echo.
18 fn set_echo(&self, enabled: bool);
19 /// Returns whether local echo is enabled.
20 fn is_echo_enabled(&self) -> bool;
21
22 /// Enable or disable canonical (line) mode.
23 fn set_canonical(&self, enabled: bool);
24 /// Returns whether canonical (line) mode is enabled.
25 fn is_canonical(&self) -> bool;
26
27 /// Set terminal window size in character cells.
28 fn set_winsize(&self, cols: u16, rows: u16);
29 /// Get terminal window size in character cells.
30 fn get_winsize(&self) -> (u16, u16);
31}
32
33/// Composite endpoint trait for TTY devices (byte stream + neutral controls)
34pub trait TtyDeviceEndpoint: CharDevice + TtyControl {}
35impl<T: CharDevice + TtyControl> TtyDeviceEndpoint for T {}
36
37/// Seek operations for character device positioning
38#[derive(Debug, Clone, Copy)]
39pub enum SeekFrom {
40 /// Seek from the beginning of the device
41 Start(u64),
42 /// Seek relative to the current position
43 Current(i64),
44 /// Seek relative to the end of the device
45 End(i64),
46}
47
48/// Character device interface
49///
50/// This trait defines the interface for character devices.
51/// It provides methods for querying device information and handling character I/O operations.
52/// Uses internal mutability for thread-safe shared access.
53pub trait CharDevice: Device {
54 /// Read a single byte from the device
55 ///
56 /// For blocking devices (like TTY), this method will block until data is available.
57 /// For non-blocking devices, this returns None if no data is available.
58 ///
59 /// # Returns
60 ///
61 /// The byte read from the device, or None if no data is available
62 fn read_byte(&self) -> Option<u8>;
63
64 /// Write a single byte to the device
65 ///
66 /// # Arguments
67 ///
68 /// * `byte` - The byte to write to the device
69 ///
70 /// # Returns
71 ///
72 /// Result indicating success or failure
73 fn write_byte(&self, byte: u8) -> Result<(), &'static str>;
74
75 /// Read multiple bytes from the device
76 ///
77 /// # Arguments
78 ///
79 /// * `buffer` - The buffer to read data into
80 ///
81 /// # Returns
82 ///
83 /// The number of bytes actually read
84 fn read(&self, buffer: &mut [u8]) -> usize {
85 let mut bytes_read = 0;
86 for i in 0..buffer.len() {
87 if let Some(byte) = self.read_byte() {
88 buffer[i] = byte;
89 bytes_read += 1;
90 } else {
91 break;
92 }
93 }
94 bytes_read
95 }
96
97 /// Write multiple bytes to the device
98 ///
99 /// # Arguments
100 ///
101 /// * `buffer` - The buffer containing data to write
102 ///
103 /// # Returns
104 ///
105 /// Result containing the number of bytes written or an error
106 fn write(&self, buffer: &[u8]) -> Result<usize, &'static str> {
107 let mut bytes_written = 0;
108 for &byte in buffer {
109 self.write_byte(byte)?;
110 bytes_written += 1;
111 }
112 Ok(bytes_written)
113 }
114
115 /// Check if the device is ready for reading
116 fn can_read(&self) -> bool;
117
118 /// Check if the device is ready for writing
119 fn can_write(&self) -> bool;
120
121 /// Read data from a specific position in the device
122 ///
123 /// Default implementation falls back to sequential read for stream devices.
124 /// Devices that support random access (like framebuffer, memory devices) should override this.
125 ///
126 /// # Arguments
127 ///
128 /// * `position` - Byte offset to read from
129 /// * `buffer` - Buffer to read data into
130 ///
131 /// # Returns
132 ///
133 /// Result containing the number of bytes read or an error
134 fn read_at(&self, _position: u64, buffer: &mut [u8]) -> Result<usize, &'static str> {
135 // Default: use sequential read for stream devices
136 Ok(self.read(buffer))
137 }
138
139 /// Write data to a specific position in the device
140 ///
141 /// Default implementation falls back to sequential write for stream devices.
142 /// Devices that support random access (like framebuffer, memory devices) should override this.
143 ///
144 /// # Arguments
145 ///
146 /// * `position` - Byte offset to write to
147 /// * `buffer` - Buffer containing data to write
148 ///
149 /// # Returns
150 ///
151 /// Result containing the number of bytes written or an error
152 fn write_at(&self, _position: u64, buffer: &[u8]) -> Result<usize, &'static str> {
153 // Default: use sequential write for stream devices
154 self.write(buffer)
155 }
156
157 /// Check if this device supports seek operations
158 ///
159 /// Default implementation returns false for stream devices.
160 /// Devices that support seeking should override this.
161 ///
162 /// # Returns
163 ///
164 /// True if the device supports seek operations
165 fn can_seek(&self) -> bool {
166 false
167 }
168}
169
170/// A generic implementation of a character device
171pub struct GenericCharDevice {
172 device_name: &'static str,
173 read_fn: fn() -> Option<u8>,
174 write_fn: fn(u8) -> Result<(), &'static str>,
175 can_read_fn: fn() -> bool,
176 can_write_fn: fn() -> bool,
177}
178
179impl GenericCharDevice {
180 pub fn new(
181 device_name: &'static str,
182 read_fn: fn() -> Option<u8>,
183 write_fn: fn(u8) -> Result<(), &'static str>,
184 can_read_fn: fn() -> bool,
185 can_write_fn: fn() -> bool,
186 ) -> Self {
187 Self {
188 device_name,
189 read_fn,
190 write_fn,
191 can_read_fn,
192 can_write_fn,
193 }
194 }
195}
196
197impl Device for GenericCharDevice {
198 fn device_type(&self) -> super::DeviceType {
199 super::DeviceType::Char
200 }
201
202 fn name(&self) -> &'static str {
203 self.device_name
204 }
205
206 fn as_any(&self) -> &dyn Any {
207 self
208 }
209
210 fn as_any_mut(&mut self) -> &mut dyn Any {
211 self
212 }
213
214 fn as_char_device(&self) -> Option<&dyn CharDevice> {
215 Some(self)
216 }
217}
218
219impl CharDevice for GenericCharDevice {
220 fn read_byte(&self) -> Option<u8> {
221 (self.read_fn)()
222 }
223
224 fn write_byte(&self, byte: u8) -> Result<(), &'static str> {
225 (self.write_fn)(byte)
226 }
227
228 fn can_read(&self) -> bool {
229 (self.can_read_fn)()
230 }
231
232 fn can_write(&self) -> bool {
233 (self.can_write_fn)()
234 }
235}
236
237impl ControlOps for GenericCharDevice {
238 // Generic character devices don't support control operations by default
239 fn control(&self, _command: u32, _arg: usize) -> Result<i32, &'static str> {
240 Err("Control operations not supported")
241 }
242}
243
244impl MemoryMappingOps for GenericCharDevice {
245 fn get_mapping_info(
246 &self,
247 _offset: usize,
248 _length: usize,
249 ) -> Result<(usize, usize, bool), &'static str> {
250 Err("Memory mapping not supported by this character device")
251 }
252
253 fn on_mapped(&self, _vaddr: usize, _paddr: usize, _length: usize, _offset: usize) {
254 // Generic character devices don't support memory mapping
255 }
256
257 fn on_unmapped(&self, _vaddr: usize, _length: usize) {
258 // Generic character devices don't support memory mapping
259 }
260
261 fn supports_mmap(&self) -> bool {
262 false
263 }
264}
265
266impl Selectable for GenericCharDevice {
267 fn current_ready(&self, interest: ReadyInterest) -> ReadySet {
268 let mut set = ReadySet::none();
269 if interest.read {
270 set.read = self.can_read();
271 }
272 if interest.write {
273 set.write = self.can_write();
274 }
275 if interest.except {
276 set.except = false;
277 }
278 set
279 }
280
281 fn wait_until_ready(
282 &self,
283 _interest: ReadyInterest,
284 _trapframe: &mut crate::arch::Trapframe,
285 _timeout_ticks: Option<u64>,
286 ) -> SelectWaitOutcome {
287 SelectWaitOutcome::Ready
288 }
289
290 fn is_nonblocking(&self) -> bool {
291 true
292 }
293}
294
295#[cfg(test)]
296mod tests;
297
298#[cfg(test)]
299pub mod mockchar;
300
301pub mod tty;