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