-#include <stdio.h>
-#include <dos.h>
-#include <pc.h>
-#include <go32.h>
-#include <dpmi.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) {
- /* 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;
- }
-
- addr = ((uint32_t)(seg << 4) + 0xffff) & 0xffff0000;
- buffer = (void*)addr;
- } 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
+static int curblk;\r
+\r
+static void (INTERRUPT *prev_intr_handler)();\r
+\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 = 32768;\r
+ return (char*)buffer + curblk * 32768;\r
+}\r
+\r
+void sb_start(int rate, int bits, 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, 32768))) {\r
+ return;\r
+ }\r
+ curblk = 1;\r
+\r
+ _disable();\r
+ if(!prev_intr_handler) {\r
+ prev_intr_handler = _dos_getvect(IRQ_TO_INTR(irq));\r
+ }\r
+ printf("setting interrupt vector: %d\n", IRQ_TO_INTR(irq));\r
+ _dos_setvect(IRQ_TO_INTR(irq), intr_handler);\r
+ _enable();\r
+\r
+ unmask_irq(irq);\r
+\r
+ cur_bits = bits;\r
+ cur_mode = 0; /* TODO */\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
+ /*cmd |= DSP4_AUTO | DSP4_FIFO;*/\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
+ void *bptr = (unsigned char*)buffer + curblk * 32768;\r
+\r
+ curblk = (curblk + 1) & 1;\r
+\r
+ /* ask for more data */\r
+ if(!(size = audio_callback(bptr, 32768))) {\r
+ sb_stop();\r
+ } else {\r
+ dma_out(dma_chan, (uint32_t)bptr, 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