From bd35c984636a2d5dfdff7a80f8eaa4e388c6899c Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Thu, 24 May 2018 07:29:09 +0300 Subject: [PATCH] started the sound blaster audio driver --- Makefile | 5 +- src/au_sb.c | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/au_sb.h | 31 +++++++++++ src/audio.c | 30 +++++++++++ src/audio.h | 23 +++++++++ src/kmain.c | 3 ++ src/timer.c | 2 - src/timer.h | 5 +- 8 files changed, 258 insertions(+), 5 deletions(-) create mode 100644 src/au_sb.c create mode 100644 src/au_sb.h create mode 100644 src/audio.c create mode 100644 src/audio.h diff --git a/Makefile b/Makefile index 23c8eaf..07e856f 100644 --- a/Makefile +++ b/Makefile @@ -16,6 +16,7 @@ CFLAGS = $(ccarch) -march=i386 $(warn) $(opt) $(dbg) $(gccopt) $(inc) $(def) ASFLAGS = $(asarch) -march=i386 $(dbg) -nostdinc -fno-builtin $(inc) LDFLAGS = $(ldarch) -nostdlib -T pcboot.ld -print-gc-sections +QEMU_FLAGS = -fda floppy.img -serial file:serial.log -soundhw sb16 ifneq ($(shell uname -m), i386) ccarch = -m32 @@ -71,11 +72,11 @@ $(elf).sym: $(elf) .PHONY: run run: $(bin) - qemu-system-i386 -fda floppy.img -serial file:serial.log + qemu-system-i386 $(QEMU_FLAGS) .PHONY: debug debug: $(bin) $(elf).sym - qemu-system-i386 -fda floppy.img -serial file:serial.log -s -S + qemu-system-i386 $(QEMU_FLAGS) -s -S .PHONY: sym sym: $(elf).sym diff --git a/src/au_sb.c b/src/au_sb.c new file mode 100644 index 0000000..f3184ae --- /dev/null +++ b/src/au_sb.c @@ -0,0 +1,164 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include "audio.h" +#include "au_sb.h" +#include "asmops.h" + +#define REG_MIXPORT (base_port + 0x4) +#define REG_MIXDATA (base_port + 0x5) +#define REG_RESET (base_port + 0x6) +#define REG_RDATA (base_port + 0xa) +#define REG_WDATA (base_port + 0xc) +#define REG_WSTAT (base_port + 0xc) +#define REG_RSTAT (base_port + 0xe) +#define REG_INTACK (base_port + 0xe) +#define REG_INT16ACK (base_port + 0xf) + +#define WSTAT_BUSY 0x80 +#define RSTAT_RDY 0x80 + +#define CMD_SET_RATE 0x41 +#define CMD_PLAY_PCM 0xa6 +#define CMD_STOP_PCM 0xd9 +#define CMD_GET_VER 0xe1 + +#define VER_MAJOR(x) ((x) >> 8) +#define VER_MINOR(x) ((x) & 0xff) + +static void write_dsp(unsigned char val); +static unsigned char read_dsp(void); +static int get_dsp_version(void); +static const char *sbname(int ver); + +static int base_port; + +int sb_detect(void) +{ + int i, ver; + + for(i=0; i<6; i++) { + base_port = 0x200 + ((i + 1) << 4); + if(sb_reset_dsp() == 0) { + ver = get_dsp_version(); + printf("sb_detect: found %s (DSP v%d.%02d) at port %xh\n", sbname(ver), + VER_MAJOR(ver), VER_MINOR(ver), base_port); + return 1; + } + } + + return 0; +} + +int sb_reset_dsp(void) +{ + int i; + + outb(1, REG_RESET); + for(i=0; i<3; i++) iodelay(); + outb(0, REG_RESET); + + for(i=0; i<128; i++) { + if(inb(REG_RSTAT) & RSTAT_RDY) { + if(inb(REG_RDATA) == 0xaa) { + return 0; + } + } + } + + return -1; +} + +static void write_dsp(unsigned char val) +{ + while(inb(REG_WSTAT) & WSTAT_BUSY); + outb(val, REG_WDATA); +} + +static unsigned char read_dsp(void) +{ + while((inb(REG_RSTAT) & RSTAT_RDY) == 0); + return inb(REG_RDATA); +} + +static int get_dsp_version(void) +{ + int major, minor; + + write_dsp(CMD_GET_VER); + major = read_dsp(); + minor = read_dsp(); + + return (major << 8) | minor; +} + +#define V(maj, min) (((maj) << 8) | (min)) + +static const char *sbname(int ver) +{ + int major = VER_MAJOR(ver); + int minor = VER_MINOR(ver); + + switch(major) { + case 1: + if(minor == 5) { + return "Sound Blaster 1.5"; + } + return "Sound Blaster 1.0"; + + case 2: + if(minor == 1 || minor == 2) { + return "Sound Blaster 2.0"; + } + break; + + case 3: + switch(minor) { + case 0: + return "Sound Blaster Pro"; + case 1: + case 2: + return "Sound Blaster Pro 2"; + case 5: + return "Gallant SC-6000"; + default: + break; + } + break; + + case 4: + switch(minor) { + case 4: + case 5: + return "Sound Blaster 16"; + case 11: + return "Sound Blaster 16 SCSI-2"; + case 12: + return "Sound Blaster AWE 32"; + case 13: + return "Sound Blaster ViBRA16C"; + case 16: + return "Sound Blaster AWE 64"; + default: + break; + } + break; + } + + return "Unknown Sound Blaster"; +} diff --git a/src/au_sb.h b/src/au_sb.h new file mode 100644 index 0000000..9552bcd --- /dev/null +++ b/src/au_sb.h @@ -0,0 +1,31 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef AU_SB_H_ +#define AU_SB_H_ + +/* returns true (nonzero) if a sound blaster DSP is detected in the ISA bus + * and sets the internal base_port so that subsequent calls can find it + */ +int sb_detect(void); + +/* returns 0 for success, non-zero if the DSP isn't responding at the currently + * selected base port + */ +int sb_reset_dsp(void); + +#endif /* AU_SB_H_ */ diff --git a/src/audio.c b/src/audio.c new file mode 100644 index 0000000..c7142f1 --- /dev/null +++ b/src/audio.c @@ -0,0 +1,30 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#include +#include "audio.h" +#include "au_sb.h" + +void init_audio(void) +{ + if(sb_detect()) { + /* TODO use the sound blaster */ + return; + } + + printf("No supported audio device detected\n"); +} diff --git a/src/audio.h b/src/audio.h new file mode 100644 index 0000000..60b6bd5 --- /dev/null +++ b/src/audio.h @@ -0,0 +1,23 @@ +/* +pcboot - bootable PC demo/game kernel +Copyright (C) 2018 John Tsiombikas + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY, without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ +#ifndef AUDIO_H_ +#define AUDIO_H_ + +void init_audio(void); + +#endif /* AUDIO_H_ */ diff --git a/src/kmain.c b/src/kmain.c index 3c256a6..8e4eba4 100644 --- a/src/kmain.c +++ b/src/kmain.c @@ -26,6 +26,7 @@ along with this program. If not, see . #include "timer.h" #include "contty.h" #include "video.h" +#include "audio.h" #include "pci.h" #include "vbetest.h" @@ -48,6 +49,8 @@ void pcboot_main(void) /* initialize the timer */ init_timer(); + init_audio(); + enable_intr(); printf("PCBoot kernel initialized\n"); diff --git a/src/timer.c b/src/timer.c index 68a67a4..8578c94 100644 --- a/src/timer.c +++ b/src/timer.c @@ -55,8 +55,6 @@ along with this program. If not, see . #define CMD_MODE_BCD 1 -#define MSEC_TO_TICKS(ms) ((ms) * TICK_FREQ_HZ / 1000) - struct timer_event { int dt; /* remaining ticks delta from the previous event */ struct timer_event *next; diff --git a/src/timer.h b/src/timer.h index 86de220..b71e62f 100644 --- a/src/timer.h +++ b/src/timer.h @@ -18,7 +18,10 @@ along with this program. If not, see . #ifndef _TIMER_H_ #define _TIMER_H_ -unsigned long nticks; +#define MSEC_TO_TICKS(ms) ((ms) * TICK_FREQ_HZ / 1000) +#define TICKS_TO_MSEC(tk) ((tk) * 1000 / TICK_FREQ_HZ) + +volatile unsigned long nticks; void init_timer(void); -- 1.7.10.4