summary refs log tree commit diff
diff options
context:
space:
mode:
authorDaniel Verkamp <dverkamp@chromium.org>2020-03-18 13:10:49 -0700
committerCommit Bot <commit-bot@chromium.org>2020-03-24 11:29:57 +0000
commit0dcbfa1176386d1e2f8f52947fe93004db195abe (patch)
tree2b76da7fbf56d6cdb6ef55021fcecfdc8e408a69
parent83fc5c49ba930a62ef1f4d93bc2004d779b6d16f (diff)
downloadcrosvm-0dcbfa1176386d1e2f8f52947fe93004db195abe.tar
crosvm-0dcbfa1176386d1e2f8f52947fe93004db195abe.tar.gz
crosvm-0dcbfa1176386d1e2f8f52947fe93004db195abe.tar.bz2
crosvm-0dcbfa1176386d1e2f8f52947fe93004db195abe.tar.lz
crosvm-0dcbfa1176386d1e2f8f52947fe93004db195abe.tar.xz
crosvm-0dcbfa1176386d1e2f8f52947fe93004db195abe.tar.zst
crosvm-0dcbfa1176386d1e2f8f52947fe93004db195abe.zip
usb: avoid setting configuration when unnecessary
On devices with only one configuration, skip the code that attempts to
change the device's active configuration, since it must always be the
single available configuration.

This works around an issue observed with some USB devices (e.g. Servo
Micro) where the initial Get Configuration control request fails with
-EPIPE.

BUG=chromium:1061382
BUG=b:151408644
TEST=Attach servo micro, see /dev/ttyUSB[012], screen /dev/ttyUSB0

Change-Id: Ic3333e1d70a0c57b090de64e4d3b7932ce2cf81d
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2108871
Reviewed-by: Stephen Barber <smbarber@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
Tested-by: George Engelbrecht <engeg@google.com>
Commit-Queue: George Engelbrecht <engeg@google.com>
-rw-r--r--devices/src/usb/host_backend/host_device.rs40
-rw-r--r--usb_util/src/device.rs13
2 files changed, 34 insertions, 19 deletions
diff --git a/devices/src/usb/host_backend/host_device.rs b/devices/src/usb/host_backend/host_device.rs
index 3b85ea2..196fa50 100644
--- a/devices/src/usb/host_backend/host_device.rs
+++ b/devices/src/usb/host_backend/host_device.rs
@@ -305,22 +305,31 @@ impl HostDevice {
             config
         );
         self.release_interfaces();
-        let cur_config = self
-            .device
-            .lock()
-            .get_active_configuration()
-            .map_err(Error::GetActiveConfig)?;
-        usb_debug!("current config is: {}", cur_config);
-        if config != cur_config {
-            self.device
-                .lock()
-                .set_active_configuration(config)
-                .map_err(Error::SetActiveConfig)?;
+        if self.device.lock().get_num_configurations() > 1 {
+            let cur_config = match self.device.lock().get_active_configuration() {
+                Ok(c) => Some(c),
+                Err(e) => {
+                    // The device may be in the default state, in which case
+                    // GET_CONFIGURATION may fail.  Assume the device needs to be
+                    // reconfigured.
+                    usb_debug!("Failed to get active configuration: {}", e);
+                    error!("Failed to get active configuration: {}", e);
+                    None
+                }
+            };
+            if Some(config) != cur_config {
+                self.device
+                    .lock()
+                    .set_active_configuration(config)
+                    .map_err(Error::SetActiveConfig)?;
+            }
+        } else {
+            usb_debug!("Only one configuration - not calling set_active_configuration");
         }
         let config_descriptor = self
             .device
             .lock()
-            .get_active_config_descriptor()
+            .get_config_descriptor(config)
             .map_err(Error::GetActiveConfig)?;
         self.claim_interfaces(&config_descriptor);
         self.create_endpoints(&config_descriptor)?;
@@ -337,10 +346,15 @@ impl HostDevice {
             .set_interface_alt_setting(interface, alt_setting)
             .map_err(Error::SetInterfaceAltSetting)?;
         self.alt_settings.insert(interface, alt_setting);
+        let config = self
+            .device
+            .lock()
+            .get_active_configuration()
+            .map_err(Error::GetActiveConfig)?;
         let config_descriptor = self
             .device
             .lock()
-            .get_active_config_descriptor()
+            .get_config_descriptor(config)
             .map_err(Error::GetActiveConfig)?;
         self.create_endpoints(&config_descriptor)?;
         Ok(TransferStatus::Completed)
diff --git a/usb_util/src/device.rs b/usb_util/src/device.rs
index aad77db..3ac1403 100644
--- a/usb_util/src/device.rs
+++ b/usb_util/src/device.rs
@@ -261,12 +261,8 @@ impl Device {
     }
 
     /// Get active config descriptor of this device.
-    pub fn get_active_config_descriptor(&self) -> Result<ConfigDescriptorTree> {
-        let active_config = self.get_active_configuration()?;
-        match self
-            .device_descriptor_tree
-            .get_config_descriptor(active_config)
-        {
+    pub fn get_config_descriptor(&self, config: u8) -> Result<ConfigDescriptorTree> {
+        match self.device_descriptor_tree.get_config_descriptor(config) {
             Some(config_descriptor) => Ok(config_descriptor.clone()),
             None => Err(Error::NoSuchDescriptor),
         }
@@ -297,6 +293,11 @@ impl Device {
         Ok(active_config)
     }
 
+    /// Get the total number of configurations for this device.
+    pub fn get_num_configurations(&self) -> u8 {
+        self.device_descriptor_tree.bNumConfigurations
+    }
+
     /// Clear the halt/stall condition for an endpoint.
     pub fn clear_halt(&self, ep_addr: u8) -> Result<()> {
         let endpoint: c_uint = ep_addr.into();