diff --git a/src/otg/configfs.rs b/src/otg/configfs.rs index bacdd50b..6a783632 100644 --- a/src/otg/configfs.rs +++ b/src/otg/configfs.rs @@ -3,6 +3,7 @@ use std::fs::{self, File, OpenOptions}; use std::io::Write; use std::path::Path; +use std::process::Command; use crate::error::{AppError, Result}; @@ -29,6 +30,42 @@ pub fn is_configfs_available() -> bool { Path::new(CONFIGFS_PATH).exists() } +/// Ensure libcomposite support is available for USB gadget operations. +/// +/// This is a best-effort runtime fallback for systems where `libcomposite` +/// is built as a module and not loaded yet. It does not try to mount configfs; +/// mounting remains an explicit system responsibility. +pub fn ensure_libcomposite_loaded() -> Result<()> { + if is_configfs_available() { + return Ok(()); + } + + if !Path::new("/sys/module/libcomposite").exists() { + let status = Command::new("modprobe") + .arg("libcomposite") + .status() + .map_err(|e| { + AppError::Internal(format!("Failed to run modprobe libcomposite: {}", e)) + })?; + + if !status.success() { + return Err(AppError::Internal(format!( + "modprobe libcomposite failed with status {}", + status + ))); + } + } + + if is_configfs_available() { + Ok(()) + } else { + Err(AppError::Internal( + "libcomposite is not available after modprobe; check configfs mount and kernel support" + .to_string(), + )) + } +} + /// Find available UDC (USB Device Controller) pub fn find_udc() -> Option { let udc_path = Path::new("/sys/class/udc"); diff --git a/src/otg/service.rs b/src/otg/service.rs index 6daddd45..7885ae0f 100644 --- a/src/otg/service.rs +++ b/src/otg/service.rs @@ -397,6 +397,10 @@ impl OtgService { return Ok(()); } + if let Err(e) = super::configfs::ensure_libcomposite_loaded() { + warn!("Failed to ensure libcomposite is available: {}", e); + } + // Check if OTG is available if !Self::is_available() { let error = "OTG not available: ConfigFS not mounted or no UDC found".to_string();