started the sound blaster audio driver
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Thu, 24 May 2018 04:29:09 +0000 (07:29 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Thu, 24 May 2018 04:29:09 +0000 (07:29 +0300)
Makefile
src/au_sb.c [new file with mode: 0644]
src/au_sb.h [new file with mode: 0644]
src/audio.c [new file with mode: 0644]
src/audio.h [new file with mode: 0644]
src/kmain.c
src/timer.c
src/timer.h

index 23c8eaf..07e856f 100644 (file)
--- 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 (file)
index 0000000..f3184ae
--- /dev/null
@@ -0,0 +1,164 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#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 (file)
index 0000000..9552bcd
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#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 (file)
index 0000000..c7142f1
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#include <stdio.h>
+#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 (file)
index 0000000..60b6bd5
--- /dev/null
@@ -0,0 +1,23 @@
+/*
+pcboot - bootable PC demo/game kernel
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>
+
+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 <https://www.gnu.org/licenses/>.
+*/
+#ifndef AUDIO_H_
+#define AUDIO_H_
+
+void init_audio(void);
+
+#endif /* AUDIO_H_ */
index 3c256a6..8e4eba4 100644 (file)
@@ -26,6 +26,7 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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");
index 68a67a4..8578c94 100644 (file)
@@ -55,8 +55,6 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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;
index 86de220..b71e62f 100644 (file)
@@ -18,7 +18,10 @@ along with this program.  If not, see <https://www.gnu.org/licenses/>.
 #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);