starnix_core/device/
serial.rs1use crate::device::kobject::DeviceMetadata;
6use crate::device::terminal::{Terminal, TtyState};
7use crate::device::{DeviceMode, DeviceOps};
8use crate::fs::devpts::{TtyFile, new_pts_fs_with_state};
9use crate::task::dynamic_thread_spawner::SpawnRequestBuilder;
10use crate::task::{CurrentTask, EventHandler, Kernel, ThreadLockupDetector, Waiter};
11use crate::vfs::{FileOps, FsString, NamespaceNode, VecInputBuffer, VecOutputBuffer};
12use anyhow::Error;
13use fidl::endpoints::ClientEnd;
14use fidl_fuchsia_hardware_serial as fserial;
15use starnix_uapi::auth::FsCred;
16use starnix_uapi::device_id::{DeviceId, TTY_MAJOR};
17use starnix_uapi::errors::Errno;
18use starnix_uapi::from_status_like_fdio;
19use starnix_uapi::open_flags::OpenFlags;
20use starnix_uapi::vfs::FdEvents;
21use std::sync::Arc;
22
23struct ForwardTask {
24 terminal: Arc<Terminal>,
25 serial_proxy: Arc<fserial::DeviceSynchronousProxy>,
26}
27
28impl ForwardTask {
29 fn new(terminal: Arc<Terminal>, serial_proxy: Arc<fserial::DeviceSynchronousProxy>) -> Self {
30 terminal.main_open();
31 Self { terminal, serial_proxy }
32 }
33
34 fn spawn_reader(&self, kernel: &Kernel) {
35 let terminal = self.terminal.clone();
36 let serial_proxy = self.serial_proxy.clone();
37 let closure = move |current_task: &CurrentTask| {
38 let _result = move || -> Result<(), Error> {
39 let waiter = Waiter::new();
40 loop {
41 terminal.main_wait_async(&waiter, FdEvents::POLLOUT, EventHandler::None);
44
45 if !terminal.main_query_events().contains(FdEvents::POLLOUT) {
47 waiter.wait(current_task)?;
48 }
49
50 let data = {
51 let _waiting_guard = ThreadLockupDetector::pause_tracking();
52 serial_proxy
53 .read(zx::MonotonicInstant::INFINITE)?
54 .map_err(|e: i32| from_status_like_fdio!(zx::Status::from_raw(e)))?
55 };
56 terminal.main_write(&mut VecInputBuffer::from(data))?;
57 }
58 }();
59 };
60 let req = SpawnRequestBuilder::new()
61 .with_debug_name("serial-reader")
62 .with_sync_closure(closure)
63 .build();
64 kernel.kthreads.spawner().spawn_from_request(req);
65 }
66
67 fn spawn_writer(&self, kernel: &Kernel) {
68 let terminal = self.terminal.clone();
69 let serial_proxy = self.serial_proxy.clone();
70 let closure = move |current_task: &CurrentTask| {
71 let _result = move || -> Result<(), Error> {
72 let waiter = Waiter::new();
73 loop {
74 terminal.main_wait_async(&waiter, FdEvents::POLLIN, EventHandler::None);
77
78 if !terminal.main_query_events().contains(FdEvents::POLLIN) {
80 waiter.wait(current_task)?;
81 }
82
83 let size = terminal.read().get_available_read_size(true);
84 let mut buffer = VecOutputBuffer::new(size);
85 terminal.main_read(&mut buffer)?;
86 serial_proxy
87 .write(buffer.data(), zx::MonotonicInstant::INFINITE)?
88 .map_err(|e: i32| from_status_like_fdio!(zx::Status::from_raw(e)))?;
89 }
90 }();
91 };
92 let req = SpawnRequestBuilder::new()
93 .with_debug_name("serial-writer")
94 .with_sync_closure(closure)
95 .build();
96 kernel.kthreads.spawner().spawn_from_request(req);
97 }
98}
99
100impl Drop for ForwardTask {
101 fn drop(&mut self) {
102 self.terminal.main_close();
103 }
105}
106
107pub struct SerialDevice {
108 terminal: Arc<Terminal>,
109 _forward_task: ForwardTask,
110}
111
112impl SerialDevice {
113 pub fn new(
117 kernel: &Kernel,
118 serial_device: ClientEnd<fserial::DeviceMarker>,
119 creds: FsCred,
120 ) -> Result<Arc<Self>, Errno> {
121 let state = Arc::new(TtyState::default());
122 let fs = new_pts_fs_with_state(kernel, Default::default(), state.clone())?;
123 let terminal = state.get_next_terminal(fs.root().clone(), creds)?;
124
125 let serial_proxy = Arc::new(serial_device.into_sync_proxy());
126 let forward_task = ForwardTask::new(terminal.clone(), serial_proxy);
127 forward_task.spawn_reader(kernel);
128 forward_task.spawn_writer(kernel);
129
130 Ok(Arc::new(Self { terminal, _forward_task: forward_task }))
131 }
132}
133
134impl DeviceOps for Arc<SerialDevice> {
135 fn open(
136 &self,
137 _current_task: &CurrentTask,
138 _id: DeviceId,
139 _node: &NamespaceNode,
140 _flags: OpenFlags,
141 ) -> Result<Box<dyn FileOps>, Errno> {
142 Ok(Box::new(TtyFile::new(self.terminal.clone())))
143 }
144}
145
146pub fn register_serial_device(
151 kernel: &Kernel,
152 index: u32,
153 serial_device: Arc<SerialDevice>,
154) -> Result<(), Errno> {
155 const SERIAL_MINOR_BASE: u32 = 64;
158
159 let name = FsString::from(format!("ttyS{}", index));
160
161 let registry = &kernel.device_registry;
162 registry.register_device(
163 kernel,
164 name.as_ref(),
165 DeviceMetadata::new(
166 name.clone(),
167 DeviceId::new(TTY_MAJOR, SERIAL_MINOR_BASE + index),
168 DeviceMode::Char,
169 ),
170 registry.objects.tty_class(),
171 serial_device,
172 )?;
173 Ok(())
174}