use alloc::{boxed::Box, string::String, vec::Vec};
use ax_errno::AxError;
use rdif_input::Interface;
use rdrive::{DriverGeneric, probe::OnProbeError};
use crate::{
BindingInfo, BindingIrq, binding_info_from_acpi, binding_info_from_fdt,
registration::{BoundDevice, TakeRegistered, register_bound_device, take_registered_device},
};
#[cfg(feature = "pci")]
use crate::{PciIrqRequirement, binding_info_from_pci};
pub struct PlatformInputDevice {
name: String,
info: BindingInfo,
input: Option<Box<dyn Interface>>,
}
impl PlatformInputDevice {
fn new(name: String, input: Box<dyn Interface>, info: BindingInfo) -> Self {
Self {
name,
info,
input: Some(input),
}
}
pub fn binding_info(&self) -> &BindingInfo {
&self.info
}
pub fn irq_num(&self) -> Option<usize> {
self.info.irq_num()
}
pub fn irq(&self) -> Option<&BindingIrq> {
self.info.irq()
}
pub fn irq_cloned(&self) -> Option<BindingIrq> {
self.info.irq_cloned()
}
}
impl DriverGeneric for PlatformInputDevice {
fn name(&self) -> &str {
&self.name
}
}
impl BoundDevice for PlatformInputDevice {
fn binding_info(&self) -> &BindingInfo {
&self.info
}
}
pub struct TakenInputDevice {
pub device: Box<dyn Interface>,
pub irq: Option<BindingIrq>,
}
impl TakeRegistered for PlatformInputDevice {
type Output = TakenInputDevice;
fn take_registered(&mut self) -> Option<Self::Output> {
Some(TakenInputDevice {
device: self.input.take()?,
irq: self.info.irq_cloned(),
})
}
}
pub trait PlatformDeviceInput {
fn register_input<T>(self, dev: T) -> Option<usize>
where
T: Interface + 'static;
fn register_input_with_info<T>(self, dev: T, info: BindingInfo) -> Option<usize>
where
T: Interface + 'static;
}
impl PlatformDeviceInput for rdrive::PlatformDevice {
fn register_input<T>(self, dev: T) -> Option<usize>
where
T: Interface + 'static,
{
self.register_input_with_info(dev, BindingInfo::empty())
}
fn register_input_with_info<T>(self, dev: T, info: BindingInfo) -> Option<usize>
where
T: Interface + 'static,
{
register_input_with_info(self, dev, info)
}
}
pub trait ProbeFdtInput {
fn register_input<T>(self, dev: T) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static;
}
impl ProbeFdtInput for rdrive::probe::fdt::ProbeFdt<'_> {
fn register_input<T>(self, dev: T) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static,
{
let info = binding_info_from_fdt(self.info())?;
Ok(register_input_with_info(
self.into_platform_device(),
dev,
info,
))
}
}
pub trait ProbeAcpiInput {
fn register_input<T>(self, dev: T) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static;
}
impl ProbeAcpiInput for rdrive::probe::acpi::ProbeAcpi<'_> {
fn register_input<T>(self, dev: T) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static,
{
let info = binding_info_from_acpi(self.info())?;
Ok(register_input_with_info(
self.into_platform_device(),
dev,
info,
))
}
}
#[cfg(feature = "pci")]
pub trait ProbePciInput {
fn register_input<T>(
self,
dev: T,
requirement: PciIrqRequirement,
) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static;
}
#[cfg(feature = "pci")]
impl ProbePciInput for rdrive::probe::pci::ProbePci<'_> {
fn register_input<T>(
self,
dev: T,
requirement: PciIrqRequirement,
) -> Result<Option<usize>, OnProbeError>
where
T: Interface + 'static,
{
let info = binding_info_from_pci(self.info(), requirement)?;
Ok(register_input_with_info(
self.into_platform_device(),
dev,
info,
))
}
}
fn register_input_with_info<T>(
plat_dev: rdrive::PlatformDevice,
dev: T,
info: BindingInfo,
) -> Option<usize>
where
T: Interface + 'static,
{
let name = dev.name().into();
register_bound_device(
plat_dev,
PlatformInputDevice::new(name, Box::new(dev), info),
)
}
pub fn take_input_devices() -> Result<Vec<TakenInputDevice>, AxError> {
let mut devices = Vec::new();
for dev in rdrive::get_list::<PlatformInputDevice>() {
devices.push(take_input_device(dev)?);
}
Ok(devices)
}
fn take_input_device(
device: rdrive::Device<PlatformInputDevice>,
) -> Result<TakenInputDevice, AxError> {
take_registered_device(device).ok_or(AxError::BadState)
}
#[cfg(test)]
mod tests {
extern crate std;
use rdif_input::{EventType, InputDeviceId, InputError, InputEvent};
use super::*;
use crate::{BindingInfo, BindingIrq};
struct TestInput;
impl DriverGeneric for TestInput {
fn name(&self) -> &str {
"test-input"
}
}
impl Interface for TestInput {
fn device_id(&self) -> InputDeviceId {
InputDeviceId {
bus_type: 3,
vendor: 1,
product: 2,
version: 1,
}
}
fn physical_location(&self) -> &str {
"test/input0"
}
fn unique_id(&self) -> &str {
"input0"
}
fn get_event_bits(&mut self, _ty: EventType, out: &mut [u8]) -> Result<bool, InputError> {
if let Some(first) = out.first_mut() {
*first = 1;
}
Ok(!out.is_empty())
}
fn read_event(&mut self) -> Result<InputEvent, InputError> {
Ok(InputEvent {
event_type: EventType::Key as u16,
code: 30,
value: 1,
})
}
}
#[test]
fn platform_input_device_exposes_binding_info_irq_num() {
let irq = 43;
let device = PlatformInputDevice::new(
"test-input".into(),
Box::new(TestInput),
BindingInfo::with_irq(Some(irq)).unwrap(),
);
assert_eq!(device.binding_info().irq_num(), Some(irq));
assert_eq!(device.irq_num(), Some(irq));
assert_eq!(BoundDevice::irq_num(&device), Some(irq));
}
#[test]
fn platform_input_device_empty_binding_has_no_irq_num() {
let device = PlatformInputDevice::new(
"test-input".into(),
Box::new(TestInput),
BindingInfo::empty(),
);
assert_eq!(device.binding_info().irq_num(), None);
assert_eq!(device.irq_num(), None);
assert_eq!(BoundDevice::irq_num(&device), None);
}
#[test]
fn platform_input_device_exposes_native_binding_irq() {
let irq = BindingIrq::fdt_interrupt_with_controller(rdrive::DeviceId::new(), [0, 42, 4]);
let device = PlatformInputDevice::new(
"test-input".into(),
Box::new(TestInput),
BindingInfo::with_binding_irq(Some(irq.clone())),
);
assert_eq!(device.irq_cloned(), Some(irq));
assert_eq!(device.irq_num(), None);
}
}