12 #define REG_MIXPORT (base_port + 0x4)
\r
13 #define REG_MIXDATA (base_port + 0x5)
\r
14 #define REG_RESET (base_port + 0x6)
\r
15 #define REG_RDATA (base_port + 0xa)
\r
16 #define REG_WDATA (base_port + 0xc)
\r
17 #define REG_WSTAT (base_port + 0xc)
\r
18 #define REG_RSTAT (base_port + 0xe)
\r
19 #define REG_INTACK (base_port + 0xe)
\r
20 #define REG_INT16ACK (base_port + 0xf)
\r
22 #define WSTAT_BUSY 0x80
\r
23 #define RSTAT_RDY 0x80
\r
25 #define DSP_RATE 0x40
\r
26 #define DSP4_OUT_RATE 0x41
\r
27 #define DSP4_IN_RATE 0x42
\r
28 #define DSP_GET_VER 0xe1
\r
30 /* start DMA playback/recording. combine with fifo/auto/input flags */
\r
31 #define DSP4_START_DMA8 0xc0
\r
32 #define DSP4_START_DMA16 0xb0
\r
33 #define DSP4_FIFO 0x02
\r
34 #define DSP4_AUTO 0x04
\r
35 #define DSP4_INPUT 0x08
\r
37 /* transfer mode commands */
\r
38 #define DSP4_MODE_SIGNED 0x10
\r
39 #define DSP4_MODE_STEREO 0x20
\r
41 /* immediately pause/continue */
\r
42 #define DSP_PAUSE_DMA8 0xd0
\r
43 #define DSP_ENABLE_OUTPUT 0xd1
\r
44 #define DSP_DISABLE_OUTPUT 0xd3
\r
45 #define DSP_CONT_DMA8 0xd4
\r
46 #define DSP_PAUSE_DMA16 0xd5
\r
47 #define DSP_CONT_DMA16 0xd6
\r
49 /* end the playback at the end of the current buffer */
\r
50 #define DSP_END_DMA16 0xd9
\r
51 #define DSP_END_DMA8 0xda
\r
53 /* mixer registers */
\r
54 #define MIX_MASTER 0x02
\r
55 #define MIX_VOICE 0x0a
\r
56 #define MIX_SBPRO_VOICE 0x04
\r
57 #define MIX_SBPRO_MASTER 0x22
\r
58 #define MIX_SB16_MASTER_L 0x30
\r
59 #define MIX_SB16_MASTER_R 0x31
\r
60 #define MIX_SB16_VOICE_L 0x32
\r
61 #define MIX_SB16_VOICE_R 0x33
\r
62 #define MIX_SB16_IRQ_SEL 0x80
\r
63 #define MIX_SB16_DMA_SEL 0x81
\r
65 #define VER_MAJOR(x) ((x) >> 8)
\r
66 #define VER_MINOR(x) ((x) & 0xff)
\r
68 /* delay for about 1us */
\r
69 #define iodelay() outp(0x80, 0)
\r
71 static void INTERRUPT intr_handler();
\r
72 static void start_dsp4(int bits, unsigned int mode, int num_samples);
\r
73 static void start_dsp(int nchan, int num_samples);
\r
74 static void write_dsp(unsigned char val);
\r
75 static unsigned char read_dsp(void);
\r
76 static void write_mix(unsigned char val, int reg);
\r
77 static unsigned char read_mix(int reg);
\r
78 static int get_dsp_version(void);
\r
79 static int dsp4_detect_irq(void);
\r
80 static int dsp4_detect_dma(void);
\r
81 static void print_dsp_info(void);
\r
82 static const char *sbname(int ver);
\r
84 static int base_port;
\r
85 static int irq, dma_chan, dma16_chan, dsp_ver;
\r
87 static void *buffer;
\r
88 static int xfer_mode;
\r
90 static int isplaying;
\r
91 static int cur_bits, cur_mode;
\r
94 static void (INTERRUPT *prev_intr_handler)();
\r
102 if((env = getenv("BLASTER"))) {
\r
104 if(sscanf(env, "A%x I%d D%d H%d", &base_port, &irq, &dma_chan, &dma16_chan) >= 3) {
\r
105 if(sb_reset_dsp() == 0) {
\r
106 dsp_ver = get_dsp_version();
\r
107 dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;
\r
112 printf("sb_detect: malformed BLASTER environment variable. Fallback to probing.\n");
\r
116 for(i=0; i<6; i++) {
\r
117 base_port = 0x200 + ((i + 1) << 4);
\r
118 if(sb_reset_dsp() == 0) {
\r
119 dsp_ver = get_dsp_version();
\r
120 dsp4 = VER_MAJOR(dsp_ver) >= 4 ? 1 : 0;
\r
123 if(dsp4_detect_irq() == -1) {
\r
124 printf("sb_detect: failed to configure IRQ\n");
\r
127 if(dsp4_detect_dma() == -1) {
\r
128 printf("sb_detect: failed to configure DMA\n");
\r
133 /* XXX for old sound blasters, hard-code to IRQ 5 DMA 1 for now */
\r
138 printf("sb_detect: old sound blaster dsp. assuming: irq 5, dma 1\n");
\r
149 int sb_reset_dsp(void)
\r
153 outp(REG_RESET, 1);
\r
154 for(i=0; i<3; i++) iodelay();
\r
155 outp(REG_RESET, 0);
\r
157 for(i=0; i<128; i++) {
\r
158 if(inp(REG_RSTAT) & RSTAT_RDY) {
\r
159 if(inp(REG_RDATA) == 0xaa) {
\r
168 void sb_set_output_rate(int rate)
\r
171 write_dsp(DSP4_OUT_RATE);
\r
172 write_dsp(rate >> 8);
\r
173 write_dsp(rate & 0xff);
\r
175 int tcon = 256 - 1000000 / rate;
\r
176 write_dsp(DSP_RATE);
\r
181 void *sb_buffer(int *size)
\r
184 return (char*)buffer + curblk * 32768;
\r
187 void sb_start(int rate, int bits, int nchan)
\r
189 uint16_t seg, pmsel;
\r
194 /* allocate a 64k-aligned 64k buffer in low memory */
\r
195 if(!(seg = dpmi_alloc(65536 * 2 / 16, &pmsel))) {
\r
196 fprintf(stderr, "sb_start: failed to allocate DMA buffer\n");
\r
200 printf("DBG allocated seg: %x, addr: %lx\n", (unsigned int)seg,
\r
201 (unsigned long)seg << 4);
\r
203 addr = ((uint32_t)(seg << 4) + 0xffff) & 0xffff0000;
\r
204 printf("DBG aligned: %lx\n", (unsigned long)addr);
\r
205 buffer = (void*)addr;
\r
207 addr = (uint32_t)buffer;
\r
210 if(!(size = audio_callback(buffer, 32768))) {
\r
216 if(!prev_intr_handler) {
\r
217 prev_intr_handler = _dos_getvect(IRQ_TO_INTR(irq));
\r
219 printf("setting interrupt vector: %d\n", IRQ_TO_INTR(irq));
\r
220 _dos_setvect(IRQ_TO_INTR(irq), intr_handler);
\r
226 cur_mode = 0; /* TODO */
\r
228 cur_mode |= DSP4_MODE_STEREO;
\r
231 write_dsp(DSP_ENABLE_OUTPUT);
\r
232 dma_out(dma_chan, addr, size, DMA_SINGLE);
\r
233 sb_set_output_rate(rate);
\r
234 start_dsp4(cur_bits, cur_mode, size);
\r
238 static void start_dsp4(int bits, unsigned int mode, int num_samples)
\r
240 unsigned char cmd = bits == 8 ? DSP4_START_DMA8 : DSP4_START_DMA16;
\r
241 assert(bits == 8 || bits == 16);
\r
243 /* program the DSP to start the DMA transfer */
\r
247 write_dsp(num_samples & 0xff);
\r
248 write_dsp((num_samples >> 8) & 0xff);
\r
251 static void start_dsp(int nchan, int num_samples)
\r
253 /* program the DSP to start the DMA transfer */
\r
257 void sb_pause(void)
\r
259 write_dsp(cur_bits == 8 ? DSP_PAUSE_DMA8 : DSP_PAUSE_DMA16);
\r
262 void sb_continue(void)
\r
264 write_dsp(cur_bits == 8 ? DSP_CONT_DMA8 : DSP_CONT_DMA16);
\r
269 write_dsp(DSP_DISABLE_OUTPUT);
\r
272 /* TODO: don't _enable, restore state */
\r
274 _dos_setvect(IRQ_TO_INTR(irq), prev_intr_handler);
\r
277 /* no need to stop anything if we're in single-cycle mode */
\r
278 if(cur_mode & DSP4_AUTO) {
\r
279 write_dsp(cur_bits == 8 ? DSP_END_DMA8 : DSP_END_DMA16);
\r
284 int sb_isplaying(void)
\r
289 void sb_volume(int vol)
\r
294 static void INTERRUPT intr_handler()
\r
297 void *bptr = (unsigned char*)buffer + curblk * 32768;
\r
299 curblk = (curblk + 1) & 1;
\r
301 /* ask for more data */
\r
302 if(!(size = audio_callback(bptr, 32768))) {
\r
305 dma_out(dma_chan, (uint32_t)bptr, size, DMA_SINGLE);
\r
306 start_dsp4(cur_bits, cur_mode, size);
\r
309 /* acknowledge the interrupt */
\r
313 outp(PIC2_CMD, OCW2_EOI);
\r
315 outp(PIC1_CMD, OCW2_EOI);
\r
318 static void write_dsp(unsigned char val)
\r
320 while(inp(REG_WSTAT) & WSTAT_BUSY);
\r
321 outp(REG_WDATA, val);
\r
324 static unsigned char read_dsp(void)
\r
326 while((inp(REG_RSTAT) & RSTAT_RDY) == 0);
\r
327 return inp(REG_RDATA);
\r
330 static void write_mix(unsigned char val, int reg)
\r
332 outp(REG_MIXPORT, reg);
\r
333 outp(REG_MIXDATA, val);
\r
336 static unsigned char read_mix(int reg)
\r
338 outp(REG_MIXPORT, reg);
\r
339 return inp(REG_MIXDATA);
\r
342 static int get_dsp_version(void)
\r
346 write_dsp(DSP_GET_VER);
\r
347 major = read_dsp();
\r
348 minor = read_dsp();
\r
350 return (major << 8) | minor;
\r
353 static int dsp4_detect_irq(void)
\r
356 static int irqtab[] = {2, 5, 7, 10};
\r
359 irqsel = read_mix(MIX_SB16_IRQ_SEL);
\r
360 for(i=0; i<4; i++) {
\r
361 if(irqsel & (1 << i)) {
\r
367 /* try to force IRQ 5 */
\r
368 write_mix(2, MIX_SB16_IRQ_SEL); /* bit1 selects irq 5 */
\r
370 /* re-read to verify */
\r
371 irqsel = read_mix(MIX_SB16_IRQ_SEL);
\r
381 static int dsp4_detect_dma(void)
\r
383 int i, dmasel, tmp;
\r
384 static int dmatab[] = {0, 1, -1, 3, -1, 5, 6, 7};
\r
388 dmasel = read_mix(MIX_SB16_DMA_SEL);
\r
389 for(i=0; i<4; i++) {
\r
390 if(dmasel & (1 << i)) {
\r
391 dma_chan = dmatab[i];
\r
395 for(i=5; i<8; i++) {
\r
396 if(dmasel & (1 << i)) {
\r
397 dma16_chan = dmatab[i];
\r
401 if(dma_chan == -1) {
\r
402 /* try to force DMA 1 */
\r
405 if(dma16_chan == -1) {
\r
406 /* try to force 16bit DMA 5 */
\r
410 if(dma_chan == -1 || dma16_chan == -1) {
\r
411 write_mix(dmasel, MIX_SB16_DMA_SEL);
\r
413 /* re-read to verify */
\r
414 tmp = read_mix(MIX_SB16_DMA_SEL);
\r
415 if(tmp != dmasel) {
\r
425 static void print_dsp_info(void)
\r
427 int master[2], voice[2];
\r
430 printf("sb_detect: %s (DSP v%d.%02d) port %xh, irq %d", sbname(dsp_ver),
\r
431 VER_MAJOR(dsp_ver), VER_MINOR(dsp_ver), base_port, irq);
\r
432 if(VER_MAJOR(dsp_ver) >= 4) {
\r
433 printf(" dma %d/%d\n", dma_chan, dma16_chan);
\r
435 printf(" dma %d\n", dma_chan);
\r
438 if(VER_MAJOR(dsp_ver) >= 4) {
\r
439 master[0] = 100 * (int)(read_mix(MIX_SB16_MASTER_L) >> 3) / 31;
\r
440 master[1] = 100 * (int)(read_mix(MIX_SB16_MASTER_R) >> 3) / 31;
\r
441 voice[0] = 100 * (int)(read_mix(MIX_SB16_VOICE_L) >> 3) / 31;
\r
442 voice[1] = 100 * (int)(read_mix(MIX_SB16_VOICE_R) >> 3) / 31;
\r
443 } else if(VER_MAJOR(dsp_ver) >= 3) {
\r
444 val = read_mix(MIX_SBPRO_MASTER);
\r
445 master[0] = 100 * (val >> 5) / 7;
\r
446 master[1] = 100 * ((val >> 1) & 7) / 7;
\r
447 val = read_mix(MIX_SBPRO_VOICE);
\r
448 voice[0] = 100 * (val >> 5) / 7;
\r
449 voice[1] = 100 * ((val >> 1) & 7) / 7;
\r
451 val = read_mix(MIX_MASTER);
\r
452 master[0] = master[1] = 100 * ((val >> 1) & 7) / 7;
\r
453 val = read_mix(MIX_VOICE);
\r
454 voice[0] = voice[1] = 100 * ((val >> 1) & 3) / 3;
\r
456 printf(" mixer: master(%d|%d) voice(%d|%d)\n", master[0], master[1],
\r
457 voice[0], voice[1]);
\r
460 #define V(maj, min) (((maj) << 8) | (min))
\r
462 static const char *sbname(int ver)
\r
464 int major = VER_MAJOR(ver);
\r
465 int minor = VER_MINOR(ver);
\r
470 return "Sound Blaster 1.5";
\r
472 return "Sound Blaster 1.0";
\r
475 if(minor == 1 || minor == 2) {
\r
476 return "Sound Blaster 2.0";
\r
483 return "Sound Blaster Pro";
\r
486 return "Sound Blaster Pro 2";
\r
488 return "Gallant SC-6000";
\r
498 return "Sound Blaster 16";
\r
500 return "Sound Blaster 16 SCSI-2";
\r
502 return "Sound Blaster AWE 32";
\r
504 return "Sound Blaster ViBRA16C";
\r
506 return "Sound Blaster AWE 64";
\r
513 return "Unknown Sound Blaster";
\r