starnix_modules_nanohub/
nanohub.rs1use crate::datachannel_file::DataChannelDevice;
6use crate::nanohub_comms_directory::{
7 build_display_comms_directory, build_nanohub_comms_directory,
8};
9use crate::nanohub_gpio_stub::register_gpio_chip_device;
10use crate::socket_tunnel_file::register_socket_tunnel_device;
11use fidl_fuchsia_hardware_google_nanohub as fnanohub;
12use fidl_fuchsia_hardware_serial as fserial;
13use fuchsia_component::client::Service;
14use futures::TryStreamExt;
15use starnix_core::device::serial::SerialDevice;
16use starnix_core::fs::sysfs::build_device_directory;
17use starnix_core::task::{CurrentTask, Kernel};
18use starnix_logging::{log_error, log_info, log_warn};
19use starnix_sync::{Locked, Unlocked};
20use std::ops::DerefMut;
21use std::sync::Arc;
22
23const SERIAL_DIRECTORY: &str = "/dev/class/serial";
24
25pub fn nanohub_device_init(locked: &mut Locked<Unlocked>, current_task: &CurrentTask) {
26 register_gpio_chip_device(locked, current_task, "gpiochipwake0");
27
28 register_socket_tunnel_device(
29 locked,
30 current_task,
31 "/dev/display_comms".into(),
32 "display_comms".into(),
33 "display".into(),
34 build_display_comms_directory,
35 );
36
37 register_socket_tunnel_device(
40 locked,
41 current_task,
42 "/dev/nanohub_comms".into(),
43 "nanohub_comms".into(),
44 "nanohub".into(),
45 build_nanohub_comms_directory,
46 );
47
48 current_task.kernel().kthreads.spawn_future(
50 {
51 let kernel = current_task.kernel().clone();
52 move || async move { register_serial_device(kernel).await }
53 },
54 "register_serial_device",
55 );
56
57 current_task.kernel().kthreads.spawn_future(
58 {
59 let kernel = current_task.kernel().clone();
60 move || async move { register_datachannel_devices(kernel).await }
61 },
62 "register_datachannel_devices",
63 );
64}
65
66async fn register_datachannel_devices(kernel: Arc<Kernel>) {
67 let current_task = kernel.kthreads.system_task();
68 let service = match Service::open(fnanohub::StarnixDataChannelServiceMarker) {
69 Ok(service) => service,
70 Err(e) => {
71 log_warn!("Failed to open DriverService: {:?}", e);
72 return;
73 }
74 };
75 let mut watcher = match service.watch().await {
76 Ok(watcher) => watcher,
77 Err(e) => {
78 log_warn!("Failed to create watcher: {:?}", e);
79 return;
80 }
81 };
82
83 while let Ok(Some(data_channel_service_proxy)) = watcher.try_next().await {
84 let name = match (|| {
85 let device_proxy = data_channel_service_proxy.connect_to_waitable_sync()?;
86 let id = device_proxy.get_identifier(zx::MonotonicInstant::INFINITE)?;
87 Ok::<std::option::Option<std::string::String>, fidl::Error>(id.name)
88 })() {
89 Ok(Some(name)) => name,
90 Ok(None) => {
91 log_error!("Data channel device has no name, skipping registration");
92 continue;
93 }
94 Err(e) => {
95 log_error!("Failed to get device info: {:?}", e);
96 continue;
97 }
98 };
99
100 let registry = &kernel.device_registry;
101
102 let device_class =
103 registry.objects.get_or_create_class("nanohub".into(), registry.objects.virtual_bus());
104
105 if let Err(e) = registry.register_dyn_device_with_dir(
106 current_task.kernel().kthreads.unlocked_for_async().deref_mut(),
107 current_task,
108 name.as_bytes().into(),
109 device_class,
110 build_device_directory,
111 DataChannelDevice::new(
112 data_channel_service_proxy,
113 current_task.kernel().suspend_resume_manager.clone(),
114 ),
115 ) {
116 log_warn!("Failed to register datachannel device: {:?}", e);
117 }
118 }
119}
120
121async fn register_serial_device(kernel: Arc<Kernel>) {
122 let dir =
124 match fuchsia_fs::directory::open_in_namespace(SERIAL_DIRECTORY, fuchsia_fs::PERM_READABLE)
125 {
126 Ok(dir) => dir,
127 Err(e) => {
128 log_error!("Failed to open serial directory: {:}", e);
129 return;
130 }
131 };
132
133 let mut watcher = match fuchsia_fs::directory::Watcher::new(&dir).await {
134 Ok(watcher) => watcher,
135 Err(e) => {
136 log_info!("Failed to create directory watcher for serial device: {:}", e);
137 return;
138 }
139 };
140
141 loop {
142 match watcher.try_next().await {
143 Ok(Some(watch_msg)) => {
144 let current_task = kernel.kthreads.system_task();
145 let mut locked = kernel.kthreads.unlocked_for_async();
146 let locked = &mut locked;
147 let filename = watch_msg
148 .filename
149 .as_path()
150 .to_str()
151 .expect("Failed to convert watch_msg to str");
152 if filename == "." {
153 continue;
154 }
155 if watch_msg.event == fuchsia_fs::directory::WatchEvent::ADD_FILE
156 || watch_msg.event == fuchsia_fs::directory::WatchEvent::EXISTING
157 {
158 let instance_path = format!("{}/{}", SERIAL_DIRECTORY, filename);
159 let (client_channel, server_channel) = zx::Channel::create();
160 if let Err(_) = fdio::service_connect(&instance_path, server_channel) {
161 continue;
162 }
163
164 let device_proxy = fserial::DeviceProxy_SynchronousProxy::new(client_channel);
168 let (serial_proxy, server_end) =
169 fidl::endpoints::create_sync_proxy::<fserial::DeviceMarker>();
170
171 if let Err(_) = device_proxy.get_channel(server_end) {
173 continue;
174 }
175
176 let device_class = match serial_proxy.get_class(zx::MonotonicInstant::INFINITE)
178 {
179 Ok(class) => class,
180 Err(_) => continue,
181 };
182
183 if device_class == fserial::Class::Mcu {
184 let serial_device = SerialDevice::new(
185 locked,
186 current_task,
187 serial_proxy.into_channel().into(),
188 )
189 .expect("Can create SerialDevice wrapper");
190
191 let registry = ¤t_task.kernel().device_registry;
195 registry
196 .register_dyn_device(
197 locked,
198 current_task,
199 "ttyHS1".into(),
200 registry.objects.tty_class(),
201 serial_device,
202 )
203 .expect("Can register serial device");
204 break;
205 }
206 }
207 }
208 Ok(None) => {
209 break;
210 }
211 Err(e) => {
212 log_error!("Serial driver stream ended with error: {:}", e);
213 break;
214 }
215 }
216 }
217}