Skip to content

Commit 37d8e30

Browse files
Duncan MillardCQ Bot
authored andcommitted
[starnix][nanohub] Integrate with serial device
Bug: 394110973 Change-Id: I6a6717cdd849c6d982eab13976a69a77950774e4 Reviewed-on: https://fuchsia-review.googlesource.com/c/fuchsia/+/1232026 Reviewed-by: Adam Barth <[email protected]> Commit-Queue: Duncan Millard <[email protected]>
1 parent 4201219 commit 37d8e30

File tree

7 files changed

+154
-10
lines changed

7 files changed

+154
-10
lines changed

src/starnix/kernel/device/registry.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,7 +391,7 @@ impl DeviceRegistry {
391391
/// registrations with these device numbers, use this function instead to register the device.
392392
///
393393
/// Note: We do not currently allocate from this entire range because we have mistakenly
394-
/// hardcoded some device registrations from the dynamic range. Once we fix these regirations
394+
/// hardcoded some device registrations from the dynamic range. Once we fix these registrations
395395
/// to be dynamic, we should expand to using the full dynamic range.
396396
///
397397
/// See `register_device` for an explanation of the parameters.

src/starnix/kernel/device/serial.rs

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,15 @@ impl ForwardTask {
3838
let _result = move || -> Result<(), Error> {
3939
let waiter = Waiter::new();
4040
loop {
41+
// Register edge triggered waiter for POLLOUT on terminal main side
42+
// This is waiting for the terminal to flag it can receive data
4143
terminal.main_wait_async(&waiter, FdEvents::POLLOUT, EventHandler::None);
42-
waiter.wait(locked, current_task)?;
44+
45+
// Only await the event if it is not already asserted
46+
if !terminal.main_query_events().contains(FdEvents::POLLOUT) {
47+
waiter.wait(locked, current_task)?;
48+
}
49+
4350
let data = serial_proxy
4451
.read(zx::MonotonicInstant::INFINITE)?
4552
.map_err(|e: i32| from_status_like_fdio!(zx::Status::from_raw(e)))?;
@@ -56,8 +63,15 @@ impl ForwardTask {
5663
let _result = move || -> Result<(), Error> {
5764
let waiter = Waiter::new();
5865
loop {
66+
// Register edge triggered waiter for POLLIN on terminal main side
67+
// This is waiting for the terminal to flag it has data to send
5968
terminal.main_wait_async(&waiter, FdEvents::POLLIN, EventHandler::None);
60-
waiter.wait(locked, current_task)?;
69+
70+
// Only await the event if it is not already asserted
71+
if !terminal.main_query_events().contains(FdEvents::POLLIN) {
72+
waiter.wait(locked, current_task)?;
73+
}
74+
6175
let size = terminal.read().get_available_read_size(true);
6276
let mut buffer = VecOutputBuffer::new(size);
6377
terminal.main_read(locked, &mut buffer)?;
@@ -87,7 +101,6 @@ impl SerialDevice {
87101
///
88102
/// To register the device, call `register_serial_device`.
89103
pub fn new(
90-
_locked: &mut Locked<'_, Unlocked>,
91104
current_task: &CurrentTask,
92105
serial_device: ClientEnd<fserial::DeviceMarker>,
93106
) -> Result<Arc<Self>, Errno> {

src/starnix/kernel/meta/starnix_kernel.cml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,12 @@
6060
path: "/dev/class/gpu",
6161
availability: "optional",
6262
},
63+
{
64+
directory: "dev-serial",
65+
rights: [ "r*" ],
66+
path: "/dev/class/serial",
67+
availability: "optional",
68+
},
6369
{
6470
// This service replaces the directory capability above.
6571
service: "fuchsia.gpu.magma.Service",

src/starnix/modules/nanohub/BUILD.gn

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,18 @@ rustc_library("nanohub") {
2828
]
2929

3030
deps = [
31+
"//sdk/fidl/fuchsia.hardware.serial:fuchsia.hardware.serial_rust",
3132
"//sdk/fidl/fuchsia.hardware.sockettunnel:fuchsia.hardware.sockettunnel_rust",
3233
"//sdk/rust/zx",
34+
"//src/lib/fdio/rust:fdio",
35+
"//src/lib/fidl/rust/fidl",
3336
"//src/lib/fuchsia-component",
37+
"//src/lib/fuchsia-fs",
3438
"//src/starnix/kernel:starnix_core",
39+
"//src/starnix/kernel:starnix_logging",
3540
"//src/starnix/lib/starnix_sync",
3641
"//src/starnix/lib/starnix_syscalls",
3742
"//src/starnix/lib/starnix_uapi",
43+
"//third_party/rust_crates:futures",
3844
]
3945
}

src/starnix/modules/nanohub/nanohub.rs

Lines changed: 113 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,23 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
use std::ops::DerefMut;
6+
use std::sync::Arc;
7+
58
use crate::nanohub_comms_directory::NanohubCommsDirectory;
69
use crate::socket_tunnel_file::register_socket_tunnel_device;
10+
use fidl_fuchsia_hardware_serial as fserial;
11+
use futures::TryStreamExt;
12+
use starnix_core::device::serial::SerialDevice;
713
use starnix_core::fs::sysfs::DeviceDirectory;
8-
use starnix_core::task::CurrentTask;
14+
use starnix_core::task::{CurrentTask, Kernel};
915
use starnix_core::vfs::{BytesFile, FsString, StaticDirectoryBuilder};
10-
use starnix_sync::{FileOpsCore, LockBefore, Locked};
16+
use starnix_logging::{log_error, log_info};
17+
use starnix_sync::{Locked, Unlocked};
1118
use starnix_uapi::mode;
1219

20+
const SERIAL_DIRECTORY: &str = "/dev/class/serial";
21+
1322
/// Function to be invoked by ProcDirectory while constructing /proc/device-tree
1423
pub fn nanohub_procfs_builder(
1524
builder: &'_ mut StaticDirectoryBuilder<'_>,
@@ -25,10 +34,7 @@ pub fn nanohub_procfs_builder(
2534
});
2635
}
2736

28-
pub fn nanohub_device_init<L>(locked: &mut Locked<'_, L>, current_task: &CurrentTask)
29-
where
30-
L: LockBefore<FileOpsCore>,
31-
{
37+
pub fn nanohub_device_init(locked: &mut Locked<'_, Unlocked>, current_task: &CurrentTask) {
3238
struct Descriptor {
3339
socket_label: FsString,
3440
dev_node_name: FsString,
@@ -100,4 +106,105 @@ where
100106
"nanohub".into(),
101107
NanohubCommsDirectory::new,
102108
);
109+
110+
// Spawn future to bind and configure serial device
111+
current_task.kernel().kthreads.spawn_future({
112+
let kernel = current_task.kernel().clone();
113+
async move { register_serial_device(kernel).await }
114+
});
115+
}
116+
117+
async fn register_serial_device(kernel: Arc<Kernel>) {
118+
let current_task = kernel.kthreads.system_task();
119+
120+
// TODO Move this to expect once test support is enabled
121+
let dir =
122+
match fuchsia_fs::directory::open_in_namespace(SERIAL_DIRECTORY, fuchsia_fs::PERM_READABLE)
123+
{
124+
Ok(dir) => dir,
125+
Err(e) => {
126+
log_error!("Failed to open serial directory: {:}", e);
127+
return;
128+
}
129+
};
130+
131+
let mut watcher = match fuchsia_fs::directory::Watcher::new(&dir).await {
132+
Ok(watcher) => watcher,
133+
Err(e) => {
134+
log_info!("Failed to create directory watcher for serial device: {:}", e);
135+
return;
136+
}
137+
};
138+
139+
loop {
140+
match watcher.try_next().await {
141+
Ok(Some(watch_msg)) => {
142+
let filename = watch_msg
143+
.filename
144+
.as_path()
145+
.to_str()
146+
.expect("Failed to convert watch_msg to str");
147+
if filename == "." {
148+
continue;
149+
}
150+
if watch_msg.event == fuchsia_fs::directory::WatchEvent::ADD_FILE
151+
|| watch_msg.event == fuchsia_fs::directory::WatchEvent::EXISTING
152+
{
153+
let instance_path = format!("{}/{}", SERIAL_DIRECTORY, filename);
154+
let (client_channel, server_channel) = zx::Channel::create();
155+
if let Err(_) = fdio::service_connect(&instance_path, server_channel) {
156+
continue;
157+
}
158+
159+
// `fuchsia.hardware.serial` exposes a `DeviceProxy` type used for binding with
160+
// a `Device` type. This should not be confused with the `DeviceProxy` generated
161+
// by FIDL
162+
let device_proxy = fserial::DeviceProxy_SynchronousProxy::new(client_channel);
163+
let (serial_proxy, server_end) =
164+
fidl::endpoints::create_sync_proxy::<fserial::DeviceMarker>();
165+
166+
// Instruct the serial driver to bind the connection to the underlying device
167+
if let Err(_) = device_proxy.get_channel(server_end) {
168+
continue;
169+
}
170+
171+
// Fetch the device class to see if this is the correct instance
172+
let device_class = match serial_proxy.get_class(zx::MonotonicInstant::INFINITE)
173+
{
174+
Ok(class) => class,
175+
Err(_) => continue,
176+
};
177+
178+
if device_class == fserial::Class::Mcu {
179+
let serial_device =
180+
SerialDevice::new(current_task, serial_proxy.into_channel().into())
181+
.expect("Can create SerialDevice wrapper");
182+
183+
// TODO This will register with an incorrect device number. We should be
184+
// dynamically registering a major device and this should be minor device 1
185+
// of that major device.
186+
let registry = &current_task.kernel().device_registry;
187+
registry
188+
.register_dyn_device(
189+
current_task.kernel().kthreads.unlocked_for_async().deref_mut(),
190+
current_task,
191+
"ttyHS1".into(),
192+
registry.objects.tty_class(),
193+
DeviceDirectory::new,
194+
serial_device,
195+
)
196+
.expect("Can register serial device");
197+
break;
198+
}
199+
}
200+
}
201+
Ok(None) => {
202+
break;
203+
}
204+
Err(e) => {
205+
log_error!("Serial driver stream ended with error: {:}", e);
206+
break;
207+
}
208+
}
209+
}
103210
}

src/starnix/runner/meta/starnix_runner.cml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,11 @@
151151
from: "parent",
152152
to: [ "#kernels" ],
153153
},
154+
{
155+
directory: "dev-serial",
156+
from: "parent",
157+
to: [ "#kernels" ],
158+
},
154159
{
155160
// This service replaces the directory capability above.
156161
service: "fuchsia.gpu.magma.Service",

src/starnix/runner/meta/starnix_runner.core_shard.cml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@
143143
to: [ "#starnix_runner" ],
144144
subdir: "gpu",
145145
},
146+
{
147+
directory: "dev-class",
148+
from: "parent",
149+
as: "dev-serial",
150+
to: [ "#starnix_runner" ],
151+
subdir: "serial",
152+
},
146153
{
147154
// This service replaces the directory capability above.
148155
service: "fuchsia.gpu.magma.Service",

0 commit comments

Comments
 (0)