1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//! Functions and types for managing a device.

use std::fmt::Display;

pub use twizzler_abi::device::{BusType, DeviceRepr, DeviceType};
use twizzler_abi::kso::{KactionCmd, KactionError, KactionFlags, KactionGenericCmd, KactionValue};
use twizzler_object::{ObjID, Object, ObjectInitError, ObjectInitFlags, Protections};

mod children;
pub mod events;
mod info;
mod mmio;

pub use children::DeviceChildrenIterator;
pub use info::InfoObject;
pub use mmio::MmioObject;

/// A handle for a device.
pub struct Device {
    obj: Object<DeviceRepr>,
}

impl Display for Device {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let repr = self.repr();
        repr.fmt(f)
    }
}

impl Device {
    fn new(id: ObjID) -> Result<Self, ObjectInitError> {
        let obj = Object::init_id(
            id,
            Protections::WRITE | Protections::READ,
            ObjectInitFlags::empty(),
        )?;

        Ok(Self { obj })
    }

    fn get_subobj(&self, ty: u8, idx: u8) -> Option<ObjID> {
        let cmd = KactionCmd::Generic(KactionGenericCmd::GetSubObject(ty, idx));
        let result = twizzler_abi::syscall::sys_kaction(
            cmd,
            Some(self.obj.id()),
            0,
            0,
            KactionFlags::empty(),
        )
        .ok()?;
        result.objid()
    }

    /// Get a reference to a device's representation data.
    pub fn repr(&self) -> &DeviceRepr {
        self.obj.base().unwrap()
    }

    /// Get a mutable reference to a device's representation data.
    pub fn repr_mut(&self) -> &mut DeviceRepr {
        unsafe { self.obj.base_mut_unchecked() }
    }

    /// Is this device a bus?
    pub fn is_bus(&self) -> bool {
        let repr = self.repr();
        repr.device_type == DeviceType::Bus
    }

    /// Get the bus type of this device.
    pub fn bus_type(&self) -> BusType {
        self.repr().bus_type
    }

    /// Execute a kaction operation on a device.
    pub fn kaction(
        &self,
        action: KactionCmd,
        value: u64,
        flags: KactionFlags,
        value2: u64,
    ) -> Result<KactionValue, KactionError> {
        twizzler_abi::syscall::sys_kaction(action, Some(self.obj.id()), value, value2, flags)
    }
}