#define DSP_RATE 0x40\r
#define DSP4_OUT_RATE 0x41\r
#define DSP4_IN_RATE 0x42\r
+#define DSP_BLOCKSZ 0x48\r
#define DSP_GET_VER 0xe1\r
\r
/* start DMA playback/recording. combine with fifo/auto/input flags */\r
#define MIX_SB16_MASTER_R 0x31\r
#define MIX_SB16_VOICE_L 0x32\r
#define MIX_SB16_VOICE_R 0x33\r
+\r
+#define MIX_SBPRO_STEREO 0x0e\r
#define MIX_SB16_IRQ_SEL 0x80\r
#define MIX_SB16_DMA_SEL 0x81\r
#define MIX_SB16_INTSTAT 0x82\r
\r
static int reset_dsp(void);\r
static void *sb_buffer(int *size);\r
-static void set_output_rate(int rate);\r
static void start(int rate, int bits, int nchan);\r
static void pause(void);\r
static void cont(void);\r
static void setvolume(int ctl, int vol);\r
static int getvolume(int ctl);\r
\r
+static void set_sbpro_stereo(void);\r
+static int start_dsp4(int rate, int bits, unsigned int mode, int num_samples);\r
+static int start_dsp(int rate, int nchan, int num_samples);\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(int reg, unsigned char val);\r
\r
static int base_port;\r
static int irq, dma_chan, dma16_chan, dsp_ver;\r
-static int dsp4;\r
\r
static void *buffer[2];\r
static volatile int wrbuf;\r
\r
static volatile int playing;\r
-static int cur_bits, cur_mode, auto_init;\r
+static int cur_bits, auto_init, high_speed;\r
\r
static void (INTERRUPT *prev_intr_handler)();\r
\r
if(sscanf(env, "A%x I%d D%d H%d", &base_port, &irq, &dma_chan, &dma16_chan) >= 3) {\r
if(reset_dsp() == 0) {\r
dsp_ver = get_dsp_version();\r
- dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
print_dsp_info();\r
*drv = sbdrv;\r
return 1;\r
base_port = 0x200 + ((i + 1) << 4);\r
if(reset_dsp() == 0) {\r
dsp_ver = get_dsp_version();\r
- dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;\r
\r
- if(dsp4) {\r
+ if(dsp_ver >= 0x400) {\r
if(dsp4_detect_irq() == -1) {\r
printf("sb_detect: failed to configure IRQ\n");\r
return 0;\r
return -1;\r
}\r
\r
-static void 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
static void start(int rate, int bits, int nchan)\r
{\r
uint16_t seg, pmsel;\r
uint32_t addr, next64k;\r
- int size, num_samples;\r
+ int size, mode, num_samples, dsp_num_samples;\r
\r
if(!buffer[1]) {\r
/* allocate a buffer in low memory that doesn't cross 64k boundaries */\r
wrbuf = 0;\r
}\r
\r
- /* Auto-init playback mode:\r
- * fill the whole buffer with data, program the DMA for BUFSIZE transfer,\r
- * and program the DSP for BUFSIZE/2 transfer. We'll get an interrupt in the\r
- * middle, while the DSP uses the upper half, and we'll refill the bottom half.\r
- * Then continue ping-ponging the two halves of the buffer until we run out of\r
- * data.\r
- */\r
- auto_init = 1;\r
\r
- /* TODO: if size <= BUFSIZE, do a single transfer instead */\r
wrbuf = 0;\r
if(!(size = audio_callback(buffer[wrbuf], BUFSIZE))) {\r
return;\r
addr = (uint32_t)buffer[wrbuf];\r
num_samples = bits == 8 ? size : size / 2;\r
\r
+ if(size < BUFSIZE) {\r
+ auto_init = 0; /* single transfer mode */\r
+ dsp_num_samples = num_samples;\r
+ } else {\r
+ /* Auto-init playback mode:\r
+ * fill the whole buffer with data, program the DMA for BUFSIZE transfer,\r
+ * and program the DSP for BUFSIZE/2 transfer. We'll get an interrupt in the\r
+ * middle, while the DSP uses the upper half, and we'll refill the bottom half.\r
+ * Then continue ping-ponging the two halves of the buffer until we run out of\r
+ * data.\r
+ */\r
+ auto_init = 1;\r
+ dsp_num_samples = num_samples / 2;\r
+ }\r
+\r
_disable();\r
if(!prev_intr_handler) {\r
prev_intr_handler = _dos_getvect(IRQ_TO_INTR(irq));\r
unmask_irq(irq);\r
\r
cur_bits = bits;\r
- cur_mode = bits == 8 ? 0 : DSP4_MODE_SIGNED;\r
- if(nchan > 1) {\r
- cur_mode |= DSP4_MODE_STEREO;\r
- }\r
\r
write_dsp(DSP_ENABLE_OUTPUT);\r
- dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | DMA_AUTO);\r
- set_output_rate(rate);\r
- start_dsp4(cur_bits, cur_mode, num_samples / 2);\r
- playing = 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
- cmd |= DSP4_AUTO | DSP4_FIFO;\r
+ dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | auto_init ? DMA_AUTO : 0);\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
+ if(dsp_ver >= 0x400) {\r
+ int mode = bits == 8 ? 0 : DSP4_MODE_SIGNED;\r
+ if(nchan > 1) {\r
+ mode |= DSP4_MODE_STEREO;\r
+ }\r
+ start_dsp4(rate, cur_bits, mode, dsp_num_samples);\r
+ } else {\r
+ if(nchan > 1 && dsp_ver >= 0x300) {\r
+ set_sbpro_stereo();\r
+ }\r
+ start_dsp(rate, cur_bits, dsp_num_samples);\r
+ }\r
+ playing = 1;\r
}\r
\r
static void pause(void)\r
int left, right;\r
unsigned char val;\r
\r
- if(VER_MAJOR(dsp_ver) >= 4) {\r
+ if(dsp_ver >= 0x400) {\r
/* DSP 4.x - SB16 */\r
int lreg, rreg;\r
if(ctl == AUDIO_PCM) {\r
val = read_mix(rreg);\r
right = (val & 0xf8) | (val >> 5);\r
\r
- } else if(VER_MAJOR(dsp_ver) >= 3) {\r
+ } else if(dsp_ver >= 0x300) {\r
/* DSP 3.x - SBPro */\r
val = read_mix(ctl == AUDIO_PCM ? MIX_SBPRO_VOICE : MIX_SBPRO_MASTER);\r
\r
return (left + right) >> 1;\r
}\r
\r
+static void set_sbpro_stereo(void)\r
+{\r
+}\r
+\r
+static int start_dsp4(int rate, int bits, unsigned int mode, int num_samples)\r
+{\r
+ unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16;\r
+ if(auto_init) {\r
+ cmd |= DSP4_AUTO | DSP4_FIFO;\r
+ }\r
+\r
+ /* set output rate */\r
+ write_dsp(DSP4_OUT_RATE);\r
+ write_dsp(rate >> 8);\r
+ write_dsp(rate & 0xff);\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
+ return 0;\r
+}\r
+\r
+static int start_dsp(int rate, int nchan, int num_samples)\r
+{\r
+ /* set time constant */\r
+ int tcon = 256 - 1000000 / rate;\r
+ write_dsp(DSP_RATE);\r
+ write_dsp(tcon);\r
+\r
+ if(nchan > 1) {\r
+ /* stereo */\r
+ if(dsp_ver < 0x300) return -1; /* need a sb pro for stereo */\r
+\r
+ set_sbpro_stereo();\r
+ high_speed = rate >= 11025;\r
+ } else {\r
+ /* mono */\r
+ high_speed = rate >= 23000;\r
+ }\r
+\r
+ /* program the DSP to start the DMA transfer */\r
+ return -1; /* TODO */\r
+}\r
+\r
+\r
static void INTERRUPT intr_handler()\r
{\r
int size;\r