improved the soundblaster code, but still doesn't work on the real
authorJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 15 Jan 2019 18:46:41 +0000 (20:46 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Tue, 15 Jan 2019 18:46:41 +0000 (20:46 +0200)
hardware

13 files changed:
Makefile
Makefile.wat [new file with mode: 0644]
src/au_sb.c
src/au_sb.h
src/audio.c
src/audio.h
src/dma.c
src/dma.h
src/dpmi.c [new file with mode: 0644]
src/dpmi.h [new file with mode: 0644]
src/intr.h [new file with mode: 0644]
src/inttypes.h [new file with mode: 0644]
src/main.c

index 118d4f0..0b4be9e 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,56 +1,30 @@
-src = $(wildcard src/*.c)
-ssrc = $(wildcard src/*.s)
-asmsrc = $(wildcard src/*.asm)
-obj = $(src:.c=.o) $(ssrc:.s=.o) $(asmsrc:.asm=.o)
-dep = $(src:.c=.d)
-bin = sbtest.exe
-
-ifeq ($(findstring COMMAND.COM, $(SHELL)), COMMAND.COM)
-       hostsys = dos
-else
-       hostsys = unix
-       TOOLPREFIX = i586-pc-msdosdjgpp-
-endif
-
-inc = -Isrc
-opt = -O3 -ffast-math -fno-strict-aliasing
-dbg = -g
-warn = -pedantic -Wall -Wno-unused-function -Wno-unused-variable
-
-AS = $(TOOLPREFIX)as
-CC = $(TOOLPREFIX)gcc
-AR = $(TOOLPREFIX)ar
-CFLAGS = $(warn) -march=pentium $(dbg) $(opt) $(inc)
-LDFLAGS =
-
-$(bin): $(obj)
-       $(CC) -o $@ -Wl,-Map=ld.map $(obj) $(LDFLAGS)
-
-%.o: %.asm
-       nasm -f coff -o $@ $<
-
--include $(dep)
-
-%.o: %.c
-       $(CC) $(CFLAGS) -o $@ -c $<
-
-%.d: %.c
-       @echo "gen dep $< -> $@"; $(CPP) $(CFLAGS) $< -MM -MT $(@:.d=.o) >$@
-
-.PHONY: clean
-.PHONY: cleandep
-
-ifeq ($(hostsys), dos)
-clean:
-       del src\*.o
-       del $(bin)
-
-cleandep:
-       del src\*.d
-else
-clean:
-       rm -f $(obj) $(bin)
-
-cleandep:
-       rm -f $(dep)
-endif
+src = $(wildcard src/*.c)\r
+#obj = $(src:.c=.obj)\r
+obj = src\main.obj src\audio.obj src\au_sb.obj src\dma.obj\r
+bin = sbtest.exe\r
+\r
+opt = -5\r
+dbg = -d1\r
+\r
+incpath = -Isrc\r
+\r
+AS = nasm\r
+CC = wcc386\r
+ASFLAGS = -fobj\r
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath)\r
+LDFLAGS = option map\r
+LD = wlink\r
+RM = del\r
+\r
+$(bin): $(obj)\r
+       $(LD) debug all name $@ system dos4g file { $(obj) } $(LDFLAGS)\r
+\r
+%.obj: %.c\r
+       $(CC) -fo=$@ $(CFLAGS) $<\r
+\r
+%.obj: %.asm\r
+       $(AS) $(ASFLAGS) -o $@ $<\r
+\r
+clean:\r
+       $(RM) src\*.obj\r
+       $(RM) $(bin)\r
diff --git a/Makefile.wat b/Makefile.wat
new file mode 100644 (file)
index 0000000..bc174e2
--- /dev/null
@@ -0,0 +1,36 @@
+\r
+obj = main.obj audio.obj au_sb.obj dma.obj\r
+bin = sbtest.exe\r
+opt = -5\r
+dbg = -d1\r
+\r
+!ifdef __UNIX__\r
+RM = rm -f\r
+!else\r
+RM = del\r
+!endif\r
+\r
+incpath = -Isrc\r
+\r
+AS = nasm\r
+CC = wcc386\r
+ASFLAGS = -fobj\r
+CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath)\r
+LDFLAGS = option map\r
+LD = wlink\r
+\r
+$(bin): $(obj)\r
+       $(LD) debug all name $@ system dos4g file { $(obj) } $(LDFLAGS)\r
+\r
+.c: src\r
+.asm: src\r
+\r
+.c.obj: .autodepend\r
+       $(CC) -fo=$@ $(CFLAGS) $[*\r
+\r
+.asm.obj:\r
+       $(AS) $(ASFLAGS) -o $@ $[*.asm\r
+\r
+clean: .symbolic\r
+       $(RM) *.obj\r
+       $(RM) $(bin)\r
index 2046f91..c49b2cf 100644 (file)
-#include <stdio.h>
-#include <dos.h>
-#include <pc.h>
-#include <go32.h>
-#include <dpmi.h>
-#include <sys/nearptr.h>
-#include "audio.h"
-#include "au_sb.h"
-#include "dma.h"
-
-#define IRQ_TO_INTR(x) ((x) + 8)
-
-/* PIC command and data ports */
-#define PIC1_CMD       0x20
-#define PIC1_DATA      0x21
-#define PIC2_CMD       0xa0
-#define PIC2_DATA      0xa1
-/* PIC operation command word 2 bits */
-#define OCW2_EOI       (1 << 5)
-
-#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_RATE                       0x40
-#define CMD_SB16_OUT_RATE      0x41
-#define CMD_SB16_IN_RATE       0x42
-#define CMD_GET_VER                    0xe1
-
-/* start DMA playback/recording. combine with fifo/auto/input flags */
-#define CMD_START_DMA8         0xc0
-#define CMD_START_DMA16                0xb0
-#define CMD_FIFO                       0x02
-#define CMD_AUTO                       0x04
-#define CMD_INPUT                      0x08
-
-/* immediately pause/continue */
-#define CMD_PAUSE_DMA8         0xd0
-#define CMD_ENABLE_OUTPUT      0xd1
-#define CMD_DISABLE_OUTPUT     0xd3
-#define CMD_CONT_DMA8          0xd4
-#define CMD_PAUSE_DMA16                0xd5
-#define CMD_CONT_DMA16         0xd6
-
-/* end the playback at the end of the current buffer */
-#define CMD_END_DMA16          0xd9
-#define CMD_END_DMA8           0xda
-
-/* transfer mode commands */
-#define CMD_MODE_SIGNED                0x10
-#define CMD_MODE_STEREO                0x20
-
-/* mixer registers */
-#define MIX_IRQ_SEL                    0x80
-#define MIX_DMA_SEL                    0x81
-
-#define VER_MAJOR(x)   ((x) >> 8)
-#define VER_MINOR(x)   ((x) & 0xff)
-
-/* delay for about 1us */
-#define iodelay()      outportb(0x80, 0)
-
-static void intr_handler();
-static void start_dma_transfer(uint32_t addr, int size);
-static void write_dsp(unsigned char val);
-static unsigned char read_dsp(void);
-static void write_mix(unsigned char val, int reg);
-static unsigned char read_mix(int reg);
-static int get_dsp_version(void);
-static int sb16_detect_irq(void);
-static int sb16_detect_dma(void);
-static const char *sbname(int ver);
-
-extern unsigned char low_mem_buffer[];
-
-static int base_port;
-static int irq, dma_chan, dma16_chan;
-static int sb16;
-static void *buffer;
-static int xfer_mode;
-
-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();
-                       sb16 = VER_MAJOR(ver) >= 4;
-
-                       if(sb16) {
-                               if(sb16_detect_irq() == -1) {
-                                       printf("sb_detect: failed to configure IRQ\n");
-                                       return 0;
-                               }
-                               if(sb16_detect_dma() == -1) {
-                                       printf("sb_detect: failed to configure DMA\n");
-                                       return 0;
-                               }
-
-                               printf("sb_detect: found %s (DSP v%d.%02d) at port %xh, irq %d, dma %d/%d\n",
-                                               sbname(ver), VER_MAJOR(ver), VER_MINOR(ver),
-                                               base_port, irq, dma_chan, dma16_chan);
-
-                       } else {
-                               /* XXX for old sound blasters, hard-code to IRQ 5 DMA 1 for now */
-                               irq = 5;
-                               dma_chan = 1;
-                               dma16_chan = -1;
-
-                               printf("sb_detect: found %s (DSP v%d.%02d) at port %xh\n", sbname(ver),
-                                               VER_MAJOR(ver), VER_MINOR(ver), base_port);
-                               printf("sb_detect: old sound blaster dsp. assuming: irq 5, dma 1\n");
-                       }
-
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-int sb_reset_dsp(void)
-{
-       int i;
-
-       outportb(REG_RESET, 1);
-       for(i=0; i<3; i++) iodelay();
-       outportb(REG_RESET, 0);
-
-       for(i=0; i<128; i++) {
-               if(inportb(REG_RSTAT) & RSTAT_RDY) {
-                       if(inportb(REG_RDATA) == 0xaa) {
-                               return 0;
-                       }
-               }
-       }
-
-       return -1;
-}
-
-void sb_set_output_rate(int rate)
-{
-       if(sb16) {
-               write_dsp(CMD_SB16_OUT_RATE);
-               write_dsp(rate >> 8);
-               write_dsp(rate & 0xff);
-       } else {
-               int tcon = 256 - 1000000 / rate;
-               write_dsp(CMD_RATE);
-               write_dsp(tcon);
-       }
-}
-
-void *sb_buffer(int *size)
-{
-       *size = 65536;
-       return buffer;
-}
-
-void sb_start(int rate, int nchan)
-{
-       int seg, pmsel;
-       uint32_t addr;
-       int size;
-       _go32_dpmi_seginfo intr;
-
-       if(!buffer) {
-               __djgpp_nearptr_enable();
-
-               /* allocate a 64k-aligned 64k buffer in low memory */
-               if((seg = __dpmi_allocate_dos_memory(65536 * 2 / 16, &pmsel)) <= 0) {
-                       fprintf(stderr, "sb_start: failed to allocate DMA buffer\n");
-                       return;
-               }
-
-               printf("allocated seg: %d, addr: %lx\n", seg, (unsigned long)seg << 4);
-
-               addr = ((uint32_t)(seg << 4) + 0xffff) & 0xffff0000;
-               printf("aligned: %lx\n", (unsigned long)addr);
-               buffer = (void*)(addr - __djgpp_base_address);
-       } else {
-               addr = (uint32_t)buffer;
-       }
-
-       xfer_mode = CMD_MODE_SIGNED;
-       if(nchan > 1) {
-               xfer_mode |= CMD_MODE_STEREO;
-       }
-
-       if(!(size = audio_callback(buffer, 65536))) {
-               return;
-       }
-
-       intr.pm_offset = (intptr_t)intr_handler;
-       intr.pm_selector = _go32_my_cs();
-       _disable();
-       _go32_dpmi_set_protected_mode_interrupt_vector(IRQ_TO_INTR(irq), &intr);
-       _enable();
-
-       sb_set_output_rate(rate);
-       start_dma_transfer(addr, size);
-       write_dsp(CMD_ENABLE_OUTPUT);
-}
-
-void sb_pause(void)
-{
-       write_dsp(CMD_PAUSE_DMA8);
-}
-
-void sb_continue(void)
-{
-       write_dsp(CMD_CONT_DMA8);
-}
-
-void sb_stop(void)
-{
-       write_dsp(CMD_END_DMA8);
-       write_dsp(CMD_DISABLE_OUTPUT);
-}
-
-void sb_volume(int vol)
-{
-       /* TODO */
-}
-
-static void intr_handler()
-{
-       int size;
-
-       /* ask for more data */
-       if(!(size = audio_callback(buffer, 65536))) {
-               sb_stop();
-               return;
-       }
-       start_dma_transfer((uint32_t)buffer, size);
-
-       /* acknowledge the interrupt */
-       inportb(REG_INTACK);
-
-       if(irq > 7) {
-               outportb(PIC2_CMD, OCW2_EOI);
-       }
-       outportb(PIC1_CMD, OCW2_EOI);
-}
-
-static void start_dma_transfer(uint32_t addr, int size)
-{
-       /* set up the next DMA transfer */
-       dma_out(dma_chan, addr, size, DMA_SINGLE);
-
-       /* program the DSP to accept the DMA transfer */
-       write_dsp(CMD_START_DMA8 | CMD_FIFO);
-       write_dsp(xfer_mode);
-       size--;
-       write_dsp(size & 0xff);
-       write_dsp((size >> 8) & 0xff);
-}
-
-static void write_dsp(unsigned char val)
-{
-       while(inportb(REG_WSTAT) & WSTAT_BUSY);
-       outportb(REG_WDATA, val);
-}
-
-static unsigned char read_dsp(void)
-{
-       while((inportb(REG_RSTAT) & RSTAT_RDY) == 0);
-       return inportb(REG_RDATA);
-}
-
-static void write_mix(unsigned char val, int reg)
-{
-       outportb(REG_MIXPORT, reg);
-       outportb(REG_MIXDATA, val);
-}
-
-static unsigned char read_mix(int reg)
-{
-       outportb(REG_MIXPORT, reg);
-       return inportb(REG_MIXDATA);
-}
-
-static int get_dsp_version(void)
-{
-       int major, minor;
-
-       write_dsp(CMD_GET_VER);
-       major = read_dsp();
-       minor = read_dsp();
-
-       return (major << 8) | minor;
-}
-
-static int sb16_detect_irq(void)
-{
-       int i, irqsel;
-       static int irqtab[] = {2, 5, 7, 10};
-
-       irq = 0;
-       irqsel = read_mix(MIX_IRQ_SEL);
-       for(i=0; i<4; i++) {
-               if(irqsel & (1 << i)) {
-                       irq = irqtab[i];
-                       break;
-               }
-       }
-       if(!irq) {
-               /* try to force IRQ 5 */
-               write_mix(2, MIX_IRQ_SEL);      /* bit1 selects irq 5 */
-
-               /* re-read to verify */
-               irqsel = read_mix(MIX_IRQ_SEL);
-               if(irqsel != 2) {
-                       return -1;
-               }
-               irq = 5;
-       }
-
-       return irq;
-}
-
-static int sb16_detect_dma(void)
-{
-       int i, dmasel, tmp;
-       static int dmatab[] = {0, 1, -1, 3, -1, 5, 6, 7};
-
-       dma_chan = -1;
-       dma16_chan = -1;
-       dmasel = read_mix(MIX_DMA_SEL);
-       for(i=0; i<4; i++) {
-               if(dmasel & (1 << i)) {
-                       dma_chan = dmatab[i];
-                       break;
-               }
-       }
-       for(i=5; i<8; i++) {
-               if(dmasel & (1 << i)) {
-                       dma16_chan = dmatab[i];
-                       break;
-               }
-       }
-       if(dma_chan == -1) {
-               /* try to force DMA 1 */
-               dmasel |= 2;
-       }
-       if(dma16_chan == -1) {
-               /* try to force 16bit DMA 5 */
-               dmasel |= 0x20;
-       }
-
-       if(dma_chan == -1 || dma16_chan == -1) {
-               write_mix(dmasel, MIX_DMA_SEL);
-
-               /* re-read to verify */
-               tmp = read_mix(MIX_DMA_SEL);
-               if(tmp != dmasel) {
-                       return -1;
-               }
-               dma_chan = 1;
-               dma16_chan = 5;
-       }
-
-       return dma_chan;
-}
-
-#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";
-}
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <assert.h>\r
+#include <dos.h>\r
+#include <conio.h>\r
+#include "audio.h"\r
+#include "au_sb.h"\r
+#include "dpmi.h"\r
+#include "dma.h"\r
+#include "intr.h"\r
+\r
+#define REG_MIXPORT            (base_port + 0x4)\r
+#define REG_MIXDATA            (base_port + 0x5)\r
+#define REG_RESET              (base_port + 0x6)\r
+#define REG_RDATA              (base_port + 0xa)\r
+#define REG_WDATA              (base_port + 0xc)\r
+#define REG_WSTAT              (base_port + 0xc)\r
+#define REG_RSTAT              (base_port + 0xe)\r
+#define REG_INTACK             (base_port + 0xe)\r
+#define REG_INT16ACK   (base_port + 0xf)\r
+\r
+#define WSTAT_BUSY             0x80\r
+#define RSTAT_RDY              0x80\r
+\r
+#define DSP_RATE                       0x40\r
+#define DSP4_OUT_RATE          0x41\r
+#define DSP4_IN_RATE           0x42\r
+#define DSP_GET_VER                    0xe1\r
+\r
+/* start DMA playback/recording. combine with fifo/auto/input flags */\r
+#define DSP4_START_DMA8                0xc0\r
+#define DSP4_START_DMA16       0xb0\r
+#define DSP4_FIFO                      0x02\r
+#define DSP4_AUTO                      0x04\r
+#define DSP4_INPUT                     0x08\r
+\r
+/* transfer mode commands */\r
+#define DSP4_MODE_SIGNED       0x10\r
+#define DSP4_MODE_STEREO       0x20\r
+\r
+/* immediately pause/continue */\r
+#define DSP_PAUSE_DMA8         0xd0\r
+#define DSP_ENABLE_OUTPUT      0xd1\r
+#define DSP_DISABLE_OUTPUT     0xd3\r
+#define DSP_CONT_DMA8          0xd4\r
+#define DSP_PAUSE_DMA16                0xd5\r
+#define DSP_CONT_DMA16         0xd6\r
+\r
+/* end the playback at the end of the current buffer */\r
+#define DSP_END_DMA16          0xd9\r
+#define DSP_END_DMA8           0xda\r
+\r
+/* mixer registers */\r
+#define MIX_MASTER                     0x02\r
+#define MIX_VOICE                      0x0a\r
+#define MIX_SBPRO_VOICE                0x04\r
+#define MIX_SBPRO_MASTER       0x22\r
+#define MIX_SB16_MASTER_L      0x30\r
+#define MIX_SB16_MASTER_R      0x31\r
+#define MIX_SB16_VOICE_L       0x32\r
+#define MIX_SB16_VOICE_R       0x33\r
+#define MIX_SB16_IRQ_SEL       0x80\r
+#define MIX_SB16_DMA_SEL       0x81\r
+\r
+#define VER_MAJOR(x)   ((x) >> 8)\r
+#define VER_MINOR(x)   ((x) & 0xff)\r
+\r
+/* delay for about 1us */\r
+#define iodelay()      outp(0x80, 0)\r
+\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(unsigned char val, int reg);\r
+static unsigned char read_mix(int reg);\r
+static int get_dsp_version(void);\r
+static int dsp4_detect_irq(void);\r
+static int dsp4_detect_dma(void);\r
+static void print_dsp_info(void);\r
+static const char *sbname(int ver);\r
+\r
+static int base_port;\r
+static int irq, dma_chan, dma16_chan, dsp_ver;\r
+static int dsp4;\r
+static void *buffer;\r
+static int xfer_mode;\r
+\r
+static int isplaying;\r
+static int cur_bits, cur_mode;\r
+\r
+static void (INTERRUPT *prev_intr_handler)();\r
+\r
+int sb_detect(void)\r
+{\r
+       int i;\r
+       char *env;\r
+\r
+       if((env = getenv("BLASTER"))) {\r
+               dma16_chan = -1;\r
+               if(sscanf(env, "A%x I%d D%d H%d", &base_port, &irq, &dma_chan, &dma16_chan) >= 3) {\r
+                       if(sb_reset_dsp() == 0) {\r
+                               dsp_ver = get_dsp_version();\r
+                               dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
+                               print_dsp_info();\r
+                               return 1;\r
+                       }\r
+               } else {\r
+                       printf("sb_detect: malformed BLASTER environment variable. Fallback to probing.\n");\r
+               }\r
+       }\r
+\r
+       for(i=0; i<6; i++) {\r
+               base_port = 0x200 + ((i + 1) << 4);\r
+               if(sb_reset_dsp() == 0) {\r
+                       dsp_ver = get_dsp_version();\r
+                       dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
+\r
+                       if(dsp4) {\r
+                               if(dsp4_detect_irq() == -1) {\r
+                                       printf("sb_detect: failed to configure IRQ\n");\r
+                                       return 0;\r
+                               }\r
+                               if(dsp4_detect_dma() == -1) {\r
+                                       printf("sb_detect: failed to configure DMA\n");\r
+                                       return 0;\r
+                               }\r
+\r
+                       } else {\r
+                               /* XXX for old sound blasters, hard-code to IRQ 5 DMA 1 for now */\r
+                               irq = 5;\r
+                               dma_chan = 1;\r
+                               dma16_chan = -1;\r
+\r
+                               printf("sb_detect: old sound blaster dsp. assuming: irq 5, dma 1\n");\r
+                       }\r
+                       print_dsp_info();\r
+\r
+                       return 1;\r
+               }\r
+       }\r
+\r
+       return 0;\r
+}\r
+\r
+int sb_reset_dsp(void)\r
+{\r
+       int i;\r
+\r
+       outp(REG_RESET, 1);\r
+       for(i=0; i<3; i++) iodelay();\r
+       outp(REG_RESET, 0);\r
+\r
+       for(i=0; i<128; i++) {\r
+               if(inp(REG_RSTAT) & RSTAT_RDY) {\r
+                       if(inp(REG_RDATA) == 0xaa) {\r
+                               return 0;\r
+                       }\r
+               }\r
+       }\r
+\r
+       return -1;\r
+}\r
+\r
+void sb_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
+void *sb_buffer(int *size)\r
+{\r
+       *size = 65536;\r
+       return buffer;\r
+}\r
+\r
+void sb_start(int rate, int nchan)\r
+{\r
+       uint16_t seg, pmsel;\r
+       uint32_t addr;\r
+       int size;\r
+\r
+       if(!buffer) {\r
+               /* allocate a 64k-aligned 64k buffer in low memory */\r
+               if(!(seg = dpmi_alloc(65536 * 2 / 16, &pmsel))) {\r
+                       fprintf(stderr, "sb_start: failed to allocate DMA buffer\n");\r
+                       return;\r
+               }\r
+\r
+               printf("DBG allocated seg: %x, addr: %lx\n", (unsigned int)seg,\r
+                               (unsigned long)seg << 4);\r
+\r
+               addr = ((uint32_t)(seg << 4) + 0xffff) & 0xffff0000;\r
+               printf("DBG aligned: %lx\n", (unsigned long)addr);\r
+               buffer = (void*)addr;\r
+       } else {\r
+               addr = (uint32_t)buffer;\r
+       }\r
+\r
+       if(!(size = audio_callback(buffer, 65536))) {\r
+               return;\r
+       }\r
+\r
+       _disable();\r
+       if(!prev_intr_handler) {\r
+               prev_intr_handler = _dos_getvect(IRQ_TO_INTR(irq));\r
+       }\r
+       _dos_setvect(IRQ_TO_INTR(irq), intr_handler);\r
+       _enable();\r
+\r
+       unmask_irq(irq);\r
+\r
+       cur_bits = 8;\r
+       cur_mode = 0;\r
+       if(nchan > 1) {\r
+               cur_mode |= DSP4_MODE_STEREO;\r
+       }\r
+\r
+       write_dsp(DSP_ENABLE_OUTPUT);\r
+       dma_out(dma_chan, addr, size, DMA_SINGLE);\r
+       sb_set_output_rate(rate);\r
+       start_dsp4(cur_bits, cur_mode, size);\r
+       isplaying = 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
+       assert(bits == 8 || bits == 16);\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
+}\r
+\r
+void sb_pause(void)\r
+{\r
+       write_dsp(cur_bits == 8 ? DSP_PAUSE_DMA8 : DSP_PAUSE_DMA16);\r
+}\r
+\r
+void sb_continue(void)\r
+{\r
+       write_dsp(cur_bits == 8 ? DSP_CONT_DMA8 : DSP_CONT_DMA16);\r
+}\r
+\r
+void sb_stop(void)\r
+{\r
+       write_dsp(DSP_DISABLE_OUTPUT);\r
+\r
+       mask_irq(irq);\r
+       /* TODO: don't _enable, restore state */\r
+       _disable();\r
+       _dos_setvect(IRQ_TO_INTR(irq), prev_intr_handler);\r
+       _enable();\r
+\r
+       /* no need to stop anything if we're in single-cycle mode */\r
+       if(cur_mode & DSP4_AUTO) {\r
+               write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16);\r
+       }\r
+       isplaying = 0;\r
+}\r
+\r
+int sb_isplaying(void)\r
+{\r
+       return isplaying;\r
+}\r
+\r
+void sb_volume(int vol)\r
+{\r
+       /* TODO */\r
+}\r
+\r
+static void INTERRUPT intr_handler()\r
+{\r
+       int size;\r
+\r
+       /* ask for more data */\r
+       if(!(size = audio_callback(buffer, 65536))) {\r
+               sb_stop();\r
+       } else {\r
+               dma_out(dma_chan, (uint32_t)buffer, size, DMA_SINGLE);\r
+               start_dsp4(cur_bits, cur_mode, size);\r
+       }\r
+\r
+       /* acknowledge the interrupt */\r
+       inp(REG_INTACK);\r
+\r
+       if(irq > 7) {\r
+               outp(PIC2_CMD, OCW2_EOI);\r
+       }\r
+       outp(PIC1_CMD, OCW2_EOI);\r
+}\r
+\r
+static void write_dsp(unsigned char val)\r
+{\r
+       while(inp(REG_WSTAT) & WSTAT_BUSY);\r
+       outp(REG_WDATA, val);\r
+}\r
+\r
+static unsigned char read_dsp(void)\r
+{\r
+       while((inp(REG_RSTAT) & RSTAT_RDY) == 0);\r
+       return inp(REG_RDATA);\r
+}\r
+\r
+static void write_mix(unsigned char val, int reg)\r
+{\r
+       outp(REG_MIXPORT, reg);\r
+       outp(REG_MIXDATA, val);\r
+}\r
+\r
+static unsigned char read_mix(int reg)\r
+{\r
+       outp(REG_MIXPORT, reg);\r
+       return inp(REG_MIXDATA);\r
+}\r
+\r
+static int get_dsp_version(void)\r
+{\r
+       int major, minor;\r
+\r
+       write_dsp(DSP_GET_VER);\r
+       major = read_dsp();\r
+       minor = read_dsp();\r
+\r
+       return (major << 8) | minor;\r
+}\r
+\r
+static int dsp4_detect_irq(void)\r
+{\r
+       int i, irqsel;\r
+       static int irqtab[] = {2, 5, 7, 10};\r
+\r
+       irq = 0;\r
+       irqsel = read_mix(MIX_SB16_IRQ_SEL);\r
+       for(i=0; i<4; i++) {\r
+               if(irqsel & (1 << i)) {\r
+                       irq = irqtab[i];\r
+                       break;\r
+               }\r
+       }\r
+       if(!irq) {\r
+               /* try to force IRQ 5 */\r
+               write_mix(2, MIX_SB16_IRQ_SEL); /* bit1 selects irq 5 */\r
+\r
+               /* re-read to verify */\r
+               irqsel = read_mix(MIX_SB16_IRQ_SEL);\r
+               if(irqsel != 2) {\r
+                       return -1;\r
+               }\r
+               irq = 5;\r
+       }\r
+\r
+       return irq;\r
+}\r
+\r
+static int dsp4_detect_dma(void)\r
+{\r
+       int i, dmasel, tmp;\r
+       static int dmatab[] = {0, 1, -1, 3, -1, 5, 6, 7};\r
+\r
+       dma_chan = -1;\r
+       dma16_chan = -1;\r
+       dmasel = read_mix(MIX_SB16_DMA_SEL);\r
+       for(i=0; i<4; i++) {\r
+               if(dmasel & (1 << i)) {\r
+                       dma_chan = dmatab[i];\r
+                       break;\r
+               }\r
+       }\r
+       for(i=5; i<8; i++) {\r
+               if(dmasel & (1 << i)) {\r
+                       dma16_chan = dmatab[i];\r
+                       break;\r
+               }\r
+       }\r
+       if(dma_chan == -1) {\r
+               /* try to force DMA 1 */\r
+               dmasel |= 2;\r
+       }\r
+       if(dma16_chan == -1) {\r
+               /* try to force 16bit DMA 5 */\r
+               dmasel |= 0x20;\r
+       }\r
+\r
+       if(dma_chan == -1 || dma16_chan == -1) {\r
+               write_mix(dmasel, MIX_SB16_DMA_SEL);\r
+\r
+               /* re-read to verify */\r
+               tmp = read_mix(MIX_SB16_DMA_SEL);\r
+               if(tmp != dmasel) {\r
+                       return -1;\r
+               }\r
+               dma_chan = 1;\r
+               dma16_chan = 5;\r
+       }\r
+\r
+       return dma_chan;\r
+}\r
+\r
+static void print_dsp_info(void)\r
+{\r
+       int master[2], voice[2];\r
+       int val;\r
+\r
+       printf("sb_detect: %s (DSP v%d.%02d) port %xh, irq %d", sbname(dsp_ver),\r
+                       VER_MAJOR(dsp_ver), VER_MINOR(dsp_ver), base_port, irq);\r
+       if(VER_MAJOR(dsp_ver) >= 4) {\r
+               printf(" dma %d/%d\n", dma_chan, dma16_chan);\r
+       } else {\r
+               printf(" dma %d\n", dma_chan);\r
+       }\r
+\r
+       if(VER_MAJOR(dsp_ver) >= 4) {\r
+               master[0] = 100 * (int)(read_mix(MIX_SB16_MASTER_L) >> 3) / 31;\r
+               master[1] = 100 * (int)(read_mix(MIX_SB16_MASTER_R) >> 3) / 31;\r
+               voice[0] = 100 * (int)(read_mix(MIX_SB16_VOICE_L) >> 3) / 31;\r
+               voice[1] = 100 * (int)(read_mix(MIX_SB16_VOICE_R) >> 3) / 31;\r
+       } else if(VER_MAJOR(dsp_ver) >= 3) {\r
+               val = read_mix(MIX_SBPRO_MASTER);\r
+               master[0] = 100 * (val >> 5) / 7;\r
+               master[1] = 100 * ((val >> 1) & 7) / 7;\r
+               val = read_mix(MIX_SBPRO_VOICE);\r
+               voice[0] = 100 * (val >> 5) / 7;\r
+               voice[1] = 100 * ((val >> 1) & 7) / 7;\r
+       } else {\r
+               val = read_mix(MIX_MASTER);\r
+               master[0] = master[1] = 100 * ((val >> 1) & 7) / 7;\r
+               val = read_mix(MIX_VOICE);\r
+               voice[0] = voice[1] = 100 * ((val >> 1) & 3) / 3;\r
+       }\r
+       printf("  mixer: master(%d|%d) voice(%d|%d)\n", master[0], master[1],\r
+                       voice[0], voice[1]);\r
+}\r
+\r
+#define V(maj, min)    (((maj) << 8) | (min))\r
+\r
+static const char *sbname(int ver)\r
+{\r
+       int major = VER_MAJOR(ver);\r
+       int minor = VER_MINOR(ver);\r
+\r
+       switch(major) {\r
+       case 1:\r
+               if(minor == 5) {\r
+                       return "Sound Blaster 1.5";\r
+               }\r
+               return "Sound Blaster 1.0";\r
+\r
+       case 2:\r
+               if(minor == 1 || minor == 2) {\r
+                       return "Sound Blaster 2.0";\r
+               }\r
+               break;\r
+\r
+       case 3:\r
+               switch(minor) {\r
+               case 0:\r
+                       return "Sound Blaster Pro";\r
+               case 1:\r
+               case 2:\r
+                       return "Sound Blaster Pro 2";\r
+               case 5:\r
+                       return "Gallant SC-6000";\r
+               default:\r
+                       break;\r
+               }\r
+               break;\r
+\r
+       case 4:\r
+               switch(minor) {\r
+               case 4:\r
+               case 5:\r
+                       return "Sound Blaster 16";\r
+               case 11:\r
+                       return "Sound Blaster 16 SCSI-2";\r
+               case 12:\r
+                       return "Sound Blaster AWE 32";\r
+               case 13:\r
+                       return "Sound Blaster ViBRA16C";\r
+               case 16:\r
+                       return "Sound Blaster AWE 64";\r
+               default:\r
+                       break;\r
+               }\r
+               break;\r
+       }\r
+\r
+       return "Unknown Sound Blaster";\r
+}\r
index d437ff7..0981ba6 100644 (file)
@@ -1,42 +1,26 @@
-/*
-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);
-
-void *sb_buffer(int *size);
-
-void sb_set_output_rate(int rate);
-
-void sb_start(int rate, int nchan);
-void sb_pause(void);
-void sb_continue(void);
-void sb_stop(void);
-
-void sb_volume(int vol);
-
-#endif /* AU_SB_H_ */
+#ifndef AU_SB_H_\r
+#define AU_SB_H_\r
+\r
+/* returns true (nonzero) if a sound blaster DSP is detected in the ISA bus\r
+ * and sets the internal base_port so that subsequent calls can find it\r
+ */\r
+int sb_detect(void);\r
+\r
+/* returns 0 for success, non-zero if the DSP isn't responding at the currently\r
+ * selected base port\r
+ */\r
+int sb_reset_dsp(void);\r
+\r
+void *sb_buffer(int *size);\r
+\r
+void sb_set_output_rate(int rate);\r
+\r
+void sb_start(int rate, int nchan);\r
+void sb_pause(void);\r
+void sb_continue(void);\r
+void sb_stop(void);\r
+int sb_isplaying(void);\r
+\r
+void sb_volume(int vol);\r
+\r
+#endif /* AU_SB_H_ */\r
index d783559..adb8e3e 100644 (file)
@@ -1,71 +1,78 @@
-#include <stdio.h>
-#include "audio.h"
-#include "au_sb.h"
-
-struct audrv {
-       void *(*get_buffer)(int *size);
-       void (*start)(int rate, int nchan);
-       void (*pause)(void);
-       void (*cont)(void);
-       void (*stop)(void);
-       void (*volume)(int vol);
-};
-
-static struct audrv drv;
-
-static audio_callback_func cbfunc;
-static void *cbcls;
-
-void audio_init(void)
-{
-       if(sb_detect()) {
-               drv.get_buffer = sb_buffer;
-               drv.start = sb_start;
-               drv.pause = sb_pause;
-               drv.cont = sb_continue;
-               drv.stop = sb_stop;
-               drv.volume = sb_volume;
-               return;
-       }
-
-       printf("No supported audio device detected\n");
-}
-
-void audio_set_callback(audio_callback_func func, void *cls)
-{
-       cbfunc = func;
-       cbcls = cls;
-}
-
-int audio_callback(void *buf, int sz)
-{
-       if(!cbfunc) {
-               return 0;
-       }
-       return cbfunc(buf, sz, cbcls);
-}
-
-void audio_play(int rate, int nchan)
-{
-       drv.start(rate, nchan);
-}
-
-void audio_pause(void)
-{
-       drv.pause();
-}
-
-void audio_resume(void)
-{
-       drv.cont();
-}
-
-void audio_stop(void)
-{
-       drv.stop();
-}
-
-void audio_volume(int vol)
-{
-       drv.volume(vol);
-}
+#include <stdio.h>\r
+#include "audio.h"\r
+#include "au_sb.h"\r
+\r
+struct audrv {\r
+       void *(*get_buffer)(int *size);\r
+       void (*start)(int rate, int nchan);\r
+       void (*pause)(void);\r
+       void (*cont)(void);\r
+       void (*stop)(void);\r
+       void (*volume)(int vol);\r
+       int (*isplaying)(void);\r
+};\r
+\r
+static struct audrv drv;\r
+\r
+static audio_callback_func cbfunc;\r
+static void *cbcls;\r
+\r
+void audio_init(void)\r
+{\r
+       if(sb_detect()) {\r
+               drv.get_buffer = sb_buffer;\r
+               drv.start = sb_start;\r
+               drv.pause = sb_pause;\r
+               drv.cont = sb_continue;\r
+               drv.stop = sb_stop;\r
+               drv.volume = sb_volume;\r
+               drv.isplaying = sb_isplaying;\r
+               return;\r
+       }\r
+\r
+       printf("No supported audio device detected\n");\r
+}\r
+\r
+void audio_set_callback(audio_callback_func func, void *cls)\r
+{\r
+       cbfunc = func;\r
+       cbcls = cls;\r
+}\r
+\r
+int audio_callback(void *buf, int sz)\r
+{\r
+       if(!cbfunc) {\r
+               return 0;\r
+       }\r
+       return cbfunc(buf, sz, cbcls);\r
+}\r
+\r
+void audio_play(int rate, int nchan)\r
+{\r
+       drv.start(rate, nchan);\r
+}\r
+\r
+void audio_pause(void)\r
+{\r
+       drv.pause();\r
+}\r
+\r
+void audio_resume(void)\r
+{\r
+       drv.cont();\r
+}\r
+\r
+void audio_stop(void)\r
+{\r
+       drv.stop();\r
+}\r
+\r
+void audio_volume(int vol)\r
+{\r
+       drv.volume(vol);\r
+}\r
+\r
+int audio_isplaying(void)\r
+{\r
+       return drv.isplaying();\r
+}\r
index 9b528c2..1fde706 100644 (file)
@@ -1,35 +1,36 @@
-/*
-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_
-
-typedef int (*audio_callback_func)(void *buffer, int size, void *cls);
-
-void audio_init(void);
-
-void audio_set_callback(audio_callback_func func, void *cls);
-int audio_callback(void *buf, int sz);
-
-void audio_play(int rate, int nchan);
-void audio_pause(void);
-void audio_resume(void);
-void audio_stop(void);
-
-void audio_volume(int vol);
-
-#endif /* AUDIO_H_ */
+/*\r
+pcboot - bootable PC demo/game kernel\r
+Copyright (C) 2018  John Tsiombikas <nuclear@member.fsf.org>\r
+\r
+This program is free software: you can redistribute it and/or modify\r
+it under the terms of the GNU General Public License as published by\r
+the Free Software Foundation, either version 3 of the License, or\r
+(at your option) any later version.\r
+\r
+This program is distributed in the hope that it will be useful,\r
+but WITHOUT ANY WARRANTY, without even the implied warranty of\r
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
+GNU General Public License for more details.\r
+\r
+You should have received a copy of the GNU General Public License\r
+along with this program.  If not, see <https://www.gnu.org/licenses/>.\r
+*/\r
+#ifndef AUDIO_H_\r
+#define AUDIO_H_\r
+\r
+typedef int (*audio_callback_func)(void *buffer, int size, void *cls);\r
+\r
+void audio_init(void);\r
+\r
+void audio_set_callback(audio_callback_func func, void *cls);\r
+int audio_callback(void *buf, int sz);\r
+\r
+void audio_play(int rate, int nchan);\r
+void audio_pause(void);\r
+void audio_resume(void);\r
+void audio_stop(void);\r
+int audio_isplaying(void);\r
+\r
+void audio_volume(int vol);\r
+\r
+#endif /* AUDIO_H_ */\r
index e483002..92f0a1b 100644 (file)
--- a/src/dma.c
+++ b/src/dma.c
-#include <pc.h>
-#include "dma.h"
-
-/* 8bit DMA ports */
-#define DMA_0_ADDR     0x00
-#define DMA_0_COUNT    0x01
-#define DMA_1_ADDR     0x02
-#define DMA_1_COUNT    0x03
-#define DMA_2_ADDR     0x04
-#define DMA_2_COUNT    0x05
-#define DMA_3_ADDR     0x06
-#define DMA_3_COUNT    0x07
-/* 16bit DMA ports */
-#define DMA_4_ADDR     0xc0
-#define DMA_4_COUNT    0xc2
-#define DMA_5_ADDR     0xc4
-#define DMA_5_COUNT    0xc6
-#define DMA_6_ADDR     0xc8
-#define DMA_6_COUNT    0xca
-#define DMA_7_ADDR     0xcc
-#define DMA_7_COUNT    0xce
-
-#define DMA_ADDR(c)    \
-       ((c < 4) ? DMA_0_ADDR + ((c) << 1) : (DMA_4_ADDR + ((c) << 2)))
-#define DMA_COUNT(c) \
-       ((c < 4) ? DMA_0_COUNT + ((c) << 1) : (DMA_4_COUNT + ((c) << 2)))
-
-#define DMA8_MASK                      0x0a
-#define DMA8_MODE                      0x0b
-#define DMA8_CLR_FLIPFLOP      0x0c
-#define DMA8_RESET                     0x0d
-#define DMA8_MASK_RST          0x0e
-#define DMA8_RMASK                     0x0f
-#define DMA16_MASK                     0xd4
-#define DMA16_MODE                     0xd6
-#define DMA16_CLR_FLIPFLOP     0xd8
-#define DMA16_RESET                    0xda
-#define DMA16_MASK_RST         0xdc
-#define DMA16_RMASK            0xde
-
-#define DMA_MASK(c)    ((c) < 4 ? DMA8_MASK : DMA16_MASK)
-#define DMA_MODE(c)    ((c) < 4 ? DMA8_MODE : DMA16_MODE)
-#define DMA_CLR_FLIPFLOP(c)    ((c) < 4 ? DMA8_CLR_FLIPFLOP : DMA16_CLR_FLIPFLOP)
-#define DMA_RESET(c)   ((c) < 4 ? DMA8_RESET : DMA16_RESET)
-#define DMA_MASK_RST(c)        ((c) < 4 ? DMA8_MASK_RST : DMA16_MASK_RST)
-#define DMA_RMASK(c)   ((c) < 4 ? DMA8_RMASK : DMA16_RMASK)
-
-#define DMA_0_PAGE             0x87
-#define DMA_1_PAGE             0x83
-#define DMA_2_PAGE             0x81
-#define DMA_3_PAGE             0x82
-#define DMA_4_PAGE             0x8f
-#define DMA_5_PAGE             0x8b
-#define DMA_6_PAGE             0x89
-#define DMA_7_PAGE             0x8a
-
-#define MODE_CHAN(x)   ((x) & 3)
-#define MODE_WRITE             0x04
-#define MODE_READ              0x08
-#define MODE_AUTO              0x10
-#define MODE_DECR              0x20
-#define MODE_SINGLE            0x40
-#define MODE_BLOCK             0x80
-#define MODE_CASCADE   0xc0
-
-#define MASK_CHAN(x)   ((x) & 3)
-#define MASK_DISABLE   0x04
-
-#define RMASK_CHAN(x)  (1 << ((x) & 3))
-
-#define IS_16BIT(c)    ((c) >= 4)
-
-static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir);
-static inline void mask(int chan);
-static inline void unmask(int chan);
-
-static int page_port[] = {
-       DMA_0_PAGE, DMA_1_PAGE, DMA_2_PAGE, DMA_3_PAGE,
-       DMA_4_PAGE, DMA_5_PAGE, DMA_6_PAGE, DMA_7_PAGE
-};
-
-void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags)
-{
-       dma_io(chan, phyaddr, size, flags, MODE_READ);
-}
-
-void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags)
-{
-       dma_io(chan, phyaddr, size, flags, MODE_WRITE);
-}
-
-static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir)
-{
-       unsigned int mode;
-       int addr_port, count_port;
-
-       addr_port = DMA_ADDR(chan);
-       count_port = DMA_COUNT(chan);
-
-       mask(chan);
-       outportb(DMA_CLR_FLIPFLOP(chan), 0);
-
-       /* single / block / cascade */
-       mode = ((flags & 3) << 6) | MODE_CHAN(chan);
-       if(flags & DMA_DECR) mode |= MODE_DECR;
-       if(flags & DMA_AUTO) mode |= MODE_AUTO;
-       outportb(DMA_MODE(chan), mode);
-
-       if(IS_16BIT(chan)) {
-               phyaddr >>= 1;
-               size >>= 1;
-       }
-
-       outportb(addr_port, phyaddr & 0xff);
-       outportb(addr_port, (phyaddr >> 8) & 0xff);
-       outportb(page_port[chan], (phyaddr >> 16) & 0xff);
-
-       size--;
-       outportb(count_port, size & 0xff);
-       outportb(count_port, (size >> 8) & 0xff);
-
-       unmask(chan);
-}
-
-static inline void mask(int chan)
-{
-       outportb(DMA_MASK(chan), MASK_CHAN(chan) | MASK_DISABLE);
-}
-
-static inline void unmask(int chan)
-{
-       outportb(DMA_MASK(chan), MASK_CHAN(chan));
-}
+#include <dos.h>\r
+#include "dma.h"\r
+\r
+/* 8bit DMA ports */\r
+#define DMA_0_ADDR     0x00\r
+#define DMA_0_COUNT    0x01\r
+#define DMA_1_ADDR     0x02\r
+#define DMA_1_COUNT    0x03\r
+#define DMA_2_ADDR     0x04\r
+#define DMA_2_COUNT    0x05\r
+#define DMA_3_ADDR     0x06\r
+#define DMA_3_COUNT    0x07\r
+/* 16bit DMA ports */\r
+#define DMA_4_ADDR     0xc0\r
+#define DMA_4_COUNT    0xc2\r
+#define DMA_5_ADDR     0xc4\r
+#define DMA_5_COUNT    0xc6\r
+#define DMA_6_ADDR     0xc8\r
+#define DMA_6_COUNT    0xca\r
+#define DMA_7_ADDR     0xcc\r
+#define DMA_7_COUNT    0xce\r
+\r
+#define DMA_ADDR(c)    \\r
+       ((c < 4) ? DMA_0_ADDR + ((c) << 1) : (DMA_4_ADDR + ((c) << 2)))\r
+#define DMA_COUNT(c) \\r
+       ((c < 4) ? DMA_0_COUNT + ((c) << 1) : (DMA_4_COUNT + ((c) << 2)))\r
+\r
+#define DMA8_MASK                      0x0a\r
+#define DMA8_MODE                      0x0b\r
+#define DMA8_CLR_FLIPFLOP      0x0c\r
+#define DMA8_RESET                     0x0d\r
+#define DMA8_MASK_RST          0x0e\r
+#define DMA8_RMASK                     0x0f\r
+#define DMA16_MASK                     0xd4\r
+#define DMA16_MODE                     0xd6\r
+#define DMA16_CLR_FLIPFLOP     0xd8\r
+#define DMA16_RESET                    0xda\r
+#define DMA16_MASK_RST         0xdc\r
+#define DMA16_RMASK            0xde\r
+\r
+#define DMA_MASK(c)    ((c) < 4 ? DMA8_MASK : DMA16_MASK)\r
+#define DMA_MODE(c)    ((c) < 4 ? DMA8_MODE : DMA16_MODE)\r
+#define DMA_CLR_FLIPFLOP(c)    ((c) < 4 ? DMA8_CLR_FLIPFLOP : DMA16_CLR_FLIPFLOP)\r
+#define DMA_RESET(c)   ((c) < 4 ? DMA8_RESET : DMA16_RESET)\r
+#define DMA_MASK_RST(c)        ((c) < 4 ? DMA8_MASK_RST : DMA16_MASK_RST)\r
+#define DMA_RMASK(c)   ((c) < 4 ? DMA8_RMASK : DMA16_RMASK)\r
+\r
+#define DMA_0_PAGE             0x87\r
+#define DMA_1_PAGE             0x83\r
+#define DMA_2_PAGE             0x81\r
+#define DMA_3_PAGE             0x82\r
+#define DMA_4_PAGE             0x8f\r
+#define DMA_5_PAGE             0x8b\r
+#define DMA_6_PAGE             0x89\r
+#define DMA_7_PAGE             0x8a\r
+\r
+#define MODE_CHAN(x)   ((x) & 3)\r
+#define MODE_WRITE             0x04\r
+#define MODE_READ              0x08\r
+#define MODE_AUTO              0x10\r
+#define MODE_DECR              0x20\r
+#define MODE_SINGLE            0x40\r
+#define MODE_BLOCK             0x80\r
+#define MODE_CASCADE   0xc0\r
+\r
+#define MASK_CHAN(x)   ((x) & 3)\r
+#define MASK_DISABLE   0x04\r
+\r
+#define RMASK_CHAN(x)  (1 << ((x) & 3))\r
+\r
+#define IS_16BIT(c)    ((c) >= 4)\r
+\r
+static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir);\r
+static __inline void mask(int chan);\r
+static __inline void unmask(int chan);\r
+\r
+static int page_port[] = {\r
+       DMA_0_PAGE, DMA_1_PAGE, DMA_2_PAGE, DMA_3_PAGE,\r
+       DMA_4_PAGE, DMA_5_PAGE, DMA_6_PAGE, DMA_7_PAGE\r
+};\r
+\r
+void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags)\r
+{\r
+       dma_io(chan, phyaddr, size, flags, MODE_READ);\r
+}\r
+\r
+void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags)\r
+{\r
+       dma_io(chan, phyaddr, size, flags, MODE_WRITE);\r
+}\r
+\r
+static void dma_io(int chan, uint32_t phyaddr, int size, unsigned int flags, unsigned int dir)\r
+{\r
+       unsigned int mode;\r
+       int addr_port, count_port;\r
+\r
+       addr_port = DMA_ADDR(chan);\r
+       count_port = DMA_COUNT(chan);\r
+\r
+       mask(chan);\r
+       outp(DMA_CLR_FLIPFLOP(chan), 0);\r
+\r
+       /* single / block / cascade */\r
+       mode = ((flags & 3) << 6) | MODE_CHAN(chan);\r
+       if(flags & DMA_DECR) mode |= MODE_DECR;\r
+       if(flags & DMA_AUTO) mode |= MODE_AUTO;\r
+       outp(DMA_MODE(chan), mode);\r
+\r
+       if(IS_16BIT(chan)) {\r
+               phyaddr >>= 1;\r
+               size >>= 1;\r
+       }\r
+\r
+       outp(addr_port, phyaddr & 0xff);\r
+       outp(addr_port, (phyaddr >> 8) & 0xff);\r
+       outp(page_port[chan], (phyaddr >> 16) & 0xff);\r
+\r
+       size--;\r
+       outp(count_port, size & 0xff);\r
+       outp(count_port, (size >> 8) & 0xff);\r
+\r
+       unmask(chan);\r
+}\r
+\r
+static __inline void mask(int chan)\r
+{\r
+       outp(DMA_MASK(chan), MASK_CHAN(chan) | MASK_DISABLE);\r
+}\r
+\r
+static __inline void unmask(int chan)\r
+{\r
+       outp(DMA_MASK(chan), MASK_CHAN(chan));\r
+}\r
index ca12ad1..93cfa5d 100644 (file)
--- a/src/dma.h
+++ b/src/dma.h
@@ -1,17 +1,17 @@
-#ifndef DMA_H_
-#define DMA_H_
-
-#include <inttypes.h>
-
-enum {
-       DMA_SINGLE      = 0x01,
-       DMA_BLOCK       = 0x02,
-       DMA_CASCADE = DMA_SINGLE | DMA_BLOCK,
-       DMA_DECR        = 0x08,
-       DMA_AUTO        = 0x10
-};
-
-void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags);
-void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags);
-
-#endif /* DMA_H_ */
+#ifndef DMA_H_\r
+#define DMA_H_\r
+\r
+#include <inttypes.h>\r
+\r
+enum {\r
+       DMA_SINGLE      = 0x01,\r
+       DMA_BLOCK       = 0x02,\r
+       DMA_CASCADE = DMA_SINGLE | DMA_BLOCK,\r
+       DMA_DECR        = 0x08,\r
+       DMA_AUTO        = 0x10\r
+};\r
+\r
+void dma_out(int chan, uint32_t phyaddr, int size, unsigned int flags);\r
+void dma_in(int chan, uint32_t phyaddr, int size, unsigned int flags);\r
+\r
+#endif /* DMA_H_ */\r
diff --git a/src/dpmi.c b/src/dpmi.c
new file mode 100644 (file)
index 0000000..7d2c2b5
--- /dev/null
@@ -0,0 +1,55 @@
+#include "dpmi.h"
+
+void dpmi_real_int(int inum, struct dpmi_real_regs *regs)
+{
+       unsigned char int_num = (unsigned char)inum;
+       __asm {
+               mov eax, 0x300
+               mov edi, regs
+               mov bl, int_num
+               mov bh, 0
+               xor ecx, ecx
+               int 0x31
+       }
+}
+
+void *dpmi_mmap(uint32_t phys_addr, unsigned int size)
+{
+       uint16_t mem_high, mem_low;
+       uint16_t phys_high = phys_addr >> 16;
+       uint16_t phys_low = phys_addr & 0xffff;
+       uint16_t size_high = size >> 16;
+       uint16_t size_low = size & 0xffff;
+       unsigned int err, res = 0;
+
+       __asm {
+               mov eax, 0x800
+               mov bx, phys_high
+               mov cx, phys_low
+               mov si, size_high
+               mov di, size_low
+               int 0x31
+               add res, 1
+               mov err, eax
+               mov mem_high, bx
+               mov mem_low, cx
+       }
+
+       if(res == 2) {
+               return 0;
+       }
+       return (void*)(((uint32_t)mem_high << 16) | ((uint32_t)mem_low));
+}
+
+void dpmi_munmap(void *addr)
+{
+       uint16_t mem_high = (uint32_t)addr >> 16;
+       uint16_t mem_low = (uint16_t)addr;
+
+       __asm {
+               mov eax, 0x801
+               mov bx, mem_high
+               mov cx, mem_low
+               int 0x31
+       }
+}
diff --git a/src/dpmi.h b/src/dpmi.h
new file mode 100644 (file)
index 0000000..5f06823
--- /dev/null
@@ -0,0 +1,34 @@
+#ifndef DPMI_H_
+#define DPMI_H_
+
+#include "inttypes.h"
+
+struct dpmi_real_regs {
+       uint32_t edi, esi, ebp;
+       uint32_t reserved;
+       uint32_t ebx, edx, ecx, eax;
+       uint16_t flags;
+       uint16_t es, ds, fs, gs;
+       uint16_t ip, cs, sp, ss;
+};
+
+uint16_t dpmi_alloc(unsigned int par, uint16_t *sel);
+void dpmi_free(uint16_t sel);
+
+#pragma aux dpmi_alloc = \
+               "mov eax, 0x100" \
+               "int 0x31" \
+               "mov [edi], dx" \
+               value[ax] parm[ebx][edi];
+
+#pragma aux dpmi_free = \
+               "mov eax, 0x101" \
+               "int 0x31" \
+               parm[dx];
+
+void dpmi_real_int(int inum, struct dpmi_real_regs *regs);
+
+void *dpmi_mmap(uint32_t phys_addr, unsigned int size);
+void dpmi_munmap(void *addr);
+
+#endif /* DPMI_H_ */
diff --git a/src/intr.h b/src/intr.h
new file mode 100644 (file)
index 0000000..3345324
--- /dev/null
@@ -0,0 +1,60 @@
+#ifndef INTR_H_\r
+#define INTR_H_\r
+\r
+#define INTERRUPT      __interrupt __far\r
+\r
+#define IRQ_TO_INTR(x) ((x) + 8)\r
+\r
+/* PIC command and data ports */\r
+#define PIC1_CMD       0x20\r
+#define PIC1_DATA      0x21\r
+#define PIC2_CMD       0xa0\r
+#define PIC2_DATA      0xa1\r
+/* PIC operation command word 2 bits */\r
+#define OCW2_EOI       (1 << 5)\r
+\r
+unsigned char get_irq_mask(int pic);\r
+#pragma aux get_irq_mask = \\r
+               "cmp bx, 0" \\r
+               "jnz getpic2" \\r
+               "in al, 0x21" \\r
+               "jmp getend" \\r
+               "getpic2:" \\r
+               "in al, 0xa1" \\r
+               "getend:" \\r
+               value[al] parm[ebx];\r
+\r
+void mask_irq(int irq);\r
+#pragma aux mask_irq = \\r
+               "mov dx, 0x21" \\r
+               "cmp ax, 8" \\r
+               "jb skip_mask_pic2" \\r
+               "mov dx, 0xa1" \\r
+               "sub ax, 8" \\r
+               "skip_mask_pic2:" \\r
+               "mov cl, al" \\r
+               "mov ah, 1" \\r
+               "shl ah, cl" \\r
+               "in al, dx" \\r
+               "or al, ah" \\r
+               "out dx, al" \\r
+               parm[eax] modify[cl dx];\r
+\r
+void unmask_irq(int irq);\r
+#pragma aux unmask_irq = \\r
+               "mov dx, 0x21" \\r
+               "cmp ax, 8" \\r
+               "jb skip_unmask_pic2" \\r
+               "mov dx, 0xa1" \\r
+               "sub ax, 8" \\r
+               "skip_unmask_pic2:" \\r
+               "mov cl, al" \\r
+               "mov ah, 1" \\r
+               "shl ah, cl" \\r
+               "not ah" \\r
+               "in al, dx" \\r
+               "and al, ah" \\r
+               "out dx, al" \\r
+               parm[eax] modify[cl dx];\r
+\r
+#endif /* INTR_H_ */\r
diff --git a/src/inttypes.h b/src/inttypes.h
new file mode 100644 (file)
index 0000000..1742166
--- /dev/null
@@ -0,0 +1,18 @@
+#ifndef INT_TYPES_H_
+#define INT_TYPES_H_
+
+#if defined(__DOS__) || defined(WIN32)
+typedef char int8_t;
+typedef short int16_t;
+typedef long int32_t;
+
+typedef unsigned char uint8_t;
+typedef unsigned short uint16_t;
+typedef unsigned long uint32_t;
+
+typedef unsigned long intptr_t;
+#else
+#include <stdint.h>
+#endif
+
+#endif /* INT_TYPES_H_ */
index c7630e5..264c04e 100644 (file)
@@ -1,42 +1,75 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "audio.h"
-
-static int au_callback(void *buffer, int size, void *cls);
-
-static signed char *snd_click;
-static int snd_click_size;
-
-int main(int argc, char **argv)
-{
-       FILE *fp;
-
-       if(!(fp = fopen("click.pcm", "rb"))) {
-               fprintf(stderr, "failed to open click.pcm\n");
-               return 1;
-       }
-       fseek(fp, 0, SEEK_END);
-       snd_click_size = ftell(fp);
-       rewind(fp);
-       if(!(snd_click = malloc(snd_click_size))) {
-               fprintf(stderr, "failed to allocate sound sample\n");
-               return 1;
-       }
-       fread(snd_click, 1, snd_click_size, fp);
-       fclose(fp);
-
-       audio_init();
-       audio_set_callback(au_callback, 0);
-
-       audio_play(22050, 1);
-
-       return 0;
-}
-
-/* snd_click_size is < 65536 so we can just throw it all at once in there */
-static int au_callback(void *buffer, int size, void *cls)
-{
-       memcpy(buffer, snd_click, snd_click_size);
-       return snd_click_size;
-}
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <string.h>\r
+#include <dos.h>\r
+#include <conio.h>\r
+#include "audio.h"\r
+\r
+static int au_callback(void *buffer, int size, void *cls);\r
+\r
+static signed char *snd_click;\r
+static int snd_click_size;\r
+\r
+static int dbg_cbcalled;\r
+\r
+int main(int argc, char **argv)\r
+{\r
+       FILE *fp;\r
+\r
+       if(!(fp = fopen("click.pcm", "rb"))) {\r
+               fprintf(stderr, "failed to open click.pcm\n");\r
+               return 1;\r
+       }\r
+       fseek(fp, 0, SEEK_END);\r
+       snd_click_size = ftell(fp);\r
+       rewind(fp);\r
+       if(!(snd_click = malloc(snd_click_size))) {\r
+               fprintf(stderr, "failed to allocate sound sample\n");\r
+               return 1;\r
+       }\r
+       fread(snd_click, 1, snd_click_size, fp);\r
+       fclose(fp);\r
+\r
+       audio_init();\r
+       audio_set_callback(au_callback, 0);\r
+\r
+       for(;;) {\r
+               if(kbhit()) {\r
+                       int c = getch();\r
+                       switch(c) {\r
+                       case 27:\r
+                               goto end;\r
+                       case ' ':\r
+                               if(audio_isplaying()) {\r
+                                       audio_stop();\r
+                               } else {\r
+                                       audio_play(22050, 1);\r
+                               }\r
+                               break;\r
+                       default:\r
+                               break;\r
+                       }\r
+               }\r
+\r
+               _disable();\r
+               if(dbg_cbcalled) {\r
+                       dbg_cbcalled = 0;\r
+                       _enable();\r
+                       printf("callback called!\n");\r
+               } else {\r
+                       _enable();\r
+               }\r
+       }\r
+\r
+end:\r
+       audio_stop();\r
+       return 0;\r
+}\r
+\r
+/* snd_click_size is < 65536 so we can just throw it all at once in there */\r
+static int au_callback(void *buffer, int size, void *cls)\r
+{\r
+       dbg_cbcalled = 1;\r
+       memcpy(buffer, snd_click, snd_click_size);\r
+       return snd_click_size;\r
+}\r