kernel/device/char/
tty.rs

1//! TTY (Terminal) device implementation.
2//! 
3//! This module implements a TTY device that acts as a terminal interface
4//! providing line discipline, echo, and basic terminal I/O operations.
5
6extern crate alloc;
7use core::any::Any;
8use alloc::collections::VecDeque;
9use alloc::sync::Arc;
10use spin::Mutex;
11use crate::arch::get_cpu;
12use crate::device::{Device, DeviceType};
13use crate::device::char::CharDevice;
14use crate::device::events::{DeviceEvent, DeviceEventListener, InputEvent, EventCapableDevice};
15use crate::device::manager::DeviceManager;
16use crate::drivers::uart;
17use crate::sync::waker::Waker;
18use crate::late_initcall;
19use crate::task::mytask;
20
21/// TTY subsystem initialization
22fn init_tty_subsystem() {
23    let result = try_init_tty_subsystem();
24    if let Err(e) = result {
25        crate::early_println!("Failed to initialize TTY subsystem: {}", e);
26    }
27}
28
29fn try_init_tty_subsystem() -> Result<(), &'static str> {
30    let device_manager = DeviceManager::get_manager();
31    
32    // Find the first UART device and use its ID for TTY initialization
33    if let Some(uart_device_id) = device_manager.get_first_device_by_type(crate::device::DeviceType::Char) {
34        // Create TTY device with UART device ID for lookup
35        let tty_device = Arc::new(TtyDevice::new("tty0", uart_device_id));
36        let uart_device = device_manager.get_device(uart_device_id).ok_or("UART device not found")?;
37        
38        // Register TTY device as event listener for UART
39        if let Some(uart) = uart_device.as_any().downcast_ref::<crate::drivers::uart::virt::Uart>() {
40            let weak_tty = Arc::downgrade(&tty_device);
41            // Register TTY as event listener for UART input events
42            uart.register_event_listener(weak_tty);
43            crate::early_println!("TTY registered as UART event listener");
44        } else {
45            crate::early_println!("Failed to cast UART device to specific type");
46        }
47        
48        // Register TTY device with device manager
49        let _tty_id = device_manager.register_device_with_name("tty0".into(), tty_device);
50        
51        crate::early_println!("TTY subsystem initialized successfully");
52        Ok(())
53    } else {
54        Err("No UART device found for TTY initialization")
55    }
56}
57
58late_initcall!(init_tty_subsystem);
59
60/// TTY device implementation.
61/// 
62/// This device provides terminal functionality including line discipline,
63/// echo, and basic terminal I/O operations.
64pub struct TtyDevice {
65    name: &'static str,
66    uart_device_id: usize,
67    
68    // Input buffer for line discipline
69    input_buffer: Arc<Mutex<VecDeque<u8>>>,
70    
71    // Waker for blocking reads
72    input_waker: Waker,
73    
74    // Line discipline flags (Phase 2 expansion)
75    canonical_mode: bool,
76    echo_enabled: bool,
77    
78    // Terminal state (placeholder for future features)
79    // process_group: Option<ProcessGroupId>,  // Job control placeholder
80    // session_id: Option<SessionId>,           // Session management placeholder
81}
82
83impl TtyDevice {
84    pub fn new(name: &'static str, uart_device_id: usize) -> Self {
85        Self {
86            name,
87            uart_device_id,
88            input_buffer: Arc::new(Mutex::new(VecDeque::new())),
89            input_waker: Waker::new_interruptible("tty_input"),
90            canonical_mode: true,
91            echo_enabled: true,
92        }
93    }
94    
95    /// Handle input byte from UART device.
96    /// 
97    /// This method processes incoming bytes and applies line discipline.
98    fn handle_input_byte(&self, byte: u8) {
99        // crate::early_println!("TTY processing byte: {:02x}", byte);
100        
101        // Phase 2: Canonical mode processing
102        if self.canonical_mode {
103            match byte {
104                // Backspace/DEL
105                0x08 | 0x7F => {
106                    // crate::early_println!("TTY: Backspace detected");
107                    let mut input_buffer = self.input_buffer.lock();
108                    if input_buffer.pop_back().is_some() && self.echo_enabled {
109                        self.echo_backspace();
110                    }
111                }
112                // Enter/Line feed
113                b'\r' | b'\n' => {
114                    // crate::early_println!("TTY: Enter/newline detected");
115                    if self.echo_enabled {
116                        self.echo_char(b'\r');
117                        self.echo_char(b'\n');
118                    }
119                    let mut input_buffer = self.input_buffer.lock();
120                    input_buffer.push_back(b'\n');
121                    // crate::early_println!("TTY: Line added to buffer, size now: {}", input_buffer.len());
122                    // Wake up waiting processes
123                    drop(input_buffer);
124                    self.input_waker.wake_all();
125                }
126                // Control characters (placeholder for signal processing)
127                0x03 => {
128                    crate::early_println!("TTY: Ctrl+C detected");
129                    // Ctrl+C: Send SIGINT (placeholder)
130                    // TODO: Implement signal processing when process management is ready
131                }
132                0x1A => {
133                    crate::early_println!("TTY: Ctrl+Z detected");
134                    // Ctrl+Z: Send SIGTSTP (placeholder)
135                    // TODO: Implement job control when process management is ready
136                }
137                // Regular characters
138                byte => {
139                    // crate::early_println!("TTY: Regular character: {:02x}", byte);
140                    if self.echo_enabled {
141                        self.echo_char(byte);
142                    }
143                    let mut input_buffer = self.input_buffer.lock();
144                    input_buffer.push_back(byte);
145                    // crate::early_println!("TTY: Character added to buffer, size now: {}", input_buffer.len());
146                    // Wake up waiting processes in RAW mode or for immediate input
147                    drop(input_buffer);
148                    if !self.canonical_mode {
149                        self.input_waker.wake_all();
150                    }
151                }
152            }
153        } else {
154            // RAW mode: Pass through directly
155            let mut input_buffer = self.input_buffer.lock();
156            input_buffer.push_back(byte);
157            drop(input_buffer);
158            // Wake up waiting processes immediately in RAW mode
159            self.input_waker.wake_all();
160        }
161    }
162    
163    /// Echo character back to output.
164    fn echo_char(&self, byte: u8) {
165        // Get actual UART device and output
166        let device_manager = DeviceManager::get_manager();
167        if let Some(uart_device) = device_manager.get_device(self.uart_device_id) {
168            // Use the new CharDevice API with internal mutability
169            if let Some(char_device) = uart_device.as_char_device() {
170                let _ = char_device.write_byte(byte);
171            }
172        }
173    }
174    
175    /// Echo backspace sequence.
176    fn echo_backspace(&self) {
177        // Backspace echo: BS + space + BS
178        self.echo_char(0x08);
179        self.echo_char(b' ');
180        self.echo_char(0x08);
181    }
182}
183
184impl DeviceEventListener for TtyDevice {
185    fn on_device_event(&self, event: &dyn DeviceEvent) {
186        if let Some(input_event) = event.as_any().downcast_ref::<InputEvent>() {
187            // crate::early_println!("TTY received input event: byte={:02x} ('{}')", 
188            //     input_event.data, 
189            //     if input_event.data.is_ascii_graphic() || input_event.data == b' ' { 
190            //         input_event.data as char 
191            //     } else { 
192            //         '?' 
193            //     });
194            self.handle_input_byte(input_event.data);
195        }
196    }
197    
198    fn interested_in(&self, event_type: &str) -> bool {
199        event_type == "input"
200    }
201}
202
203impl Device for TtyDevice {
204    fn device_type(&self) -> DeviceType {
205        DeviceType::Char
206    }
207    
208    fn name(&self) -> &'static str {
209        self.name
210    }
211    
212    fn as_any(&self) -> &dyn Any {
213        self
214    }
215    
216    fn as_any_mut(&mut self) -> &mut dyn Any {
217        self
218    }
219    
220    fn as_char_device(&self) -> Option<&dyn CharDevice> {
221        Some(self)
222    }
223}
224
225impl CharDevice for TtyDevice {
226    fn read_byte(&self) -> Option<u8> {
227        let mut input_buffer = self.input_buffer.lock();
228        if let Some(byte) = input_buffer.pop_front() {
229            return Some(byte);
230        }
231        drop(input_buffer);
232        
233        // No data available, block the current task
234        if let Some(mut task) = mytask() {
235            let mut cpu = get_cpu();
236
237            // This never returns - the syscall will be restarted when the task is woken up
238            self.input_waker.wait(&mut task, &mut cpu);
239        }
240
241        None
242    }
243    
244    fn write_byte(&self, byte: u8) -> Result<(), &'static str> {
245        // Forward to UART device with line ending conversion
246        let device_manager = DeviceManager::get_manager();
247        if let Some(uart_device) = device_manager.get_device(self.uart_device_id) {
248            // Use the new CharDevice API with internal mutability
249            if let Some(char_device) = uart_device.as_char_device() {
250                // Handle line ending conversion for terminals
251                if byte == b'\n' {
252                    char_device.write_byte(b'\r')?;
253                    char_device.write_byte(b'\n')?;
254                } else {
255                    char_device.write_byte(byte)?;
256                }
257                return Ok(());
258            }
259        }
260        Err("UART device not available")
261    }
262    
263    fn can_read(&self) -> bool {
264        let input_buffer = self.input_buffer.lock();
265        !input_buffer.is_empty()
266    }
267    
268    fn can_write(&self) -> bool {
269        // Check if UART device is available
270        let device_manager = DeviceManager::get_manager();
271        if let Some(uart_device) = device_manager.get_device(self.uart_device_id) {
272            if let Some(uart) = uart_device.as_any().downcast_ref::<crate::drivers::uart::virt::Uart>() {
273                return uart.can_write();
274            }
275        }
276        false
277    }
278}