c0587f9a2d
The 556MB monolithic redox.patch was impossible to manage, unreviewable, blocked GitHub pushes, and could only grow. This commit: - Moves all 64 absorbed patches from absorbed/ to active use in base/ - Removes the absorbed/ directory (consolidation history is now PATCH-HISTORY.md) - Removes the redox.patch symlink from recipes/core/base/ - Fixes all recipe symlinks to point to active patches (not absorbed/) - Patches are now individually wired, reviewable, and independently rebasable The redox.patch mega-file is no longer needed — individual patches are applied directly from the recipe.toml patches list.
159 lines
6.4 KiB
Diff
159 lines
6.4 KiB
Diff
# P2-usb-pm-and-drivers.patch
|
|
#
|
|
# USB power management and driver interface improvements:
|
|
# suspend/resume commands, SCSI driver enablement, PortPmState type,
|
|
# IRQ reactor staged port state fallback.
|
|
#
|
|
# Covers:
|
|
# - usbctl/main.rs: pm-state, suspend, resume subcommands
|
|
# - xhcid/drivers.toml: enable SCSI over USB driver (was commented out)
|
|
# - xhcid/driver_interface.rs: PortPmState enum, suspend/resume/port_pm_state methods
|
|
# - xhcid/irq_reactor.rs: staged_port_states fallback in with_ring/with_ring_mut
|
|
#
|
|
diff --git a/drivers/usb/usbctl/src/main.rs b/drivers/usb/usbctl/src/main.rs
|
|
index 9b5773d9..232f7cfc 100644
|
|
--- a/drivers/usb/usbctl/src/main.rs
|
|
+++ b/drivers/usb/usbctl/src/main.rs
|
|
@@ -15,6 +15,9 @@ fn main() {
|
|
Command::new("port")
|
|
.arg(Arg::new("PORT").num_args(1).required(true))
|
|
.subcommand(Command::new("status"))
|
|
+ .subcommand(Command::new("pm-state"))
|
|
+ .subcommand(Command::new("suspend"))
|
|
+ .subcommand(Command::new("resume"))
|
|
.subcommand(
|
|
Command::new("endpoint")
|
|
.arg(Arg::new("ENDPOINT_NUM").num_args(1).required(true))
|
|
@@ -38,7 +41,16 @@ fn main() {
|
|
if let Some(_status_scmd_matches) = port_scmd_matches.subcommand_matches("status") {
|
|
let state = handle.port_state().expect("Failed to get port state");
|
|
println!("{}", state.as_str());
|
|
+ } else if let Some(_pm_state_scmd_matches) = port_scmd_matches.subcommand_matches("pm-state") {
|
|
+ let state = handle
|
|
+ .port_pm_state()
|
|
+ .expect("Failed to get port power-management state");
|
|
+ println!("{}", state.as_str());
|
|
+ } else if let Some(_suspend_scmd_matches) = port_scmd_matches.subcommand_matches("suspend") {
|
|
+ handle.suspend_device().expect("Failed to suspend device");
|
|
+ } else if let Some(_resume_scmd_matches) = port_scmd_matches.subcommand_matches("resume") {
|
|
+ handle.resume_device().expect("Failed to resume device");
|
|
} else if let Some(endp_scmd_matches) = port_scmd_matches.subcommand_matches("endpoint") {
|
|
let endp_num = endp_scmd_matches
|
|
|
|
.get_one::<String>("ENDPOINT_NUM")
|
|
diff --git a/drivers/usb/xhcid/drivers.toml b/drivers/usb/xhcid/drivers.toml
|
|
index 83c90e23..470ec063 100644
|
|
--- a/drivers/usb/xhcid/drivers.toml
|
|
+++ b/drivers/usb/xhcid/drivers.toml
|
|
@@ -1,10 +1,9 @@
|
|
-#TODO: causes XHCI errors
|
|
-#[[drivers]]
|
|
-#name = "SCSI over USB"
|
|
-#class = 8 # Mass Storage class
|
|
-#subclass = 6 # SCSI transparent command set
|
|
-#command = ["usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"]
|
|
+[[drivers]]
|
|
+name = "SCSI over USB"
|
|
+class = 8 # Mass Storage class
|
|
+subclass = 6 # SCSI transparent command set
|
|
+command = ["usbscsid", "$SCHEME", "$PORT", "$IF_PROTO"]
|
|
|
|
[[drivers]]
|
|
name = "USB HUB"
|
|
|
|
diff --git a/drivers/usb/xhcid/src/driver_interface.rs b/drivers/usb/xhcid/src/driver_interface.rs
|
|
index 727f8d7e..82f839ae 100644
|
|
--- a/drivers/usb/xhcid/src/driver_interface.rs
|
|
+++ b/drivers/usb/xhcid/src/driver_interface.rs
|
|
@@ -444,6 +444,33 @@ impl str::FromStr for PortState {
|
|
}
|
|
}
|
|
|
|
+#[repr(u8)]
|
|
+#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
|
+pub enum PortPmState {
|
|
+ Active,
|
|
+ Suspended,
|
|
+}
|
|
+impl PortPmState {
|
|
+ pub fn as_str(&self) -> &'static str {
|
|
+ match self {
|
|
+ Self::Active => "active",
|
|
+ Self::Suspended => "suspended",
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+impl str::FromStr for PortPmState {
|
|
+ type Err = Invalid;
|
|
+
|
|
+ fn from_str(s: &str) -> result::Result<Self, Self::Err> {
|
|
+ Ok(match s {
|
|
+ "active" => Self::Active,
|
|
+ "suspended" => Self::Suspended,
|
|
+ _ => return Err(Invalid("read reserved port PM state")),
|
|
+ })
|
|
+ }
|
|
+}
|
|
+
|
|
#[repr(u8)]
|
|
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
|
pub enum EndpointStatus {
|
|
@@ -560,6 +587,16 @@ impl XhciClientHandle {
|
|
let _bytes_written = file.write(&[])?;
|
|
Ok(())
|
|
}
|
|
+ pub fn suspend_device(&self) -> result::Result<(), XhciClientHandleError> {
|
|
+ let file = self.fd.openat("suspend", libredox::flag::O_WRONLY, 0)?;
|
|
+ let _bytes_written = file.write(&[])?;
|
|
+ Ok(())
|
|
+ }
|
|
+ pub fn resume_device(&self) -> result::Result<(), XhciClientHandleError> {
|
|
+ let file = self.fd.openat("resume", libredox::flag::O_WRONLY, 0)?;
|
|
+ let _bytes_written = file.write(&[])?;
|
|
+ Ok(())
|
|
+ }
|
|
pub fn get_standard_descs(&self) -> result::Result<DevDesc, XhciClientHandleError> {
|
|
let json = self.read("descriptors")?;
|
|
Ok(serde_json::from_slice(&json)?)
|
|
@@ -582,7 +619,11 @@ impl XhciClientHandle {
|
|
let string = self.read_to_string("state")?;
|
|
Ok(string.parse()?)
|
|
}
|
|
+ pub fn port_pm_state(&self) -> result::Result<PortPmState, XhciClientHandleError> {
|
|
+ let string = self.read_to_string("pm_state")?;
|
|
+ Ok(string.parse()?)
|
|
+ }
|
|
pub fn open_endpoint_ctl(&self, num: u8) -> result::Result<File, XhciClientHandleError> {
|
|
let path = format!("endpoints/{}/ctl", num);
|
|
let fd = self.fd.openat(&path, libredox::flag::O_RDWR, 0)?;
|
|
|
|
diff --git a/drivers/usb/xhcid/src/xhci/irq_reactor.rs b/drivers/usb/xhcid/src/xhci/irq_reactor.rs
|
|
index ac492d5b..310fe51f 100644
|
|
--- a/drivers/usb/xhcid/src/xhci/irq_reactor.rs
|
|
+++ b/drivers/usb/xhcid/src/xhci/irq_reactor.rs
|
|
@@ -633,7 +633,10 @@ impl<const N: usize> Xhci<N> {
|
|
pub fn with_ring<T, F: FnOnce(&Ring) -> T>(&self, id: RingId, function: F) -> Option<T> {
|
|
use super::RingOrStreams;
|
|
|
|
- let slot_state = self.port_states.get(&id.port)?;
|
|
+ let slot_state = self
|
|
+ .port_states
|
|
+ .get(&id.port)
|
|
+ .or_else(|| self.staged_port_states.get(&id.port))?;
|
|
let endpoint_state = slot_state.endpoint_states.get(&id.endpoint_num)?;
|
|
|
|
let ring_ref = match endpoint_state.transfer {
|
|
@@ -650,7 +653,10 @@ impl<const N: usize> Xhci<N> {
|
|
) -> Option<T> {
|
|
use super::RingOrStreams;
|
|
|
|
- let mut slot_state = self.port_states.get_mut(&id.port)?;
|
|
+ let mut slot_state = self
|
|
+ .port_states
|
|
+ .get_mut(&id.port)
|
|
+ .or_else(|| self.staged_port_states.get_mut(&id.port))?;
|
|
let mut endpoint_state = slot_state.endpoint_states.get_mut(&id.endpoint_num)?;
|
|
|
|
let ring_ref = match endpoint_state.transfer {
|