1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2021 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use std::fs::OpenOptions;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::path::Path;
7*bb4ee6a4SAndroid Build Coastguard Worker use std::path::PathBuf;
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "pci-hotplug")]
10*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::anyhow;
11*bb4ee6a4SAndroid Build Coastguard Worker use anyhow::Result as AnyHowResult;
12*bb4ee6a4SAndroid Build Coastguard Worker use base::open_file_or_duplicate;
13*bb4ee6a4SAndroid Build Coastguard Worker use remain::sorted;
14*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error;
15*bb4ee6a4SAndroid Build Coastguard Worker
16*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
17*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::gpu::do_gpu_display_add;
18*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
19*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::gpu::do_gpu_display_list;
20*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
21*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::gpu::do_gpu_display_remove;
22*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
23*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::gpu::do_gpu_set_display_mouse_mode;
24*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "gpu")]
25*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::gpu::ModifyGpuResult;
26*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::sys::handle_request;
27*bb4ee6a4SAndroid Build Coastguard Worker pub use crate::sys::handle_request_with_timeout;
28*bb4ee6a4SAndroid Build Coastguard Worker use crate::BatControlCommand;
29*bb4ee6a4SAndroid Build Coastguard Worker use crate::BatControlResult;
30*bb4ee6a4SAndroid Build Coastguard Worker use crate::BatteryType;
31*bb4ee6a4SAndroid Build Coastguard Worker use crate::SwapCommand;
32*bb4ee6a4SAndroid Build Coastguard Worker use crate::UsbControlCommand;
33*bb4ee6a4SAndroid Build Coastguard Worker use crate::UsbControlResult;
34*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmRequest;
35*bb4ee6a4SAndroid Build Coastguard Worker use crate::VmResponse;
36*bb4ee6a4SAndroid Build Coastguard Worker use crate::USB_CONTROL_MAX_PORTS;
37*bb4ee6a4SAndroid Build Coastguard Worker
38*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
39*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
40*bb4ee6a4SAndroid Build Coastguard Worker enum ModifyBatError {
41*bb4ee6a4SAndroid Build Coastguard Worker #[error("{0}")]
42*bb4ee6a4SAndroid Build Coastguard Worker BatControlErr(BatControlResult),
43*bb4ee6a4SAndroid Build Coastguard Worker }
44*bb4ee6a4SAndroid Build Coastguard Worker
45*bb4ee6a4SAndroid Build Coastguard Worker #[sorted]
46*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Error, Debug)]
47*bb4ee6a4SAndroid Build Coastguard Worker pub enum ModifyUsbError {
48*bb4ee6a4SAndroid Build Coastguard Worker #[error("failed to open device {0}: {1}")]
49*bb4ee6a4SAndroid Build Coastguard Worker FailedToOpenDevice(PathBuf, base::Error),
50*bb4ee6a4SAndroid Build Coastguard Worker #[error("socket failed")]
51*bb4ee6a4SAndroid Build Coastguard Worker SocketFailed,
52*bb4ee6a4SAndroid Build Coastguard Worker #[error("unexpected response: {0}")]
53*bb4ee6a4SAndroid Build Coastguard Worker UnexpectedResponse(VmResponse),
54*bb4ee6a4SAndroid Build Coastguard Worker #[error("{0}")]
55*bb4ee6a4SAndroid Build Coastguard Worker UsbControl(UsbControlResult),
56*bb4ee6a4SAndroid Build Coastguard Worker }
57*bb4ee6a4SAndroid Build Coastguard Worker
58*bb4ee6a4SAndroid Build Coastguard Worker pub type ModifyUsbResult<T> = std::result::Result<T, ModifyUsbError>;
59*bb4ee6a4SAndroid Build Coastguard Worker
60*bb4ee6a4SAndroid Build Coastguard Worker pub type VmsRequestResult = std::result::Result<(), ()>;
61*bb4ee6a4SAndroid Build Coastguard Worker
62*bb4ee6a4SAndroid Build Coastguard Worker /// Send a `VmRequest` that expects a `VmResponse::Ok` reply.
vms_request<T: AsRef<Path> + std::fmt::Debug>( request: &VmRequest, socket_path: T, ) -> VmsRequestResult63*bb4ee6a4SAndroid Build Coastguard Worker pub fn vms_request<T: AsRef<Path> + std::fmt::Debug>(
64*bb4ee6a4SAndroid Build Coastguard Worker request: &VmRequest,
65*bb4ee6a4SAndroid Build Coastguard Worker socket_path: T,
66*bb4ee6a4SAndroid Build Coastguard Worker ) -> VmsRequestResult {
67*bb4ee6a4SAndroid Build Coastguard Worker match handle_request(request, socket_path)? {
68*bb4ee6a4SAndroid Build Coastguard Worker VmResponse::Ok => Ok(()),
69*bb4ee6a4SAndroid Build Coastguard Worker r => {
70*bb4ee6a4SAndroid Build Coastguard Worker println!("unexpected response: {r}");
71*bb4ee6a4SAndroid Build Coastguard Worker Err(())
72*bb4ee6a4SAndroid Build Coastguard Worker }
73*bb4ee6a4SAndroid Build Coastguard Worker }
74*bb4ee6a4SAndroid Build Coastguard Worker }
75*bb4ee6a4SAndroid Build Coastguard Worker
76*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "pci-hotplug")]
77*bb4ee6a4SAndroid Build Coastguard Worker /// Send a `VmRequest` for PCI hotplug that expects `VmResponse::PciResponse::AddOk(bus)`
do_net_add<T: AsRef<Path> + std::fmt::Debug>( tap_name: &str, socket_path: T, ) -> AnyHowResult<u8>78*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_net_add<T: AsRef<Path> + std::fmt::Debug>(
79*bb4ee6a4SAndroid Build Coastguard Worker tap_name: &str,
80*bb4ee6a4SAndroid Build Coastguard Worker socket_path: T,
81*bb4ee6a4SAndroid Build Coastguard Worker ) -> AnyHowResult<u8> {
82*bb4ee6a4SAndroid Build Coastguard Worker let request =
83*bb4ee6a4SAndroid Build Coastguard Worker VmRequest::HotPlugNetCommand(crate::NetControlCommand::AddTap(tap_name.to_owned()));
84*bb4ee6a4SAndroid Build Coastguard Worker let response = handle_request(&request, socket_path).map_err(|()| anyhow!("socket error: "))?;
85*bb4ee6a4SAndroid Build Coastguard Worker match response {
86*bb4ee6a4SAndroid Build Coastguard Worker VmResponse::PciHotPlugResponse { bus } => Ok(bus),
87*bb4ee6a4SAndroid Build Coastguard Worker e => Err(anyhow!("Unexpected response: {:#}", e)),
88*bb4ee6a4SAndroid Build Coastguard Worker }
89*bb4ee6a4SAndroid Build Coastguard Worker }
90*bb4ee6a4SAndroid Build Coastguard Worker
91*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "pci-hotplug"))]
92*bb4ee6a4SAndroid Build Coastguard Worker /// Send a `VmRequest` for PCI hotplug that expects `VmResponse::PciResponse::AddOk(bus)`
do_net_add<T: AsRef<Path> + std::fmt::Debug>( _tap_name: &str, _socket_path: T, ) -> AnyHowResult<u8>93*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_net_add<T: AsRef<Path> + std::fmt::Debug>(
94*bb4ee6a4SAndroid Build Coastguard Worker _tap_name: &str,
95*bb4ee6a4SAndroid Build Coastguard Worker _socket_path: T,
96*bb4ee6a4SAndroid Build Coastguard Worker ) -> AnyHowResult<u8> {
97*bb4ee6a4SAndroid Build Coastguard Worker anyhow::bail!("Unsupported: pci-hotplug feature disabled");
98*bb4ee6a4SAndroid Build Coastguard Worker }
99*bb4ee6a4SAndroid Build Coastguard Worker
100*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(feature = "pci-hotplug")]
101*bb4ee6a4SAndroid Build Coastguard Worker /// Send a `VmRequest` for removing hotplugged PCI device that expects `VmResponse::Ok`
do_net_remove<T: AsRef<Path> + std::fmt::Debug>( bus_num: u8, socket_path: T, ) -> AnyHowResult<()>102*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_net_remove<T: AsRef<Path> + std::fmt::Debug>(
103*bb4ee6a4SAndroid Build Coastguard Worker bus_num: u8,
104*bb4ee6a4SAndroid Build Coastguard Worker socket_path: T,
105*bb4ee6a4SAndroid Build Coastguard Worker ) -> AnyHowResult<()> {
106*bb4ee6a4SAndroid Build Coastguard Worker let request = VmRequest::HotPlugNetCommand(crate::NetControlCommand::RemoveTap(bus_num));
107*bb4ee6a4SAndroid Build Coastguard Worker let response = handle_request(&request, socket_path).map_err(|()| anyhow!("socket error: "))?;
108*bb4ee6a4SAndroid Build Coastguard Worker match response {
109*bb4ee6a4SAndroid Build Coastguard Worker VmResponse::Ok => Ok(()),
110*bb4ee6a4SAndroid Build Coastguard Worker e => Err(anyhow!("Unexpected response: {:#}", e)),
111*bb4ee6a4SAndroid Build Coastguard Worker }
112*bb4ee6a4SAndroid Build Coastguard Worker }
113*bb4ee6a4SAndroid Build Coastguard Worker
114*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(not(feature = "pci-hotplug"))]
115*bb4ee6a4SAndroid Build Coastguard Worker /// Send a `VmRequest` for removing hotplugged PCI device that expects `VmResponse::Ok`
do_net_remove<T: AsRef<Path> + std::fmt::Debug>( _bus_num: u8, _socket_path: T, ) -> AnyHowResult<()>116*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_net_remove<T: AsRef<Path> + std::fmt::Debug>(
117*bb4ee6a4SAndroid Build Coastguard Worker _bus_num: u8,
118*bb4ee6a4SAndroid Build Coastguard Worker _socket_path: T,
119*bb4ee6a4SAndroid Build Coastguard Worker ) -> AnyHowResult<()> {
120*bb4ee6a4SAndroid Build Coastguard Worker anyhow::bail!("Unsupported: pci-hotplug feature disabled");
121*bb4ee6a4SAndroid Build Coastguard Worker }
122*bb4ee6a4SAndroid Build Coastguard Worker
do_usb_attach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, dev_path: &Path, ) -> ModifyUsbResult<UsbControlResult>123*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_usb_attach<T: AsRef<Path> + std::fmt::Debug>(
124*bb4ee6a4SAndroid Build Coastguard Worker socket_path: T,
125*bb4ee6a4SAndroid Build Coastguard Worker dev_path: &Path,
126*bb4ee6a4SAndroid Build Coastguard Worker ) -> ModifyUsbResult<UsbControlResult> {
127*bb4ee6a4SAndroid Build Coastguard Worker let usb_file = open_file_or_duplicate(dev_path, OpenOptions::new().read(true).write(true))
128*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| ModifyUsbError::FailedToOpenDevice(dev_path.into(), e))?;
129*bb4ee6a4SAndroid Build Coastguard Worker
130*bb4ee6a4SAndroid Build Coastguard Worker let request = VmRequest::UsbCommand(UsbControlCommand::AttachDevice { file: usb_file });
131*bb4ee6a4SAndroid Build Coastguard Worker let response =
132*bb4ee6a4SAndroid Build Coastguard Worker handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
133*bb4ee6a4SAndroid Build Coastguard Worker match response {
134*bb4ee6a4SAndroid Build Coastguard Worker VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
135*bb4ee6a4SAndroid Build Coastguard Worker r => Err(ModifyUsbError::UnexpectedResponse(r)),
136*bb4ee6a4SAndroid Build Coastguard Worker }
137*bb4ee6a4SAndroid Build Coastguard Worker }
138*bb4ee6a4SAndroid Build Coastguard Worker
do_security_key_attach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, dev_path: &Path, ) -> ModifyUsbResult<UsbControlResult>139*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_security_key_attach<T: AsRef<Path> + std::fmt::Debug>(
140*bb4ee6a4SAndroid Build Coastguard Worker socket_path: T,
141*bb4ee6a4SAndroid Build Coastguard Worker dev_path: &Path,
142*bb4ee6a4SAndroid Build Coastguard Worker ) -> ModifyUsbResult<UsbControlResult> {
143*bb4ee6a4SAndroid Build Coastguard Worker let usb_file = open_file_or_duplicate(dev_path, OpenOptions::new().read(true).write(true))
144*bb4ee6a4SAndroid Build Coastguard Worker .map_err(|e| ModifyUsbError::FailedToOpenDevice(dev_path.into(), e))?;
145*bb4ee6a4SAndroid Build Coastguard Worker
146*bb4ee6a4SAndroid Build Coastguard Worker let request = VmRequest::UsbCommand(UsbControlCommand::AttachSecurityKey { file: usb_file });
147*bb4ee6a4SAndroid Build Coastguard Worker let response =
148*bb4ee6a4SAndroid Build Coastguard Worker handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
149*bb4ee6a4SAndroid Build Coastguard Worker match response {
150*bb4ee6a4SAndroid Build Coastguard Worker VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
151*bb4ee6a4SAndroid Build Coastguard Worker r => Err(ModifyUsbError::UnexpectedResponse(r)),
152*bb4ee6a4SAndroid Build Coastguard Worker }
153*bb4ee6a4SAndroid Build Coastguard Worker }
154*bb4ee6a4SAndroid Build Coastguard Worker
do_usb_detach<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, port: u8, ) -> ModifyUsbResult<UsbControlResult>155*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_usb_detach<T: AsRef<Path> + std::fmt::Debug>(
156*bb4ee6a4SAndroid Build Coastguard Worker socket_path: T,
157*bb4ee6a4SAndroid Build Coastguard Worker port: u8,
158*bb4ee6a4SAndroid Build Coastguard Worker ) -> ModifyUsbResult<UsbControlResult> {
159*bb4ee6a4SAndroid Build Coastguard Worker let request = VmRequest::UsbCommand(UsbControlCommand::DetachDevice { port });
160*bb4ee6a4SAndroid Build Coastguard Worker let response =
161*bb4ee6a4SAndroid Build Coastguard Worker handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
162*bb4ee6a4SAndroid Build Coastguard Worker match response {
163*bb4ee6a4SAndroid Build Coastguard Worker VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
164*bb4ee6a4SAndroid Build Coastguard Worker r => Err(ModifyUsbError::UnexpectedResponse(r)),
165*bb4ee6a4SAndroid Build Coastguard Worker }
166*bb4ee6a4SAndroid Build Coastguard Worker }
167*bb4ee6a4SAndroid Build Coastguard Worker
do_usb_list<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, ) -> ModifyUsbResult<UsbControlResult>168*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_usb_list<T: AsRef<Path> + std::fmt::Debug>(
169*bb4ee6a4SAndroid Build Coastguard Worker socket_path: T,
170*bb4ee6a4SAndroid Build Coastguard Worker ) -> ModifyUsbResult<UsbControlResult> {
171*bb4ee6a4SAndroid Build Coastguard Worker let mut ports: [u8; USB_CONTROL_MAX_PORTS] = Default::default();
172*bb4ee6a4SAndroid Build Coastguard Worker for (index, port) in ports.iter_mut().enumerate() {
173*bb4ee6a4SAndroid Build Coastguard Worker *port = index as u8
174*bb4ee6a4SAndroid Build Coastguard Worker }
175*bb4ee6a4SAndroid Build Coastguard Worker let request = VmRequest::UsbCommand(UsbControlCommand::ListDevice { ports });
176*bb4ee6a4SAndroid Build Coastguard Worker let response =
177*bb4ee6a4SAndroid Build Coastguard Worker handle_request(&request, socket_path).map_err(|_| ModifyUsbError::SocketFailed)?;
178*bb4ee6a4SAndroid Build Coastguard Worker match response {
179*bb4ee6a4SAndroid Build Coastguard Worker VmResponse::UsbResponse(usb_resp) => Ok(usb_resp),
180*bb4ee6a4SAndroid Build Coastguard Worker r => Err(ModifyUsbError::UnexpectedResponse(r)),
181*bb4ee6a4SAndroid Build Coastguard Worker }
182*bb4ee6a4SAndroid Build Coastguard Worker }
183*bb4ee6a4SAndroid Build Coastguard Worker
184*bb4ee6a4SAndroid Build Coastguard Worker pub type DoModifyBatteryResult = std::result::Result<(), ()>;
185*bb4ee6a4SAndroid Build Coastguard Worker
do_modify_battery<T: AsRef<Path> + std::fmt::Debug>( socket_path: T, battery_type: &str, property: &str, target: &str, ) -> DoModifyBatteryResult186*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_modify_battery<T: AsRef<Path> + std::fmt::Debug>(
187*bb4ee6a4SAndroid Build Coastguard Worker socket_path: T,
188*bb4ee6a4SAndroid Build Coastguard Worker battery_type: &str,
189*bb4ee6a4SAndroid Build Coastguard Worker property: &str,
190*bb4ee6a4SAndroid Build Coastguard Worker target: &str,
191*bb4ee6a4SAndroid Build Coastguard Worker ) -> DoModifyBatteryResult {
192*bb4ee6a4SAndroid Build Coastguard Worker let response = match battery_type.parse::<BatteryType>() {
193*bb4ee6a4SAndroid Build Coastguard Worker Ok(type_) => match BatControlCommand::new(property.to_string(), target.to_string()) {
194*bb4ee6a4SAndroid Build Coastguard Worker Ok(cmd) => {
195*bb4ee6a4SAndroid Build Coastguard Worker let request = VmRequest::BatCommand(type_, cmd);
196*bb4ee6a4SAndroid Build Coastguard Worker Ok(handle_request(&request, socket_path)?)
197*bb4ee6a4SAndroid Build Coastguard Worker }
198*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => Err(ModifyBatError::BatControlErr(e)),
199*bb4ee6a4SAndroid Build Coastguard Worker },
200*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => Err(ModifyBatError::BatControlErr(e)),
201*bb4ee6a4SAndroid Build Coastguard Worker };
202*bb4ee6a4SAndroid Build Coastguard Worker
203*bb4ee6a4SAndroid Build Coastguard Worker match response {
204*bb4ee6a4SAndroid Build Coastguard Worker Ok(response) => {
205*bb4ee6a4SAndroid Build Coastguard Worker println!("{}", response);
206*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
207*bb4ee6a4SAndroid Build Coastguard Worker }
208*bb4ee6a4SAndroid Build Coastguard Worker Err(e) => {
209*bb4ee6a4SAndroid Build Coastguard Worker println!("error {}", e);
210*bb4ee6a4SAndroid Build Coastguard Worker Err(())
211*bb4ee6a4SAndroid Build Coastguard Worker }
212*bb4ee6a4SAndroid Build Coastguard Worker }
213*bb4ee6a4SAndroid Build Coastguard Worker }
214*bb4ee6a4SAndroid Build Coastguard Worker
do_swap_status<T: AsRef<Path> + std::fmt::Debug>(socket_path: T) -> VmsRequestResult215*bb4ee6a4SAndroid Build Coastguard Worker pub fn do_swap_status<T: AsRef<Path> + std::fmt::Debug>(socket_path: T) -> VmsRequestResult {
216*bb4ee6a4SAndroid Build Coastguard Worker let response = handle_request(&VmRequest::Swap(SwapCommand::Status), socket_path)?;
217*bb4ee6a4SAndroid Build Coastguard Worker match &response {
218*bb4ee6a4SAndroid Build Coastguard Worker VmResponse::SwapStatus(_) => {
219*bb4ee6a4SAndroid Build Coastguard Worker println!("{}", response);
220*bb4ee6a4SAndroid Build Coastguard Worker Ok(())
221*bb4ee6a4SAndroid Build Coastguard Worker }
222*bb4ee6a4SAndroid Build Coastguard Worker r => {
223*bb4ee6a4SAndroid Build Coastguard Worker println!("unexpected response: {r:?}");
224*bb4ee6a4SAndroid Build Coastguard Worker Err(())
225*bb4ee6a4SAndroid Build Coastguard Worker }
226*bb4ee6a4SAndroid Build Coastguard Worker }
227*bb4ee6a4SAndroid Build Coastguard Worker }
228*bb4ee6a4SAndroid Build Coastguard Worker
229*bb4ee6a4SAndroid Build Coastguard Worker pub type HandleRequestResult = std::result::Result<VmResponse, ()>;
230