extern crate alloc;
use alloc::boxed::Box;
use rd_net::{Interface, NetError};
use rdrive::{Device, DriverGeneric, probe::OnProbeError};
use crate::{
BindingInfo, BindingIrq, binding_info_from_acpi, binding_info_from_fdt,
registration::{BoundDevice, register_bound_device},
};
#[cfg(feature = "pci")]
use crate::{PciIrqRequirement, binding_info_from_pci};
pub struct PlatformNetDevice {
name: &'static str,
info: BindingInfo,
net: Option<rd_net::Net>,
}
impl PlatformNetDevice {
fn new(name: &'static str, net: rd_net::Net, info: BindingInfo) -> Self {
Self {
name,
info,
net: Some(net),
}
}
pub fn take_net(&mut self) -> Option<(rd_net::Net, &'static str, Option<BindingIrq>)> {
Some((self.net.take()?, self.name, self.info.irq_cloned()))
}
pub fn binding_info(&self) -> &BindingInfo {
&self.info
}
pub fn irq_num(&self) -> Option<usize> {
self.info.irq_num()
}
}
pub fn take_rd_net_device(
device: Device<PlatformNetDevice>,
) -> Result<(rd_net::Net, &'static str, Option<BindingIrq>), NetError> {
let mut dev = device
.lock()
.map_err(|_| NetError::Other(Box::new(rd_net::KError::Unknown("device locked"))))?;
dev.take_net()
.ok_or_else(|| NetError::Other(Box::new(rd_net::KError::Unknown("device already taken"))))
}
impl DriverGeneric for PlatformNetDevice {
fn name(&self) -> &str {
self.name
}
}
impl BoundDevice for PlatformNetDevice {
fn binding_info(&self) -> &BindingInfo {
&self.info
}
}
pub trait PlatformDeviceNet {
fn register_net<T>(self, name: &'static str, dev: T) -> Option<usize>
where
T: Interface + 'static;
fn register_net_with_info<T>(
self,
name: &'static str,
dev: T,
info: BindingInfo,
) -> Option<usize>
where
T: Interface + 'static;
}
impl PlatformDeviceNet for rdrive::PlatformDevice {
fn register_net<T>(self, name: &'static str, dev: T) -> Option<usize>
where
T: Interface + 'static,
{
self.register_net_with_info(name, dev, BindingInfo::empty())
}
fn register_net_with_info<T>(
self,
name: &'static str,
dev: T,
info: BindingInfo,
) -> Option<usize>
where
T: Interface + 'static,
{
register_net_with_info(self, name, dev, info)
}
}
pub trait ProbeFdtNet {
fn register_net<T>(self, name: &'static str, dev: T) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static;
}
impl ProbeFdtNet for rdrive::probe::fdt::ProbeFdt<'_> {
fn register_net<T>(self, name: &'static str, dev: T) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static,
{
let info = binding_info_from_fdt(self.info())?;
Ok(register_net_with_info(
self.into_platform_device(),
name,
dev,
info,
))
}
}
pub trait ProbeAcpiNet {
fn register_net<T>(self, name: &'static str, dev: T) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static;
}
impl ProbeAcpiNet for rdrive::probe::acpi::ProbeAcpi<'_> {
fn register_net<T>(self, name: &'static str, dev: T) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static,
{
let info = binding_info_from_acpi(self.info())?;
Ok(register_net_with_info(
self.into_platform_device(),
name,
dev,
info,
))
}
}
#[cfg(feature = "pci")]
pub trait ProbePciNet {
fn register_net<T>(
self,
name: &'static str,
dev: T,
requirement: PciIrqRequirement,
) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static;
}
#[cfg(feature = "pci")]
impl ProbePciNet for rdrive::probe::pci::ProbePci<'_> {
fn register_net<T>(
self,
name: &'static str,
dev: T,
requirement: PciIrqRequirement,
) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static,
{
let info = binding_info_from_pci(self.info(), requirement)?;
Ok(register_net_with_info(
self.into_platform_device(),
name,
dev,
info,
))
}
}
fn register_net_with_info<T>(
plat_dev: rdrive::PlatformDevice,
name: &'static str,
dev: T,
info: BindingInfo,
) -> Option<usize>
where
T: Interface + 'static,
{
let net = rd_net::Net::new(dev, axklib::dma::op());
register_bound_device(plat_dev, PlatformNetDevice::new(name, net, info))
}