Allow subdrivers to get the capability structs.
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
use orbclient;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::str;
|
||||
|
||||
@@ -7,7 +7,8 @@ use std::os::unix::io::{FromRawFd, RawFd};
|
||||
use serde::{Serialize, Deserialize, de::DeserializeOwned};
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::pci;
|
||||
pub use crate::pci::PciBar;
|
||||
pub use crate::pci::msi::{MsiCapability, MsixCapability, MsixTableEntry};
|
||||
|
||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||
pub struct PciFunction {
|
||||
@@ -18,7 +19,7 @@ pub struct PciFunction {
|
||||
/// Number of PCI function
|
||||
pub func_num: u8,
|
||||
/// PCI Base Address Registers
|
||||
pub bars: [pci::PciBar; 6],
|
||||
pub bars: [PciBar; 6],
|
||||
/// BAR sizes
|
||||
pub bar_sizes: [u32; 6],
|
||||
/// Legacy IRQ line
|
||||
@@ -49,6 +50,9 @@ impl FeatureStatus {
|
||||
Self::Disabled
|
||||
}
|
||||
}
|
||||
pub fn is_enabled(&self) -> bool {
|
||||
if let &Self::Enabled = self { true } else { false }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
@@ -56,6 +60,19 @@ pub enum PciFeature {
|
||||
Msi,
|
||||
MsiX,
|
||||
}
|
||||
impl PciFeature {
|
||||
pub fn is_msi(&self) -> bool {
|
||||
if let &Self::Msi = self { true } else { false }
|
||||
}
|
||||
pub fn is_msix(&self) -> bool {
|
||||
if let &Self::MsiX = self { true } else { false }
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum PciFeatureInfo {
|
||||
Msi(MsiCapability),
|
||||
MsiX(MsixCapability),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum PcidClientHandleError {
|
||||
@@ -83,6 +100,7 @@ pub enum PcidClientRequest {
|
||||
RequestFeatures,
|
||||
EnableFeature(PciFeature),
|
||||
FeatureStatus(PciFeature),
|
||||
FeatureInfo(PciFeature),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
@@ -99,6 +117,7 @@ pub enum PcidClientResponse {
|
||||
FeatureEnabled(PciFeature),
|
||||
FeatureStatus(PciFeature, FeatureStatus),
|
||||
Error(PcidServerResponseError),
|
||||
FeatureInfo(PciFeature, PciFeatureInfo),
|
||||
}
|
||||
|
||||
// TODO: Ideally, pcid might have its own scheme, like lots of other Redox drivers, where this kind of IPC is done. Otherwise, instead of writing serde messages over
|
||||
@@ -158,4 +177,32 @@ impl PcidServerHandle {
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn fetch_all_features(&mut self) -> Result<Vec<(PciFeature, FeatureStatus)>> {
|
||||
self.send(&PcidClientRequest::RequestFeatures)?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::AllFeatures(a) => Ok(a),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn feature_status(&mut self, feature: PciFeature) -> Result<FeatureStatus> {
|
||||
self.send(&PcidClientRequest::FeatureStatus(feature))?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::FeatureStatus(feat, status) if feat == feature => Ok(status),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn enable_feature(&mut self, feature: PciFeature) -> Result<()> {
|
||||
self.send(&PcidClientRequest::EnableFeature(feature))?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::FeatureEnabled(feat) if feat == feature => Ok(()),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
pub fn feature_info(&mut self, feature: PciFeature) -> Result<PciFeatureInfo> {
|
||||
self.send(&PcidClientRequest::FeatureInfo(feature))?;
|
||||
match self.recv()? {
|
||||
PcidClientResponse::FeatureInfo(feat, info) if feat == feature => Ok(info),
|
||||
other => Err(PcidClientHandleError::InvalidResponse(other)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+14
-1
@@ -105,6 +105,18 @@ impl DriverHandler {
|
||||
None
|
||||
}).unwrap_or(FeatureStatus::Disabled),
|
||||
}),
|
||||
PcidClientRequest::FeatureInfo(feature) => PcidClientResponse::FeatureInfo(feature, match feature {
|
||||
PciFeature::Msi => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msi()) {
|
||||
PciFeatureInfo::Msi(*info)
|
||||
} else {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
|
||||
}
|
||||
PciFeature::MsiX => if let Some(info) = self.capabilities.iter().find_map(|(_, capability)| capability.as_msix()) {
|
||||
PciFeatureInfo::MsiX(*info)
|
||||
} else {
|
||||
return PcidClientResponse::Error(PcidServerResponseError::NonexistentFeature(feature));
|
||||
}
|
||||
}),
|
||||
}
|
||||
}
|
||||
fn handle_spawn(mut self, pcid_to_client_write: Option<usize>, pcid_from_client_read: Option<usize>, args: driver_interface::SubdriverArguments) {
|
||||
@@ -116,7 +128,7 @@ impl DriverHandler {
|
||||
|
||||
while let Ok(msg) = recv(&mut pcid_from_client) {
|
||||
let response = self.respond(msg, &args);
|
||||
send(&mut pcid_to_client, &response);
|
||||
send(&mut pcid_to_client, &response).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -294,6 +306,7 @@ fn handle_parsed_header(state: Arc<State>, config: &Config, bus_num: u8,
|
||||
};
|
||||
crate::pci::cap::CapabilitiesIter { inner: crate::pci::cap::CapabilityOffsetsIter::new(header.cap_pointer(), &func) }.collect::<Vec<_>>()
|
||||
};
|
||||
println!("PCI DEVICE CAPABILITIES for {}: {:?}", args.iter().map(|string| string.as_ref()).nth(0).unwrap_or("[unknown]"), capabilities);
|
||||
|
||||
let func = driver_interface::PciFunction {
|
||||
bars,
|
||||
|
||||
+4
-205
@@ -1,4 +1,5 @@
|
||||
use super::func::{ConfigReader, ConfigWriter};
|
||||
use super::func::ConfigReader;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
pub struct CapabilityOffsetsIter<'a, R> {
|
||||
offset: u8,
|
||||
@@ -42,7 +43,7 @@ pub enum CapabilityId {
|
||||
Pcie = 0x10,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub enum MsiCapability {
|
||||
_32BitAddress {
|
||||
message_control: u32,
|
||||
@@ -72,220 +73,18 @@ pub enum MsiCapability {
|
||||
},
|
||||
}
|
||||
|
||||
impl MsiCapability {
|
||||
pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8;
|
||||
pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7;
|
||||
|
||||
pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E;
|
||||
pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1;
|
||||
|
||||
pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070;
|
||||
pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4;
|
||||
|
||||
pub const MC_MSI_ENABLED_BIT: u16 = 1;
|
||||
|
||||
pub unsafe fn parse<R: ConfigReader>(reader: &R, offset: u8) -> Self {
|
||||
let dword = reader.read_u32(offset);
|
||||
|
||||
let message_control = (dword >> 16) as u16;
|
||||
|
||||
if message_control & Self::MC_PVT_CAPABLE_BIT != 0 {
|
||||
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
|
||||
Self::_64BitAddressWithPvm {
|
||||
message_control: dword,
|
||||
message_address_lo: reader.read_u32(offset + 4),
|
||||
message_address_hi: reader.read_u32(offset + 8),
|
||||
message_data: reader.read_u32(offset + 12),
|
||||
mask_bits: reader.read_u32(offset + 16),
|
||||
pending_bits: reader.read_u32(offset + 20),
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddressWithPvm {
|
||||
message_control: dword,
|
||||
message_address: reader.read_u32(offset + 4),
|
||||
message_data: reader.read_u32(offset + 8),
|
||||
mask_bits: reader.read_u32(offset + 12),
|
||||
pending_bits: reader.read_u32(offset + 16),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
|
||||
Self::_64BitAddress {
|
||||
message_control: dword,
|
||||
message_address_lo: reader.read_u32(offset + 4),
|
||||
message_address_hi: reader.read_u32(offset + 8),
|
||||
message_data: reader.read_u32(offset + 12),
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddress {
|
||||
message_control: dword,
|
||||
message_address: reader.read_u32(offset + 4),
|
||||
message_data: reader.read_u32(offset + 8),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn message_control_raw(&self) -> u32 {
|
||||
match self {
|
||||
Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control,
|
||||
}
|
||||
}
|
||||
pub fn message_control(&self) -> u16 {
|
||||
self.message_control_raw() as u16
|
||||
}
|
||||
pub unsafe fn set_message_control<W: ConfigWriter>(&mut self, writer: &W, offset: u8, value: u16) {
|
||||
let mut new_message_control = self.message_control_raw();
|
||||
new_message_control &= 0x0000_FFFF;
|
||||
new_message_control |= u32::from(value) << 16;
|
||||
writer.write_u32(offset, new_message_control);
|
||||
|
||||
match self {
|
||||
Self::_32BitAddress { ref mut message_control, .. }
|
||||
| Self::_64BitAddress { ref mut message_control, .. }
|
||||
| Self::_32BitAddressWithPvm { ref mut message_control, .. }
|
||||
| Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control,
|
||||
}
|
||||
}
|
||||
pub fn is_pvt_capable(&self) -> bool {
|
||||
self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0
|
||||
}
|
||||
pub fn has_64_bit_addr(&self) -> bool {
|
||||
self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0
|
||||
}
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.message_control() & Self::MC_MSI_ENABLED_BIT != 0
|
||||
}
|
||||
pub unsafe fn set_enabled<W: ConfigWriter>(&mut self, writer: &W, offset: u8, enabled: bool) {
|
||||
let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT);
|
||||
new_message_control |= u16::from(enabled);
|
||||
self.set_message_control(writer, offset, new_message_control)
|
||||
}
|
||||
pub fn multi_message_capable(&self) -> u8 {
|
||||
((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8
|
||||
}
|
||||
pub fn multi_message_enabled(&self) -> u8 {
|
||||
((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_MASK) as u8
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub struct PcieCapability {
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, Serialize, Deserialize)]
|
||||
pub struct MsixCapability {
|
||||
pub a: u32,
|
||||
pub b: u32,
|
||||
pub c: u32,
|
||||
}
|
||||
|
||||
impl MsixCapability {
|
||||
pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15;
|
||||
pub const MC_MSIX_ENABLED_SHIFT: u8 = 15;
|
||||
pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14;
|
||||
pub const MC_FUNCTION_MASK_SHIFT: u8 = 14;
|
||||
pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF;
|
||||
|
||||
/// The Message Control field, containing the enabled and function mask bits, as well as the
|
||||
/// table size.
|
||||
pub const fn message_control(&self) -> u16 {
|
||||
(self.a >> 16) as u16
|
||||
}
|
||||
|
||||
pub fn set_message_control(&mut self, message_control: u16) {
|
||||
self.a &= 0x0000_FFFF;
|
||||
self.a |= u32::from(message_control) << 16;
|
||||
}
|
||||
/// Returns the MSI-X table size, subtracted by one.
|
||||
pub const fn table_size_raw(&self) -> u16 {
|
||||
self.message_control() & Self::MC_TABLE_SIZE_MASK
|
||||
}
|
||||
/// Returns the MSI-X table size.
|
||||
pub const fn table_size(&self) -> u16 {
|
||||
self.table_size_raw() + 1
|
||||
}
|
||||
/// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the
|
||||
/// MSI capability structure.
|
||||
pub const fn msix_enabled(&self) -> bool {
|
||||
self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0
|
||||
}
|
||||
/// The MSI-X function mask, which overrides each of the vectors' mask bit, when set.
|
||||
pub const fn function_mask(&self) -> bool {
|
||||
self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0
|
||||
}
|
||||
|
||||
pub fn set_msix_enabled(&mut self, enabled: bool) {
|
||||
let mut new_message_control = self.message_control();
|
||||
new_message_control &= !(Self::MC_MSIX_ENABLED_BIT);
|
||||
new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT;
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
|
||||
pub fn set_function_mask(&mut self, function_mask: bool) {
|
||||
let mut new_message_control = self.message_control();
|
||||
new_message_control &= !(Self::MC_FUNCTION_MASK_BIT);
|
||||
new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT;
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8;
|
||||
pub const TABLE_BIR_MASK: u32 = 0x0000_0007;
|
||||
|
||||
/// The table offset is guaranteed to be QWORD aligned (8 bytes).
|
||||
pub const fn table_offset(&self) -> u32 {
|
||||
self.b & Self::TABLE_OFFSET_MASK
|
||||
}
|
||||
/// The table BIR, which is used to map the offset to a memory location.
|
||||
pub const fn table_bir(&self) -> u8 {
|
||||
(self.b & Self::TABLE_BIR_MASK) as u8
|
||||
}
|
||||
|
||||
pub fn set_table_offset(&mut self, offset: u32) {
|
||||
assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned");
|
||||
self.b &= !Self::TABLE_OFFSET_MASK;
|
||||
self.b |= offset;
|
||||
}
|
||||
pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8;
|
||||
pub const PBA_BIR_MASK: u32 = 0x0000_0007;
|
||||
|
||||
/// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes).
|
||||
pub const fn pba_offset(&self) -> u32 {
|
||||
self.b & Self::PBA_OFFSET_MASK
|
||||
}
|
||||
/// The Pending Bit Array BIR, which is used to map the offset to a memory location.
|
||||
pub const fn pba_bir(&self) -> u8 {
|
||||
(self.b & Self::PBA_BIR_MASK) as u8
|
||||
}
|
||||
|
||||
pub fn set_pba_offset(&mut self, offset: u32) {
|
||||
assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned");
|
||||
self.c &= !Self::PBA_OFFSET_MASK;
|
||||
self.c |= offset;
|
||||
}
|
||||
|
||||
/// Write the first DWORD into configuration space (containing the partially modifiable Message
|
||||
/// Control field).
|
||||
pub unsafe fn write_a<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset, self.a)
|
||||
}
|
||||
/// Write the second DWORD into configuration space (containing the modifiable table
|
||||
/// offset and the readonly table BIR).
|
||||
pub unsafe fn write_b<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset + 4, self.a)
|
||||
}
|
||||
/// Write the third DWORD into configuration space (containing the modifiable pending bit array
|
||||
/// offset, and the readonly PBA BIR).
|
||||
pub unsafe fn write_c<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset + 8, self.a)
|
||||
}
|
||||
/// Write this capability structure back to configuration space.
|
||||
pub unsafe fn write_all<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
self.write_a(writer, offset);
|
||||
self.write_b(writer, offset);
|
||||
self.write_c(writer, offset);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum Capability {
|
||||
Msi(MsiCapability),
|
||||
|
||||
@@ -14,6 +14,7 @@ mod class;
|
||||
mod dev;
|
||||
mod func;
|
||||
pub mod header;
|
||||
pub mod msi;
|
||||
|
||||
pub struct Pci {
|
||||
lock: Mutex<()>,
|
||||
|
||||
@@ -0,0 +1,296 @@
|
||||
use std::fmt;
|
||||
|
||||
use super::bar::PciBar;
|
||||
pub use super::cap::{MsiCapability, MsixCapability};
|
||||
use super::func::{ConfigReader, ConfigWriter};
|
||||
|
||||
use syscall::{Io, Mmio};
|
||||
|
||||
impl MsiCapability {
|
||||
pub const MC_PVT_CAPABLE_BIT: u16 = 1 << 8;
|
||||
pub const MC_64_BIT_ADDR_BIT: u16 = 1 << 7;
|
||||
|
||||
pub const MC_MULTI_MESSAGE_MASK: u16 = 0x000E;
|
||||
pub const MC_MULTI_MESSAGE_SHIFT: u8 = 1;
|
||||
|
||||
pub const MC_MULTI_MESSAGE_ENABLE_MASK: u16 = 0x0070;
|
||||
pub const MC_MULTI_MESSAGE_ENABLE_SHIFT: u8 = 4;
|
||||
|
||||
pub const MC_MSI_ENABLED_BIT: u16 = 1;
|
||||
|
||||
pub unsafe fn parse<R: ConfigReader>(reader: &R, offset: u8) -> Self {
|
||||
let dword = reader.read_u32(offset);
|
||||
|
||||
let message_control = (dword >> 16) as u16;
|
||||
|
||||
if message_control & Self::MC_PVT_CAPABLE_BIT != 0 {
|
||||
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
|
||||
Self::_64BitAddressWithPvm {
|
||||
message_control: dword,
|
||||
message_address_lo: reader.read_u32(offset + 4),
|
||||
message_address_hi: reader.read_u32(offset + 8),
|
||||
message_data: reader.read_u32(offset + 12),
|
||||
mask_bits: reader.read_u32(offset + 16),
|
||||
pending_bits: reader.read_u32(offset + 20),
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddressWithPvm {
|
||||
message_control: dword,
|
||||
message_address: reader.read_u32(offset + 4),
|
||||
message_data: reader.read_u32(offset + 8),
|
||||
mask_bits: reader.read_u32(offset + 12),
|
||||
pending_bits: reader.read_u32(offset + 16),
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if message_control & Self::MC_64_BIT_ADDR_BIT != 0 {
|
||||
Self::_64BitAddress {
|
||||
message_control: dword,
|
||||
message_address_lo: reader.read_u32(offset + 4),
|
||||
message_address_hi: reader.read_u32(offset + 8),
|
||||
message_data: reader.read_u32(offset + 12),
|
||||
}
|
||||
} else {
|
||||
Self::_32BitAddress {
|
||||
message_control: dword,
|
||||
message_address: reader.read_u32(offset + 4),
|
||||
message_data: reader.read_u32(offset + 8),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn message_control_raw(&self) -> u32 {
|
||||
match self {
|
||||
Self::_32BitAddress { message_control, .. } | Self::_64BitAddress { message_control, .. } | Self::_32BitAddressWithPvm { message_control, .. } | Self::_64BitAddressWithPvm { message_control, .. } => *message_control,
|
||||
}
|
||||
}
|
||||
pub fn message_control(&self) -> u16 {
|
||||
(self.message_control_raw() >> 16) as u16
|
||||
}
|
||||
pub unsafe fn set_message_control<W: ConfigWriter>(&mut self, writer: &W, offset: u8, value: u16) {
|
||||
let mut new_message_control = self.message_control_raw();
|
||||
new_message_control &= 0x0000_FFFF;
|
||||
new_message_control |= u32::from(value) << 16;
|
||||
writer.write_u32(offset, new_message_control);
|
||||
|
||||
match self {
|
||||
Self::_32BitAddress { ref mut message_control, .. }
|
||||
| Self::_64BitAddress { ref mut message_control, .. }
|
||||
| Self::_32BitAddressWithPvm { ref mut message_control, .. }
|
||||
| Self::_64BitAddressWithPvm { ref mut message_control, .. } => *message_control = new_message_control,
|
||||
}
|
||||
}
|
||||
pub fn is_pvt_capable(&self) -> bool {
|
||||
self.message_control() & Self::MC_PVT_CAPABLE_BIT != 0
|
||||
}
|
||||
pub fn has_64_bit_addr(&self) -> bool {
|
||||
self.message_control() & Self::MC_64_BIT_ADDR_BIT != 0
|
||||
}
|
||||
pub fn enabled(&self) -> bool {
|
||||
self.message_control() & Self::MC_MSI_ENABLED_BIT != 0
|
||||
}
|
||||
pub unsafe fn set_enabled<W: ConfigWriter>(&mut self, writer: &W, offset: u8, enabled: bool) {
|
||||
let mut new_message_control = self.message_control() & (!Self::MC_MSI_ENABLED_BIT);
|
||||
new_message_control |= u16::from(enabled);
|
||||
self.set_message_control(writer, offset, new_message_control)
|
||||
}
|
||||
pub fn multi_message_capable(&self) -> u8 {
|
||||
((self.message_control() & Self::MC_MULTI_MESSAGE_MASK) >> Self::MC_MULTI_MESSAGE_SHIFT) as u8
|
||||
}
|
||||
pub fn multi_message_enabled(&self) -> u8 {
|
||||
((self.message_control() & Self::MC_MULTI_MESSAGE_ENABLE_MASK) >> Self::MC_MULTI_MESSAGE_ENABLE_SHIFT) as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl MsixCapability {
|
||||
pub const MC_MSIX_ENABLED_BIT: u16 = 1 << 15;
|
||||
pub const MC_MSIX_ENABLED_SHIFT: u8 = 15;
|
||||
pub const MC_FUNCTION_MASK_BIT: u16 = 1 << 14;
|
||||
pub const MC_FUNCTION_MASK_SHIFT: u8 = 14;
|
||||
pub const MC_TABLE_SIZE_MASK: u16 = 0x03FF;
|
||||
|
||||
/// The Message Control field, containing the enabled and function mask bits, as well as the
|
||||
/// table size.
|
||||
pub const fn message_control(&self) -> u16 {
|
||||
(self.a >> 16) as u16
|
||||
}
|
||||
|
||||
pub fn set_message_control(&mut self, message_control: u16) {
|
||||
self.a &= 0x0000_FFFF;
|
||||
self.a |= u32::from(message_control) << 16;
|
||||
}
|
||||
/// Returns the MSI-X table size, subtracted by one.
|
||||
pub const fn table_size_raw(&self) -> u16 {
|
||||
self.message_control() & Self::MC_TABLE_SIZE_MASK
|
||||
}
|
||||
/// Returns the MSI-X table size.
|
||||
pub const fn table_size(&self) -> u16 {
|
||||
self.table_size_raw() + 1
|
||||
}
|
||||
/// Returns the MSI-X enabled bit, which enables MSI-X if the MSI enable bit is also set in the
|
||||
/// MSI capability structure.
|
||||
pub const fn msix_enabled(&self) -> bool {
|
||||
self.message_control() & Self::MC_MSIX_ENABLED_BIT != 0
|
||||
}
|
||||
/// The MSI-X function mask, which overrides each of the vectors' mask bit, when set.
|
||||
pub const fn function_mask(&self) -> bool {
|
||||
self.message_control() & Self::MC_FUNCTION_MASK_BIT != 0
|
||||
}
|
||||
|
||||
pub fn set_msix_enabled(&mut self, enabled: bool) {
|
||||
let mut new_message_control = self.message_control();
|
||||
new_message_control &= !(Self::MC_MSIX_ENABLED_BIT);
|
||||
new_message_control |= u16::from(enabled) << Self::MC_MSIX_ENABLED_SHIFT;
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
|
||||
pub fn set_function_mask(&mut self, function_mask: bool) {
|
||||
let mut new_message_control = self.message_control();
|
||||
new_message_control &= !(Self::MC_FUNCTION_MASK_BIT);
|
||||
new_message_control |= u16::from(function_mask) << Self::MC_FUNCTION_MASK_SHIFT;
|
||||
self.set_message_control(new_message_control);
|
||||
}
|
||||
pub const TABLE_OFFSET_MASK: u32 = 0xFFFF_FFF8;
|
||||
pub const TABLE_BIR_MASK: u32 = 0x0000_0007;
|
||||
|
||||
/// The table offset is guaranteed to be QWORD aligned (8 bytes).
|
||||
pub const fn table_offset(&self) -> u32 {
|
||||
self.b & Self::TABLE_OFFSET_MASK
|
||||
}
|
||||
/// The table BIR, which is used to map the offset to a memory location.
|
||||
pub const fn table_bir(&self) -> u8 {
|
||||
(self.b & Self::TABLE_BIR_MASK) as u8
|
||||
}
|
||||
|
||||
pub fn set_table_offset(&mut self, offset: u32) {
|
||||
assert_eq!(offset & Self::TABLE_OFFSET_MASK, offset, "MSI-X table offset has to be QWORD aligned");
|
||||
self.b &= !Self::TABLE_OFFSET_MASK;
|
||||
self.b |= offset;
|
||||
}
|
||||
pub const PBA_OFFSET_MASK: u32 = 0xFFFF_FFF8;
|
||||
pub const PBA_BIR_MASK: u32 = 0x0000_0007;
|
||||
|
||||
/// The Pending Bit Array offset is guaranteed to be QWORD aligned (8 bytes).
|
||||
pub const fn pba_offset(&self) -> u32 {
|
||||
self.c & Self::PBA_OFFSET_MASK
|
||||
}
|
||||
/// The Pending Bit Array BIR, which is used to map the offset to a memory location.
|
||||
pub const fn pba_bir(&self) -> u8 {
|
||||
(self.c & Self::PBA_BIR_MASK) as u8
|
||||
}
|
||||
|
||||
pub fn set_pba_offset(&mut self, offset: u32) {
|
||||
assert_eq!(offset & Self::PBA_OFFSET_MASK, offset, "MSI-X Pending Bit Array offset has to be QWORD aligned");
|
||||
self.c &= !Self::PBA_OFFSET_MASK;
|
||||
self.c |= offset;
|
||||
}
|
||||
|
||||
pub fn table_base_pointer(&self, bars: [PciBar; 6]) -> usize {
|
||||
if self.table_bir() > 5 {
|
||||
panic!("MSI-X Table BIR contained a reserved enum value: {}", self.table_bir());
|
||||
}
|
||||
let base = bars[usize::from(self.table_bir())];
|
||||
|
||||
if let PciBar::Memory(ptr) = base {
|
||||
ptr as usize + self.table_offset() as usize
|
||||
} else {
|
||||
panic!("MSI-X Table BIR referenced a non-memory BAR: {:?}", base);
|
||||
}
|
||||
}
|
||||
pub fn table_pointer(&self, bars: [PciBar; 6], k: u16) -> usize {
|
||||
self.table_base_pointer(bars) + k as usize * 16
|
||||
}
|
||||
|
||||
pub fn pba_base_pointer(&self, bars: [PciBar; 6]) -> usize {
|
||||
if self.pba_bir() > 5 {
|
||||
panic!("MSI-X PBA BIR contained a reserved enum value: {}", self.pba_bir());
|
||||
}
|
||||
let base = bars[usize::from(self.pba_bir())];
|
||||
|
||||
if let PciBar::Memory(ptr) = base {
|
||||
ptr as usize + self.pba_offset() as usize
|
||||
} else {
|
||||
panic!("MSI-X PBA BIR referenced a non-memory BAR: {:?}", base);
|
||||
}
|
||||
}
|
||||
pub fn pba_pointer_dword(&self, bars: [PciBar; 6], k: u16) -> usize {
|
||||
self.pba_base_pointer(bars) + (k as usize / 32) * 4
|
||||
}
|
||||
pub const fn pba_bit_dword(&self, k: u16) -> u8 {
|
||||
(k % 32) as u8
|
||||
}
|
||||
|
||||
pub fn pba_pointer_qword(&self, bars: [PciBar; 6], k: u16) -> usize {
|
||||
self.pba_base_pointer(bars) + (k as usize / 64) * 8
|
||||
}
|
||||
pub const fn pba_bit_qword(&self, k: u16) -> u8 {
|
||||
(k % 64) as u8
|
||||
}
|
||||
|
||||
/// Write the first DWORD into configuration space (containing the partially modifiable Message
|
||||
/// Control field).
|
||||
pub unsafe fn write_a<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset, self.a)
|
||||
}
|
||||
/// Write the second DWORD into configuration space (containing the modifiable table
|
||||
/// offset and the readonly table BIR).
|
||||
pub unsafe fn write_b<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset + 4, self.a)
|
||||
}
|
||||
/// Write the third DWORD into configuration space (containing the modifiable pending bit array
|
||||
/// offset, and the readonly PBA BIR).
|
||||
pub unsafe fn write_c<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
writer.write_u32(offset + 8, self.a)
|
||||
}
|
||||
/// Write this capability structure back to configuration space.
|
||||
pub unsafe fn write_all<W: ConfigWriter>(&self, writer: &W, offset: u8) {
|
||||
self.write_a(writer, offset);
|
||||
self.write_b(writer, offset);
|
||||
self.write_c(writer, offset);
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(packed)]
|
||||
pub struct MsixTableEntry {
|
||||
pub addr_lo: Mmio<u32>,
|
||||
pub addr_hi: Mmio<u32>,
|
||||
pub msg_data: Mmio<u32>,
|
||||
pub vec_ctl: Mmio<u32>,
|
||||
}
|
||||
|
||||
impl MsixTableEntry {
|
||||
pub fn addr_lo(&self) -> u32 {
|
||||
self.addr_lo.read()
|
||||
}
|
||||
pub fn addr_hi(&self) -> u32 {
|
||||
self.addr_hi.read()
|
||||
}
|
||||
pub fn msg_data(&self) -> u32 {
|
||||
self.msg_data.read()
|
||||
}
|
||||
pub fn vec_ctl(&self) -> u32 {
|
||||
self.vec_ctl.read()
|
||||
}
|
||||
pub fn addr(&self) -> u64 {
|
||||
u64::from(self.addr_lo()) | (u64::from(self.addr_hi()) << 32)
|
||||
}
|
||||
pub const VEC_CTL_MASK_BIT: u32 = 1;
|
||||
|
||||
pub fn mask(&mut self) {
|
||||
self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, true)
|
||||
}
|
||||
pub fn unmask(&mut self) {
|
||||
self.vec_ctl.writef(Self::VEC_CTL_MASK_BIT, false)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for MsixTableEntry {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_struct("MsixTableEntry")
|
||||
.field("addr", &self.addr())
|
||||
.field("msg_data", &self.msg_data())
|
||||
.field("vec_ctl", &self.vec_ctl())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
+157
-96
@@ -4,6 +4,9 @@ extern crate event;
|
||||
extern crate plain;
|
||||
extern crate syscall;
|
||||
|
||||
use pcid_interface::{PcidServerHandle, PciFeature, PciFeatureInfo};
|
||||
use pcid_interface::MsixTableEntry;
|
||||
|
||||
use event::{Event, EventQueue};
|
||||
use std::cell::RefCell;
|
||||
use std::fs::File;
|
||||
@@ -23,127 +26,185 @@ mod usb;
|
||||
mod xhci;
|
||||
|
||||
fn main() {
|
||||
println!("xhcid started");
|
||||
let mut pcid_handle = pcid_interface::PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid");
|
||||
dbg!();
|
||||
println!("XHCI from PCI config: {:?}", pcid_handle.fetch_config().expect("xhcid: failed to fetch config"));
|
||||
let mut pcid_handle = PcidServerHandle::connect_default().expect("xhcid: failed to setup channel to pcid");
|
||||
let pci_config = pcid_handle.fetch_config().expect("xhcid: failed to fetch config");
|
||||
println!("XHCI PCI CONFIG: {:?}", pci_config);
|
||||
|
||||
// Close the pipe, allowing pcid to continue.
|
||||
drop(pcid_handle);
|
||||
let bar = pci_config.func.bars[0];
|
||||
let irq = pci_config.func.legacy_interrupt_line;
|
||||
|
||||
let bar_ptr = match bar {
|
||||
pcid_interface::PciBar::Memory(ptr) => ptr,
|
||||
other => panic!("Expected memory bar, found {}", other),
|
||||
};
|
||||
|
||||
let address = unsafe {
|
||||
syscall::physmap(bar_ptr as usize, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)
|
||||
.expect("xhcid: failed to map address")
|
||||
};
|
||||
|
||||
let all_pci_features = pcid_handle.fetch_all_features().expect("xhcid: failed to fetch pci features");
|
||||
println!("XHCI PCI FEATURES: {:?}", all_pci_features);
|
||||
|
||||
let (has_msi, mut msi_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msi(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
let (has_msix, mut msix_enabled) = all_pci_features.iter().map(|(feature, status)| (feature.is_msix(), status.is_enabled())).find(|&(f, _)| f).unwrap_or((false, false));
|
||||
|
||||
dbg!(has_msi, msi_enabled);
|
||||
dbg!(has_msix, msix_enabled);
|
||||
|
||||
if has_msi && !msi_enabled {
|
||||
pcid_handle.enable_feature(PciFeature::Msi).expect("xhcid: failed to enable MSI");
|
||||
msi_enabled = true;
|
||||
println!("Enabled MSI");
|
||||
}
|
||||
if has_msi && msi_enabled && has_msix && !msix_enabled {
|
||||
pcid_handle.enable_feature(PciFeature::MsiX).expect("xhcid: failed to enable MSI-X");
|
||||
msix_enabled = true;
|
||||
println!("Enabled MSI-X");
|
||||
}
|
||||
|
||||
if msi_enabled && !msix_enabled {
|
||||
todo!("only msi-x is currently implemented")
|
||||
}
|
||||
if msix_enabled {
|
||||
let capability = match pcid_handle.feature_info(PciFeature::MsiX).expect("xhcid: failed to retrieve the MSI-X capability structure from pcid") {
|
||||
PciFeatureInfo::Msi(_) => panic!(),
|
||||
PciFeatureInfo::MsiX(s) => s,
|
||||
};
|
||||
let table_size = capability.table_size();
|
||||
let table_base = capability.table_base_pointer(pci_config.func.bars);
|
||||
let table_min_length = table_size * 16;
|
||||
let pba_min_length = crate::xhci::scheme::div_round_up(table_size, 8);
|
||||
|
||||
let pba_base = capability.pba_base_pointer(pci_config.func.bars);
|
||||
dbg!(table_size, table_base, table_min_length, pba_base);
|
||||
|
||||
if !(bar_ptr..bar_ptr + 65536).contains(&(table_base as u32 + table_min_length as u32)) {
|
||||
todo!()
|
||||
}
|
||||
if !(bar_ptr..bar_ptr + 65536).contains(&(pba_base as u32 + pba_min_length as u32)) {
|
||||
todo!()
|
||||
}
|
||||
|
||||
let virt_table_base = ((table_base - bar_ptr as usize) + address) as *const MsixTableEntry;
|
||||
let virt_pba_base = ((pba_base - bar_ptr as usize) + address) as *const u64;
|
||||
|
||||
for k in 0..table_size {
|
||||
assert_eq!(std::mem::size_of::<MsixTableEntry>(), 16);
|
||||
let table_entry_pointer = unsafe { virt_table_base.offset(k as isize).as_ref().unwrap() };
|
||||
let pba_pointer = unsafe { virt_pba_base.offset(k as isize / 64).as_ref().unwrap() };
|
||||
let pba_bit = k % 64;
|
||||
|
||||
dbg!(table_entry_pointer, (*pba_pointer >> pba_bit) & 1);
|
||||
}
|
||||
}
|
||||
|
||||
std::thread::sleep(std::time::Duration::from_millis(300));
|
||||
|
||||
// Daemonize
|
||||
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } != 0 {
|
||||
return;
|
||||
}
|
||||
|
||||
let mut args = env::args().skip(1);
|
||||
|
||||
let mut name = args.next().expect("xhcid: no name provided");
|
||||
name.push_str("_xhci");
|
||||
|
||||
let bar_str = args.next().expect("xhcid: no address provided");
|
||||
let bar = usize::from_str_radix(&bar_str, 16).expect("xhcid: failed to parse address");
|
||||
|
||||
let irq_str = args.next().expect("xhcid: no IRQ provided");
|
||||
let irq = irq_str.parse::<u8>().expect("xhcid: failed to parse irq");
|
||||
|
||||
print!(
|
||||
"{}",
|
||||
format!(" + XHCI {} on: {:X} IRQ: {}\n", name, bar, irq)
|
||||
format!(" + XHCI {} on: {} IRQ: {}\n", name, bar, irq)
|
||||
);
|
||||
|
||||
// Daemonize
|
||||
if unsafe { syscall::clone(CloneFlags::empty()).unwrap() } == 0 {
|
||||
let socket_fd = syscall::open(
|
||||
format!(":usb/{}", name),
|
||||
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
|
||||
)
|
||||
.expect("xhcid: failed to create usb scheme");
|
||||
let socket = Arc::new(RefCell::new(unsafe {
|
||||
File::from_raw_fd(socket_fd as RawFd)
|
||||
}));
|
||||
let socket_fd = syscall::open(
|
||||
format!(":usb/{}", name),
|
||||
syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
|
||||
)
|
||||
.expect("xhcid: failed to create usb scheme");
|
||||
let socket = Arc::new(RefCell::new(unsafe {
|
||||
File::from_raw_fd(socket_fd as RawFd)
|
||||
}));
|
||||
|
||||
let mut irq_file =
|
||||
File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file");
|
||||
let mut irq_file =
|
||||
File::open(format!("irq:{}", irq)).expect("xhcid: failed to open IRQ file");
|
||||
|
||||
let address = unsafe {
|
||||
syscall::physmap(bar, 65536, PHYSMAP_WRITE | PHYSMAP_NO_CACHE)
|
||||
.expect("xhcid: failed to map address")
|
||||
};
|
||||
{
|
||||
let hci = Arc::new(RefCell::new(
|
||||
Xhci::new(name, address).expect("xhcid: failed to allocate device"),
|
||||
));
|
||||
{
|
||||
let hci = Arc::new(RefCell::new(
|
||||
Xhci::new(name, address).expect("xhcid: failed to allocate device"),
|
||||
));
|
||||
|
||||
hci.borrow_mut().probe().expect("xhcid: failed to probe");
|
||||
hci.borrow_mut().probe().expect("xhcid: failed to probe");
|
||||
|
||||
let mut event_queue =
|
||||
EventQueue::<()>::new().expect("xhcid: failed to create event queue");
|
||||
let mut event_queue =
|
||||
EventQueue::<()>::new().expect("xhcid: failed to create event queue");
|
||||
|
||||
syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace");
|
||||
syscall::setrens(0, 0).expect("xhcid: failed to enter null namespace");
|
||||
|
||||
let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));
|
||||
let todo = Arc::new(RefCell::new(Vec::<Packet>::new()));
|
||||
|
||||
let hci_irq = hci.clone();
|
||||
let socket_irq = socket.clone();
|
||||
let todo_irq = todo.clone();
|
||||
event_queue
|
||||
.add(irq_file.as_raw_fd(), move |_| -> Result<Option<()>> {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.read(&mut irq)?;
|
||||
let hci_irq = hci.clone();
|
||||
let socket_irq = socket.clone();
|
||||
let todo_irq = todo.clone();
|
||||
event_queue
|
||||
.add(irq_file.as_raw_fd(), move |_| -> Result<Option<()>> {
|
||||
let mut irq = [0; 8];
|
||||
irq_file.read(&mut irq)?;
|
||||
|
||||
if hci_irq.borrow_mut().trigger_irq() {
|
||||
irq_file.write(&mut irq)?;
|
||||
if hci_irq.borrow_mut().trigger_irq() {
|
||||
irq_file.write(&mut irq)?;
|
||||
|
||||
let mut todo = todo_irq.borrow_mut();
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
let a = todo[i].a;
|
||||
hci_irq.borrow_mut().handle(&mut todo[i]);
|
||||
if todo[i].a == (-EWOULDBLOCK) as usize {
|
||||
todo[i].a = a;
|
||||
i += 1;
|
||||
} else {
|
||||
socket_irq.borrow_mut().write(&mut todo[i])?;
|
||||
todo.remove(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on IRQ file");
|
||||
|
||||
let socket_fd = socket.borrow().as_raw_fd();
|
||||
let socket_packet = socket.clone();
|
||||
event_queue
|
||||
.add(socket_fd, move |_| -> Result<Option<()>> {
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
match socket_packet.borrow_mut().read(&mut packet) {
|
||||
Ok(0) => break,
|
||||
Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
||||
let a = packet.a;
|
||||
hci.borrow_mut().handle(&mut packet);
|
||||
if packet.a == (-EWOULDBLOCK) as usize {
|
||||
packet.a = a;
|
||||
todo.borrow_mut().push(packet);
|
||||
let mut todo = todo_irq.borrow_mut();
|
||||
let mut i = 0;
|
||||
while i < todo.len() {
|
||||
let a = todo[i].a;
|
||||
hci_irq.borrow_mut().handle(&mut todo[i]);
|
||||
if todo[i].a == (-EWOULDBLOCK) as usize {
|
||||
todo[i].a = a;
|
||||
i += 1;
|
||||
} else {
|
||||
socket_packet.borrow_mut().write(&mut packet)?;
|
||||
socket_irq.borrow_mut().write(&mut todo[i])?;
|
||||
todo.remove(i);
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on scheme file");
|
||||
}
|
||||
|
||||
event_queue
|
||||
.trigger_all(Event { fd: 0, flags: 0 })
|
||||
.expect("xhcid: failed to trigger events");
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on IRQ file");
|
||||
|
||||
event_queue.run().expect("xhcid: failed to handle events");
|
||||
}
|
||||
unsafe {
|
||||
let _ = syscall::physunmap(address);
|
||||
}
|
||||
let socket_fd = socket.borrow().as_raw_fd();
|
||||
let socket_packet = socket.clone();
|
||||
event_queue
|
||||
.add(socket_fd, move |_| -> Result<Option<()>> {
|
||||
loop {
|
||||
let mut packet = Packet::default();
|
||||
match socket_packet.borrow_mut().read(&mut packet) {
|
||||
Ok(0) => break,
|
||||
Err(err) if err.kind() == io::ErrorKind::WouldBlock => break,
|
||||
Ok(_) => (),
|
||||
Err(err) => return Err(err),
|
||||
}
|
||||
|
||||
let a = packet.a;
|
||||
hci.borrow_mut().handle(&mut packet);
|
||||
if packet.a == (-EWOULDBLOCK) as usize {
|
||||
packet.a = a;
|
||||
todo.borrow_mut().push(packet);
|
||||
} else {
|
||||
socket_packet.borrow_mut().write(&mut packet)?;
|
||||
}
|
||||
}
|
||||
Ok(None)
|
||||
})
|
||||
.expect("xhcid: failed to catch events on scheme file");
|
||||
|
||||
event_queue
|
||||
.trigger_all(Event { fd: 0, flags: 0 })
|
||||
.expect("xhcid: failed to trigger events");
|
||||
|
||||
event_queue.run().expect("xhcid: failed to handle events");
|
||||
}
|
||||
unsafe {
|
||||
let _ = syscall::physunmap(address);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ mod operational;
|
||||
mod port;
|
||||
mod ring;
|
||||
mod runtime;
|
||||
mod scheme;
|
||||
pub mod scheme;
|
||||
mod trb;
|
||||
|
||||
use self::capability::CapabilityRegs;
|
||||
@@ -306,7 +306,7 @@ impl Xhci {
|
||||
Ok(cloned_event_trb.event_slot())
|
||||
}
|
||||
pub fn disable_port_slot(&mut self, slot: u8) -> Result<()> {
|
||||
self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.enable_slot(0, cycle))?;
|
||||
self.execute_command("DISABLE_SLOT", |cmd, cycle| cmd.disable_slot(0, cycle))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -2003,7 +2003,7 @@ impl Xhci {
|
||||
}
|
||||
}
|
||||
use std::ops::{Add, Div, Rem};
|
||||
fn div_round_up<T>(a: T, b: T) -> T
|
||||
pub fn div_round_up<T>(a: T, b: T) -> T
|
||||
where
|
||||
T: Add<Output = T> + Div<Output = T> + Rem<Output = T> + PartialEq + From<u8> + Copy,
|
||||
{
|
||||
|
||||
@@ -203,6 +203,15 @@ impl Trb {
|
||||
| (cycle as u32),
|
||||
);
|
||||
}
|
||||
pub fn disable_slot(&mut self, slot: u8, cycle: bool) {
|
||||
self.set(
|
||||
0,
|
||||
0,
|
||||
(u32::from(slot) << 24)
|
||||
| ((TrbType::DisableSlot as u32) << 10)
|
||||
| u32::from(cycle)
|
||||
);
|
||||
}
|
||||
|
||||
pub fn address_device(&mut self, slot_id: u8, input_ctx_ptr: usize, bsr: bool, cycle: bool) {
|
||||
assert_eq!(
|
||||
|
||||
Reference in New Issue
Block a user