/* 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 . */ #include #include #include #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 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 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); }