From 09f26f1820ea56717927018422e28e1871a31722 Mon Sep 17 00:00:00 2001 From: Alex Date: Thu, 9 Mar 2023 06:47:53 +0200 Subject: [PATCH] Implemented AC'97 audio driver --- Audio/AudioCodec97/AudioCodec97Driver.cpp | 379 ++++++++++++++++++++++ Audio/AudioCodec97/Makefile | 99 ++++++ Audio/AudioCodec97/ac97.hpp | 325 +++++++++++++++++++ Audio/AudioCodec97/linker.ld | 40 +++ Audio/Makefile | 4 +- 5 files changed, 845 insertions(+), 2 deletions(-) create mode 100644 Audio/AudioCodec97/AudioCodec97Driver.cpp create mode 100644 Audio/AudioCodec97/Makefile create mode 100644 Audio/AudioCodec97/ac97.hpp create mode 100644 Audio/AudioCodec97/linker.ld diff --git a/Audio/AudioCodec97/AudioCodec97Driver.cpp b/Audio/AudioCodec97/AudioCodec97Driver.cpp new file mode 100644 index 00000000..9fd6492f --- /dev/null +++ b/Audio/AudioCodec97/AudioCodec97Driver.cpp @@ -0,0 +1,379 @@ +#include "ac97.hpp" +#include "../../../Kernel/DAPI.hpp" +#include "../../../Kernel/Fex.hpp" + +extern "C" int DriverEntry(void *Data); +int CallbackHandler(KernelCallback *Data); + +HEAD(FexFormatType_Driver, FexOSType_Fennix, DriverEntry); + +#pragma GCC diagnostic ignored "-Wmissing-field-initializers" + +__attribute__((section(".extended"))) FexExtended ExtendedHeader = { + .Driver = { + .Name = "Audio Codec '97 Driver", + .Type = FexDriverType_Audio, + .TypeFlags = FexDriverInputTypes_None, + .OverrideOnConflict = false, + .Callback = CallbackHandler, + .Bind = { + .Type = BIND_PCI, + .PCI = { + .VendorID = {0x8086}, + .DeviceID = {0x2415}, + .Class = 0x4, + .SubClass = 0x3, + .ProgIF = 0x0, + }}}}; + +KernelAPI *KAPI; + +#define print(msg) KAPI->Util.DebugPrint((char *)(msg), KAPI->Info.DriverUID) + +/* --------------------------------------------------------------------------------------------------------- */ + +/* https://wiki.osdev.org/AC97 */ + +PCIDeviceHeader *PCIBaseAddress; +BARData BAR; +BufferDescriptorList *DescriptorList = nullptr; + +AudioEncodingValues Encoding = AE_PCMs16le; +char Channels = 2; +char Volume = AV_Maximum; +bool Mute = false; +int SampleRate = 48000; +char SampleSize = 2; + +uint16_t MixerVolume(uint8_t Left, uint8_t Right, bool Mute) +{ + return ((uint16_t)((Right & 0x3F) | + ((Left & 0x3F) << 0x8) | + (Mute & 1 << 0xF))); +} + +int DriverEntry(void *Data) +{ + if (!Data) + return INVALID_KERNEL_API; + KAPI = (KernelAPI *)Data; + if (KAPI->Version.Major < 0 || KAPI->Version.Minor < 0 || KAPI->Version.Patch < 0) + return KERNEL_API_VERSION_NOT_SUPPORTED; + + return OK; +} + +int CallbackHandler(KernelCallback *Data) +{ + switch (Data->Reason) + { + case AcknowledgeReason: + { + print("Kernel acknowledged the driver."); + break; + } + case ConfigurationReason: + { + print("Driver received configuration data."); + PCIBaseAddress = reinterpret_cast(Data->RawPtr); + PCIBaseAddress->Command |= PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY; + + /* Native Audio Mixer Base Address */ + uint32_t PCIBAR0 = ((PCIHeader0 *)PCIBaseAddress)->BAR0; + + /* Native Audio Bus Master Base Address */ + uint32_t PCIBAR1 = ((PCIHeader0 *)PCIBaseAddress)->BAR1; + + BAR.Type = PCIBAR0 & 1; + BAR.MixerAddress = PCIBAR0 & (~3); + BAR.BusMasterAddress = PCIBAR1 & (~15); + + if (BAR.Type != 1) + { + print("BAR0 is not I/O."); + return INVALID_PCI_BAR; + } + uint16_t OutputPCMTransferControl = BAR.BusMasterAddress + PCMOUT_TransferControl; + + /* DescriptorList address MUST be physical. */ + DescriptorList = (BufferDescriptorList *)KAPI->Memory.RequestPage((sizeof(BufferDescriptorList) * DescriptorListLength) / KAPI->Memory.PageSize + 1); + KAPI->Util.memset(DescriptorList, 0, sizeof(BufferDescriptorList) * DescriptorListLength); + + for (int i = 0; i < DescriptorListLength; i++) + { + DescriptorList[i] = { + .Address = (uint32_t)(uint64_t)KAPI->Memory.RequestPage(sizeof(uint16_t *) / KAPI->Memory.PageSize + 1), + .SampleCount = (uint16_t)(KAPI->Memory.PageSize / SampleSize), + .Flags = 0, + }; + } + + outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute)); + outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute)); + + outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) | TC_TransferReset); + while (inb(OutputPCMTransferControl) & TC_TransferReset) + ; + + uint32_t GlobalControl = inl(BAR.BusMasterAddress + NABM_GlobalControl); + GlobalControl = (GlobalControl & ~((0x3U) << 22)); /* PCM 16-bit mode */ + GlobalControl = (GlobalControl & ~((0x3U) << 20)); /* 2 channels */ + GlobalControl |= GC_GlobalInterruptEnable; + GlobalControl &= ~GC_ShutDown; + + outl(BAR.BusMasterAddress + PCMOUT_BufferDescriptorList, (uint32_t)(uint64_t)DescriptorList); + outl(BAR.BusMasterAddress + NABM_GlobalControl, GlobalControl); + + uint8_t TransferControl = inb(OutputPCMTransferControl); + TransferControl |= TC_LastBufferEntryInterruptEnable | TC_IOCInterruptEnable | TC_FifoERRORInterruptEnable; + outb(OutputPCMTransferControl, TransferControl); + + // Stop DMA + outb(OutputPCMTransferControl, inb(OutputPCMTransferControl) & ~TC_DMAControllerControl); + print("AC'97 configured."); + break; + } + case AdjustReason: + { + if (Data->AudioCallback.Adjust._Volume) + { + Volume = Data->AudioCallback.Adjust.Volume; + outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(Volume, Volume, Mute)); + outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(Volume, Volume, Mute)); + } + else if (Data->AudioCallback.Adjust._Encoding) + { + print("Encoding changing not supported yet."); + } + else if (Data->AudioCallback.Adjust._SampleRate) + { + switch (Data->AudioCallback.Adjust.SampleRate) + { + case 0: + { + SampleRate = 8000; + break; + } + case 1: + { + SampleRate = 11025; + break; + } + case 2: + { + SampleRate = 16000; + break; + } + case 3: + { + SampleRate = 22050; + break; + } + case 4: + { + SampleRate = 32000; + break; + } + case 5: + { + SampleRate = 44100; + break; + } + case 6: + { + SampleRate = 48000; + break; + } + case 7: + { + SampleRate = 88200; + break; + } + case 8: + { + SampleRate = 96000; + break; + } + default: + { + SampleRate = 16000; + print("Invalid sample rate. Defaulting to 16000."); + break; + } + } + } + else if (Data->AudioCallback.Adjust._Channels) + { + switch (Data->AudioCallback.Adjust.Channels) + { + case 0: + { + Channels = 1; // Mono + break; + } + case 1: + { + Channels = 2; // Stereo + break; + } + default: + { + Channels = 2; + print("Invalid channel count. Defaulting to 2."); + break; + } + } + } + break; + } + case FetchReason: + { + Data->AudioCallback.Fetch.Volume = Volume; + Data->AudioCallback.Fetch.Encoding = Encoding; /* FIXME */ + Data->AudioCallback.Fetch.SampleRate = SampleRate; + Data->AudioCallback.Fetch.Channels = Channels; + break; + } + case SendReason: + { + unsigned char *Buffer = (unsigned char *)Data->AudioCallback.Send.Data; + unsigned int Length = Data->AudioCallback.Send.Length; + + if (Length % (SampleSize * Channels)) + { + print("Invalid buffer length."); + return INVALID_DATA; + } + + int TotalBDLToFill = (Length + KAPI->Memory.PageSize - 1) >> 12; + + while (Length > 0) + { + bool ActiveDMA = !(inw(BAR.BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl); + + if (ActiveDMA) + { + int RemainingBDL = 0; + + do + { + int CurrentBDL = inb(BAR.BusMasterAddress + PCMOUT_BufferDescriptorEntry); + int LastBDL = inb(BAR.BusMasterAddress + PCMOUT_DescriptorEntries); + + RemainingBDL = LastBDL - CurrentBDL; + if (RemainingBDL < 0) + RemainingBDL += DescriptorListLength; + + RemainingBDL += 1; + + if (RemainingBDL >= DescriptorListLength - 1) + { + long SampleCount = DescriptorList[(CurrentBDL + 1) % DescriptorListLength].SampleCount / Channels; + if (SampleCount > 0) + { + // KAPI->Util.Sleep(SampleCount * 1000000 / SampleRate); // microseconds + KAPI->Util.Sleep(SampleCount * 1000 / SampleRate); // milliseconds + } + } + + } while (RemainingBDL >= DescriptorListLength - 1 && (!inw(BAR.BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl)); + } + + { + int CurrentBDL = inb(BAR.BusMasterAddress + PCMOUT_BufferDescriptorEntry); + int LastBDL = inb(BAR.BusMasterAddress + PCMOUT_DescriptorEntries); + int NextBDL = LastBDL % DescriptorListLength; + + ActiveDMA = !(inw(BAR.BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl); + if (ActiveDMA) + { + NextBDL = (LastBDL + 1) % DescriptorListLength; + if (NextBDL == CurrentBDL) + continue; + } + + do + { + int Wrote = ((KAPI->Memory.PageSize > Length) ? Length : KAPI->Memory.PageSize); + + if (Wrote == 0) + break; + KAPI->Util.memcpy((void *)DescriptorList[NextBDL].Address, Buffer, Wrote); + DescriptorList[NextBDL].Flags = 0; + + Buffer += Wrote; + Length -= Wrote; + + DescriptorList[NextBDL].SampleCount = Wrote / SampleSize; + TotalBDLToFill--; + NextBDL = (NextBDL + 1) % DescriptorListLength; + } while (TotalBDLToFill-- && NextBDL != CurrentBDL); + + outb(BAR.BusMasterAddress + PCMOUT_DescriptorEntries, NextBDL - 1); + + ActiveDMA = !(inw(BAR.BusMasterAddress + PCMOUT_Status) & TC_DMAControllerControl); + if (!ActiveDMA) + { + // Start DMA + outb(BAR.BusMasterAddress + PCMOUT_TransferControl, inb(BAR.BusMasterAddress + PCMOUT_TransferControl) | TC_DMAControllerControl); + } + } + } + break; + } + case StopReason: + { + outw(BAR.MixerAddress + NAM_MasterVolume, MixerVolume(AV_Maximum, AV_Maximum, true)); + outw(BAR.MixerAddress + NAM_PCMOutVolume, MixerVolume(AV_Maximum, AV_Maximum, true)); + + // Stop DMA + outb(BAR.BusMasterAddress + PCMOUT_TransferControl, inb(BAR.BusMasterAddress + PCMOUT_TransferControl) & ~TC_DMAControllerControl); + + // Disable interrupts + uint8_t TransferControl = inb(BAR.BusMasterAddress + PCMOUT_TransferControl); + TransferControl &= ~(TC_LastBufferEntryInterruptEnable | TC_IOCInterruptEnable | TC_FifoERRORInterruptEnable); + outb(BAR.BusMasterAddress + PCMOUT_TransferControl, TransferControl); + + // Disable global control + uint32_t GlobalControl = inl(BAR.BusMasterAddress + NABM_GlobalControl); + GlobalControl &= ~GC_GlobalInterruptEnable; + GlobalControl |= GC_ShutDown; + outl(BAR.BusMasterAddress + NABM_GlobalControl, GlobalControl); + + print("Driver stopped."); + break; + } + case InterruptReason: + { + uint16_t Status = inw(BAR.MixerAddress + PCMOUT_Status); + + if (Status & TC_IOCInterruptEnable) + { + print("Interrupt on completion."); + } + else if (Status & TC_LastBufferEntryInterruptEnable) + { + print("Last buffer entry."); + // Stop DMA + outb(BAR.BusMasterAddress + PCMOUT_TransferControl, inb(BAR.BusMasterAddress + PCMOUT_TransferControl) & ~TC_DMAControllerControl); + } + else if (Status & TC_FifoERRORInterruptEnable) + { + print("FIFO error."); + } + else + { + print("Unknown status."); + } + + outw(BAR.MixerAddress + PCMOUT_Status, 0xFFFF); + break; + } + default: + { + print("Unknown reason."); + break; + } + } + return OK; +} diff --git a/Audio/AudioCodec97/Makefile b/Audio/AudioCodec97/Makefile new file mode 100644 index 00000000..4da34e42 --- /dev/null +++ b/Audio/AudioCodec97/Makefile @@ -0,0 +1,99 @@ +# Config file +include ../../../Makefile.conf + +FILENAME = AudioCodec97.fex + +CC = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)gcc +CPP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)g++ +LD = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)ld +AS = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)as +OBJDUMP = ../../../$(COMPILER_PATH)/$(COMPILER_ARCH)objdump + +GIT_COMMIT = $(shell git rev-parse HEAD) +GIT_COMMIT_SHORT = $(shell git rev-parse --short HEAD) + +ifeq ($(OSARCH), amd64) +S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*") +C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*") +CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/i686/*" -not -path "./arch/aarch64/*") +else ifeq ($(OSARCH), i686) +S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") +C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") +CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/aarch64/*") +else ifeq ($(OSARCH), aarch64) +S_SOURCES = $(shell find ./ -type f -name '*.S' -not -path "./arch/amd64/*" -not -path "./arch/i686/*") +C_SOURCES = $(shell find ./ -type f -name '*.c' -not -path "./arch/amd64/*" -not -path "./arch/i686/*") +CPP_SOURCES = $(shell find ./ -type f -name '*.cpp' -not -path "./arch/amd64/*" -not -path "./arch/i686/*") +endif +HEADERS = $(sort $(dir $(wildcard ../../include/*))) +OBJ = $(C_SOURCES:.c=.o) $(CPP_SOURCES:.cpp=.o) $(ASM_SOURCES:.asm=.o) $(S_SOURCES:.S=.o) $(PSF_SOURCES:.psf=.o) $(BMP_SOURCES:.bmp=.o) +INCLUDE_DIR = ../../include + +LDFLAGS := \ + -fPIC -fPIE -pie -Wl,-eDriverEntry \ + -Wl,-static,--no-dynamic-linker,-ztext,--no-warn-rwx-segment \ + -nostdlib -nodefaultlibs -nolibc \ + -zmax-page-size=0x1000 \ + -Wl,-Map file.map -static -Tlinker.ld + +WARNCFLAG = -Wall -Wextra + +CFLAGS := \ + -I$(INCLUDE_DIR) \ + -DGIT_COMMIT='"$(GIT_COMMIT)"' \ + -DGIT_COMMIT_SHORT='"$(GIT_COMMIT_SHORT)"' + +ifeq ($(OSARCH), amd64) + +CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \ + -mno-red-zone -mno-sse -mno-sse2 \ + -march=x86-64 -pipe -ffunction-sections \ + -msoft-float -fno-builtin + +else ifeq ($(OSARCH), i686) + +CFLAGS += -fPIC -fPIE -pie -mno-80387 -mno-mmx -mno-3dnow \ + -mno-red-zone -mno-sse -mno-sse2 \ + -march=i686 -pipe -ffunction-sections \ + -msoft-float -fno-builtin + +else ifeq ($(OSARCH), aarch64) + +CFLAGS += -pipe -fno-builtin -fPIC + +endif + +build: $(FILENAME) +ifeq ($(OSARCH), amd64) + $(OBJDUMP) -b binary -D -m i386:x86-64 -d $(FILENAME) > file_dump.map +else ifeq ($(OSARCH), i686) + +else ifeq ($(OSARCH), aarch64) + +endif + mv $(FILENAME) ../../out/$(FILENAME) + +$(FILENAME): $(OBJ) + $(info Linking $@) + $(CC) $(LDFLAGS) $(OBJ) -o $@ + +%.o: %.c $(HEADERS) + $(info Compiling $<) + $(CC) $(CFLAGS) $(WARNCFLAG) -std=c17 -c $< -o $@ + +%.o: %.cpp $(HEADERS) + $(info Compiling $<) + $(CPP) $(CFLAGS) $(WARNCFLAG) -std=c++20 -fexceptions -c $< -o $@ + +%.o: %.S + $(info Compiling $<) +ifeq ($(OSARCH), amd64) + $(AS) -o $@ $< +else ifeq ($(OSARCH), i686) + $(AS) -o $@ $< +else ifeq ($(OSARCH), aarch64) + $(AS) -o $@ $< +endif + +clean: + rm -f *.o file.map file_dump.map $(OBJ) diff --git a/Audio/AudioCodec97/ac97.hpp b/Audio/AudioCodec97/ac97.hpp new file mode 100644 index 00000000..6c2a3912 --- /dev/null +++ b/Audio/AudioCodec97/ac97.hpp @@ -0,0 +1,325 @@ +#ifndef __FENNIX_API_AC97_H__ +#define __FENNIX_API_AC97_H__ + +#include +#include +#include + +#define DescriptorListLength 0x20 + +enum AudioVolumeValues +{ + AV_Maximum = 0x0, + AV_Minimum = 0x3F, +}; + +enum AudioEncodingValues +{ + AE_PCMs8, + AE_PCMu8, + + AE_PCMs16le, + AE_PCMs20le, + AE_PCMs24le, + AE_PCMs32le, + + AE_PCMu16le, + AE_PCMu20le, + AE_PCMu24le, + AE_PCMu32le, + + AE_PCMs16be, + AE_PCMs20be, + AE_PCMs24be, + AE_PCMs32be, + + AE_PCMu16be, + AE_PCMu20be, + AE_PCMu24be, + AE_PCMu32be, +}; + +enum NativeAudioMixerRegisters +{ + /** + * @brief Reset Register + * @note Length: word + */ + NAM_Reset = 0x00, + + /** + * @brief Master Volume Register + * @note Length: word + */ + NAM_MasterVolume = 0x02, + + /** + * @brief Microphone Volume Register + * @note Length: word + */ + NAM_MicrophoneVolume = 0x0E, + + /** + * @brief PCM Out Volume Register + * @note Length: word + */ + NAM_PCMOutVolume = 0x18, + + /** + * @brief Select Record Input Register + * @note Length: word + */ + NAM_SelectRecordInput = 0x1A, + + /** + * @brief Record Gain Register + * @note Length: word + */ + NAM_RecordGain = 0x1C, + + /** + * @brief Record Gain Microphone Register + * @note Length: word + */ + NAM_RecordGainMicrophone = 0x1E, +}; + +enum NativeAudioBusMasterRegisters +{ + /** + * @brief Register box for PCM IN + * @note Length: below + */ + NABM_PCMInBox = 0x00, + + /** + * @brief Register box for PCM OUT + * @note Length: below + */ + NABM_PCMOutBox = 0x10, + + /** + * @brief Register box for Microphone + * @note Length: below + */ + NABM_MicrophoneBox = 0x20, + + /** + * @brief Global Control Register + * @note Length: dword + */ + NABM_GlobalControl = 0x2C, /* 0x30 */ + + /** + * @brief Global Status Register + * @note Length: dword + */ + NABM_GlobalStatus = 0x30, /* 0x34 */ +}; + +enum NativeAudioBusMasterBoxOffsets +{ + /** + * @brief Physical Address of Buffer Descriptor List + * @note Length: dword + */ + NABMBOFF_BufferDescriptorList = 0x00, + + /** + * @brief Number of Actual Processed Buffer Descriptor Entry + * @note Length: byte + */ + NABMBOFF_BufferDescriptorEntry = 0x04, + + /** + * @brief Number of all Descriptor Entries + * @note Length: byte + */ + NABMBOFF_DescriptorEntries = 0x05, + + /** + * @brief Status of transferring Data + * @note Length: word + */ + NABMBOFF_Status = 0x06, + + /** + * @brief Number of transferred Samples in Actual Processed Entry + * @note Length: word + */ + NABMBOFF_TransferredSamples = 0x08, + + /** + * @brief Number of next processed Buffer Entry + * @note Length: byte + */ + NABMBOFF_NextProcessedBufferEntry = 0x0A, + + /** + * @brief Transfer Control + * @note Length: byte + */ + NABMBOFF_TransferControl = 0x0B, +}; + +enum OutputPulseCodeModulationRegisters +{ + /** + * @brief Physical Address of Buffer Descriptor List + * @note Length: dword + */ + PCMOUT_BufferDescriptorList = NABM_PCMOutBox + NABMBOFF_BufferDescriptorList, + + /** + * @brief Number of Actual Processed Buffer Descriptor Entry + * @note Length: byte + */ + PCMOUT_BufferDescriptorEntry = NABM_PCMOutBox + NABMBOFF_BufferDescriptorEntry, + + /** + * @brief Number of all Descriptor Entries + * @note Length: byte + */ + PCMOUT_DescriptorEntries = NABM_PCMOutBox + NABMBOFF_DescriptorEntries, + + /** + * @brief Status of transferring Data + * @note Length: word + */ + PCMOUT_Status = NABM_PCMOutBox + NABMBOFF_Status, + + /** + * @brief Number of transferred Samples in Actual Processed Entry + * @note Length: word + */ + PCMOUT_TransferredSamples = NABM_PCMOutBox + NABMBOFF_TransferredSamples, + + /** + * @brief Number of next processed Buffer Entry + * @note Length: byte + */ + PCMOUT_NextProcessedBufferEntry = NABM_PCMOutBox + NABMBOFF_NextProcessedBufferEntry, + + /** + * @brief Transfer Control + * @note Length: byte + */ + PCMOUT_TransferControl = NABM_PCMOutBox + NABMBOFF_TransferControl, +}; + +enum TransferControlRegisters +{ + /** + * @brief DMA controller control + * 0 = Pause transfer + * 1 = Transfer sound data + */ + TC_DMAControllerControl = 0x01, + + /** + * @brief Reset + * 0 = Remove reset condition + * 1 = Reset this NABM register box, this bit is cleared by card when is reset complete + */ + TC_TransferReset = 0x02, + + /** + * @brief Last Buffer Entry Interrupt enable + * 0 = Disable interrupt + * 1 = Enable interrupt + */ + TC_LastBufferEntryInterruptEnable = 0x04, + + /** + * @brief IOC Interrupt enable + * 0 = Disable interrupt + * 1 = Enable interrupt + */ + TC_IOCInterruptEnable = 0x08, + + /** + * @brief Fifo ERROR Interrupt enable + * 0 = Disable interrupt + * 1 = Enable interrupt + */ + TC_FifoERRORInterruptEnable = 0x10, +}; + +enum GlobalControlRegisters +{ + /** + * @brief Global Interrupt Enable + * 0 = Disable Interrupts + * 1 = Enable Interrupts + */ + GC_GlobalInterruptEnable = 0x01, + + /** + * @brief Cold reset + * 0 = Device is in reset and can not be used + * 1 = Resume to operational state + */ + GC_ColdReset = 0x02, + + /** + * @brief Warm reset + */ + GC_WarmReset = 0x04, + + /** + * @brief Shut down + * 0 = Device is powered + * 1 = Shut down + */ + GC_ShutDown = 0x08, + + /** + * @brief Channels for PCM Output + * 00 = 2 channels + * 01 = 4 channels + * 10 = 6 channels + * 11 = Reserved + */ + GC_ChannelsForPCMOutput = 0x30, + + /** + * @brief PCM Output mode + * 00 = 16 bit samples + * 01 = 20 bit samples + */ + GC_PCMOutputMode = 0xC0, +}; + +struct BufferDescriptorList +{ + /** + * @brief Physical Address to sound data in memory + * @note Length: dword + */ + uint32_t Address; + + /** + * @brief Number of samples in this buffer + * @note Length: word + */ + uint16_t SampleCount; + + /** + * @brief Flags + * @note Length: word + * + * Bit 15 = Interrupt fired when data from this entry is transferred + * Bit 14 = Last entry of buffer, stop playing + * Other bits = Reserved + */ + uint16_t Flags; +} __attribute__((packed)); + +struct BARData +{ + uint8_t Type; + uint64_t MixerAddress; + uint64_t BusMasterAddress; +}; + +#endif // !__FENNIX_API_AC97_H__ diff --git a/Audio/AudioCodec97/linker.ld b/Audio/AudioCodec97/linker.ld new file mode 100644 index 00000000..29cd11cd --- /dev/null +++ b/Audio/AudioCodec97/linker.ld @@ -0,0 +1,40 @@ +OUTPUT_FORMAT(binary) +OUTPUT_ARCH(i386:x86-64) + +ENTRY(DriverEntry) + +SECTIONS +{ + .header : + { + *(.header .header.*) + *(.extended .extended.*) + } + + .text : + { + *(.text .text.*) + } + + .data : + { + *(.data .data.*) + } + + .rodata : + { + *(.rodata .rodata.*) + } + + .bss : + { + *(COMMON) + *(.bss .bss.*) + } + + /DISCARD/ : + { + *(.eh_frame) + *(.note .note.*) + } +} diff --git a/Audio/Makefile b/Audio/Makefile index 81aab704..e27f6453 100644 --- a/Audio/Makefile +++ b/Audio/Makefile @@ -1,5 +1,5 @@ build: - + make --quiet -C AudioCodec97 build clean: - + make -C AudioCodec97 clean