6 #include <sys/nearptr.h>
11 #define IRQ_TO_INTR(x) ((x) + 8)
13 /* PIC command and data ports */
15 #define PIC1_DATA 0x21
17 #define PIC2_DATA 0xa1
18 /* PIC operation command word 2 bits */
19 #define OCW2_EOI (1 << 5)
21 #define REG_MIXPORT (base_port + 0x4)
22 #define REG_MIXDATA (base_port + 0x5)
23 #define REG_RESET (base_port + 0x6)
24 #define REG_RDATA (base_port + 0xa)
25 #define REG_WDATA (base_port + 0xc)
26 #define REG_WSTAT (base_port + 0xc)
27 #define REG_RSTAT (base_port + 0xe)
28 #define REG_INTACK (base_port + 0xe)
29 #define REG_INT16ACK (base_port + 0xf)
31 #define WSTAT_BUSY 0x80
32 #define RSTAT_RDY 0x80
35 #define CMD_SB16_OUT_RATE 0x41
36 #define CMD_SB16_IN_RATE 0x42
37 #define CMD_GET_VER 0xe1
39 /* start DMA playback/recording. combine with fifo/auto/input flags */
40 #define CMD_START_DMA8 0xc0
41 #define CMD_START_DMA16 0xb0
44 #define CMD_INPUT 0x08
46 /* immediately pause/continue */
47 #define CMD_PAUSE_DMA8 0xd0
48 #define CMD_ENABLE_OUTPUT 0xd1
49 #define CMD_DISABLE_OUTPUT 0xd3
50 #define CMD_CONT_DMA8 0xd4
51 #define CMD_PAUSE_DMA16 0xd5
52 #define CMD_CONT_DMA16 0xd6
54 /* end the playback at the end of the current buffer */
55 #define CMD_END_DMA16 0xd9
56 #define CMD_END_DMA8 0xda
58 /* transfer mode commands */
59 #define CMD_MODE_SIGNED 0x10
60 #define CMD_MODE_STEREO 0x20
63 #define MIX_IRQ_SEL 0x80
64 #define MIX_DMA_SEL 0x81
66 #define VER_MAJOR(x) ((x) >> 8)
67 #define VER_MINOR(x) ((x) & 0xff)
69 /* delay for about 1us */
70 #define iodelay() outportb(0x80, 0)
72 static void intr_handler();
73 static void start_dma_transfer(uint32_t addr, int size);
74 static void write_dsp(unsigned char val);
75 static unsigned char read_dsp(void);
76 static void write_mix(unsigned char val, int reg);
77 static unsigned char read_mix(int reg);
78 static int get_dsp_version(void);
79 static int sb16_detect_irq(void);
80 static int sb16_detect_dma(void);
81 static const char *sbname(int ver);
83 extern unsigned char low_mem_buffer[];
86 static int irq, dma_chan, dma16_chan;
96 base_port = 0x200 + ((i + 1) << 4);
97 if(sb_reset_dsp() == 0) {
98 ver = get_dsp_version();
99 sb16 = VER_MAJOR(ver) >= 4;
102 if(sb16_detect_irq() == -1) {
103 printf("sb_detect: failed to configure IRQ\n");
106 if(sb16_detect_dma() == -1) {
107 printf("sb_detect: failed to configure DMA\n");
111 printf("sb_detect: found %s (DSP v%d.%02d) at port %xh, irq %d, dma %d/%d\n",
112 sbname(ver), VER_MAJOR(ver), VER_MINOR(ver),
113 base_port, irq, dma_chan, dma16_chan);
116 /* XXX for old sound blasters, hard-code to IRQ 5 DMA 1 for now */
121 printf("sb_detect: found %s (DSP v%d.%02d) at port %xh\n", sbname(ver),
122 VER_MAJOR(ver), VER_MINOR(ver), base_port);
123 printf("sb_detect: old sound blaster dsp. assuming: irq 5, dma 1\n");
133 int sb_reset_dsp(void)
137 outportb(REG_RESET, 1);
138 for(i=0; i<3; i++) iodelay();
139 outportb(REG_RESET, 0);
141 for(i=0; i<128; i++) {
142 if(inportb(REG_RSTAT) & RSTAT_RDY) {
143 if(inportb(REG_RDATA) == 0xaa) {
152 void sb_set_output_rate(int rate)
155 write_dsp(CMD_SB16_OUT_RATE);
156 write_dsp(rate >> 8);
157 write_dsp(rate & 0xff);
159 int tcon = 256 - 1000000 / rate;
165 void *sb_buffer(int *size)
171 void sb_start(int rate, int nchan)
176 _go32_dpmi_seginfo intr;
179 __djgpp_nearptr_enable();
181 /* allocate a 64k-aligned 64k buffer in low memory */
182 if((seg = __dpmi_allocate_dos_memory(65536 * 2 / 16, &pmsel)) <= 0) {
183 fprintf(stderr, "sb_start: failed to allocate DMA buffer\n");
187 printf("allocated seg: %d, addr: %lx\n", seg, (unsigned long)seg << 4);
189 addr = ((uint32_t)(seg << 4) + 0xffff) & 0xffff0000;
190 printf("aligned: %lx\n", (unsigned long)addr);
191 buffer = (void*)(addr - __djgpp_base_address);
193 addr = (uint32_t)buffer;
196 xfer_mode = CMD_MODE_SIGNED;
198 xfer_mode |= CMD_MODE_STEREO;
201 if(!(size = audio_callback(buffer, 65536))) {
205 intr.pm_offset = (intptr_t)intr_handler;
206 intr.pm_selector = _go32_my_cs();
208 _go32_dpmi_set_protected_mode_interrupt_vector(IRQ_TO_INTR(irq), &intr);
211 sb_set_output_rate(rate);
212 start_dma_transfer(addr, size);
213 write_dsp(CMD_ENABLE_OUTPUT);
218 write_dsp(CMD_PAUSE_DMA8);
221 void sb_continue(void)
223 write_dsp(CMD_CONT_DMA8);
228 write_dsp(CMD_END_DMA8);
229 write_dsp(CMD_DISABLE_OUTPUT);
232 void sb_volume(int vol)
237 static void intr_handler()
241 /* ask for more data */
242 if(!(size = audio_callback(buffer, 65536))) {
246 start_dma_transfer((uint32_t)buffer, size);
248 /* acknowledge the interrupt */
252 outportb(PIC2_CMD, OCW2_EOI);
254 outportb(PIC1_CMD, OCW2_EOI);
257 static void start_dma_transfer(uint32_t addr, int size)
259 /* set up the next DMA transfer */
260 dma_out(dma_chan, addr, size, DMA_SINGLE);
262 /* program the DSP to accept the DMA transfer */
263 write_dsp(CMD_START_DMA8 | CMD_FIFO);
264 write_dsp(xfer_mode);
266 write_dsp(size & 0xff);
267 write_dsp((size >> 8) & 0xff);
270 static void write_dsp(unsigned char val)
272 while(inportb(REG_WSTAT) & WSTAT_BUSY);
273 outportb(REG_WDATA, val);
276 static unsigned char read_dsp(void)
278 while((inportb(REG_RSTAT) & RSTAT_RDY) == 0);
279 return inportb(REG_RDATA);
282 static void write_mix(unsigned char val, int reg)
284 outportb(REG_MIXPORT, reg);
285 outportb(REG_MIXDATA, val);
288 static unsigned char read_mix(int reg)
290 outportb(REG_MIXPORT, reg);
291 return inportb(REG_MIXDATA);
294 static int get_dsp_version(void)
298 write_dsp(CMD_GET_VER);
302 return (major << 8) | minor;
305 static int sb16_detect_irq(void)
308 static int irqtab[] = {2, 5, 7, 10};
311 irqsel = read_mix(MIX_IRQ_SEL);
313 if(irqsel & (1 << i)) {
319 /* try to force IRQ 5 */
320 write_mix(2, MIX_IRQ_SEL); /* bit1 selects irq 5 */
322 /* re-read to verify */
323 irqsel = read_mix(MIX_IRQ_SEL);
333 static int sb16_detect_dma(void)
336 static int dmatab[] = {0, 1, -1, 3, -1, 5, 6, 7};
340 dmasel = read_mix(MIX_DMA_SEL);
342 if(dmasel & (1 << i)) {
343 dma_chan = dmatab[i];
348 if(dmasel & (1 << i)) {
349 dma16_chan = dmatab[i];
354 /* try to force DMA 1 */
357 if(dma16_chan == -1) {
358 /* try to force 16bit DMA 5 */
362 if(dma_chan == -1 || dma16_chan == -1) {
363 write_mix(dmasel, MIX_DMA_SEL);
365 /* re-read to verify */
366 tmp = read_mix(MIX_DMA_SEL);
377 #define V(maj, min) (((maj) << 8) | (min))
379 static const char *sbname(int ver)
381 int major = VER_MAJOR(ver);
382 int minor = VER_MINOR(ver);
387 return "Sound Blaster 1.5";
389 return "Sound Blaster 1.0";
392 if(minor == 1 || minor == 2) {
393 return "Sound Blaster 2.0";
400 return "Sound Blaster Pro";
403 return "Sound Blaster Pro 2";
405 return "Gallant SC-6000";
415 return "Sound Blaster 16";
417 return "Sound Blaster 16 SCSI-2";
419 return "Sound Blaster AWE 32";
421 return "Sound Blaster ViBRA16C";
423 return "Sound Blaster AWE 64";
430 return "Unknown Sound Blaster";