diff --git a/crates/openlogi-hid/src/route.rs b/crates/openlogi-hid/src/route.rs index 6ef415d7..c09b2e5d 100644 --- a/crates/openlogi-hid/src/route.rs +++ b/crates/openlogi-hid/src/route.rs @@ -91,12 +91,14 @@ pub const BOLT_PIDS: &[u16] = &[0xc548]; /// Unifying, so it routes as [`DeviceRoute::Unifying`]. pub const UNIFYING_PIDS: &[u16] = &[0xc52b, 0xc532, 0xc539]; -/// USB product IDs that identify Logitech Lightspeed nano receivers — the -/// receivers bundled with G-series wireless mice such as the G305. They speak -/// the same HID++ 1.0 receiver register protocol as Unifying, so they are -/// enumerated, routed, and paired through the Unifying code path; only the -/// user-facing receiver name (see [`receiver_display_name`]) differs. -pub const LIGHTSPEED_PIDS: &[u16] = &[0xc53f]; +/// USB product IDs that identify Logitech Lightspeed receivers — the +/// receivers bundled with G-series wireless devices. `0xc53f` is the nano +/// receiver of wireless mice such as the G305; `0xc547` ships with newer +/// G-series devices such as the G915 keyboard and the G502 X LIGHTSPEED. +/// They speak the same HID++ 1.0 receiver register protocol as Unifying, so +/// they are enumerated, routed, and paired through the Unifying code path; +/// only the user-facing receiver name (see [`receiver_display_name`]) differs. +pub const LIGHTSPEED_PIDS: &[u16] = &[0xc53f, 0xc547]; /// Whether `product_id` is a receiver that speaks the Unifying HID++ 1.0 /// register protocol — a Unifying receiver proper, or a protocol-compatible @@ -336,6 +338,7 @@ mod tests { #[test] fn lightspeed_receiver_has_its_own_display_name() { assert_eq!(receiver_display_name(0xc53f), "Lightspeed Receiver"); + assert_eq!(receiver_display_name(0xc547), "Lightspeed Receiver"); assert_eq!(receiver_display_name(0xc52b), "Unifying Receiver"); } diff --git a/crates/openlogi-hid/src/transport.rs b/crates/openlogi-hid/src/transport.rs index afe57815..1d5b7a56 100644 --- a/crates/openlogi-hid/src/transport.rs +++ b/crates/openlogi-hid/src/transport.rs @@ -241,6 +241,7 @@ fn is_receiver_child_sysfs_path(path: &str) -> bool { crate::BOLT_PIDS .iter() .chain(crate::UNIFYING_PIDS.iter()) + .chain(crate::LIGHTSPEED_PIDS.iter()) .any(|&pid| { let marker = format!(":{LOGITECH_VID:04X}:{pid:04X}."); // A parent component contains the marker followed by at least one diff --git a/crates/openlogi-hid/src/transport/tests.rs b/crates/openlogi-hid/src/transport/tests.rs index a499e8b7..6a05340a 100644 --- a/crates/openlogi-hid/src/transport/tests.rs +++ b/crates/openlogi-hid/src/transport/tests.rs @@ -85,6 +85,9 @@ const UNIFYING_RECEIVER: &str = "/sys/devices/pci0000:00/0000:00:14.0/usb3/3-5/3 // Sysfs path: child of Bolt receiver const BOLT_CHILD: &str = "/sys/devices/pci0000:00/0000:00:14.0/usb3/3-5/\ 0003:046D:C548.0001/0003:046D:B037.0002"; +// Sysfs path: child of a Lightspeed receiver (a G915, wpid 407C, on c547) +const LIGHTSPEED_CHILD: &str = "/sys/devices/pci0000:00/0000:00:14.0/usb3/3-5/\ + 0003:046D:C547.0003/0003:046D:407C.0004"; // Sysfs path: unrelated non-Logitech device const UNRELATED: &str = "/sys/devices/pci0000:00/0000:00:15.0/i2c-0/0018:06CB:CE67.0001"; @@ -103,6 +106,11 @@ fn child_of_bolt_receiver_is_detected() { assert!(is_receiver_child_sysfs_path(BOLT_CHILD)); } +#[test] +fn child_of_lightspeed_receiver_is_detected() { + assert!(is_receiver_child_sysfs_path(LIGHTSPEED_CHILD)); +} + #[test] fn unrelated_device_is_not_a_child() { assert!(!is_receiver_child_sysfs_path(UNRELATED)); diff --git a/crates/openlogi-hidpp/src/receiver/unifying.rs b/crates/openlogi-hidpp/src/receiver/unifying.rs index 1fac152b..acef9314 100755 --- a/crates/openlogi-hidpp/src/receiver/unifying.rs +++ b/crates/openlogi-hidpp/src/receiver/unifying.rs @@ -23,16 +23,20 @@ use crate::{ /// receivers. /// /// `046d:c539` is the Lightspeed gaming receiver; `046d:c53f` is the Lightspeed -/// nano receiver (bundled with G-series wireless mice such as the G305). Both -/// answer the same HID++ 1.0 registers (pairing count, connection state, pairing -/// information) as Unifying receivers. Callers that surface a user-facing -/// receiver name label Lightspeed PIDs separately (see `openlogi-hid`). -/// `0xc53f` was verified against a G305 (paired device wpid `0x4074`). +/// nano receiver (bundled with G-series wireless mice such as the G305); +/// `046d:c547` is the Lightspeed receiver bundled with newer G-series devices +/// such as the G915 keyboard and the G502 X LIGHTSPEED. All answer the same +/// HID++ 1.0 registers (pairing count, connection state, pairing information) +/// as Unifying receivers. Callers that surface a user-facing receiver name +/// label Lightspeed PIDs separately (see `openlogi-hid`). +/// `0xc53f` was verified against a G305 (paired device wpid `0x4074`); +/// `0xc547` against a G915 (paired device wpid `0x407c`). pub const VPID_PAIRS: &[(u16, u16)] = &[ (0x046d, 0xc52b), (0x046d, 0xc532), (0x046d, 0xc539), (0x046d, 0xc53f), + (0x046d, 0xc547), ]; /// All known registers of the Unifying receiver.