Program Listing for File device.hpp¶
↰ Return to documentation for file (dev/pci/device.hpp
)
/* SPDX-License-Identifier: BSD-2-Clause */
#pragma once
#include "lai/host.h"
#include "vm/heap.hpp"
#include <dev/devkit/service.hpp>
#include <frg/span.hpp>
namespace Gaia::Dev {
enum class PciOffset : uint16_t {
VENDOR_ID = 0x0,
DEVICE_ID = 0x2,
COMMAND = 0x4,
STATUS = 0x6,
SUBCLASS = 0xa,
CLASS = 0xb,
HEADER_TYPE = 0xe,
BASE_ADDRESS = 0x10,
CAPABILITIES_POINTER = 0x34, // Linked-list of capabilities
PIN = 0x3d,
};
enum class PciStatusBit : uint8_t {
CAPABILITIES_LIST =
(1 << 4) // Whether the device implements the linked-list of caps
};
enum class Command {
IO_SPACE = (1 << 0),
MEM_SPACE = (1 << 1),
BUS_MASTER = (1 << 2),
INTERRUPT_DISABLE = (1 << 10),
};
class PciDevice : public Service {
public:
PciDevice(uint8_t bus, uint8_t slot, uint8_t fun);
template <typename T> T read(PciOffset offset) {
if (sizeof(T) == sizeof(uint8_t)) {
return laihost_pci_readb(0, bus, slot, fun, (uint16_t)offset);
} else if (sizeof(T) == sizeof(uint16_t)) {
return laihost_pci_readw(0, bus, slot, fun, (uint16_t)offset);
} else if (sizeof(T) == sizeof(uint32_t)) {
return laihost_pci_readd(0, bus, slot, fun, (uint16_t)offset);
}
}
template <typename T> void write(PciOffset offset, T value) {
if (sizeof(T) == sizeof(uint8_t)) {
laihost_pci_writeb(0, bus, slot, fun, (uint16_t)offset, value);
} else if (sizeof(T) == sizeof(uint16_t)) {
laihost_pci_writew(0, bus, slot, fun, (uint16_t)offset, value);
} else if (sizeof(T) == sizeof(uint32_t)) {
laihost_pci_writed(0, bus, slot, fun, (uint16_t)offset, value);
}
}
inline void enable_cmd_flag(Command flag) {
write<uint16_t>(PciOffset::COMMAND,
read<uint16_t>(PciOffset::COMMAND) | (uint8_t)flag);
}
inline void disable_cmd_flag(Command flag) {
write<uint16_t>(PciOffset::COMMAND,
read<uint16_t>(PciOffset::COMMAND) & ~(uint8_t)flag);
}
struct Info {
uint8_t bus;
uint8_t slot;
uint8_t fun;
uint8_t _class, subclass;
uint16_t vendor, device_id;
uint8_t pin;
uint8_t gsi;
bool lopol, edge;
};
Info get_info() { return info; };
void start(Service *provider) override;
bool match_properties(Properties &props) override;
const char *class_name() override { return "PciDevice"; }
const char *name() override { return _name.data(); };
template <typename F> void iter_capabilities(F callback) {
if (read<uint16_t>(PciOffset::STATUS) &
(uint8_t)PciStatusBit::CAPABILITIES_LIST) {
auto cap_off = read<uint8_t>(PciOffset::CAPABILITIES_POINTER);
while (cap_off) {
callback(cap_off);
cap_off = read<uint8_t>(static_cast<PciOffset>(cap_off + 1));
}
}
}
inline void set_cmd(Command command, bool enabled) {
if (enabled)
enable_cmd_flag(command);
else
disable_cmd_flag(command);
}
inline void set_bus_mastering(bool enabled) {
set_cmd(Command::BUS_MASTER, enabled);
}
inline void set_memory_space(bool enabled) {
set_cmd(Command::MEM_SPACE, enabled);
}
inline void set_io_space(bool enabled) {
set_cmd(Command::IO_SPACE, enabled);
}
frg::span<uint8_t> get_bar(uint8_t num);
private:
uint8_t bus, slot, fun;
uint16_t vendor, device_id;
frg::string<Gaia::Vm::HeapAllocator> _name = "";
Vm::UniquePtr<Service> driver;
Info info;
};
} // namespace Gaia::Dev