mirror of
https://github.com/Fennix-Project/Drivers.git
synced 2025-05-28 15:34:29 +00:00
Implemented AC'97 audio driver
This commit is contained in:
parent
1f4751f90f
commit
09f26f1820
379
Audio/AudioCodec97/AudioCodec97Driver.cpp
Normal file
379
Audio/AudioCodec97/AudioCodec97Driver.cpp
Normal file
@ -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<PCIDeviceHeader *>(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;
|
||||||
|
}
|
99
Audio/AudioCodec97/Makefile
Normal file
99
Audio/AudioCodec97/Makefile
Normal file
@ -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)
|
325
Audio/AudioCodec97/ac97.hpp
Normal file
325
Audio/AudioCodec97/ac97.hpp
Normal file
@ -0,0 +1,325 @@
|
|||||||
|
#ifndef __FENNIX_API_AC97_H__
|
||||||
|
#define __FENNIX_API_AC97_H__
|
||||||
|
|
||||||
|
#include <types.h>
|
||||||
|
#include <pci.h>
|
||||||
|
#include <io.h>
|
||||||
|
|
||||||
|
#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__
|
40
Audio/AudioCodec97/linker.ld
Normal file
40
Audio/AudioCodec97/linker.ld
Normal file
@ -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.*)
|
||||||
|
}
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
build:
|
build:
|
||||||
|
make --quiet -C AudioCodec97 build
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
make -C AudioCodec97 clean
|
||||||
|
Loading…
x
Reference in New Issue
Block a user