EnderIce2 bf1e3432d7
feat(kernel/drivers): migrate drivers to the kernel
make the drivers builtin

Signed-off-by: EnderIce2 <enderice2@protonmail.com>
2025-03-02 21:37:01 +00:00

211 lines
4.2 KiB
C++

/*
This file is part of Fennix Kernel.
Fennix Kernel is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation, either version 3 of
the License, or (at your option) any later version.
Fennix Kernel is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Fennix Kernel. If not, see <https://www.gnu.org/licenses/>.
*/
#include <driver.hpp>
#include <cpu.hpp>
#include <pci.hpp>
#include "hda.hpp"
extern Driver::Manager *DriverManager;
extern PCI::Manager *PCIManager;
namespace Driver::HighDefinitionAudio
{
dev_t DriverID;
class HDADevice
{
private:
PCI::PCIHeader0 *Header;
bool Initialized = false;
ControllerRegisters *CTL;
uint32_t *CORB;
uint64_t *RIRB;
public:
bool IsInitialized() { return Initialized; }
size_t write(uint8_t *, size_t Size)
{
return Size;
}
int ioctl(AudioIoctl, void *)
{
return 0;
}
void OnInterruptReceived(CPU::TrapFrame *)
{
}
void Panic()
{
}
HDADevice(PCI::PCIHeader0 *_Header)
: Header(_Header),
CORB((uint32_t *)(uintptr_t)DriverManager->AllocateMemory(DriverID, 1)),
RIRB((uint64_t *)DriverManager->AllocateMemory(DriverID, 1))
{
CTL = (ControllerRegisters *)(uintptr_t)Header->BAR0;
fixme("Unimplemented HDA driver");
return;
Initialized = true;
}
~HDADevice()
{
if (!Initialized)
return;
}
};
std::unordered_map<dev_t, HDADevice *> Drivers;
int Ioctl(struct Inode *Node, unsigned long Request, void *Argp)
{
return Drivers[Node->GetMinor()]->ioctl((AudioIoctl)Request, Argp);
}
ssize_t Write(struct Inode *Node, const void *Buffer, size_t Size, off_t Offset)
{
return Drivers[Node->GetMinor()]->write((uint8_t *)Buffer, Size);
}
const struct InodeOperations ops = {
.Lookup = nullptr,
.Create = nullptr,
.Remove = nullptr,
.Rename = nullptr,
.Read = nullptr,
.Write = Write,
.Truncate = nullptr,
.Open = nullptr,
.Close = nullptr,
.Ioctl = Ioctl,
.ReadDir = nullptr,
.MkDir = nullptr,
.RmDir = nullptr,
.SymLink = nullptr,
.ReadLink = nullptr,
.Seek = nullptr,
.Stat = nullptr,
};
std::list<PCI::PCIDevice> Devices;
int Entry()
{
for (auto &&dev : Devices)
{
PCI::PCIHeader0 *hdr0 = (PCI::PCIHeader0 *)dev.Header;
uint8_t type = hdr0->BAR0 & 1;
if (type == 1)
{
debug("Device %x:%x.%d BAR0 is I/O.",
hdr0->Header.VendorID,
hdr0->Header.DeviceID,
hdr0->Header.ProgIF);
continue;
}
PCIManager->InitializeDevice(dev, KernelPageTable);
HDADevice *driver = new HDADevice((PCI::PCIHeader0 *)dev.Header);
if (driver->IsInitialized())
{
dev_t ret = v0::RegisterDevice(DriverID, AUDIO_TYPE_PCM, &ops);
Drivers[ret] = driver;
}
}
if (Drivers.empty())
{
debug("No valid HDA device found.");
return -EINVAL;
}
return 0;
}
int Final()
{
for (auto &&dev : Drivers)
{
dev_t ret = dev.first;
v0::UnregisterDevice(DriverID, ret);
delete dev.second;
}
return 0;
}
int Panic()
{
for (auto &&i : Drivers)
i.second->Panic();
return 0;
}
int Probe()
{
Devices = PCIManager->FindPCIDevice(
{
0x8086, /* Intel */
0x15AD, /* VMware */
},
{
0x9D71, /* Sunrise Point-LP HD Audio */
0x2668, /* ICH6 */
0x293E, /* ICH9 */
});
if (Devices.empty())
{
trace("No HDA device found.");
return -ENODEV;
}
for (auto &&dev : Devices)
{
PCI::PCIHeader0 *PCIBaseAddress = (PCI::PCIHeader0 *)dev.Header;
uint32_t PCIBAR0 = PCIBaseAddress->BAR0;
uint8_t Type = PCIBAR0 & 1;
if (Type == 1)
{
debug("Device %x:%x.%d BAR0 is I/O.",
PCIBaseAddress->Header.VendorID,
PCIBaseAddress->Header.DeviceID,
PCIBaseAddress->Header.ProgIF);
continue;
}
}
return 0;
}
REGISTER_BUILTIN_DRIVER(hda,
"Intel High Definition Audio Driver",
"enderice2",
1, 0, 0,
Entry,
Final,
Panic,
Probe);
}