Skip to content

Commit

Permalink
Start adding basic Soundblaster 16 support
Browse files Browse the repository at this point in the history
  • Loading branch information
valtyr committed Jun 16, 2021
1 parent f8c20d8 commit 9371d34
Show file tree
Hide file tree
Showing 8 changed files with 155 additions and 4 deletions.
Binary file added bios-graphics/popcorn.pcm16
Binary file not shown.
4 changes: 2 additions & 2 deletions commands.fish
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ function clean-artifacts
end

function run-kernel
qemu-system-i386 -rtc base=localtime -serial stdio -cdrom dist/x86_64/kernel.iso
qemu-system-i386 -rtc base=localtime -serial stdio -device sb16 -cdrom dist/x86_64/kernel.iso
end

function build-kernel
Expand All @@ -24,4 +24,4 @@ end

function kill-system
killall qemu-system-i386
end
end
6 changes: 6 additions & 0 deletions src/impl/kernel/io.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ u8 inb(u16 port)
: "dN"(port));
return v;
}

void delay(size_t microseconds)
{
for (size_t i = 0; i < microseconds; ++i)
inb(0x80);
}
7 changes: 7 additions & 0 deletions src/impl/kernel/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,15 @@
#include "dt.h"
#include "ps2.h"
#include "rtc.h"
#include "sb16.h"

MultibootInfo systemInfo;

extern FBImage popcorn_logo;

extern u16 popcorn_chime[];
extern u32 popcorn_chime_length;

void kernel_main(u32 magic, void *addr)
{
BIOSGreeting();
Expand All @@ -32,6 +36,9 @@ void kernel_main(u32 magic, void *addr)

PS2Init();

SB16Init();
SB16DirectPlay(popcorn_chime, popcorn_chime_length);

while (true)
{
__asm__("nop");
Expand Down
121 changes: 121 additions & 0 deletions src/impl/kernel/sb16.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include "sb16.h"

#define DSP_READ 0x22A
#define DSP_WRITE 0x22C
#define DSP_STATUS 0x22E
#define DSP_R_ACK 0x22F

typedef enum
{
SampleFormatSigned = 0x10,
SampleFormatStereo = 0x20,
} SampleFormat;

void dsp_write(u8 value)
{
while (inb(DSP_WRITE) & 0x80)
{
// Chill
}
outb(DSP_WRITE, value);
}

u8 dsp_read()
{
while (!(inb(DSP_STATUS) & 0x80))
{
// Chill
}
return inb(DSP_READ);
}

void set_sample_rate(u16 hz)
{
dsp_write(0x41); // output
dsp_write((u8)(hz >> 8));
dsp_write((u8)hz);
dsp_write(0x42); // input
dsp_write((u8)(hz >> 8));
dsp_write((u8)hz);
}

void SB16Init()
{
// Disable interrupts
cli();

outb(0x226, 1);
delay(32);
outb(0x226, 0);

u8 data = dsp_read();
if (data != 0xAA)
{
BIOSPrintf("Soundblaster not ready :(");
return;
}

// Get the version info
dsp_write(0xe1);
u8 majorVersion = dsp_read();
u8 minorVersion = dsp_read();

sti();

BIOSPrintf("SB16: Found version %d.%d", majorVersion, minorVersion);

// set_irq_register(SB16_DEFAULT_IRQ);
// dmesgln("SB16: IRQ {}", get_irq_line());
}

void SB16DirectPlay(u16 *buffer, u32 length)
{

const int sample_rate = 12000;
set_sample_rate(sample_rate);

const u8 channel = 5; // 16-bit samples use DMA channel 5 (on the master DMA controller)
const u8 mode = 0x48;
const u32 addr = (u32)buffer;

// Disable the DMA channel
outb(0xd4, 4 + (channel % 4));

// Clear the byte pointer flip-flop
outb(0xd8, 0);

// Write the DMA mode for the transfer
outb(0xd6, (channel % 4) | mode);

// Write the offset of the buffer
u16 offset = (addr / 2) % 65536;
outb(0xc4, (u8)offset);
outb(0xc4, (u8)(offset >> 8));

// Write the transfer length
outb(0xc6, (u8)(length - 1));
outb(0xc6, (u8)((length - 1) >> 8));

// Write the buffer
outb(0x8b, addr >> 16);

// Enable the DMA channel
outb(0xd4, (channel % 4));

u8 command = 0xb0;
u8 sampleMode = (u8)SampleFormatSigned | (u8)SampleFormatStereo;

u16 sample_count = length / sizeof(u16);
if (mode & (u8)SampleFormatStereo)
sample_count /= 2;

sample_count -= 1;

// cli();
// enable_irq();

dsp_write(command);
dsp_write(sampleMode);
dsp_write((u8)sample_count);
dsp_write((u8)(sample_count >> 8));
}
9 changes: 8 additions & 1 deletion src/impl/x86_64/boot/main.asm
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
global start
global video_back_buffer
global popcorn_logo
global popcorn_chime
global popcorn_chime_length

extern kernel_main

Expand All @@ -9,6 +11,11 @@ section .data
popcorn_logo:
incbin "bios-graphics/fbi/test-image.fbi"

popcorn_chime:
incbin "bios-graphics/popcorn.pcm16"
popcorn_chime_length:
dd (popcorn_chime_length-popcorn_chime)

section .text
bits 32

Expand Down Expand Up @@ -36,4 +43,4 @@ stack_bottom:
stack_top:

video_back_buffer:
resb 1024 * 768 * 4
resb 1024 * 768 * 4
4 changes: 3 additions & 1 deletion src/intf/io.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#pragma once

#include "types.h"
#include "stddef.h"

void outb(u16 port, u8 v);
u8 inb(u16 port);
u8 inb(u16 port);
void delay(size_t microseconds);
8 changes: 8 additions & 0 deletions src/intf/sb16.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#pragma once

#include "types.h"
#include "io.h"
#include "bios.h"

void SB16Init();
void SB16DirectPlay(u16 *buffer, u32 length);

0 comments on commit 9371d34

Please sign in to comment.