2#ifndef PEDIGREE_PCI_EXTENDED_CAPABILITIES_H
3#define PEDIGREE_PCI_EXTENDED_CAPABILITIES_H
5#include "pedigree/kernel/processor/types.h"
7namespace PciExtendedCapabilities {
15enum class ScanResult { Complete, Stopped, Unavailable, Malformed };
16enum class FindResult { Found, Absent, Unavailable, Malformed };
18template <
class Config,
class Visitor>
19ScanResult walk(Config& config, Visitor visitor) {
22 uint32_t visited[30] = {};
23 uint16_t offset = 0x100;
25 const unsigned slot = (offset - 0x100) / 4;
26 const uint32_t mask = 1U << (slot % 32);
27 if (visited[slot / 32] & mask) {
28 return ScanResult::Malformed;
30 visited[slot / 32] |= mask;
33 if (!config.read32(offset, header)) {
34 return offset == 0x100 ? ScanResult::Unavailable : ScanResult::Malformed;
36 if (header == 0 || header == 0xffffffffU) {
37 if (offset != 0x100) {
38 return ScanResult::Malformed;
40 return header == 0 ? ScanResult::Complete : ScanResult::Unavailable;
43 Capability cap{uint16_t(header), uint8_t((header >> 16) & 0xfU), offset,
44 uint16_t(header >> 20)};
45 if (!cap.id || cap.id == 0xffffU || !cap.version ||
46 (cap.next && (cap.next < 0x100 || cap.next > 0xffc || (cap.next & 3U)))) {
47 return ScanResult::Malformed;
50 return ScanResult::Stopped;
53 return ScanResult::Complete;
59template <
class Config>
60FindResult find(Config& config, uint16_t
id, Capability& result) {
63 const ScanResult status = walk(config, [&](
const Capability& cap) {
64 if (!present && cap.id ==
id) {
70 if (status == ScanResult::Unavailable) {
71 return FindResult::Unavailable;
73 if (status != ScanResult::Complete) {
74 return FindResult::Malformed;
77 return FindResult::Absent;
80 return FindResult::Found;