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)
}