Controlling USB Hub Port Power Via Rust on Linux

    pub async fn set_port_power(
        &self,
        find_vendor_id: &str,
        find_product_id: &str,
        port: u32,
        enable: bool
    ) -> Result<()> {
        let find_vendor_id = find_vendor_id.to_string();
        let find_product_id = find_product_id.to_string();
        let map = Self::find_ports(find_vendor_id, find_product_id).await?;
        let (_, path) = map.get_key_value(&port).ok_or(anyhow!("Port not fond"))?;
        let contents = if enable {
            "0".as_bytes()
        } else {
            "1".as_bytes()
        };

        tokio::fs::write(path, contents).await?;

        Ok(())
    }

    async fn find_ports(
        find_vendor_id: String,
        find_product_id: String,
    ) -> Result<HashMap<u32, String>> {
        const SYS_PATH: &'static str = "/sys/bus/usb/devices";
        let devices = tokio::fs::read_dir(SYS_PATH).await?;
        let mut devices = ReadDirStream::new(devices);
        let mut ports = HashMap::new();
        while let Some(Ok(entry)) = devices.next().await {
            let file_name = entry.file_name();
            let device_path = file_name.to_string_lossy();
            if device_path.contains(":") {
                continue;
            }
            let vendor_id_path = format!("{}/{}/idVendor", SYS_PATH, device_path);
            let product_id_path = format!("{}/{}/idProduct", SYS_PATH, device_path);

            let vendor_id = String::from_utf8(tokio::fs::read(vendor_id_path).await?)?;
            let product_id = String::from_utf8(tokio::fs::read(product_id_path).await?)?;
            let vendor_id = vendor_id.trim();
            let product_id = product_id.trim();

            if find_vendor_id != vendor_id || find_product_id != product_id {
                continue;
            }

            let ports_control_dir = format!("{}/{}:1.0", SYS_PATH, device_path);

            let mut stream = ReadDirStream::new(tokio::fs::read_dir(&ports_control_dir).await?);
            while let Some(Ok(entry)) =
                stream
                    .next()
                    .await
            {
                let port_name = entry.file_name();
                let port_name = port_name.to_string_lossy().to_string();
                if !port_name.contains("-port") {
                    continue;
                }
                let parts: Vec<String> = port_name.split("-").into_iter().map(|e|e.to_string()).collect();
                let port :u32 = parts.get(2).unwrap().clone().replace("port","").parse()?;
                ports.insert(port, format!("{}/{}:1.0/{}/disable", SYS_PATH, device_path, port_name));
            }
            if !ports.is_empty() {
                return Ok(ports)
            }
        }
        Err(anyhow!("Not found"))
    }
}

Related Posts

Leave a Reply

Your email address will not be published. Required fields are marked *