reorganized the soundblaster code a bit, adding support for DSP < 4 master
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 5 Feb 2019 17:08:29 +0000 (19:08 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 5 Feb 2019 17:08:29 +0000 (19:08 +0200)
Makefile.dj [deleted file]
src/au_sb.c

diff --git a/Makefile.dj b/Makefile.dj
deleted file mode 100644 (file)
index 549ba09..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-src = $(wildcard src/*.c)\r
-obj = $(src:.c=.o)\r
-dep = $(obj:.o=.d)\r
-\r
-ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)\r
-       hostsys = dos\r
-else\r
-       hostsys = unix\r
-       TOOLPREFIX = i586-pc-msdosdjgpp-\r
-endif\r
-bin = auplay.exe\r
-\r
-warn = -pedantic -Wall\r
-opt = -march=pentium -O0\r
-dbg = -g\r
-def = -DLITTLEENDIAN\r
-\r
-incpath = -Isrc\r
-\r
-AS = nasm\r
-CC = $(TOOLPREFIX)gcc\r
-ASFLAGS = -f coff\r
-CFLAGS = $(dbg) $(opt) $(def) $(incpath)\r
-LDFLAGS = -Wl,-Map=ld.map\r
-LD = wlink\r
-\r
-$(bin): $(obj)\r
-       $(CC) -o $@ $(obj) $(LDFLAGS)\r
-\r
--include $(dep)\r
-\r
-%.o: %.asm\r
-       $(AS) $(ASFLAGS) -o $@ $<\r
-\r
-%.d: %.c\r
-       @echo depfile $@\r
-       @$(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@\r
-\r
-.PHONY: clean\r
-.PHONY: cleandep\r
-\r
-ifeq ($(hostsys), dos)\r
-clean:\r
-       del src\*.o\r
-       del $(bin)\r
-\r
-cleandep:\r
-       del src\*.d\r
-else\r
-clean:\r
-       rm -f $(obj) $(bin)\r
-\r
-cleandep:\r
-       rm -f $(dep)\r
-endif\r
index 63fb49d..c8ca586 100644 (file)
@@ -27,6 +27,7 @@
 #define DSP_RATE                       0x40\r
 #define DSP4_OUT_RATE          0x41\r
 #define DSP4_IN_RATE           0x42\r
+#define DSP_BLOCKSZ                    0x48\r
 #define DSP_GET_VER                    0xe1\r
 \r
 /* start DMA playback/recording. combine with fifo/auto/input flags */\r
@@ -61,6 +62,8 @@
 #define MIX_SB16_MASTER_R      0x31\r
 #define MIX_SB16_VOICE_L       0x32\r
 #define MIX_SB16_VOICE_R       0x33\r
+\r
+#define MIX_SBPRO_STEREO       0x0e\r
 #define MIX_SB16_IRQ_SEL       0x80\r
 #define MIX_SB16_DMA_SEL       0x81\r
 #define MIX_SB16_INTSTAT       0x82\r
@@ -78,7 +81,6 @@
 \r
 static int reset_dsp(void);\r
 static void *sb_buffer(int *size);\r
-static void set_output_rate(int rate);\r
 static void start(int rate, int bits, int nchan);\r
 static void pause(void);\r
 static void cont(void);\r
@@ -87,9 +89,10 @@ static int isplaying(void);
 static void setvolume(int ctl, int vol);\r
 static int getvolume(int ctl);\r
 \r
+static void set_sbpro_stereo(void);\r
+static int start_dsp4(int rate, int bits, unsigned int mode, int num_samples);\r
+static int start_dsp(int rate, int nchan, int num_samples);\r
 static void INTERRUPT intr_handler();\r
-static void start_dsp4(int bits, unsigned int mode, int num_samples);\r
-static void start_dsp(int nchan, int num_samples);\r
 static void write_dsp(unsigned char val);\r
 static unsigned char read_dsp(void);\r
 static void write_mix(int reg, unsigned char val);\r
@@ -114,13 +117,12 @@ static const struct audrv sbdrv = {
 \r
 static int base_port;\r
 static int irq, dma_chan, dma16_chan, dsp_ver;\r
-static int dsp4;\r
 \r
 static void *buffer[2];\r
 static volatile int wrbuf;\r
 \r
 static volatile int playing;\r
-static int cur_bits, cur_mode, auto_init;\r
+static int cur_bits, auto_init, high_speed;\r
 \r
 static void (INTERRUPT *prev_intr_handler)();\r
 \r
@@ -135,7 +137,6 @@ int sb_detect(struct audrv *drv)
                if(sscanf(env, "A%x I%d D%d H%d", &base_port, &irq, &dma_chan, &dma16_chan) >= 3) {\r
                        if(reset_dsp() == 0) {\r
                                dsp_ver = get_dsp_version();\r
-                               dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
                                print_dsp_info();\r
                                *drv = sbdrv;\r
                                return 1;\r
@@ -149,9 +150,8 @@ int sb_detect(struct audrv *drv)
                base_port = 0x200 + ((i + 1) << 4);\r
                if(reset_dsp() == 0) {\r
                        dsp_ver = get_dsp_version();\r
-                       dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
 \r
-                       if(dsp4) {\r
+                       if(dsp_ver >= 0x400) {\r
                                if(dsp4_detect_irq() == -1) {\r
                                        printf("sb_detect: failed to configure IRQ\n");\r
                                        return 0;\r
@@ -198,24 +198,11 @@ static int reset_dsp(void)
        return -1;\r
 }\r
 \r
-static void set_output_rate(int rate)\r
-{\r
-       if(dsp4) {\r
-               write_dsp(DSP4_OUT_RATE);\r
-               write_dsp(rate >> 8);\r
-               write_dsp(rate & 0xff);\r
-       } else {\r
-               int tcon = 256 - 1000000 / rate;\r
-               write_dsp(DSP_RATE);\r
-               write_dsp(tcon);\r
-       }\r
-}\r
-\r
 static void start(int rate, int bits, int nchan)\r
 {\r
        uint16_t seg, pmsel;\r
        uint32_t addr, next64k;\r
-       int size, num_samples;\r
+       int size, mode, num_samples, dsp_num_samples;\r
 \r
        if(!buffer[1]) {\r
                /* allocate a buffer in low memory that doesn't cross 64k boundaries */\r
@@ -235,16 +222,7 @@ static void start(int rate, int bits, int nchan)
                wrbuf = 0;\r
        }\r
 \r
-       /* Auto-init playback mode:\r
-        * fill the whole buffer with data, program the DMA for BUFSIZE transfer,\r
-        * and program the DSP for BUFSIZE/2 transfer. We'll get an interrupt in the\r
-        * middle, while the DSP uses the upper half, and we'll refill the bottom half.\r
-        * Then continue ping-ponging the two halves of the buffer until we run out of\r
-        * data.\r
-        */\r
-       auto_init = 1;\r
 \r
-       /* TODO: if size <= BUFSIZE, do a single transfer instead */\r
        wrbuf = 0;\r
        if(!(size = audio_callback(buffer[wrbuf], BUFSIZE))) {\r
                return;\r
@@ -252,6 +230,21 @@ static void start(int rate, int bits, int nchan)
        addr = (uint32_t)buffer[wrbuf];\r
        num_samples = bits == 8 ? size : size / 2;\r
 \r
+       if(size < BUFSIZE) {\r
+               auto_init = 0;  /* single transfer mode */\r
+               dsp_num_samples = num_samples;\r
+       } else {\r
+               /* Auto-init playback mode:\r
+                * fill the whole buffer with data, program the DMA for BUFSIZE transfer,\r
+                * and program the DSP for BUFSIZE/2 transfer. We'll get an interrupt in the\r
+                * middle, while the DSP uses the upper half, and we'll refill the bottom half.\r
+                * Then continue ping-ponging the two halves of the buffer until we run out of\r
+                * data.\r
+                */\r
+               auto_init = 1;\r
+               dsp_num_samples = num_samples / 2;\r
+       }\r
+\r
        _disable();\r
        if(!prev_intr_handler) {\r
                prev_intr_handler = _dos_getvect(IRQ_TO_INTR(irq));\r
@@ -262,35 +255,23 @@ static void start(int rate, int bits, int nchan)
        unmask_irq(irq);\r
 \r
        cur_bits = bits;\r
-       cur_mode = bits == 8 ? 0 : DSP4_MODE_SIGNED;\r
-       if(nchan > 1) {\r
-               cur_mode |= DSP4_MODE_STEREO;\r
-       }\r
 \r
        write_dsp(DSP_ENABLE_OUTPUT);\r
-       dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | DMA_AUTO);\r
-       set_output_rate(rate);\r
-       start_dsp4(cur_bits, cur_mode, num_samples / 2);\r
-       playing = 1;\r
-}\r
-\r
-static void start_dsp4(int bits, unsigned int mode, int num_samples)\r
-{\r
-       unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16;\r
-       cmd |= DSP4_AUTO | DSP4_FIFO;\r
+       dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | auto_init ? DMA_AUTO : 0);\r
 \r
-       /* program the DSP to start the DMA transfer */\r
-       write_dsp(cmd);\r
-       write_dsp(mode);\r
-       num_samples--;\r
-       write_dsp(num_samples & 0xff);\r
-       write_dsp((num_samples >> 8) & 0xff);\r
-}\r
-\r
-static void start_dsp(int nchan, int num_samples)\r
-{\r
-       /* program the DSP to start the DMA transfer */\r
-       /* TODO */\r
+       if(dsp_ver >= 0x400) {\r
+               int mode = bits == 8 ? 0 : DSP4_MODE_SIGNED;\r
+               if(nchan > 1) {\r
+                       mode |= DSP4_MODE_STEREO;\r
+               }\r
+               start_dsp4(rate, cur_bits, mode, dsp_num_samples);\r
+       } else {\r
+               if(nchan > 1 && dsp_ver >= 0x300) {\r
+                       set_sbpro_stereo();\r
+               }\r
+               start_dsp(rate, cur_bits, dsp_num_samples);\r
+       }\r
+       playing = 1;\r
 }\r
 \r
 static void pause(void)\r
@@ -365,7 +346,7 @@ static int getvolume(int ctl)
        int left, right;\r
        unsigned char val;\r
 \r
-       if(VER_MAJOR(dsp_ver) >= 4) {\r
+       if(dsp_ver >= 0x400) {\r
                /* DSP 4.x - SB16 */\r
                int lreg, rreg;\r
                if(ctl == AUDIO_PCM) {\r
@@ -381,7 +362,7 @@ static int getvolume(int ctl)
                val = read_mix(rreg);\r
                right = (val & 0xf8) | (val >> 5);\r
 \r
-       } else if(VER_MAJOR(dsp_ver) >= 3) {\r
+       } else if(dsp_ver >= 0x300) {\r
                /* DSP 3.x - SBPro */\r
                val = read_mix(ctl == AUDIO_PCM ? MIX_SBPRO_VOICE : MIX_SBPRO_MASTER);\r
 \r
@@ -409,6 +390,55 @@ static int getvolume(int ctl)
        return (left + right) >> 1;\r
 }\r
 \r
+static void set_sbpro_stereo(void)\r
+{\r
+}\r
+\r
+static int start_dsp4(int rate, int bits, unsigned int mode, int num_samples)\r
+{\r
+       unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16;\r
+       if(auto_init) {\r
+               cmd |= DSP4_AUTO | DSP4_FIFO;\r
+       }\r
+\r
+       /* set output rate */\r
+       write_dsp(DSP4_OUT_RATE);\r
+       write_dsp(rate >> 8);\r
+       write_dsp(rate & 0xff);\r
+\r
+       /* program the DSP to start the DMA transfer */\r
+       write_dsp(cmd);\r
+       write_dsp(mode);\r
+       num_samples--;\r
+       write_dsp(num_samples & 0xff);\r
+       write_dsp((num_samples >> 8) & 0xff);\r
+\r
+       return 0;\r
+}\r
+\r
+static int start_dsp(int rate, int nchan, int num_samples)\r
+{\r
+       /* set time constant */\r
+       int tcon = 256 - 1000000 / rate;\r
+       write_dsp(DSP_RATE);\r
+       write_dsp(tcon);\r
+\r
+       if(nchan > 1) {\r
+               /* stereo */\r
+               if(dsp_ver < 0x300) return -1;  /* need a sb pro for stereo */\r
+\r
+               set_sbpro_stereo();\r
+               high_speed = rate >= 11025;\r
+       } else {\r
+               /* mono */\r
+               high_speed = rate >= 23000;\r
+       }\r
+\r
+       /* program the DSP to start the DMA transfer */\r
+       return -1;      /* TODO */\r
+}\r
+\r
+\r
 static void INTERRUPT intr_handler()\r
 {\r
        int size;\r