.{string, memory, buffer, log} := @use("stn")

PCIAddress := struct {
	bus: u8,
	device: u8,
	function: u8,
}

PCI_ID := struct {
	vendor: u16,
	device: u16,
	inner: int,
}

get_ids := fn(bus: u8, device: u8, function: u8): PCI_ID {
	res := config_read32(bus, device, function, 0)
	dev_id := res >> 16
	dev_id &= 0xFFFF

	vnd_id := res & 0xFFFF
	return PCI_ID.(dev_id, vnd_id, 0)
}

PciDeviceInfo := struct {
	header_type: u8,
	device: u8,
	bus: u8,
	device_id: PCI_ID,
	class: u16,
	rev_id: u8,
}

calculate_address := fn(bus: u8, device: u8, function: u8, offset: u8): int {
	address := bus << 16
	address |= device << 11
	address |= function << 8
	address |= offset & 0xFC
	address |= 0x80000000
	return address
}

get_header_type := fn(bus: u8, device: u8, function: u8): u8 {
	res := config_read32(bus, device, function, 0xC)
	ret := res >> 16
	ret &= 0xFF

	return ret
}

check_device := fn(bus: u8, device: u8): PciDeviceInfo {
	pci_id := get_ids(bus, device, 0)

	if pci_id.vendor == 0xFFFF {
		log.warn(":|")
	} else {
		log.info(":)")
	}
	address := calculate_address(bus, device, 0, 0x8)
	reg2 := config_read32(bus, device, 0, 0x8)

	class := reg2 >> 16 & 0xFFFF

	header_type := get_header_type(bus, device, 0)

	rev_id := reg2 & 0xFF
	return PciDeviceInfo.(header_type, device, bus, pci_id, class, rev_id)
}

find_device := fn(vendor_id: int, device_id: int, pci_address: PCIAddress): PCI_ID {
	pci_id := get_ids(0, 2, 0)

	return pci_id
}

scan_bus := fn(): void {
}

config_read32 := fn(bus: u32, device: u32, func: u32, offset: u32): u32 {
	// construct address param
	offset_and := offset & 0xFC

	address := bus << 16
	address |= device << 11
	address |= func << 8
	address |= offset_and
	address |= 0x80000000

	// write address
	memory.outl(0xCF8, address)

	// read data
	return memory.inl(0xCFC)
}