X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dos_auplay;a=blobdiff_plain;f=src%2Fau_sb.c;h=c8ca586f8b405fa616539585b4c06c3d937d5e80;hp=06f862ad8eda500a0581e4522b638cd1ec1e3c58;hb=3932cfd54ab14cec36729db7bb32461a58658675;hpb=6e29178202fe1876a0fb0231e71fa0e75a7b6460 diff --git a/src/au_sb.c b/src/au_sb.c index 06f862a..c8ca586 100644 --- a/src/au_sb.c +++ b/src/au_sb.c @@ -27,6 +27,7 @@ #define DSP_RATE 0x40 #define DSP4_OUT_RATE 0x41 #define DSP4_IN_RATE 0x42 +#define DSP_BLOCKSZ 0x48 #define DSP_GET_VER 0xe1 /* start DMA playback/recording. combine with fifo/auto/input flags */ @@ -61,8 +62,15 @@ #define MIX_SB16_MASTER_R 0x31 #define MIX_SB16_VOICE_L 0x32 #define MIX_SB16_VOICE_R 0x33 + +#define MIX_SBPRO_STEREO 0x0e #define MIX_SB16_IRQ_SEL 0x80 #define MIX_SB16_DMA_SEL 0x81 +#define MIX_SB16_INTSTAT 0x82 + +#define INTSTAT_DMA8 0x01 +#define INTSTAT_DMA16 0x02 +#define INTSTAT_MPU401 0x04 #define VER_MAJOR(x) ((x) >> 8) #define VER_MINOR(x) ((x) & 0xff) @@ -73,7 +81,6 @@ static int reset_dsp(void); static void *sb_buffer(int *size); -static void set_output_rate(int rate); static void start(int rate, int bits, int nchan); static void pause(void); static void cont(void); @@ -82,12 +89,13 @@ static int isplaying(void); static void setvolume(int ctl, int vol); static int getvolume(int ctl); +static void set_sbpro_stereo(void); +static int start_dsp4(int rate, int bits, unsigned int mode, int num_samples); +static int start_dsp(int rate, int nchan, int num_samples); 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 void write_mix(int reg, unsigned char val); static unsigned char read_mix(int reg); static int get_dsp_version(void); static int dsp4_detect_irq(void); @@ -109,13 +117,12 @@ static const struct audrv sbdrv = { static int base_port; static int irq, dma_chan, dma16_chan, dsp_ver; -static int dsp4; static void *buffer[2]; static volatile int wrbuf; static volatile int playing; -static int cur_bits, cur_mode, auto_init; +static int cur_bits, auto_init, high_speed; static void (INTERRUPT *prev_intr_handler)(); @@ -130,7 +137,6 @@ int sb_detect(struct audrv *drv) if(sscanf(env, "A%x I%d D%d H%d", &base_port, &irq, &dma_chan, &dma16_chan) >= 3) { if(reset_dsp() == 0) { dsp_ver = get_dsp_version(); - dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0; print_dsp_info(); *drv = sbdrv; return 1; @@ -144,9 +150,8 @@ int sb_detect(struct audrv *drv) base_port = 0x200 + ((i + 1) << 4); if(reset_dsp() == 0) { dsp_ver = get_dsp_version(); - dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0; - if(dsp4) { + if(dsp_ver >= 0x400) { if(dsp4_detect_irq() == -1) { printf("sb_detect: failed to configure IRQ\n"); return 0; @@ -193,24 +198,11 @@ static int reset_dsp(void) return -1; } -static void 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); - } -} - static void start(int rate, int bits, int nchan) { uint16_t seg, pmsel; uint32_t addr, next64k; - int size, num_samples; + int size, mode, num_samples, dsp_num_samples; if(!buffer[1]) { /* allocate a buffer in low memory that doesn't cross 64k boundaries */ @@ -219,31 +211,18 @@ static void start(int rate, int bits, int nchan) return; } - printf("DBG allocated seg: %x, addr: %lx\n", (unsigned int)seg, - (unsigned long)seg << 4); - addr = (uint32_t)seg << 4; next64k = (addr + 0x10000) & 0xffff0000; if(next64k - addr < BUFSIZE) { addr = next64k; } - printf("DBG aligned: %lx (mid: %lx)\n", (unsigned long)addr, (unsigned long)(addr + BUFSIZE / 2)); buffer[0] = (void*)addr; buffer[1] = (void*)(addr + BUFSIZE / 2); wrbuf = 0; } - /* Auto-init playback mode: - * fill the whole buffer with data, program the DMA for BUFSIZE transfer, - * and program the DSP for BUFSIZE/2 transfer. We'll get an interrupt in the - * middle, while the DSP uses the upper half, and we'll refill the bottom half. - * Then continue ping-ponging the two halves of the buffer until we run out of - * data. - */ - auto_init = 1; - /* TODO: if size <= BUFSIZE, do a single transfer instead */ wrbuf = 0; if(!(size = audio_callback(buffer[wrbuf], BUFSIZE))) { return; @@ -251,6 +230,21 @@ static void start(int rate, int bits, int nchan) addr = (uint32_t)buffer[wrbuf]; num_samples = bits == 8 ? size : size / 2; + if(size < BUFSIZE) { + auto_init = 0; /* single transfer mode */ + dsp_num_samples = num_samples; + } else { + /* Auto-init playback mode: + * fill the whole buffer with data, program the DMA for BUFSIZE transfer, + * and program the DSP for BUFSIZE/2 transfer. We'll get an interrupt in the + * middle, while the DSP uses the upper half, and we'll refill the bottom half. + * Then continue ping-ponging the two halves of the buffer until we run out of + * data. + */ + auto_init = 1; + dsp_num_samples = num_samples / 2; + } + _disable(); if(!prev_intr_handler) { prev_intr_handler = _dos_getvect(IRQ_TO_INTR(irq)); @@ -261,35 +255,23 @@ static void start(int rate, int bits, int nchan) unmask_irq(irq); cur_bits = bits; - cur_mode = bits == 8 ? 0 : DSP4_MODE_SIGNED; - if(nchan > 1) { - cur_mode |= DSP4_MODE_STEREO; - } write_dsp(DSP_ENABLE_OUTPUT); - dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | DMA_AUTO); - set_output_rate(rate); - start_dsp4(cur_bits, cur_mode, num_samples / 2); - playing = 1; -} + dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | auto_init ? DMA_AUTO : 0); -static void start_dsp4(int bits, unsigned int mode, int num_samples) -{ - unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16; - cmd |= DSP4_AUTO | DSP4_FIFO; - - /* 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 */ + if(dsp_ver >= 0x400) { + int mode = bits == 8 ? 0 : DSP4_MODE_SIGNED; + if(nchan > 1) { + mode |= DSP4_MODE_STEREO; + } + start_dsp4(rate, cur_bits, mode, dsp_num_samples); + } else { + if(nchan > 1 && dsp_ver >= 0x300) { + set_sbpro_stereo(); + } + start_dsp(rate, cur_bits, dsp_num_samples); + } + playing = 1; } static void pause(void) @@ -329,11 +311,11 @@ static void setvolume(int ctl, int vol) /* DSP 4.x - SB16 */ val = vol & 0xf8; if(ctl == AUDIO_PCM) { - write_mix(MIX_SB16_VOICE_L, vol); - write_mix(MIX_SB16_VOICE_R, vol); + write_mix(MIX_SB16_VOICE_L, val); + write_mix(MIX_SB16_VOICE_R, val); } else { - write_mix(MIX_SB16_MASTER_L, vol); - write_mix(MIX_SB16_MASTER_R, vol); + write_mix(MIX_SB16_MASTER_L, val); + write_mix(MIX_SB16_MASTER_R, val); } } else if(VER_MAJOR(dsp_ver) >= 3) { @@ -364,7 +346,7 @@ static int getvolume(int ctl) int left, right; unsigned char val; - if(VER_MAJOR(dsp_ver) >= 4) { + if(dsp_ver >= 0x400) { /* DSP 4.x - SB16 */ int lreg, rreg; if(ctl == AUDIO_PCM) { @@ -376,11 +358,11 @@ static int getvolume(int ctl) } val = read_mix(lreg); - left = (val & 0xf8) | ((val >> 3) & 7); /* duplicate last 3 bits */ + left = (val & 0xf8) | (val >> 5); val = read_mix(rreg); - right = (val & 0xf8) | ((val >> 3) & 7); + right = (val & 0xf8) | (val >> 5); - } else if(VER_MAJOR(dsp_ver) >= 3) { + } else if(dsp_ver >= 0x300) { /* DSP 3.x - SBPro */ val = read_mix(ctl == AUDIO_PCM ? MIX_SBPRO_VOICE : MIX_SBPRO_MASTER); @@ -408,6 +390,55 @@ static int getvolume(int ctl) return (left + right) >> 1; } +static void set_sbpro_stereo(void) +{ +} + +static int start_dsp4(int rate, int bits, unsigned int mode, int num_samples) +{ + unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16; + if(auto_init) { + cmd |= DSP4_AUTO | DSP4_FIFO; + } + + /* set output rate */ + write_dsp(DSP4_OUT_RATE); + write_dsp(rate >> 8); + write_dsp(rate & 0xff); + + /* 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); + + return 0; +} + +static int start_dsp(int rate, int nchan, int num_samples) +{ + /* set time constant */ + int tcon = 256 - 1000000 / rate; + write_dsp(DSP_RATE); + write_dsp(tcon); + + if(nchan > 1) { + /* stereo */ + if(dsp_ver < 0x300) return -1; /* need a sb pro for stereo */ + + set_sbpro_stereo(); + high_speed = rate >= 11025; + } else { + /* mono */ + high_speed = rate >= 23000; + } + + /* program the DSP to start the DMA transfer */ + return -1; /* TODO */ +} + + static void INTERRUPT intr_handler() { int size; @@ -425,14 +456,10 @@ static void INTERRUPT intr_handler() if(cur_bits == 8) { inp(REG_INTACK); } else { - /* - unsigned char istat; - outp(REG_MIXPORT, 0x82); - istat = inp(REG_MIXDATA); - if(istat & 2) { - */ + unsigned char istat = read_mix(MIX_SB16_INTSTAT); + if(istat & INTSTAT_DMA16) { inp(REG_INT16ACK); - //} + } } if(irq > 7) { @@ -453,7 +480,7 @@ static unsigned char read_dsp(void) return inp(REG_RDATA); } -static void write_mix(unsigned char val, int reg) +static void write_mix(int reg, unsigned char val) { outp(REG_MIXPORT, reg); outp(REG_MIXDATA, val); @@ -491,7 +518,7 @@ static int dsp4_detect_irq(void) } if(!irq) { /* try to force IRQ 5 */ - write_mix(2, MIX_SB16_IRQ_SEL); /* bit1 selects irq 5 */ + write_mix(MIX_SB16_IRQ_SEL, 2); /* bit1 selects irq 5 */ /* re-read to verify */ irqsel = read_mix(MIX_SB16_IRQ_SEL); @@ -534,7 +561,7 @@ static int dsp4_detect_dma(void) } if(dma_chan == -1 || dma16_chan == -1) { - write_mix(dmasel, MIX_SB16_DMA_SEL); + write_mix(MIX_SB16_DMA_SEL, dmasel); /* re-read to verify */ tmp = read_mix(MIX_SB16_DMA_SEL);