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
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

//! Extension trait to simplify probing PCI [`ChipsetDevice`] devices.

use crate::spec::hwid::ClassCode;
use crate::spec::hwid::HardwareIds;
use crate::spec::hwid::ProgrammingInterface;
use crate::spec::hwid::Subclass;
use chipset_device::pci::PciConfigSpace;
use chipset_device::ChipsetDevice;

/// An extension trait to simplify probing PCI [`ChipsetDevice`] devices.
pub trait PciChipsetDeviceExt: ChipsetDevice + PciConfigSpace {
    /// Probe the PCI device's BAR registers to retrieve the BAR masks.
    fn probe_bar_masks(&mut self) -> [u32; 6];

    /// Probe the PCI device's configuration space registers to obtain the
    /// device's hardware ID values.
    fn probe_hardware_ids(&mut self) -> HardwareIds;
}

impl<T: ?Sized> PciChipsetDeviceExt for T
where
    T: ChipsetDevice + PciConfigSpace,
{
    fn probe_bar_masks(&mut self) -> [u32; 6] {
        let mut masks = [0; 6];
        for (i, addr) in (0x10..=0x24).step_by(4).enumerate() {
            let mut buf = 0;
            let old = self
                .pci_cfg_read(addr, &mut buf)
                .now_or_never()
                .map(|_| buf)
                .unwrap_or(0);
            self.pci_cfg_write(addr, !0).unwrap();
            masks[i] = self
                .pci_cfg_read(addr, &mut buf)
                .now_or_never()
                .map(|_| buf)
                .unwrap_or(0);
            self.pci_cfg_write(addr, old).unwrap();
        }
        masks
    }

    fn probe_hardware_ids(&mut self) -> HardwareIds {
        let mut p0 = 0;
        let mut p8 = 0;
        let mut p2c = 0;
        p0 = self
            .pci_cfg_read(0, &mut p0)
            .now_or_never()
            .map(|_| p0)
            .unwrap_or(0);
        p8 = self
            .pci_cfg_read(8, &mut p8)
            .now_or_never()
            .map(|_| p8)
            .unwrap_or(0);
        p2c = self
            .pci_cfg_read(0x2c, &mut p2c)
            .now_or_never()
            .map(|_| p2c)
            .unwrap_or(0);
        HardwareIds {
            vendor_id: p0 as u16,
            device_id: (p0 >> 16) as u16,
            revision_id: p8 as u8,
            prog_if: ProgrammingInterface((p8 >> 8) as u8),
            sub_class: Subclass((p8 >> 16) as u8),
            base_class: ClassCode((p8 >> 24) as u8),
            type0_sub_vendor_id: p2c as u16,
            type0_sub_system_id: (p2c >> 16) as u16,
        }
    }
}