X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fau_sb.c;h=fc9761d1970c38c62e61a4d4743d9757830aec30;hb=0a37e241149d011e038aceb3faac568b405f8ecd;hp=b42a603ad6b471072f312ec08127262608d91c1c;hpb=1e2ddab65ead32350d8ff87a6de74168e429666b;p=bootcensus diff --git a/src/au_sb.c b/src/au_sb.c index b42a603..fc9761d 100644 --- a/src/au_sb.c +++ b/src/au_sb.c @@ -49,6 +49,8 @@ along with this program. If not, see . /* 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 @@ -61,6 +63,10 @@ along with this program. If not, see . #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) @@ -68,13 +74,17 @@ 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; +static int irq, dma_chan, dma16_chan; static int sb16; static void *buffer; static int xfer_mode; @@ -88,16 +98,36 @@ int sb_detect(void) if(sb_reset_dsp() == 0) { ver = get_dsp_version(); sb16 = VER_MAJOR(ver) >= 4; - printf("sb_detect: found %s (DSP v%d.%02d) at port %xh\n", sbname(ver), - VER_MAJOR(ver), VER_MINOR(ver), base_port); + + 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; } } - /* TODO: detect these somehow? */ - irq = 5; - dma_chan = 1; - return 0; } @@ -164,6 +194,8 @@ void sb_start(int rate, int nchan) interrupt(IRQ_TO_INTR(irq), intr_handler); + write_dsp(CMD_ENABLE_OUTPUT); + sb_set_output_rate(rate); start_dma_transfer(addr, size); } @@ -180,6 +212,7 @@ void sb_continue(void) void sb_stop(void) { write_dsp(CMD_END_DMA8); + write_dsp(CMD_DISABLE_OUTPUT); } void sb_volume(int vol) @@ -208,7 +241,7 @@ static void start_dma_transfer(uint32_t addr, int size) 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(CMD_START_DMA8); write_dsp(xfer_mode); size--; write_dsp(size & 0xff); @@ -227,6 +260,18 @@ static unsigned char read_dsp(void) return inb(REG_RDATA); } +static void write_mix(unsigned char val, int reg) +{ + outb(reg, REG_MIXPORT); + outb(val, REG_MIXDATA); +} + +static unsigned char read_mix(int reg) +{ + outb(reg, REG_MIXPORT); + return inb(REG_MIXDATA); +} + static int get_dsp_version(void) { int major, minor; @@ -238,6 +283,78 @@ static int get_dsp_version(void) 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)