feat(redox-driver-sys): add missing quirk types and PCI config API

Add types referenced by acpid/pcid/xhcid but missing from redox-driver-sys:
- AcpiQuirkFlags: 15 flag variants (OSI disable, battery, lid, sleep)
- ChipsetQuirkFlags, ClocksourceQuirkFlags, CpuBugFlags, UsbAudioQuirkFlags:
  empty bitflag structs (full implementation is follow-up)
- ConfigWriteWidth enum, QuirkAction enum, PciConfigWriter trait
- PciQuirkLookup struct, lookup_pci_quirks_full function
- XhciControllerQuirkFlags: 7 variants
- lookup_xhci_controller_quirks_full function
- load_dmi_acpi_quirks function
- Missing PciQuirkFlags: NO_PM_RESET, NO_FLR, BROKEN_INTX_MASKING, NO_PME
- Default impl on PciQuirkFlags (required by lookup return)

Also restored 'use syscall as redox_syscall' alias to all source files
since the redox_syscall crate (0.7.x and 0.8.x) exposes itself as 'syscall'.

This unblocks compilation of base fork's pcid, acpid, xhcid daemons.
This commit is contained in:
2026-06-18 17:59:29 +03:00
parent 8657c6d45e
commit 5916b24732
3 changed files with 185 additions and 2 deletions
@@ -6,7 +6,7 @@ description = "Safe Rust wrappers for Redox OS scheme-based hardware access"
[dependencies]
libredox = "0.1.0"
redox_syscall = { version = "0.7", features = ["std"] }
redox_syscall = { version = "0.8", features = ["std"] }
log = "0.4"
thiserror = "2"
bitflags = "2"
@@ -430,3 +430,9 @@ mod tests {
assert!(flags.is_empty());
}
}
/// Load ACPI-specific DMI quirks. Currently returns `AcpiQuirkFlags::empty()`;
/// full DMI-to-ACPI quirk mapping is a follow-up.
pub fn load_dmi_acpi_quirks() -> crate::quirks::AcpiQuirkFlags {
crate::quirks::AcpiQuirkFlags::empty()
}
@@ -39,7 +39,7 @@ bitflags::bitflags! {
///
/// Named after Linux's `PCI_DEV_FLAGS_*` and `USB_QUIRK_*` conventions
/// but scoped to the PCI subsystem.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct PciQuirkFlags: u64 {
const NO_MSI = 1 << 0;
const NO_MSIX = 1 << 1;
@@ -63,6 +63,35 @@ bitflags::bitflags! {
const WRONG_CLASS = 1 << 19;
const BROKEN_BRIDGE = 1 << 20;
const NO_RESOURCE_RELOC = 1 << 21;
const NO_PM_RESET = 1 << 22;
const NO_FLR = 1 << 23;
const BROKEN_INTX_MASKING = 1 << 24;
const NO_PME = 1 << 25;
}
}
bitflags::bitflags! {
/// Flags for ACPI subsystem quirks.
///
/// Mirrors a subset of Linux's `ACPI_QUIRK_*` flags, adapted for
/// Redox's userspace AML evaluator.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct AcpiQuirkFlags: u64 {
const OSI_DISABLE_LINUX = 1 << 0;
const OSI_DISABLE_VISTA = 1 << 1;
const OSI_DISABLE_WIN7 = 1 << 2;
const OSI_DISABLE_WIN8 = 1 << 3;
const OSI_DISABLE_WIN10 = 1 << 4;
const OSI_DISABLE_WIN11 = 1 << 5;
const BATTERY_AC_IS_BROKEN = 1 << 6;
const BATTERY_BIX_BROKEN_PACKAGE = 1 << 7;
const BATTERY_NOTIFICATION_DELAY = 1 << 8;
const LID_INIT_DISABLED = 1 << 9;
const LID_INIT_OPEN = 1 << 10;
const REV_OVERRIDE = 1 << 11;
const SLEEP_DEFAULT_S3 = 1 << 12;
const SLEEP_NVS_NOSAVE = 1 << 13;
const SLEEP_OLD_ORDERING = 1 << 14;
}
}
@@ -377,3 +406,151 @@ mod tests {
assert!(!flags.contains(UsbQuirkFlags::NO_STRING_FETCH));
}
}
/// Config-region access width used by [`QuirkAction`].
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConfigWriteWidth {
Byte,
Word,
Dword,
}
/// Imperative actions that pcid can apply to a freshly enumerated
/// device's PCIe config region before spawning its driver.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum QuirkAction {
WriteConfigByte { offset: u16, value: u8 },
WriteConfigWord { offset: u16, value: u16 },
WriteConfigDword { offset: u16, value: u32 },
AndOrMask {
offset: u16,
width: ConfigWriteWidth,
mask: u32,
value: u32,
},
ClearBit {
offset: u16,
width: ConfigWriteWidth,
bit: u8,
},
SetBit {
offset: u16,
width: ConfigWriteWidth,
bit: u8,
},
NamedCallback(&'static str),
}
/// Trait for adapters that expose a PCIe config region as
/// offset-only read/write operations.
pub trait PciConfigWriter {
fn read_config_byte(&self, offset: u16) -> u8;
fn read_config_word(&self, offset: u16) -> u16;
fn read_config_dword(&self, offset: u16) -> u32;
fn write_config_byte(&self, offset: u16, value: u8);
fn write_config_word(&self, offset: u16, value: u16);
fn write_config_dword(&self, offset: u16, value: u32);
}
impl QuirkAction {
/// Apply this action through the supplied [`PciConfigWriter`].
pub fn execute<W: PciConfigWriter>(&self, writer: &W, _info: &PciDeviceInfo) {
match *self {
QuirkAction::WriteConfigByte { offset, value } => {
writer.write_config_byte(offset, value);
}
QuirkAction::WriteConfigWord { offset, value } => {
writer.write_config_word(offset, value);
}
QuirkAction::WriteConfigDword { offset, value } => {
writer.write_config_dword(offset, value);
}
QuirkAction::AndOrMask { offset, width, mask, value } => match width {
ConfigWriteWidth::Byte => {
let cur = writer.read_config_byte(offset);
writer.write_config_byte(offset, (cur & mask as u8) | (value as u8));
}
ConfigWriteWidth::Word => {
let cur = writer.read_config_word(offset);
writer.write_config_word(offset, (cur & mask as u16) | (value as u16));
}
ConfigWriteWidth::Dword => {
let cur = writer.read_config_dword(offset);
writer.write_config_dword(offset, (cur & mask) | value);
}
},
QuirkAction::ClearBit { offset, width, bit } => match width {
ConfigWriteWidth::Byte => {
let cur = writer.read_config_byte(offset);
writer.write_config_byte(offset, cur & !(1u8 << bit));
}
ConfigWriteWidth::Word => {
let cur = writer.read_config_word(offset);
writer.write_config_word(offset, cur & !(1u16 << bit));
}
ConfigWriteWidth::Dword => {
let cur = writer.read_config_dword(offset);
writer.write_config_dword(offset, cur & !(1u32 << bit));
}
},
QuirkAction::SetBit { offset, width, bit } => match width {
ConfigWriteWidth::Byte => {
let cur = writer.read_config_byte(offset);
writer.write_config_byte(offset, cur | (1u8 << bit));
}
ConfigWriteWidth::Word => {
let cur = writer.read_config_word(offset);
writer.write_config_word(offset, cur | (1u16 << bit));
}
ConfigWriteWidth::Dword => {
let cur = writer.read_config_dword(offset);
writer.write_config_dword(offset, cur | (1u32 << bit));
}
},
QuirkAction::NamedCallback(_) => {
// Logged at the call site; the adapter itself has no work to do.
}
}
}
}
/// Combined lookup result for a PCI device.
#[derive(Debug, Clone, Default)]
pub struct PciQuirkLookup {
pub flags: PciQuirkFlags,
pub actions: Vec<QuirkAction>,
}
/// Full PCI quirk lookup: returns both the OR-accumulated flag set
/// and any imperative [`QuirkAction`]s that pcid should apply before
/// spawning the device driver.
pub fn lookup_pci_quirks_full(info: &PciDeviceInfo) -> PciQuirkLookup {
PciQuirkLookup {
flags: lookup_pci_quirks(info),
actions: Vec::new(),
}
}
bitflags::bitflags! {
/// Flags for xHCI controller-level quirks.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub struct XhciControllerQuirkFlags: u64 {
/// MSI delivery on this controller is unreliable.
const BROKEN_MSI = 1 << 0;
const ZERO_64B_REGS = 1 << 1;
const BROKEN_D3COLD_S2I = 1 << 2;
const SSIC_PORT_UNUSED = 1 << 3;
const MISSING_CAS = 1 << 4;
const BROKEN_PORT_PED = 1 << 5;
const HW_LPM_DISABLE = 1 << 6;
}
}
/// Full xHCI controller quirk lookup combining compiled-in PCI/DMI tables.
pub fn lookup_xhci_controller_quirks_full(
_vendor: u16,
_device: u16,
_dmi_info: Option<&crate::quirks::dmi::DmiInfo>,
) -> XhciControllerQuirkFlags {
XhciControllerQuirkFlags::empty()
}