xref: /minix/minix/drivers/audio/sb16/sb16.c (revision 7f5f010b)
1 /*  Driver for SB16 ISA card
2  *  Implementing audio/audio_fw.h
3  *
4  *  February 2006   Integrated standalone driver with audio framework (Peter Boonstoppel)
5  *  August 24 2005  Ported audio driver to user space (only audio playback) (Peter Boonstoppel)
6  *  May 20 1995	    SB16 Driver: Michel R. Prevenier
7  */
8 
9 
10 #include "sb16.h"
11 #include "mixer.h"
12 
13 
14 static void dsp_dma_setup(phys_bytes address, int count, int sub_dev);
15 
16 static int dsp_ioctl(unsigned long request, void *val, int *len);
17 static int dsp_set_size(unsigned int size);
18 static int dsp_set_speed(unsigned int speed);
19 static int dsp_set_stereo(unsigned int stereo);
20 static int dsp_set_bits(unsigned int bits);
21 static int dsp_set_sign(unsigned int sign);
22 static int dsp_get_max_frag_size(u32_t *val, int *len);
23 
24 
25 static unsigned int DspStereo = DEFAULT_STEREO;
26 static unsigned int DspSpeed = DEFAULT_SPEED;
27 static unsigned int DspBits = DEFAULT_BITS;
28 static unsigned int DspSign = DEFAULT_SIGN;
29 static unsigned int DspFragmentSize;
30 
31 static phys_bytes DmaPhys;
32 static int running = FALSE;
33 
34 
35 sub_dev_t sub_dev[2];
36 special_file_t special_file[3];
37 drv_t drv;
38 
39 
40 
41 int drv_init(void) {
42 	drv.DriverName = "SB16";
43 	drv.NrOfSubDevices = 2;
44 	drv.NrOfSpecialFiles = 3;
45 
46 	sub_dev[AUDIO].readable = 1;
47 	sub_dev[AUDIO].writable = 1;
48 	sub_dev[AUDIO].DmaSize = 64 * 1024;
49 	sub_dev[AUDIO].NrOfDmaFragments = 2;
50 	sub_dev[AUDIO].MinFragmentSize = 1024;
51 	sub_dev[AUDIO].NrOfExtraBuffers = 4;
52 
53 	sub_dev[MIXER].writable = 0;
54 	sub_dev[MIXER].readable = 0;
55 
56 	special_file[0].minor_dev_nr = 0;
57 	special_file[0].write_chan = AUDIO;
58 	special_file[0].read_chan = NO_CHANNEL;
59 	special_file[0].io_ctl = AUDIO;
60 
61 	special_file[1].minor_dev_nr = 1;
62 	special_file[1].write_chan = NO_CHANNEL;
63 	special_file[1].read_chan = AUDIO;
64 	special_file[1].io_ctl = AUDIO;
65 
66 	special_file[2].minor_dev_nr = 2;
67 	special_file[2].write_chan = NO_CHANNEL;
68 	special_file[2].read_chan = NO_CHANNEL;
69 	special_file[2].io_ctl = MIXER;
70 
71 	return OK;
72 }
73 
74 
75 int drv_init_hw(void) {
76 	int i;
77 	int DspVersion[2];
78 	Dprint(("drv_init_hw():\n"));
79 
80 	if(drv_reset () != OK) {
81 		Dprint(("sb16: No SoundBlaster card detected\n"));
82 		return -1;
83 	}
84 
85 	DspVersion[0] = DspVersion[1] = 0;
86 	dsp_command(DSP_GET_VERSION);	/* Get DSP version bytes */
87 
88 	for(i = 1000; i; i--) {
89 		if(sb16_inb(DSP_DATA_AVL) & 0x80) {
90 			if(DspVersion[0] == 0) {
91 				DspVersion[0] = sb16_inb(DSP_READ);
92 			} else {
93 				DspVersion[1] = sb16_inb(DSP_READ);
94 				break;
95 			}
96 		}
97 	}
98 
99 	if(DspVersion[0] < 4) {
100 		Dprint(("sb16: No SoundBlaster 16 compatible card detected\n"));
101 		return -1;
102 	}
103 
104 	Dprint(("sb16: SoundBlaster DSP version %d.%d detected!\n", DspVersion[0], DspVersion[1]));
105 
106 	/* set SB to use our IRQ and DMA channels */
107 	mixer_set(MIXER_SET_IRQ, (1 << (SB_IRQ / 2 - 1)));
108 	mixer_set(MIXER_SET_DMA, (1 << SB_DMA_8 | 1 << SB_DMA_16));
109 
110 	DspFragmentSize = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments;
111 
112 	return OK;
113 }
114 
115 
116 
117 int drv_reset(void) {
118 	int i;
119 	Dprint(("drv_reset():\n"));
120 
121 	sb16_outb(DSP_RESET, 1);
122 	for(i = 0; i < 1000; i++); /* wait a while */
123 	sb16_outb(DSP_RESET, 0);
124 
125 	for(i = 0; i < 1000 && !(sb16_inb(DSP_DATA_AVL) & 0x80); i++);
126 
127 	if(sb16_inb(DSP_READ) != 0xAA) return EIO; /* No SoundBlaster */
128 
129 	return OK;
130 }
131 
132 
133 
134 int drv_start(int channel, int DmaMode) {
135 	Dprint(("drv_start():\n"));
136 
137 	drv_reset();
138 
139 	dsp_dma_setup(DmaPhys, DspFragmentSize * sub_dev[channel].NrOfDmaFragments, DmaMode);
140 
141 	dsp_set_speed(DspSpeed);
142 
143 	/* Put the speaker on */
144 	if(DmaMode == WRITE_DMA) {
145 		dsp_command (DSP_CMD_SPKON); /* put speaker on */
146 
147 		/* Program DSP with dma mode */
148 		dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_OUT : DSP_CMD_16BITAUTO_OUT));
149 	} else {
150 		dsp_command (DSP_CMD_SPKOFF); /* put speaker off */
151 
152 		/* Program DSP with dma mode */
153 		dsp_command((DspBits == 8 ? DSP_CMD_8BITAUTO_IN : DSP_CMD_16BITAUTO_IN));
154 	}
155 
156 	/* Program DSP with transfer mode */
157 	if (!DspSign) {
158 		dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_US : DSP_MODE_MONO_US));
159 	} else {
160 		dsp_command((DspStereo == 1 ? DSP_MODE_STEREO_S : DSP_MODE_MONO_S));
161 	}
162 
163 	/* Give length of fragment to DSP */
164 	if (DspBits == 8) { /* 8 bit transfer */
165 		/* #bytes - 1 */
166 		dsp_command((DspFragmentSize - 1) >> 0);
167 		dsp_command((DspFragmentSize - 1) >> 8);
168 	} else {             /* 16 bit transfer */
169 		/* #words - 1 */
170 		dsp_command((DspFragmentSize - 1) >> 1);
171 		dsp_command((DspFragmentSize - 1) >> 9);
172 	}
173 
174 	running = TRUE;
175 
176 	return OK;
177 }
178 
179 
180 
181 int drv_stop(int sub_dev) {
182 	if(running) {
183 		Dprint(("drv_stop():\n"));
184 		dsp_command((DspBits == 8 ? DSP_CMD_DMA8HALT : DSP_CMD_DMA16HALT));
185 		running = FALSE;
186 		drv_reenable_int(sub_dev);
187 	}
188 	return OK;
189 }
190 
191 
192 
193 int drv_set_dma(u32_t dma, u32_t UNUSED(length), int UNUSED(chan)) {
194 	Dprint(("drv_set_dma():\n"));
195 	DmaPhys = dma;
196 	return OK;
197 }
198 
199 
200 
201 int drv_reenable_int(int UNUSED(chan)) {
202 	Dprint(("drv_reenable_int()\n"));
203 	sb16_inb((DspBits == 8 ? DSP_DATA_AVL : DSP_DATA16_AVL));
204 	return OK;
205 }
206 
207 
208 
209 int drv_int_sum(void) {
210 	return mixer_get(MIXER_IRQ_STATUS) & 0x0F;
211 }
212 
213 
214 
215 int drv_int(int sub_dev) {
216 	return sub_dev == AUDIO && mixer_get(MIXER_IRQ_STATUS) & 0x03;
217 }
218 
219 
220 
221 int drv_pause(int chan) {
222 	drv_stop(chan);
223 	return OK;
224 }
225 
226 
227 
228 int drv_resume(int UNUSED(chan)) {
229 	dsp_command((DspBits == 8 ? DSP_CMD_DMA8CONT : DSP_CMD_DMA16CONT));
230 	return OK;
231 }
232 
233 
234 
235 int drv_io_ctl(unsigned long request, void *val, int *len, int sub_dev) {
236 	Dprint(("dsp_ioctl: got ioctl %lu, argument: %d sub_dev: %d\n",
237 		request, val, sub_dev));
238 
239 	if(sub_dev == AUDIO) {
240 		return dsp_ioctl(request, val, len);
241 	} else if(sub_dev == MIXER) {
242 		return mixer_ioctl(request, val, len);
243 	}
244 
245 	return EIO;
246 }
247 
248 
249 
250 int drv_get_irq(char *irq) {
251 	Dprint(("drv_get_irq():\n"));
252 	*irq = SB_IRQ;
253 	return OK;
254 }
255 
256 
257 
258 int drv_get_frag_size(u32_t *frag_size, int UNUSED(sub_dev)) {
259 	Dprint(("drv_get_frag_size():\n"));
260 	*frag_size = DspFragmentSize;
261 	return OK;
262 }
263 
264 
265 
266 static int dsp_ioctl(unsigned long request, void *val, int *len) {
267 	int status;
268 
269 	switch(request) {
270 		case DSPIORATE:		status = dsp_set_speed(*((u32_t*) val)); break;
271 		case DSPIOSTEREO:	status = dsp_set_stereo(*((u32_t*) val)); break;
272 		case DSPIOBITS:		status = dsp_set_bits(*((u32_t*) val)); break;
273 		case DSPIOSIZE:		status = dsp_set_size(*((u32_t*) val)); break;
274 		case DSPIOSIGN:		status = dsp_set_sign(*((u32_t*) val)); break;
275 		case DSPIOMAX:		status = dsp_get_max_frag_size(val, len); break;
276 		case DSPIORESET:    status = drv_reset(); break;
277 		default:            status = ENOTTY; break;
278 	}
279 
280 	return status;
281 }
282 
283 
284 
285 static void dsp_dma_setup(phys_bytes address, int count, int DmaMode) {
286 	pvb_pair_t pvb[9];
287 
288 	Dprint(("Setting up %d bit DMA\n", DspBits));
289 
290 	if(DspBits == 8) {   /* 8 bit sound */
291 		count--;
292 
293 		pv_set(pvb[0], DMA8_MASK, SB_DMA_8 | 0x04);      /* Disable DMA channel */
294 		pv_set(pvb[1], DMA8_CLEAR, 0x00);		       /* Clear flip flop */
295 
296 		/* set DMA mode */
297 		pv_set(pvb[2], DMA8_MODE, (DmaMode == WRITE_DMA ? DMA8_AUTO_PLAY : DMA8_AUTO_REC));
298 
299 		pv_set(pvb[3], DMA8_ADDR, (u8_t)(address >>  0)); /* Low_byte of address */
300 		pv_set(pvb[4], DMA8_ADDR, (u8_t)(address >>  8)); /* High byte of address */
301 		pv_set(pvb[5], DMA8_PAGE, (u8_t)(address >> 16)); /* 64K page number */
302 		pv_set(pvb[6], DMA8_COUNT, (u8_t)(count >> 0));   /* Low byte of count */
303 		pv_set(pvb[7], DMA8_COUNT, (u8_t)(count >> 8));   /* High byte of count */
304 		pv_set(pvb[8], DMA8_MASK, SB_DMA_8);              /* Enable DMA channel */
305 
306 		sys_voutb(pvb, 9);
307 	} else {  /* 16 bit sound */
308 		count -= 2;
309 
310 		pv_set(pvb[0], DMA16_MASK, (SB_DMA_16 & 3) | 0x04);	/* Disable DMA channel */
311 
312 		pv_set(pvb[1], DMA16_CLEAR, 0x00);                  /* Clear flip flop */
313 
314 		/* Set dma mode */
315 		pv_set(pvb[2], DMA16_MODE, (DmaMode == WRITE_DMA ? DMA16_AUTO_PLAY : DMA16_AUTO_REC));
316 
317 		pv_set(pvb[3], DMA16_ADDR, (address >> 1) & 0xFF);  /* Low_byte of address */
318 		pv_set(pvb[4], DMA16_ADDR, (address >> 9) & 0xFF);  /* High byte of address */
319 		pv_set(pvb[5], DMA16_PAGE, (address >> 16) & 0xFE); /* 128K page number */
320 		pv_set(pvb[6], DMA16_COUNT, (u8_t)(count >> 1));    /* Low byte of count */
321 		pv_set(pvb[7], DMA16_COUNT, (u8_t)(count >> 9));    /* High byte of count */
322 		pv_set(pvb[8], DMA16_MASK, SB_DMA_16 & 3);          /* Enable DMA channel */
323 
324 		sys_voutb(pvb, 9);
325 	}
326 }
327 
328 
329 
330 static int dsp_set_size(unsigned int size) {
331 	Dprint(("dsp_set_size(): set fragment size to %u\n", size));
332 
333 	/* Sanity checks */
334 	if(size < sub_dev[AUDIO].MinFragmentSize || size > sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments || size % 2 != 0) {
335 		return EINVAL;
336 	}
337 
338 	DspFragmentSize = size;
339 
340 	return OK;
341 }
342 
343 
344 
345 static int dsp_set_speed(unsigned int speed) {
346 	Dprint(("sb16: setting speed to %u, stereo = %d\n", speed, DspStereo));
347 
348 	if(speed < DSP_MIN_SPEED || speed > DSP_MAX_SPEED) {
349 		return EPERM;
350 	}
351 
352 	/* Soundblaster 16 can be programmed with real sample rates
353 	* instead of time constants
354 	*
355 	* Since you cannot sample and play at the same time
356 	* we set in- and output rate to the same value
357 	*/
358 
359 	dsp_command(DSP_INPUT_RATE);		/* set input rate */
360 	dsp_command(speed >> 8);			/* high byte of speed */
361 	dsp_command(speed);			 		/* low byte of speed */
362 	dsp_command(DSP_OUTPUT_RATE);		/* same for output rate */
363 	dsp_command(speed >> 8);
364 	dsp_command(speed);
365 
366 	DspSpeed = speed;
367 
368 	return OK;
369 }
370 
371 
372 
373 static int dsp_set_stereo(unsigned int stereo) {
374 	if(stereo) {
375 		DspStereo = 1;
376 	} else {
377 		DspStereo = 0;
378 	}
379 
380 	return OK;
381 }
382 
383 
384 
385 static int dsp_set_bits(unsigned int bits) {
386 	/* Sanity checks */
387 	if(bits != 8 && bits != 16) {
388 		return EINVAL;
389 	}
390 
391 	DspBits = bits;
392 
393 	return OK;
394 }
395 
396 
397 
398 static int dsp_set_sign(unsigned int sign) {
399 	Dprint(("sb16: set sign to %u\n", sign));
400 
401 	DspSign = (sign > 0 ? 1 : 0);
402 
403 	return OK;
404 }
405 
406 
407 
408 static int dsp_get_max_frag_size(u32_t *val, int *len) {
409 	*len = sizeof(*val);
410 	*val = sub_dev[AUDIO].DmaSize / sub_dev[AUDIO].NrOfDmaFragments;
411 	return OK;
412 }
413 
414 
415 
416 int dsp_command(int value) {
417 	int i;
418 
419 	for (i = 0; i < SB_TIMEOUT; i++) {
420 		if((sb16_inb(DSP_STATUS) & 0x80) == 0) {
421 			sb16_outb(DSP_COMMAND, value);
422 			return OK;
423 		}
424 	}
425 
426 	Dprint(("sb16: SoundBlaster: DSP Command(%x) timeout\n", value));
427 	return -1;
428 }
429 
430 
431 
432 int sb16_inb(int port) {
433 	int s;
434 	u32_t value;
435 
436 	if ((s=sys_inb(port, &value)) != OK)
437 		panic("sys_inb() failed: %d", s);
438 
439 	return (int) value;
440 }
441 
442 
443 
444 void sb16_outb(int port, int value) {
445 	int s;
446 
447 	if ((s=sys_outb(port, value)) != OK)
448 		panic("sys_outb() failed: %d", s);
449 }
450