diff options
author | Zach Reizner <zachr@google.com> | 2019-03-18 20:58:31 -0700 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2019-04-27 01:36:47 -0700 |
commit | aff94ca6da90b92503558b6ba7aa68e1180afd87 (patch) | |
tree | 74fc34c90d1f6e10e6e921dddea389bdd51ad3e6 | |
parent | d99cd0ae0b21d29d4e5145b889f97e9f6cd11b69 (diff) | |
download | crosvm-aff94ca6da90b92503558b6ba7aa68e1180afd87.tar crosvm-aff94ca6da90b92503558b6ba7aa68e1180afd87.tar.gz crosvm-aff94ca6da90b92503558b6ba7aa68e1180afd87.tar.bz2 crosvm-aff94ca6da90b92503558b6ba7aa68e1180afd87.tar.lz crosvm-aff94ca6da90b92503558b6ba7aa68e1180afd87.tar.xz crosvm-aff94ca6da90b92503558b6ba7aa68e1180afd87.tar.zst crosvm-aff94ca6da90b92503558b6ba7aa68e1180afd87.zip |
usb: support for listing attached usb devices
Originally, crosvm would list details about an attached usb device for a given port. This change allows getting details about multiple ports at once. This is intended to simplify command line usage and downstream consumers like concierge. TEST=various vmc commands Chrome UI for handling USB devices BUG=chromium:831850 Change-Id: I55681a7fea7425c897a22a579dcc15567683ef54 Reviewed-on: https://chromium-review.googlesource.com/1529765 Commit-Ready: Zach Reizner <zachr@chromium.org> Tested-by: Zach Reizner <zachr@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Reviewed-by: Zach Reizner <zachr@chromium.org>
-rw-r--r-- | devices/src/usb/host_backend/host_backend_device_provider.rs | 45 | ||||
-rw-r--r-- | src/main.rs | 20 | ||||
-rw-r--r-- | vm_control/src/lib.rs | 32 |
3 files changed, 65 insertions, 32 deletions
diff --git a/devices/src/usb/host_backend/host_backend_device_provider.rs b/devices/src/usb/host_backend/host_backend_device_provider.rs index 6a68951..8d39d80 100644 --- a/devices/src/usb/host_backend/host_backend_device_provider.rs +++ b/devices/src/usb/host_backend/host_backend_device_provider.rs @@ -18,7 +18,10 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::time::Duration; use sys_util::net::UnixSeqpacket; use sys_util::{error, WatchingEvents}; -use vm_control::{UsbControlCommand, UsbControlResult, UsbControlSocket}; +use vm_control::{ + UsbControlAttachedDevice, UsbControlCommand, UsbControlResult, UsbControlSocket, + USB_CONTROL_MAX_PORTS, +}; const SOCKET_TIMEOUT_MS: u64 = 2000; @@ -142,6 +145,27 @@ impl ProviderInner { } } + fn handle_list_devices(&self, ports: [u8; USB_CONTROL_MAX_PORTS]) -> UsbControlResult { + let mut devices: [UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS] = Default::default(); + for (result_index, &port_id) in ports.iter().enumerate() { + match self.usb_hub.get_port(port_id).and_then(|p| { + p.get_backend_device() + .as_ref() + .map(|d| (d.get_vid(), d.get_pid())) + }) { + Some((vendor_id, product_id)) => { + devices[result_index] = UsbControlAttachedDevice { + port: port_id, + vendor_id, + product_id, + } + } + None => continue, + } + } + UsbControlResult::Devices(devices) + } + fn on_event_helper(&self) -> Result<()> { let cmd = self.sock.recv().map_err(Error::ReadControlSock)?; match cmd { @@ -287,23 +311,8 @@ impl ProviderInner { } Ok(()) } - UsbControlCommand::ListDevice { port } => { - let port_number = port; - let result = match self.usb_hub.get_port(port_number) { - Some(port) => match port.get_backend_device().as_ref() { - Some(device) => { - let vid = device.get_vid(); - let pid = device.get_pid(); - UsbControlResult::Device { - port: port_number, - vid, - pid, - } - } - None => UsbControlResult::NoSuchDevice, - }, - None => UsbControlResult::NoSuchPort, - }; + UsbControlCommand::ListDevice { ports } => { + let result = self.handle_list_devices(ports); // The send failure will be logged, but event loop still think the event is // handled. let _ = self.sock.send(&result).map_err(Error::WriteControlSock); diff --git a/src/main.rs b/src/main.rs index b5ba7e7..48c1edd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -28,7 +28,7 @@ use sys_util::{ }; use vm_control::{ BalloonControlCommand, DiskControlCommand, MaybeOwnedFd, UsbControlCommand, UsbControlResult, - VmControlRequestSocket, VmRequest, VmResponse, + VmControlRequestSocket, VmRequest, VmResponse, USB_CONTROL_MAX_PORTS, }; use crate::argument::{print_help, set_arguments, Argument}; @@ -1105,14 +1105,12 @@ fn usb_detach(mut args: std::env::Args) -> ModifyUsbResult<UsbControlResult> { } } -fn usb_list(mut args: std::env::Args) -> ModifyUsbResult<UsbControlResult> { - let port: u8 = args - .next() - .map_or(Err(ModifyUsbError::ArgMissing("PORT")), |p| { - p.parse::<u8>() - .map_err(|e| ModifyUsbError::ArgParseInt("PORT", p.to_owned(), e)) - })?; - let request = VmRequest::UsbCommand(UsbControlCommand::ListDevice { port }); +fn usb_list(args: std::env::Args) -> ModifyUsbResult<UsbControlResult> { + let mut ports: [u8; USB_CONTROL_MAX_PORTS] = Default::default(); + for (index, port) in ports.iter_mut().enumerate() { + *port = index as u8 + } + let request = VmRequest::UsbCommand(UsbControlCommand::ListDevice { ports }); let response = handle_request(&request, args).map_err(|_| ModifyUsbError::SocketFailed)?; match response { VmResponse::UsbResponse(usb_resp) => Ok(usb_resp), @@ -1121,9 +1119,9 @@ fn usb_list(mut args: std::env::Args) -> ModifyUsbResult<UsbControlResult> { } fn modify_usb(mut args: std::env::Args) -> std::result::Result<(), ()> { - if args.len() < 3 { + if args.len() < 2 { print_help("crosvm usb", - "[attach BUS_ID:ADDR:VENDOR_ID:PRODUCT_ID [USB_DEVICE_PATH|-] | detach PORT | list PORT] VM_SOCKET...", &[]); + "[attach BUS_ID:ADDR:VENDOR_ID:PRODUCT_ID [USB_DEVICE_PATH|-] | detach PORT | list] VM_SOCKET...", &[]); return Err(()); } diff --git a/vm_control/src/lib.rs b/vm_control/src/lib.rs index 25902ea..0744b53 100644 --- a/vm_control/src/lib.rs +++ b/vm_control/src/lib.rs @@ -88,6 +88,13 @@ impl Default for VmRunMode { } } +/// The maximum number of devices that can be listed in one `UsbControlCommand`. +/// +/// This value was set to be equal to `xhci_regs::MAX_PORTS` for convenience, but it is not +/// necessary for correctness. Importing that value directly would be overkill because it would +/// require adding a big dependency for a single const. +pub const USB_CONTROL_MAX_PORTS: usize = 16; + #[derive(MsgOnSocket, Debug)] pub enum BalloonControlCommand { /// Set the size of the VM's balloon. @@ -129,10 +136,23 @@ pub enum UsbControlCommand { port: u8, }, ListDevice { - port: u8, + ports: [u8; USB_CONTROL_MAX_PORTS], }, } +#[derive(MsgOnSocket, Copy, Clone, Debug, Default)] +pub struct UsbControlAttachedDevice { + pub port: u8, + pub vendor_id: u16, + pub product_id: u16, +} + +impl UsbControlAttachedDevice { + fn valid(self) -> bool { + self.port != 0 + } +} + #[derive(MsgOnSocket, Debug)] pub enum UsbControlResult { Ok { port: u8 }, @@ -140,7 +160,7 @@ pub enum UsbControlResult { NoSuchDevice, NoSuchPort, FailedToOpenDevice, - Device { port: u8, vid: u16, pid: u16 }, + Devices([UsbControlAttachedDevice; USB_CONTROL_MAX_PORTS]), } impl Display for UsbControlResult { @@ -153,7 +173,13 @@ impl Display for UsbControlResult { NoSuchDevice => write!(f, "no_such_device"), NoSuchPort => write!(f, "no_such_port"), FailedToOpenDevice => write!(f, "failed_to_open_device"), - Device { port, vid, pid } => write!(f, "device {} {:04x} {:04x}", port, vid, pid), + Devices(devices) => { + write!(f, "devices")?; + for d in devices.iter().filter(|d| d.valid()) { + write!(f, " {} {:04x} {:04x}", d.port, d.vendor_id, d.product_id)?; + } + std::result::Result::Ok(()) + } } } } |