summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Kling <anton@kling.gg>2024-11-30 17:46:10 +0100
committerAnton Kling <anton@kling.gg>2024-11-30 17:46:10 +0100
commitf43624cf031cd387095ea12fd5714e49a087c555 (patch)
tree8347bd41d731d2bbe26f8562278e46af0a261bd8
parent5dd05779ce0a6544f4653eee87d278973386d0ab (diff)
ac97/audio: Add audio
Incomplete but still very cool
-rw-r--r--kernel/audio.c32
-rw-r--r--kernel/audio.h1
-rw-r--r--kernel/drivers/ac97.c145
-rw-r--r--kernel/drivers/ac97.h5
-rw-r--r--kernel/init/kernel.c8
5 files changed, 115 insertions, 76 deletions
diff --git a/kernel/audio.c b/kernel/audio.c
new file mode 100644
index 0000000..60df1f3
--- /dev/null
+++ b/kernel/audio.c
@@ -0,0 +1,32 @@
+// TODO: This should support multiple audio sources.
+#include <audio.h>
+#include <drivers/ac97.h>
+#include <errno.h>
+#include <fs/devfs.h>
+#include <math.h>
+
+int audio_write(u8 *buffer, u64 offset, u64 len, vfs_fd_t *fd) {
+ (void)offset;
+ (void)fd;
+ int rc = ac97_add_pcm(buffer, len);
+ if (0 == rc) {
+ return -EWOULDBLOCK;
+ }
+ return rc;
+}
+
+int audio_can_write(vfs_inode_t *inode) {
+ (void)inode;
+ return ac97_can_write();
+}
+
+static int add_files(void) {
+ devfs_add_file("/audio", NULL, audio_write, NULL, NULL, audio_can_write,
+ FS_TYPE_CHAR_DEVICE);
+ return 1;
+}
+
+void audio_init(void) {
+ ac97_init();
+ add_files();
+}
diff --git a/kernel/audio.h b/kernel/audio.h
new file mode 100644
index 0000000..be5f481
--- /dev/null
+++ b/kernel/audio.h
@@ -0,0 +1 @@
+void audio_init(void);
diff --git a/kernel/drivers/ac97.c b/kernel/drivers/ac97.c
index 24899dd..6554fdb 100644
--- a/kernel/drivers/ac97.c
+++ b/kernel/drivers/ac97.c
@@ -5,6 +5,7 @@
#include <fcntl.h>
#include <fs/vfs.h>
#include <kmalloc.h>
+#include <math.h>
#include <random.h>
struct PCI_DEVICE ac97;
@@ -19,6 +20,7 @@ u16 *pointer;
struct audio_buffer {
volatile u8 *data;
+ size_t data_written;
uintptr_t physical;
int has_played;
};
@@ -27,13 +29,15 @@ struct audio_buffer buffers[32];
void add_buffer(void) {
u16 *pointer = buffer_descriptor_list;
- for (int i = 0; i < 4; i++) {
+ for (int i = 0; i < 32; i++) {
void *physical_audio_data;
u8 *audio_data = kmalloc_align(128000, &physical_audio_data);
+ assert(audio_data);
buffers[i].data = audio_data;
buffers[i].physical = physical_audio_data;
buffers[i].has_played = 1;
+ buffers[i].data_written = 0;
*((u32 *)pointer) = physical_audio_data;
pointer += 2;
@@ -64,10 +68,6 @@ void add_to_list(u8 *buffer, size_t size) {
int entry = 0;
void start(void) {
- // // Write number of last valid buffer entry to Last Valid Entry
- // // register (NABM register 0x15)
- // outb(nabm.address + 0x10 + 0x5, 1);
-
// Set bit for transfering data (NABM register 0x1B, value 0x1)
u8 s = inb(nabm.address + 0x10 + 0xB);
if (s & (1 << 0)) {
@@ -77,34 +77,77 @@ void start(void) {
outb(nabm.address + 0x10 + 0xB, s);
}
-void play_pcm(u8 *buffer, size_t size) {
- if (entry >= 3) {
- outb(nabm.address + 0x10 + 0x5, entry - 1);
- return;
- }
+int ac97_can_write(void) {
+ u8 process_num = inb(nabm.address + 0x10 + 0x4);
if (!buffers[entry].has_played) {
- for (;;) {
- u8 process_num = inb(nabm.address + 0x10 + 0x4);
- kprintf("process_num: %d\n", process_num);
- if (process_num > entry) {
- buffers[entry].has_played = 1;
- break;
- }
+ if (31 == process_num) {
+ outb(nabm.address + 0x10 + 0x5, entry);
+ buffers[31].has_played = 1;
+ }
+ for (int i = 0; i < process_num; i++) {
+ buffers[i].has_played = 1;
+ }
+ }
+ u8 delta = abs((int)process_num - (int)entry);
+ if (delta > 3) {
+ return 0;
+ }
+ return buffers[entry].has_played;
+}
+
+static int write_buffer(u8 *buffer, size_t size) {
+ u8 process_num = inb(nabm.address + 0x10 + 0x4);
+ if (!buffers[entry].has_played && 128000 == buffers[entry].data_written) {
+ if (31 == process_num) {
+ outb(nabm.address + 0x10 + 0x5, entry);
+ buffers[31].has_played = 1;
+ }
+ for (int i = 0; i < process_num; i++) {
+ buffers[i].has_played = 1;
+ }
+ if (!buffers[entry].has_played) {
+ return 0;
}
}
- memcpy((u8 *)buffers[entry].data, buffer, size);
- outb(nabm.address + 0x10 + 0x5, entry);
+
+ u8 delta = abs((int)process_num - (int)entry);
+ if (delta > 3) {
+ return 0;
+ }
+
+ size_t offset = buffers[entry].data_written;
+ memset((u8 *)buffers[entry].data + offset, 0, 128000 - offset);
+ size_t wl = min(size, 128000 - offset);
+ memcpy((u8 *)buffers[entry].data + offset, buffer, wl);
+ buffers[entry].data_written += wl;
buffers[entry].has_played = 0;
- entry++;
+ if (128000 == buffers[entry].data_written) {
+ u8 current_valid = inb(nabm.address + 0x10 + 0x5);
+ if (current_valid <= entry) {
+ outb(nabm.address + 0x10 + 0x5, entry);
+ }
+ entry++;
+ if (entry > 31) {
+ entry = 0;
+ }
+ }
- /*
- u8 process_num = inb(nabm.address + 0x10 + 0x4);
- kprintf("process_num: %d\n", process_num);
+ start();
+ return 1;
+}
- if (0 == process_num)
- return;
- */
+int ac97_add_pcm(u8 *buffer, size_t len) {
+ size_t rc = 0;
+ for (; len > 0;) {
+ size_t wl = min(len, 128000);
+ if (!write_buffer(buffer + rc, wl)) {
+ break;
+ }
+ rc += wl;
+ len -= wl;
+ }
+ return rc;
}
void ac97_init(void) {
@@ -112,6 +155,7 @@ void ac97_init(void) {
assert(0);
return;
}
+
pointer = buffer_descriptor_list =
kmalloc_align(0x1000, &physical_buffer_descriptor_list);
@@ -151,24 +195,10 @@ void ac97_init(void) {
card support headhone output.
*/
- // 0x30 Global Status Register dword
- u32 status = inl(nabm.address + 0x30);
-
- u8 channel_capabilities = (status >> 20) & 0x3;
- u8 sample_capabilities = (status >> 22) & 0x3;
- kprintf("channel: %d\n", channel_capabilities);
- kprintf("sample: %d\n", sample_capabilities);
-
- // outw(nam.address + 0x2C, 16000 / 2);
- outw(nam.address + 0x2C, 48000 / 2);
- u16 sample_rate = inw(nam.address + 0x2C);
- kprintf("sample_rate: %d\n", sample_rate);
- sample_rate = inw(nam.address + 0x2E);
- kprintf("sample_rate: %d\n", sample_rate);
- sample_rate = inw(nam.address + 0x30);
- kprintf("sample_rate: %d\n", sample_rate);
- sample_rate = inw(nam.address + 0x32);
- kprintf("sample_rate: %d\n", sample_rate);
+ outw(nam.address + 0x2C, 32000);
+ outw(nam.address + 0x2E, 32000);
+ outw(nam.address + 0x30, 32000);
+ outw(nam.address + 0x32, 32000);
/*
As last thing, set maximal volume for
@@ -189,45 +219,18 @@ void ac97_init(void) {
outw(nam.address + 0x02, 0);
outw(nam.address + 0x04, 0);
- // SETUP?
-
// Set reset bit of output channel (NABM register 0x1B, value 0x2) and
// wait for card to clear it
u8 s = inb(nabm.address + 0x10 + 0xB);
s |= (1 << 1);
outb(nabm.address + 0x10 + 0xB, s);
- kprintf("wait for clear\n");
for (; inb(nabm.address + 0x10 + 0xB) & (1 << 1);)
;
- kprintf("cleared\n");
add_buffer();
// Write physical position of BDL to Buffer Descriptor Base Address
// register (NABM register 0x10)
outl(nabm.address + 0x10 + 0x0, physical_buffer_descriptor_list);
-
- // END SETUP?
-
- int fd = vfs_open("/hq.pcm", O_RDONLY, 0);
- assert(0 >= fd);
- size_t offset = 0;
- size_t capacity = 128000;
- char *data = kmalloc(capacity);
- for (;;) {
- int rc = vfs_pread(fd, data, capacity, offset);
- if (0 == rc) {
- break;
- }
- if (rc < 0) {
- kprintf("rc: %d\n", rc);
- assert(0);
- }
- play_pcm(data, rc);
- start();
- offset += rc;
- }
- for (;;)
- ;
}
diff --git a/kernel/drivers/ac97.h b/kernel/drivers/ac97.h
index 02be9a0..d7bacb6 100644
--- a/kernel/drivers/ac97.h
+++ b/kernel/drivers/ac97.h
@@ -1 +1,6 @@
+#include <typedefs.h>
+#include <stddef.h>
+
void ac97_init(void);
+int ac97_add_pcm(u8* buffer, size_t len);
+int ac97_can_write(void);
diff --git a/kernel/init/kernel.c b/kernel/init/kernel.c
index e53aeeb..79c6366 100644
--- a/kernel/init/kernel.c
+++ b/kernel/init/kernel.c
@@ -1,11 +1,11 @@
#include <assert.h>
+#include <audio.h>
#include <cpu/arch_inst.h>
#include <cpu/gdt.h>
#include <cpu/idt.h>
#include <cpu/spinlock.h>
#include <cpu/syscall.h>
#include <crypto/SHA1/sha1.h>
-#include <drivers/ac97.h>
#include <drivers/ahci.h>
#include <drivers/ata.h>
#include <drivers/keyboard.h>
@@ -124,11 +124,9 @@ void kernel_main(u32 kernel_end, unsigned long magic, unsigned long addr,
gen_ipv4(&ip_address, 10, 0, 2, 15);
enable_interrupts();
- add_vbe_device();
+ audio_init();
- // ac97_init();
- // for (;;)
- // ;
+ add_vbe_device();
int pid;
if (0 == (pid = fork())) {