111 lines
3.4 KiB
Rust
111 lines
3.4 KiB
Rust
#![no_std]
|
|
#![allow(clippy::new_without_default)]
|
|
#![feature(iter_array_chunks)]
|
|
|
|
extern crate alloc;
|
|
|
|
mod controller;
|
|
mod device;
|
|
mod pipe;
|
|
mod regs;
|
|
mod ring;
|
|
|
|
use alloc::boxed::Box;
|
|
pub use controller::Xhci;
|
|
use device_api::{interrupt::InterruptAffinity, Device};
|
|
use libk_mm::PageBox;
|
|
use libk_util::sync::spin_rwlock::IrqSafeRwLock;
|
|
use regs::{Mapper, PortSpeed};
|
|
use ring::{ControlTransferRing, GenericTransferRing};
|
|
use xhci_lib::context::{self, InputHandler};
|
|
use ygg_driver_pci::{
|
|
device::{PciDeviceInfo, PreferredInterruptMode},
|
|
PciCommandRegister, PciConfigurationSpace,
|
|
};
|
|
use ygg_driver_usb::error::UsbError;
|
|
use yggdrasil_abi::error::Error;
|
|
|
|
pub struct XhciContext<const N: usize> {
|
|
pub(crate) input: IrqSafeRwLock<PageBox<context::Input<N>>>,
|
|
pub(crate) output: PageBox<context::Device<N>>,
|
|
}
|
|
|
|
impl XhciContext<8> {
|
|
pub fn new_32byte() -> Result<Self, UsbError> {
|
|
let input = PageBox::new(context::Input::new_32byte()).map_err(UsbError::MemoryError)?;
|
|
let output = PageBox::new(context::Device::new_32byte()).map_err(UsbError::MemoryError)?;
|
|
|
|
Ok(Self {
|
|
input: IrqSafeRwLock::new(input),
|
|
output,
|
|
})
|
|
}
|
|
|
|
pub fn new_32byte_address_device(
|
|
default_control_ring: &ControlTransferRing,
|
|
speed: PortSpeed,
|
|
address: u8,
|
|
root_hub_port_number: u8,
|
|
) -> Result<Self, UsbError> {
|
|
let mut input =
|
|
PageBox::new(context::Input::new_32byte()).map_err(UsbError::MemoryError)?;
|
|
let output = PageBox::new(context::Device::new_32byte()).map_err(UsbError::MemoryError)?;
|
|
|
|
// Setup input context
|
|
{
|
|
let control = input.control_mut();
|
|
|
|
control.set_add_context_flag(0);
|
|
control.set_add_context_flag(1);
|
|
}
|
|
|
|
{
|
|
let slot = input.device_mut().slot_mut();
|
|
|
|
slot.set_context_entries(1);
|
|
slot.set_interrupter_target(0);
|
|
slot.set_usb_device_address(address);
|
|
slot.set_root_hub_port_number(root_hub_port_number);
|
|
slot.set_speed(speed.into());
|
|
}
|
|
|
|
{
|
|
let ep0 = input.device_mut().endpoint_mut(1);
|
|
|
|
ep0.set_endpoint_type(context::EndpointType::Control);
|
|
ep0.set_tr_dequeue_pointer(default_control_ring.dequeue_pointer().into());
|
|
ep0.set_dequeue_cycle_state();
|
|
ep0.set_error_count(3);
|
|
ep0.set_max_packet_size(speed.default_max_packet_size() as _);
|
|
}
|
|
|
|
Ok(Self {
|
|
input: IrqSafeRwLock::new(input),
|
|
output,
|
|
})
|
|
}
|
|
}
|
|
|
|
pub fn probe(info: &PciDeviceInfo) -> Result<&'static dyn Device, Error> {
|
|
// TODO Chip Hardware Reset
|
|
let bar0 = info
|
|
.config_space
|
|
.bar(0)
|
|
.expect("xHCI doesn't have BAR0 configured")
|
|
.as_memory()
|
|
.expect("xHCI's BAR0 is not memory-type");
|
|
|
|
let mut cmd = PciCommandRegister::from_bits_retain(info.config_space.command());
|
|
cmd &= !(PciCommandRegister::DISABLE_INTERRUPTS | PciCommandRegister::ENABLE_IO);
|
|
cmd |= PciCommandRegister::ENABLE_MEMORY | PciCommandRegister::BUS_MASTER;
|
|
info.config_space.set_command(cmd.bits());
|
|
|
|
let regs = unsafe { xhci_lib::Registers::new(bar0.try_into_usize().unwrap(), Mapper::new()) };
|
|
let xhci = Box::leak(Box::new(Xhci::new(regs)?));
|
|
|
|
info.init_interrupts(PreferredInterruptMode::Msi)?;
|
|
info.map_interrupt(InterruptAffinity::Any, xhci)?;
|
|
|
|
Ok(xhci)
|
|
}
|