From 02a90db8ce62f79c889967c790f8e4055342e60b Mon Sep 17 00:00:00 2001 From: Christian Meusel Date: Fri, 3 Jan 2025 22:46:28 +0100 Subject: [PATCH 1/4] Detect PCI devices too when using sysfs The PCI serial ports I have at hand have been rejected previously by the driver_override criterion: having the file present and its contents being '(null)'. Looking at the subsystem instead allows us to tell "actually existing" serial ports apart from other TTYs which are not actual serial devices. --- src/posix/enumerate.rs | 68 +++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/src/posix/enumerate.rs b/src/posix/enumerate.rs index 87dbdfe6..3399a40a 100644 --- a/src/posix/enumerate.rs +++ b/src/posix/enumerate.rs @@ -550,30 +550,39 @@ cfg_if! { u8::from_str_radix(&read_file_to_trimmed_string(dir, file)?, 16).ok() } - fn read_usb_port_info(device_path: &Path) -> Option { - let device_path = device_path + fn read_port_type(path: &Path) -> Option { + let path = path .canonicalize() .ok()?; - let subsystem = device_path.join("subsystem").canonicalize().ok()?; + let subsystem = path.join("subsystem").canonicalize().ok()?; let subsystem = subsystem.file_name()?.to_string_lossy(); - let usb_interface_path = if subsystem == "usb-serial" { - device_path.parent()? - } else if subsystem == "usb" { - &device_path - } else { - return None; - }; - let usb_device_path = usb_interface_path.parent()?; + match subsystem.as_ref() { + "pci" => Some(SerialPortType::PciPort), + "pnp" => Some(SerialPortType::Unknown), + "usb" => usb_port_type(&path), + "usb-serial" => usb_port_type(path.parent()?), + _ => None, + } + } + + fn usb_port_type(interface_path: &Path) -> Option { + let info = read_usb_port_info(interface_path)?; + Some(SerialPortType::UsbPort(info)) + } + + fn read_usb_port_info(interface_path: &Path) -> Option { + let device_path = interface_path.parent()?; - let vid = read_file_to_u16(&usb_device_path, &"idVendor")?; - let pid = read_file_to_u16(&usb_device_path, &"idProduct")?; + let vid = read_file_to_u16(&device_path, "idVendor")?; + let pid = read_file_to_u16(&device_path, "idProduct")?; #[cfg(feature = "usbportinfo-interface")] - let interface = read_file_to_u8(&usb_interface_path, &"bInterfaceNumber"); - let serial_number = read_file_to_trimmed_string(&usb_device_path, &"serial"); - let product = read_file_to_trimmed_string(&usb_device_path, &"product"); - let manufacturer = read_file_to_trimmed_string(&usb_device_path, &"manufacturer"); - Some(SerialPortType::UsbPort(UsbPortInfo { + let interface = read_file_to_u8(&interface_path, &"bInterfaceNumber"); + let serial_number = read_file_to_trimmed_string(&device_path, &"serial"); + let product = read_file_to_trimmed_string(&device_path, &"product"); + let manufacturer = read_file_to_trimmed_string(&device_path, &"manufacturer"); + + Some(UsbPortInfo { vid, pid, serial_number, @@ -581,7 +590,7 @@ cfg_if! { product, #[cfg(feature = "usbportinfo-interface")] interface, - })) + }) } /// Scans `/sys/class/tty` for serial devices (on Linux systems without libudev). @@ -589,7 +598,6 @@ cfg_if! { let mut vec = Vec::new(); let sys_path = Path::new("/sys/class/tty/"); let dev_path = Path::new("/dev"); - let mut s; for path in sys_path.read_dir().expect("/sys/class/tty/ doesn't exist on this system") { let raw_path = path?.path().clone(); let mut path = raw_path.clone(); @@ -599,16 +607,16 @@ cfg_if! { continue; } - let port_type = read_usb_port_info(&path).unwrap_or(SerialPortType::Unknown); - - path.push("driver_override"); - if path.is_file() { - s = String::new(); - File::open(path)?.read_to_string(&mut s)?; - if &s == "(null)\n" { - continue; - } - } + // Determine port type and proceed, if it's a known. + // + // TODO: Switch to a likely more readable let-else statement when our MSRV supports + // it. + let port_type = read_port_type(&path); + let port_type = if let Some(port_type) = port_type { + port_type + } else { + continue; + }; // Generate the device file path `/dev/DEVICE` from the TTY class path // `/sys/class/tty/DEVICE` and emit a serial device if this path exists. There are From 72b401391d21100c974a601b305c702c99304967 Mon Sep 17 00:00:00 2001 From: Christian Meusel Date: Sat, 4 Jan 2025 14:49:56 +0100 Subject: [PATCH 2/4] Detect UARTs of Broadcom SoCs when using sysfs For these UARTs the driver_overrive file containing '(null)' is also present and the previous filtering would have ignored them as well. --- src/posix/enumerate.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/posix/enumerate.rs b/src/posix/enumerate.rs index 3399a40a..14877d86 100644 --- a/src/posix/enumerate.rs +++ b/src/posix/enumerate.rs @@ -558,6 +558,8 @@ cfg_if! { let subsystem = subsystem.file_name()?.to_string_lossy(); match subsystem.as_ref() { + // Broadcom SoC UARTs (of Raspberry Pi devices). + "amba" => Some(SerialPortType::Unknown), "pci" => Some(SerialPortType::PciPort), "pnp" => Some(SerialPortType::Unknown), "usb" => usb_port_type(&path), From 12b0576ebb5d45c36a447b2b257791c8be7738aa Mon Sep 17 00:00:00 2001 From: Christian Meusel Date: Thu, 9 Jan 2025 22:47:46 +0100 Subject: [PATCH 3/4] Add changelog for enumerating ports from more subsystems --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 639364f0..4aaa18ed 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,10 @@ project adheres to [Semantic Versioning](https://semver.org/). ### Added ### Changed + +* Enumerate ports from more subsystems on Linux without libudev. + [#238](https://github.com/serialport/serialport-rs/pull/238) + ### Fixed ### Removed From 87cda61a4b43ad91c2727f6880bb1209989480d2 Mon Sep 17 00:00:00 2001 From: Christian Meusel Date: Thu, 9 Jan 2025 22:48:26 +0100 Subject: [PATCH 4/4] Fix spelling error in changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4aaa18ed..b0ae3f66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,7 @@ project adheres to [Semantic Versioning](https://semver.org/). ### Fixed -* Pin subdependeny `libc` to maintain compatibility with MSRV 1.59.0. +* Pin subdependency `libc` to maintain compatibility with MSRV 1.59.0. [#229](https://github.com/serialport/serialport-rs/pull/229)