#include "dma.h"\r
#include "intr.h"\r
\r
+#define BUFSIZE 16384\r
+\r
#define REG_MIXPORT (base_port + 0x4)\r
#define REG_MIXDATA (base_port + 0x5)\r
#define REG_RESET (base_port + 0x6)\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
+static void *buffer[2];\r
+static volatile int wrbuf;\r
+\r
+static volatile int isplaying;\r
+static int cur_bits, cur_mode, auto_init;\r
\r
static void (INTERRUPT *prev_intr_handler)();\r
\r
\r
void *sb_buffer(int *size)\r
{\r
- *size = 32768;\r
- return (char*)buffer + curblk * 32768;\r
+ *size = BUFSIZE / 2;\r
+ return buffer[wrbuf];\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
+ uint32_t addr, next64k;\r
+ int size, num_samples;\r
\r
- if(!buffer) {\r
- /* allocate a 64k-aligned 64k buffer in low memory */\r
- if(!(seg = dpmi_alloc(65536 * 2 / 16, &pmsel))) {\r
+ if(!buffer[1]) {\r
+ /* allocate a buffer in low memory that doesn't cross 64k boundaries */\r
+ if(!(seg = dpmi_alloc(BUFSIZE * 2 / 16, &pmsel))) {\r
fprintf(stderr, "sb_start: failed to allocate DMA buffer\n");\r
return;\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
+ addr = (uint32_t)seg << 4;\r
+ next64k = (addr + 0x10000) & 0xffff0000;\r
+ if(next64k - addr < BUFSIZE) {\r
+ addr = next64k;\r
+ }\r
+\r
+ printf("DBG aligned: %lx (mid: %lx)\n", (unsigned long)addr, (unsigned long)(addr + BUFSIZE / 2));\r
+ buffer[0] = (void*)addr;\r
+ buffer[1] = (void*)(addr + BUFSIZE / 2);\r
+ wrbuf = 0;\r
}\r
\r
- if(!(size = audio_callback(buffer, 32768))) {\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
}\r
- curblk = 1;\r
+ addr = (uint32_t)buffer[wrbuf];\r
+ num_samples = bits == 8 ? size : size / 2;\r
\r
_disable();\r
if(!prev_intr_handler) {\r
unmask_irq(irq);\r
\r
cur_bits = bits;\r
- cur_mode = 0; /* TODO */\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(dma_chan, addr, size, DMA_SINGLE);\r
+ dma_out(cur_bits == 8 ? dma_chan : dma16_chan, addr, BUFSIZE, DMA_SINGLE | DMA_AUTO);\r
sb_set_output_rate(rate);\r
- start_dsp4(cur_bits, cur_mode, size);\r
+ start_dsp4(cur_bits, cur_mode, num_samples / 2);\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
+ cmd |= DSP4_AUTO | DSP4_FIFO;\r
\r
/* program the DSP to start the DMA transfer */\r
write_dsp(cmd);\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
+ write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16);\r
isplaying = 0;\r
}\r
\r
static void INTERRUPT intr_handler()\r
{\r
int size;\r
- void *bptr = (unsigned char*)buffer + curblk * 32768;\r
+ void *bptr = buffer[wrbuf];\r
+ uint32_t addr = (uint32_t)bptr;\r
\r
- curblk = (curblk + 1) & 1;\r
+ wrbuf ^= 1;\r
\r
/* ask for more data */\r
- if(!(size = audio_callback(bptr, 32768))) {\r
+ if(!(size = audio_callback(bptr, BUFSIZE / 2))) {\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
+ if(cur_bits == 8) {\r
+ inp(REG_INTACK);\r
+ } else {\r
+ /*\r
+ unsigned char istat;\r
+ outp(REG_MIXPORT, 0x82);\r
+ istat = inp(REG_MIXDATA);\r
+ if(istat & 2) {\r
+ */\r
+ inp(REG_INT16ACK);\r
+ //}\r
+ }\r
\r
if(irq > 7) {\r
outp(PIC2_CMD, OCW2_EOI);\r