From 07c19444f4f2a55abf97d181ab62aeaa51033c62 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 15 Jan 2019 20:46:41 +0200 Subject: [PATCH] improved the soundblaster code, but still doesn't work on the real hardware --- Makefile | 86 ++---- Makefile.wat | 36 +++ src/au_sb.c | 938 ++++++++++++++++++++++++++++++-------------------------- src/au_sb.h | 68 ++-- src/audio.c | 149 ++++----- src/audio.h | 71 ++--- src/dma.c | 266 ++++++++-------- src/dma.h | 34 +- src/dpmi.c | 55 ++++ src/dpmi.h | 34 ++ src/intr.h | 60 ++++ src/inttypes.h | 18 ++ src/main.c | 117 ++++--- 13 files changed, 1105 insertions(+), 827 deletions(-) create mode 100644 Makefile.wat create mode 100644 src/dpmi.c create mode 100644 src/dpmi.h create mode 100644 src/intr.h create mode 100644 src/inttypes.h diff --git a/Makefile b/Makefile index 118d4f0..0b4be9e 100644 --- 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) +#obj = $(src:.c=.obj) +obj = src\main.obj src\audio.obj src\au_sb.obj src\dma.obj +bin = sbtest.exe + +opt = -5 +dbg = -d1 + +incpath = -Isrc + +AS = nasm +CC = wcc386 +ASFLAGS = -fobj +CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath) +LDFLAGS = option map +LD = wlink +RM = del + +$(bin): $(obj) + $(LD) debug all name $@ system dos4g file { $(obj) } $(LDFLAGS) + +%.obj: %.c + $(CC) -fo=$@ $(CFLAGS) $< + +%.obj: %.asm + $(AS) $(ASFLAGS) -o $@ $< + +clean: + $(RM) src\*.obj + $(RM) $(bin) diff --git a/Makefile.wat b/Makefile.wat new file mode 100644 index 0000000..bc174e2 --- /dev/null +++ b/Makefile.wat @@ -0,0 +1,36 @@ + +obj = main.obj audio.obj au_sb.obj dma.obj +bin = sbtest.exe +opt = -5 +dbg = -d1 + +!ifdef __UNIX__ +RM = rm -f +!else +RM = del +!endif + +incpath = -Isrc + +AS = nasm +CC = wcc386 +ASFLAGS = -fobj +CFLAGS = $(dbg) $(opt) $(def) -zq -bt=dos $(incpath) +LDFLAGS = option map +LD = wlink + +$(bin): $(obj) + $(LD) debug all name $@ system dos4g file { $(obj) } $(LDFLAGS) + +.c: src +.asm: src + +.c.obj: .autodepend + $(CC) -fo=$@ $(CFLAGS) $[* + +.asm.obj: + $(AS) $(ASFLAGS) -o $@ $[*.asm + +clean: .symbolic + $(RM) *.obj + $(RM) $(bin) diff --git a/src/au_sb.c b/src/au_sb.c index 2046f91..c49b2cf 100644 --- a/src/au_sb.c +++ b/src/au_sb.c @@ -1,431 +1,507 @@ -#include -#include -#include -#include -#include -#include -#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 +#include +#include +#include +#include +#include "audio.h" +#include "au_sb.h" +#include "dpmi.h" +#include "dma.h" +#include "intr.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 DSP_RATE 0x40 +#define DSP4_OUT_RATE 0x41 +#define DSP4_IN_RATE 0x42 +#define DSP_GET_VER 0xe1 + +/* start DMA playback/recording. combine with fifo/auto/input flags */ +#define DSP4_START_DMA8 0xc0 +#define DSP4_START_DMA16 0xb0 +#define DSP4_FIFO 0x02 +#define DSP4_AUTO 0x04 +#define DSP4_INPUT 0x08 + +/* transfer mode commands */ +#define DSP4_MODE_SIGNED 0x10 +#define DSP4_MODE_STEREO 0x20 + +/* immediately pause/continue */ +#define DSP_PAUSE_DMA8 0xd0 +#define DSP_ENABLE_OUTPUT 0xd1 +#define DSP_DISABLE_OUTPUT 0xd3 +#define DSP_CONT_DMA8 0xd4 +#define DSP_PAUSE_DMA16 0xd5 +#define DSP_CONT_DMA16 0xd6 + +/* end the playback at the end of the current buffer */ +#define DSP_END_DMA16 0xd9 +#define DSP_END_DMA8 0xda + +/* mixer registers */ +#define MIX_MASTER 0x02 +#define MIX_VOICE 0x0a +#define MIX_SBPRO_VOICE 0x04 +#define MIX_SBPRO_MASTER 0x22 +#define MIX_SB16_MASTER_L 0x30 +#define MIX_SB16_MASTER_R 0x31 +#define MIX_SB16_VOICE_L 0x32 +#define MIX_SB16_VOICE_R 0x33 +#define MIX_SB16_IRQ_SEL 0x80 +#define MIX_SB16_DMA_SEL 0x81 + +#define VER_MAJOR(x) ((x) >> 8) +#define VER_MINOR(x) ((x) & 0xff) + +/* delay for about 1us */ +#define iodelay() outp(0x80, 0) + +static void INTERRUPT intr_handler(); +static void start_dsp4(int bits, unsigned int mode, int num_samples); +static void start_dsp(int nchan, int num_samples); +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 dsp4_detect_irq(void); +static int dsp4_detect_dma(void); +static void print_dsp_info(void); +static const char *sbname(int ver); + +static int base_port; +static int irq, dma_chan, dma16_chan, dsp_ver; +static int dsp4; +static void *buffer; +static int xfer_mode; + +static int isplaying; +static int cur_bits, cur_mode; + +static void (INTERRUPT *prev_intr_handler)(); + +int sb_detect(void) +{ + int i; + char *env; + + if((env = getenv("BLASTER"))) { + dma16_chan = -1; + if(sscanf(env, "A%x I%d D%d H%d", &base_port, &irq, &dma_chan, &dma16_chan) >= 3) { + if(sb_reset_dsp() == 0) { + dsp_ver = get_dsp_version(); + dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0; + print_dsp_info(); + return 1; + } + } else { + printf("sb_detect: malformed BLASTER environment variable. Fallback to probing.\n"); + } + } + + for(i=0; i<6; i++) { + base_port = 0x200 + ((i + 1) << 4); + if(sb_reset_dsp() == 0) { + dsp_ver = get_dsp_version(); + dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0; + + if(dsp4) { + if(dsp4_detect_irq() == -1) { + printf("sb_detect: failed to configure IRQ\n"); + return 0; + } + if(dsp4_detect_dma() == -1) { + printf("sb_detect: failed to configure DMA\n"); + return 0; + } + + } 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: old sound blaster dsp. assuming: irq 5, dma 1\n"); + } + print_dsp_info(); + + return 1; + } + } + + return 0; +} + +int sb_reset_dsp(void) +{ + int i; + + outp(REG_RESET, 1); + for(i=0; i<3; i++) iodelay(); + outp(REG_RESET, 0); + + for(i=0; i<128; i++) { + if(inp(REG_RSTAT) & RSTAT_RDY) { + if(inp(REG_RDATA) == 0xaa) { + return 0; + } + } + } + + return -1; +} + +void sb_set_output_rate(int rate) +{ + if(dsp4) { + write_dsp(DSP4_OUT_RATE); + write_dsp(rate >> 8); + write_dsp(rate & 0xff); + } else { + int tcon = 256 - 1000000 / rate; + write_dsp(DSP_RATE); + write_dsp(tcon); + } +} + +void *sb_buffer(int *size) +{ + *size = 65536; + return buffer; +} + +void sb_start(int rate, int nchan) +{ + uint16_t seg, pmsel; + uint32_t addr; + int size; + + if(!buffer) { + /* allocate a 64k-aligned 64k buffer in low memory */ + if(!(seg = dpmi_alloc(65536 * 2 / 16, &pmsel))) { + fprintf(stderr, "sb_start: failed to allocate DMA buffer\n"); + return; + } + + printf("DBG allocated seg: %x, addr: %lx\n", (unsigned int)seg, + (unsigned long)seg << 4); + + addr = ((uint32_t)(seg << 4) + 0xffff) & 0xffff0000; + printf("DBG aligned: %lx\n", (unsigned long)addr); + buffer = (void*)addr; + } else { + addr = (uint32_t)buffer; + } + + if(!(size = audio_callback(buffer, 65536))) { + return; + } + + _disable(); + if(!prev_intr_handler) { + prev_intr_handler = _dos_getvect(IRQ_TO_INTR(irq)); + } + _dos_setvect(IRQ_TO_INTR(irq), intr_handler); + _enable(); + + unmask_irq(irq); + + cur_bits = 8; + cur_mode = 0; + if(nchan > 1) { + cur_mode |= DSP4_MODE_STEREO; + } + + write_dsp(DSP_ENABLE_OUTPUT); + dma_out(dma_chan, addr, size, DMA_SINGLE); + sb_set_output_rate(rate); + start_dsp4(cur_bits, cur_mode, size); + isplaying = 1; +} + +static void start_dsp4(int bits, unsigned int mode, int num_samples) +{ + unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16; + assert(bits == 8 || bits == 16); + + /* program the DSP to start the DMA transfer */ + write_dsp(cmd); + write_dsp(mode); + num_samples--; + write_dsp(num_samples & 0xff); + write_dsp((num_samples >> 8) & 0xff); +} + +static void start_dsp(int nchan, int num_samples) +{ + /* program the DSP to start the DMA transfer */ + /* TODO */ +} + +void sb_pause(void) +{ + write_dsp(cur_bits == 8 ? DSP_PAUSE_DMA8 : DSP_PAUSE_DMA16); +} + +void sb_continue(void) +{ + write_dsp(cur_bits == 8 ? DSP_CONT_DMA8 : DSP_CONT_DMA16); +} + +void sb_stop(void) +{ + write_dsp(DSP_DISABLE_OUTPUT); + + mask_irq(irq); + /* TODO: don't _enable, restore state */ + _disable(); + _dos_setvect(IRQ_TO_INTR(irq), prev_intr_handler); + _enable(); + + /* no need to stop anything if we're in single-cycle mode */ + if(cur_mode & DSP4_AUTO) { + write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16); + } + isplaying = 0; +} + +int sb_isplaying(void) +{ + return isplaying; +} + +void sb_volume(int vol) +{ + /* TODO */ +} + +static void INTERRUPT intr_handler() +{ + int size; + + /* ask for more data */ + if(!(size = audio_callback(buffer, 65536))) { + sb_stop(); + } else { + dma_out(dma_chan, (uint32_t)buffer, size, DMA_SINGLE); + start_dsp4(cur_bits, cur_mode, size); + } + + /* acknowledge the interrupt */ + inp(REG_INTACK); + + if(irq > 7) { + outp(PIC2_CMD, OCW2_EOI); + } + outp(PIC1_CMD, OCW2_EOI); +} + +static void write_dsp(unsigned char val) +{ + while(inp(REG_WSTAT) & WSTAT_BUSY); + outp(REG_WDATA, val); +} + +static unsigned char read_dsp(void) +{ + while((inp(REG_RSTAT) & RSTAT_RDY) == 0); + return inp(REG_RDATA); +} + +static void write_mix(unsigned char val, int reg) +{ + outp(REG_MIXPORT, reg); + outp(REG_MIXDATA, val); +} + +static unsigned char read_mix(int reg) +{ + outp(REG_MIXPORT, reg); + return inp(REG_MIXDATA); +} + +static int get_dsp_version(void) +{ + int major, minor; + + write_dsp(DSP_GET_VER); + major = read_dsp(); + minor = read_dsp(); + + return (major << 8) | minor; +} + +static int dsp4_detect_irq(void) +{ + int i, irqsel; + static int irqtab[] = {2, 5, 7, 10}; + + irq = 0; + irqsel = read_mix(MIX_SB16_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_SB16_IRQ_SEL); /* bit1 selects irq 5 */ + + /* re-read to verify */ + irqsel = read_mix(MIX_SB16_IRQ_SEL); + if(irqsel != 2) { + return -1; + } + irq = 5; + } + + return irq; +} + +static int dsp4_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_SB16_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_SB16_DMA_SEL); + + /* re-read to verify */ + tmp = read_mix(MIX_SB16_DMA_SEL); + if(tmp != dmasel) { + return -1; + } + dma_chan = 1; + dma16_chan = 5; + } + + return dma_chan; +} + +static void print_dsp_info(void) +{ + int master[2], voice[2]; + int val; + + printf("sb_detect: %s (DSP v%d.%02d) port %xh, irq %d", sbname(dsp_ver), + VER_MAJOR(dsp_ver), VER_MINOR(dsp_ver), base_port, irq); + if(VER_MAJOR(dsp_ver) >= 4) { + printf(" dma %d/%d\n", dma_chan, dma16_chan); + } else { + printf(" dma %d\n", dma_chan); + } + + if(VER_MAJOR(dsp_ver) >= 4) { + master[0] = 100 * (int)(read_mix(MIX_SB16_MASTER_L) >> 3) / 31; + master[1] = 100 * (int)(read_mix(MIX_SB16_MASTER_R) >> 3) / 31; + voice[0] = 100 * (int)(read_mix(MIX_SB16_VOICE_L) >> 3) / 31; + voice[1] = 100 * (int)(read_mix(MIX_SB16_VOICE_R) >> 3) / 31; + } else if(VER_MAJOR(dsp_ver) >= 3) { + val = read_mix(MIX_SBPRO_MASTER); + master[0] = 100 * (val >> 5) / 7; + master[1] = 100 * ((val >> 1) & 7) / 7; + val = read_mix(MIX_SBPRO_VOICE); + voice[0] = 100 * (val >> 5) / 7; + voice[1] = 100 * ((val >> 1) & 7) / 7; + } else { + val = read_mix(MIX_MASTER); + master[0] = master[1] = 100 * ((val >> 1) & 7) / 7; + val = read_mix(MIX_VOICE); + voice[0] = voice[1] = 100 * ((val >> 1) & 3) / 3; + } + printf(" mixer: master(%d|%d) voice(%d|%d)\n", master[0], master[1], + voice[0], voice[1]); +} + +#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 index d437ff7..0981ba6 100644 --- a/src/au_sb.h +++ b/src/au_sb.h @@ -1,42 +1,26 @@ -/* -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); - -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_ +#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); +int sb_isplaying(void); + +void sb_volume(int vol); + +#endif /* AU_SB_H_ */ diff --git a/src/audio.c b/src/audio.c index d783559..adb8e3e 100644 --- a/src/audio.c +++ b/src/audio.c @@ -1,71 +1,78 @@ -#include -#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 +#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); + int (*isplaying)(void); +}; + +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; + drv.isplaying = sb_isplaying; + 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); +} + +int audio_isplaying(void) +{ + return drv.isplaying(); +} diff --git a/src/audio.h b/src/audio.h index 9b528c2..1fde706 100644 --- a/src/audio.h +++ b/src/audio.h @@ -1,35 +1,36 @@ -/* -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_ - -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_ */ +/* +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_ + +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); +int audio_isplaying(void); + +void audio_volume(int vol); + +#endif /* AUDIO_H_ */ diff --git a/src/dma.c b/src/dma.c index e483002..92f0a1b 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1,133 +1,133 @@ -#include -#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 +#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); + outp(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; + outp(DMA_MODE(chan), mode); + + if(IS_16BIT(chan)) { + phyaddr >>= 1; + size >>= 1; + } + + outp(addr_port, phyaddr & 0xff); + outp(addr_port, (phyaddr >> 8) & 0xff); + outp(page_port[chan], (phyaddr >> 16) & 0xff); + + size--; + outp(count_port, size & 0xff); + outp(count_port, (size >> 8) & 0xff); + + unmask(chan); +} + +static __inline void mask(int chan) +{ + outp(DMA_MASK(chan), MASK_CHAN(chan) | MASK_DISABLE); +} + +static __inline void unmask(int chan) +{ + outp(DMA_MASK(chan), MASK_CHAN(chan)); +} diff --git a/src/dma.h b/src/dma.h index ca12ad1..93cfa5d 100644 --- a/src/dma.h +++ b/src/dma.h @@ -1,17 +1,17 @@ -#ifndef DMA_H_ -#define DMA_H_ - -#include - -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_ +#define DMA_H_ + +#include + +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_ */ diff --git a/src/dpmi.c b/src/dpmi.c new file mode 100644 index 0000000..7d2c2b5 --- /dev/null +++ b/src/dpmi.c @@ -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 index 0000000..5f06823 --- /dev/null +++ b/src/dpmi.h @@ -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 index 0000000..3345324 --- /dev/null +++ b/src/intr.h @@ -0,0 +1,60 @@ +#ifndef INTR_H_ +#define INTR_H_ + +#define INTERRUPT __interrupt __far + +#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) + +unsigned char get_irq_mask(int pic); +#pragma aux get_irq_mask = \ + "cmp bx, 0" \ + "jnz getpic2" \ + "in al, 0x21" \ + "jmp getend" \ + "getpic2:" \ + "in al, 0xa1" \ + "getend:" \ + value[al] parm[ebx]; + +void mask_irq(int irq); +#pragma aux mask_irq = \ + "mov dx, 0x21" \ + "cmp ax, 8" \ + "jb skip_mask_pic2" \ + "mov dx, 0xa1" \ + "sub ax, 8" \ + "skip_mask_pic2:" \ + "mov cl, al" \ + "mov ah, 1" \ + "shl ah, cl" \ + "in al, dx" \ + "or al, ah" \ + "out dx, al" \ + parm[eax] modify[cl dx]; + +void unmask_irq(int irq); +#pragma aux unmask_irq = \ + "mov dx, 0x21" \ + "cmp ax, 8" \ + "jb skip_unmask_pic2" \ + "mov dx, 0xa1" \ + "sub ax, 8" \ + "skip_unmask_pic2:" \ + "mov cl, al" \ + "mov ah, 1" \ + "shl ah, cl" \ + "not ah" \ + "in al, dx" \ + "and al, ah" \ + "out dx, al" \ + parm[eax] modify[cl dx]; + +#endif /* INTR_H_ */ diff --git a/src/inttypes.h b/src/inttypes.h new file mode 100644 index 0000000..1742166 --- /dev/null +++ b/src/inttypes.h @@ -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 +#endif + +#endif /* INT_TYPES_H_ */ diff --git a/src/main.c b/src/main.c index c7630e5..264c04e 100644 --- a/src/main.c +++ b/src/main.c @@ -1,42 +1,75 @@ -#include -#include -#include -#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 +#include +#include +#include +#include +#include "audio.h" + +static int au_callback(void *buffer, int size, void *cls); + +static signed char *snd_click; +static int snd_click_size; + +static int dbg_cbcalled; + +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); + + for(;;) { + if(kbhit()) { + int c = getch(); + switch(c) { + case 27: + goto end; + case ' ': + if(audio_isplaying()) { + audio_stop(); + } else { + audio_play(22050, 1); + } + break; + default: + break; + } + } + + _disable(); + if(dbg_cbcalled) { + dbg_cbcalled = 0; + _enable(); + printf("callback called!\n"); + } else { + _enable(); + } + } + +end: + audio_stop(); + 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) +{ + dbg_cbcalled = 1; + memcpy(buffer, snd_click, snd_click_size); + return snd_click_size; +} -- 1.7.10.4