fix(sync): skip soft connect on dwc2
This commit is contained in:
parent
7002ba514a
commit
b65bdfb259
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -1642,7 +1642,7 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
|
||||
|
||||
[[package]]
|
||||
name = "lesavka_client"
|
||||
version = "0.14.38"
|
||||
version = "0.14.39"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-stream",
|
||||
@ -1676,7 +1676,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lesavka_common"
|
||||
version = "0.14.38"
|
||||
version = "0.14.39"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
@ -1688,7 +1688,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "lesavka_server"
|
||||
version = "0.14.38"
|
||||
version = "0.14.39"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
|
||||
@ -4,7 +4,7 @@ path = "src/main.rs"
|
||||
|
||||
[package]
|
||||
name = "lesavka_client"
|
||||
version = "0.14.38"
|
||||
version = "0.14.39"
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "lesavka_common"
|
||||
version = "0.14.38"
|
||||
version = "0.14.39"
|
||||
edition = "2024"
|
||||
build = "build.rs"
|
||||
|
||||
|
||||
@ -27,6 +27,25 @@ udc_state() {
|
||||
cat "/sys/class/udc/$udc/state" 2>/dev/null || echo "unknown"
|
||||
}
|
||||
|
||||
udc_driver() {
|
||||
local udc="$1"
|
||||
local driver=""
|
||||
driver="$(readlink -f "/sys/bus/platform/devices/$udc/driver" 2>/dev/null || true)"
|
||||
[[ -n $driver ]] || return 0
|
||||
basename "$driver"
|
||||
}
|
||||
|
||||
udc_supports_soft_connect() {
|
||||
local udc="$1"
|
||||
[[ -n $udc ]] || return 1
|
||||
[[ -w /sys/class/udc/$udc/soft_connect ]] || return 1
|
||||
[[ ${LESAVKA_FORCE_SOFT_CONNECT:-0} == 1 ]] && return 0
|
||||
local driver=""
|
||||
driver="$(udc_driver "$udc")"
|
||||
[[ $driver == "dwc2" ]] && return 1
|
||||
return 0
|
||||
}
|
||||
|
||||
is_attached_state() {
|
||||
case "$1" in
|
||||
configured|addressed|default|suspended)
|
||||
@ -47,7 +66,7 @@ detach_gadget() {
|
||||
return 0
|
||||
;;
|
||||
esac
|
||||
if [[ -n $udc && -w /sys/class/udc/$udc/soft_connect ]]; then
|
||||
if udc_supports_soft_connect "$udc"; then
|
||||
echo 0 >"/sys/class/udc/$udc/soft_connect" 2>/dev/null || true
|
||||
fi
|
||||
if [[ -n ${LESAVKA_DETACH_CLEAR_UDC:-} && -e $G/UDC ]]; then
|
||||
@ -71,7 +90,7 @@ attach_gadget() {
|
||||
log "UDC not found; need full setup"
|
||||
return 1
|
||||
fi
|
||||
if [[ -n $udc && -w /sys/class/udc/$udc/soft_connect ]]; then
|
||||
if udc_supports_soft_connect "$udc"; then
|
||||
echo 1 >"/sys/class/udc/$udc/soft_connect" 2>/dev/null || true
|
||||
fi
|
||||
if [[ -n ${LESAVKA_ATTACH_WRITE_UDC:-} && -e $G/UDC ]]; then
|
||||
|
||||
@ -10,7 +10,7 @@ bench = false
|
||||
|
||||
[package]
|
||||
name = "lesavka_server"
|
||||
version = "0.14.38"
|
||||
version = "0.14.39"
|
||||
edition = "2024"
|
||||
autobins = false
|
||||
|
||||
|
||||
@ -91,8 +91,10 @@ impl UsbGadget {
|
||||
/* 1 - detach gadget */
|
||||
info!("🔌 detaching gadget from {ctrl}");
|
||||
// a) drop pull-ups (if the controller offers the switch)
|
||||
let sc = format!("{}/class/udc/{ctrl}/soft_connect", Self::sysfs_root());
|
||||
let _ = Self::write_attr(&sc, "0"); // ignore errors - not all HW has it
|
||||
let sc = Self::soft_connect_path(&ctrl);
|
||||
if let Some(sc) = sc.as_deref() {
|
||||
let _ = Self::write_attr(sc, "0"); // ignore errors - not all HW has it
|
||||
}
|
||||
|
||||
// b) clear the UDC attribute; the kernel may transiently answer EBUSY
|
||||
for attempt in 1..=10 {
|
||||
@ -124,9 +126,9 @@ impl UsbGadget {
|
||||
/* 4 - re-attach + pull-up */
|
||||
info!("🔌 re-attaching gadget to {ctrl}");
|
||||
Self::write_attr(self.udc_file, &ctrl)?;
|
||||
if Path::new(&sc).exists() {
|
||||
if let Some(sc) = sc.as_deref() {
|
||||
// try to set the pull-up; ignore if the kernel rejects it
|
||||
match Self::write_attr(&sc, "1") {
|
||||
match Self::write_attr(sc, "1") {
|
||||
Err(err) => {
|
||||
// only swallow specific errno values
|
||||
if let Some(io) = err.downcast_ref::<std::io::Error>() {
|
||||
|
||||
@ -124,4 +124,27 @@ impl UsbGadget {
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
fn platform_driver(ctrl: &str) -> Option<String> {
|
||||
fs::read_link(format!(
|
||||
"{}/bus/platform/devices/{ctrl}/driver",
|
||||
Self::sysfs_root()
|
||||
))
|
||||
.ok()
|
||||
.and_then(|path| path.file_name().map(|name| name.to_string_lossy().into_owned()))
|
||||
}
|
||||
|
||||
fn soft_connect_path(ctrl: &str) -> Option<String> {
|
||||
let path = format!("{}/class/udc/{ctrl}/soft_connect", Self::sysfs_root());
|
||||
if !Path::new(&path).exists() {
|
||||
return None;
|
||||
}
|
||||
if env::var("LESAVKA_FORCE_SOFT_CONNECT").ok().as_deref() == Some("1") {
|
||||
return Some(path);
|
||||
}
|
||||
if Self::platform_driver(ctrl).as_deref() == Some("dwc2") {
|
||||
return None;
|
||||
}
|
||||
Some(path)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -23,3 +23,18 @@ fn core_script_rebuilds_incomplete_bound_gadgets() {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn core_script_skips_soft_connect_for_dwc2() {
|
||||
for expected in [
|
||||
"udc_driver()",
|
||||
"udc_supports_soft_connect()",
|
||||
"[[ $driver == \"dwc2\" ]] && return 1",
|
||||
"if udc_supports_soft_connect \"$udc\"; then",
|
||||
] {
|
||||
assert!(
|
||||
CORE_SCRIPT.contains(expected),
|
||||
"lesavka-core soft_connect guard missing: {expected}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ mod gadget_include_contract {
|
||||
include!(env!("LESAVKA_SERVER_GADGET_SRC"));
|
||||
|
||||
use serial_test::serial;
|
||||
use std::os::unix::fs::PermissionsExt;
|
||||
use std::os::unix::fs::{PermissionsExt, symlink};
|
||||
use temp_env::with_var;
|
||||
use tempfile::{NamedTempFile, tempdir};
|
||||
|
||||
@ -47,6 +47,12 @@ mod gadget_include_contract {
|
||||
&base.join("sys/bus/platform/drivers/dwc2/bind"),
|
||||
"placeholder\n",
|
||||
);
|
||||
let driver_target = base.join("sys/bus/platform/drivers/dwc2");
|
||||
let driver_link = base.join(format!("sys/bus/platform/devices/{ctrl}/driver"));
|
||||
if let Some(parent) = driver_link.parent() {
|
||||
std::fs::create_dir_all(parent).expect("create driver link parent");
|
||||
}
|
||||
symlink(&driver_target, &driver_link).expect("link controller driver");
|
||||
write_file(
|
||||
&base.join(format!("cfg/{gadget_name}/UDC")),
|
||||
&format!("{ctrl}\n"),
|
||||
@ -181,6 +187,33 @@ mod gadget_include_contract {
|
||||
let _ = UsbGadget::probe_platform_udc();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn soft_connect_path_skips_dwc2_platform_driver() {
|
||||
let dir = tempdir().expect("tempdir");
|
||||
let ctrl = "fake-ctrl.usb";
|
||||
build_fake_tree(dir.path(), ctrl, "lesavka-test", "not attached");
|
||||
|
||||
with_fake_roots(&dir.path().join("sys"), &dir.path().join("cfg"), || {
|
||||
assert!(UsbGadget::soft_connect_path(ctrl).is_none());
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[serial]
|
||||
fn soft_connect_path_can_be_forced_for_dwc2() {
|
||||
let dir = tempdir().expect("tempdir");
|
||||
let ctrl = "fake-ctrl.usb";
|
||||
build_fake_tree(dir.path(), ctrl, "lesavka-test", "not attached");
|
||||
|
||||
with_fake_roots(&dir.path().join("sys"), &dir.path().join("cfg"), || {
|
||||
with_var("LESAVKA_FORCE_SOFT_CONNECT", Some("1"), || {
|
||||
let path = UsbGadget::soft_connect_path(ctrl).expect("forced soft_connect path");
|
||||
assert!(path.ends_with("/soft_connect"));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn find_controller_returns_name_or_error_without_panicking() {
|
||||
let result = UsbGadget::find_controller();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user