Skip to content

Commit 84f1a5f

Browse files
committed
add fallback serial detect when musl
1 parent 61245b1 commit 84f1a5f

File tree

1 file changed

+57
-4
lines changed

1 file changed

+57
-4
lines changed

espflash/src/cli/serial.rs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,19 +49,72 @@ pub fn get_serial_port(matches: &ConnectArgs, config: &Config) -> Result<String,
4949
}
5050
}
5151

52+
/// serialport's autodetect doesn't provide any port information when using musl linux
53+
/// we can do some manual parsing of sysfs to get the relevant bits without udev
54+
#[cfg(all(target_os = "linux", target_env = "musl"))]
5255
fn detect_usb_serial_ports() -> Result<Vec<SerialPortInfo>> {
56+
use serialport::UsbPortInfo;
57+
use std::fs::read_link;
58+
use std::fs::read_to_string;
59+
use std::path::PathBuf;
60+
5361
let ports = available_ports().into_diagnostic()?;
5462
let ports = ports
55-
.iter()
56-
.filter_map(|port_info| match port_info.port_type {
57-
SerialPortType::UsbPort(..) => Some(port_info.to_owned()),
58-
_ => None,
63+
.into_iter()
64+
.filter_map(|port_info| {
65+
// with musl, the paths we get are `/sys/class/tty/*`
66+
let path = PathBuf::from(&port_info.port_name);
67+
68+
// this will give something like `/sys/devices/pci0000:00/0000:00:07.1/0000:0c:00.3/usb5/5-3/5-3.1/5-3.1:1.0/ttyUSB0/tty/ttyUSB0`
69+
let mut parent_dev = path.canonicalize().ok()?;
70+
71+
// walk up 3 dirs to get to the device hosting the tty `/sys/devices/pci0000:00/0000:00:07.1/0000:0c:00.3/usb5/5-3/5-3.1/5-3.1:1.0`
72+
parent_dev.pop();
73+
parent_dev.pop();
74+
parent_dev.pop();
75+
76+
// check that the device is using the usb subsystem
77+
read_link(parent_dev.join("subsystem"))
78+
.ok()
79+
.filter(|subsystem| subsystem.ends_with("usb"))?;
80+
81+
let interface = read_to_string(parent_dev.join("interface"))
82+
.ok()
83+
.map(|s| s.trim().to_string());
84+
85+
// /sys/devices/pci0000:00/0000:00:07.1/0000:0c:00.3/usb5/5-3/5-3.1
86+
parent_dev.pop();
87+
88+
let vid = read_to_string(parent_dev.join("idVendor")).ok()?;
89+
let pid = read_to_string(parent_dev.join("idProduct")).ok()?;
90+
91+
Some(SerialPortInfo {
92+
port_type: SerialPortType::UsbPort(UsbPortInfo {
93+
vid: u16::from_str_radix(vid.trim(), 16).ok()?,
94+
pid: u16::from_str_radix(pid.trim(), 16).ok()?,
95+
product: interface,
96+
serial_number: None,
97+
manufacturer: None,
98+
}),
99+
port_name: format!("/dev/{}", path.file_name()?.to_str()?),
100+
})
59101
})
60102
.collect::<Vec<_>>();
61103

62104
Ok(ports)
63105
}
64106

107+
#[cfg(not(all(target_os = "linux", target_env = "musl")))]
108+
fn detect_usb_serial_ports() -> Result<Vec<SerialPortInfo>> {
109+
let ports = available_ports().into_diagnostic()?;
110+
let ports = ports
111+
.into_iter()
112+
.filter(|port_info| matches!(&port_info.port_type, SerialPortType::UsbPort(..)))
113+
.collect::<Vec<_>>();
114+
115+
Ok(ports)
116+
}
117+
65118
/// USB UART adapters which are known to be on common dev boards
66119
const KNOWN_DEVICES: &[UsbDevice] = &[
67120
UsbDevice {

0 commit comments

Comments
 (0)