Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add full sound support #88

Draft
wants to merge 25 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
b7821cb
Add temporary Sound dir and modified driver files.
TomAwezome Dec 24, 2022
276ab81
Change AC97 var naming convention to Zeal standard.
TomAwezome Dec 24, 2022
dcdde18
Run CursorRemove on Sound files
TomAwezome Dec 24, 2022
bff3a76
Reformat AC97 #define value tab-alignment.
TomAwezome Dec 24, 2022
ac75988
Change AC97 Pci.ZC var style convention to Zeal standard.
TomAwezome Dec 24, 2022
027edae
Fix AC97 PCI var names.
TomAwezome Dec 24, 2022
55d95ee
Fix HDAudio BeatFreq.ZC enough to compile.
TomAwezome Dec 25, 2022
8200205
Fix HDAudio Synth.ZC enough to compile.
TomAwezome Dec 25, 2022
2fd8527
Document HDAudio/AC97 sound API currently in use.
TomAwezome Dec 27, 2022
f2490f7
Reformat HDAudio.ZC
TomAwezome Dec 28, 2022
926fd92
Delete src/Home/Sound/HDAudio0 directory
TomAwezome Dec 29, 2022
b3af162
Add PCI class and subclass codes for audio.
TomAwezome Dec 30, 2022
6063c02
Make HDAudio driver find with PCI code constants.
TomAwezome Dec 30, 2022
8106bf6
Trim a few redundant HDAudio function code lines.
TomAwezome Dec 30, 2022
5696c3d
Fix HDAudio driver for machines with less than 3 cores.
TomAwezome Dec 30, 2022
74b7708
Comment out skipped lines, add TODO noting to look into what formats …
TomAwezome Dec 30, 2022
0f1a63f
Fix PCI write funcs val calculation.
TomAwezome Dec 30, 2022
64703e9
Create PCI Command Register kernel defines, replace PCNet identical d…
TomAwezome Dec 30, 2022
e599c67
Unobfuscate HDAudioInit and HDAudioScan.
TomAwezome Dec 30, 2022
d58bc8c
Add HDAudio read/write register functions.
TomAwezome Dec 31, 2022
f872968
Refactor entire HDAudio driver to use new register functions, instead…
TomAwezome Dec 31, 2022
c370588
Replace HDAudioEnd Free calls with FreeAll.
TomAwezome Dec 31, 2022
f9bb437
Replace DFT with DEFAULT in HDAudio code.
TomAwezome Jan 2, 2023
16004d0
Merge branch 'master' into sound-dev
GutPuncher Sep 5, 2023
fca070f
Merge branch 'master' into sound-dev
GutPuncher Oct 9, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 2 additions & 8 deletions src/Home/Net/Drivers/PCNet.ZC
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/* AMD PCNetII Driver
Author: TomAwezome
Authors: ($TX,"minexew",HTML="https://github.com/minexew/"$), $TX,"TomAwezome",HTML="https://github.com/TomAwezome/"$, $TX,"TheTinkerer",HTML="https://github.com/tinkeros/"$

Driver is based on:
- minexew's ShrineOS PCNet implementation
Expand All @@ -13,12 +13,6 @@
- Clear documentation.
*/

#define PCNET_CMDf_IOEN 0
#define PCNET_CMDf_BMEN 2

#define PCNET_CMDF_IOEN (1 << PCNET_CMDf_IOEN)
#define PCNET_CMDF_BMEN (1 << PCNET_CMDf_BMEN)

#define PCNET_WD_RESET 0x14 // reset reg location when card is in 16-bit mode

#define PCNET_DW_RDP 0x10
Expand Down Expand Up @@ -705,7 +699,7 @@ U0 PCNetInit()
pcnet.pci->dev,
pcnet.pci->fun,
PCIR_COMMAND,
PCNET_CMDF_IOEN | PCNET_CMDF_BMEN);
PCI_CMDF_IOEN | PCI_CMDF_BMEN);

PCNetReset;

Expand Down
240 changes: 240 additions & 0 deletions src/Home/Sound/AC97/AC97.ZC
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@

#define INT_LAST_VALID_ENTRY 1 << 2
#define INT_IOC 1 << 3
#define INT_FIFO_ERR 1 << 4

#define BDL_BUF_SIZE 2044
#define MAX_BDLS 32

#define PCM_BUF_SIZE 2048
#define PCM_IN 0
#define PCM_OUT 1
#define MIC_IN 2

// Native Audio Mixer registers (all U16)
#define RESET 0x00 // Reset Register
#define MASTER_VOL 0x02 // Set Master Output Volume
#define MIC_VOL 0x0E // Set Microphone Volume
#define PCM_VOL 0x18 // Set Output Volume of PCM patterns
#define REC_SLC 0x1A // Select Input Device
#define REC_GAIN 0x1C // Set Input Gain
#define MIC_GAIN 0x1E // Set Gain of Microphone
#define EXT_ID 0x28 // Supported extended functions
#define EXT_CTRL 0x2A // Enabling extended functions
#define EXT_FRONT_RATE 0x2C // Sample rate of front speaker

// Native Audio Bus Master registers
#define PCM_INPUT_REG_BOX 0x00 // NABM register box for PCM IN (sizeof NABM register box)
#define PCM_OUTPUT_REG_BOX 0x10 // NABM register box for PCM OUT (sizeof NABM register box)
#define MIC_INPUT_REG_BOX 0x20 // NABM register box for Microphone (sizeof NABM register box)
#define GLOBAL_CTL 0x2C // Global Control Register (U32)
#define GLOBAL_STS 0x30 // Global Status Register (U32)

// NABM register box registers
#define BUFFER_DSC_ADDR 0x00 // Physical Address of Buffer Descriptor List (U32)
#define CUR_ENTRY_VAL 0x04 // Number of Actual Processed Buffer Descriptor Entry (U8)
#define LAST_VALID_ENTRY 0x05 // Number of all Descriptor Entries (U8)
#define TRANSFER_STS 0x06 // Status of Transferring Data (U16)
#define CUR_IDX_PROC_SAMPLES 0x08 // Number of Transferred Samples in Actual Processed Entry (U16)
#define PRCSD_ENTRY 0x0A // Number of Actual Processed Buffer Entry (U8)
#define BUFFER_CNT 0x0B // Most Important Register for controlling Transfers (U8)

class CAC97BufferDescriptorListEntry
{
U32 addr;
U16 length; // length - 1
U16 flags;
};

class CAC97BufferDescriptorList
{
CAC97BufferDescriptorListEntry entries[32];
};

class CAC97
{
CPCIInfo pci;
CAC97BufferDescriptorList *bdl[3];
U16 nam;
U16 nabm;
};

CAC97 ac97;

#define AUDIO_MAX_STREAMS 16
#define AUDIO_OUTPUT_BUFFER_SIZE 1024
#define AUDIO_STREAM_FIFO_SIZE 1048576 * 16
#define AUDIO_STREAM_TYPE_INPUT 0
#define AUDIO_STREAM_TYPE_OUTPUT 1

class CAudioStream
{
CFifoI64 *data;
};

class CAudio
{
CAudioStream output[AUDIO_MAX_STREAMS];
I64 output_frames[AUDIO_MAX_STREAMS];
};

CAudio audio;

U0 AudioInit()
{
I64 i = 0;
for (i = 0; i < AUDIO_MAX_STREAMS; i++)
audio.output[i].data = FifoI64New(AUDIO_STREAM_FIFO_SIZE, sys_task);
}

AudioInit;

I64 AudioAvailableOutputStreamGet()
{
I64 stream = 0;
while (FifoI64Count(audio.output[stream].data))
stream++;
if (stream > AUDIO_MAX_STREAMS - 1)
return -1;
return stream;
}

I64 AudioSFXPlay(U32 *data, I64 length)
{
I64 i;
I64 stream = AudioAvailableOutputStreamGet;
if (stream < 0)
return stream;
for (i = 0; i < length; i++)
FifoI64Ins(audio.output[stream].data, data[i]);
return stream;
}

U0 AC97OutputMix(U32 *buf, I64 length = NULL)
{
I64 i;
I64 j;
I64 acc_sample_L = 0;
I64 acc_sample_R = 0;
I64 acc_streams = 0;
U32 sample;

if (!length)
length = AUDIO_OUTPUT_BUFFER_SIZE;
for (i = 0; i < length / 4; i++)
{
acc_sample_L = 0;
acc_sample_R = 0;
acc_streams = 0;

for (j = 0; j < AUDIO_MAX_STREAMS; j++)
{
if (FifoI64Count(audio.output[j].data))
{
FifoI64Remove(audio.output[j].data, &sample);
audio.output_frames[j]++;
acc_streams++;
acc_sample_L += sample.u16[0];
acc_sample_R += sample.u16[1];
}
}

buf[i].i16[0] = ToI64(acc_sample_L / Sqrt(acc_streams));
buf[i].i16[1] = ToI64(acc_sample_R / Sqrt(acc_streams));
}
}

U0 AC97BufferFill()
{
I64 idx = InU8(ac97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY);
U32 *buf = ac97.bdl[PCM_OUT]->entries[idx].addr;
AC97OutputMix(buf, BDL_BUF_SIZE);
OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + LAST_VALID_ENTRY, ++idx);
}

U0 AC97AudioProcess()
{
U16 status = InU16(ac97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS);
if (status & INT_IOC)
{
AC97BufferFill;
OutU16(ac97.nabm + PCM_OUTPUT_REG_BOX + TRANSFER_STS, 0x1C);
}
}

I64 AC97Init()
{
I64 i;
I64 j;
// Scan for device
j = PCIClassFind(0x040100, 0);
if (j < 0)
{
device_not_found: SysLog("\n[AC'97] Device not found\n");
return -1;
}

PCIInfoGet(j, &ac97.pci);

if (ac97.pci.vendor_id != 0x8086 || ac97.pci.device_id != 0x2415)
goto device_not_found;

ac97.nam = ac97.pci.bar[0] &0xFFFFFF00;
ac97.nabm = ac97.pci.bar[1] &0xFFFFFF00;

// Enable port IO, disable MMIO
PCIWriteU8(j.u8[2], j.u8[1], j.u8[0], 0x4, 5);

OutU32(ac97.nabm + GLOBAL_CTL, 0x03);
OutU16(ac97.nam + RESET, 0xFFFF);

// Set PCM Output to Max volume
OutU16(ac97.nam + PCM_VOL, 0x0000);

// Allocate Buffer Descriptor Lists
ac97.bdl[PCM_IN] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap);
ac97.bdl[PCM_OUT] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap);
ac97.bdl[MIC_IN] = CAllocAligned(sizeof(CAC97BufferDescriptorList), 4096, Fs->code_heap);

for (i = 0; i < MAX_BDLS; i++)
{
ac97.bdl[PCM_OUT]->entries[i].addr =
CAllocAligned(PCM_BUF_SIZE, 4096, Fs->code_heap);
ac97.bdl[PCM_OUT]->entries[i].length = BDL_BUF_SIZE / 2;
ac97.bdl[PCM_OUT]->entries[i].flags = 1 << 15;
}

// Set addresses of Buffer Descriptor Lists
// OutU32(ac97.nabm + PCM_INPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[PCM_IN]);
OutU32(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[PCM_OUT]);
// OutU32(ac97.nabm + MIC_INPUT_REG_BOX + BUFFER_DSC_ADDR, ac97.bdl[MIC_IN]);

// Set Master Volume
OutU16(ac97.nam + MASTER_VOL, 0x0F0F);

// Stop playing sound
OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 0);

// Fill one buffers
AC97BufferFill;

// Enable interrupt handler
//@pci_register_int_handler(&@ac97_int_handler);

// Start playing sound
OutU8(ac97.nabm + PCM_OUTPUT_REG_BOX + BUFFER_CNT, 1);

return 0;
}

U0 AC97Task()
{
while (1)
{
AC97AudioProcess;
Sleep(1);
}
}

AC97Init;
Spawn(&AC97Task,, "AC97 Task", 1);
98 changes: 98 additions & 0 deletions src/Home/Sound/AC97/Pci.ZC
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@

#define PCI_INTH_MAX 16

U64 pci_int_handlers[PCI_INTH_MAX];

class CPCIInfo
{
U16 vendor_id;
U16 device_id;
U16 command;
U16 status;
U32 _class;
U32 bar[6];
U32 cap_pointer;
};

class CPCICapability
{
U8 cap_vndr; /*Generic PCI field: PCI_CAP_ID_VNDR */
U8 cap_next; /*Generic PCI field: next ptr. */
U8 cap_len; /*Generic PCI field: capability length */
U8 cfg_type; /*Identifies the structure. */
U8 bar; /*Where to find it. */
U8 padding[3]; /*Pad to full dword. */
U32 offset; /*Offset within bar. */
U32 length; /*Length of the structure, in bytes. */
};

U0 PCIInfoGet(I64 i, CPCIInfo *pci)
{
I64 j;
pci->vendor_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) &0xFFFF;
pci->device_id = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x0) >> 16;
pci->command = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) &0xFFFF;
pci->status = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x4) >> 16;
pci->_class = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x8) >> 24;
for (j = 0; j < 6; j++)
pci->bar[j] = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], 0x10 + (0x04 * j));
}

U0 PCIGetCapability(I64 i, CPCICapability *cap, I64 idx)
{
I64 base = 0x40 + (idx * 16);
U32 u32;
u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base);
cap->cap_vndr = u32.u8[0];
cap->cap_next = u32.u8[1];
cap->cap_len = u32.u8[2];
cap->cfg_type = u32.u8[3];
u32 = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x04);
cap->bar = u32.u8[0];
cap->offset = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x08);
cap->length = PCIReadU32(i.u8[2], i.u8[1], i.u8[0], base + 0x0c);
}

U0 PCIInterruptReroute(I64 base, I64 cpu)
{
I64 i;
U8 *da = dev.uncached_alias + IOAPIC_REG;
U32 *_d = dev.uncached_alias + IOAPIC_DATA;

for (i = 0; i < 4; i++)
{
*da = IOREDTAB + i * 2 + 1;
*_d = dev.mp_apic_ids[cpu] << 24;
*da = IOREDTAB + i * 2;
*_d = 0x4000 + base + i;
}
}

I64 PCIInterruptHandlerRegister(U64 handler)
{
if (!handler)
return -1;
I64 i = 0;
while (pci_int_handlers[i])
i++;
if (i > PCI_INTH_MAX - 1)
return -1;
pci_int_handlers[i] = handler;
return 0;
}

interrupt U0 PCIInterruptHandler()
{
I64 i;
for (i = 0; i < PCI_INTH_MAX; i++)
if (pci_int_handlers[i])
Call(pci_int_handlers[i]);
*(dev.uncached_alias + LAPIC_EOI)(U32 *) = 0;
}

MemSet(&pci_int_handlers, NULL, sizeof(U64) * PCI_INTH_MAX);
// IntEntrySet(0x40, &PCIInterruptHandler, IDTET_IRQ);
// IntEntrySet(0x41, &PCIInterruptHandler, IDTET_IRQ);
// IntEntrySet(0x42, &PCIInterruptHandler, IDTET_IRQ);
// IntEntrySet(0x43, &PCIInterruptHandler, IDTET_IRQ);
//PCIInterruptReroute(0x40, 0);
Loading