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
drv_init(void)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
drv_init_hw(void)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
drv_reset(void)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
drv_start(int channel,int DmaMode)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
drv_stop(int sub_dev)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
drv_set_dma(u32_t dma,u32_t UNUSED (length),int UNUSED (chan))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
drv_reenable_int(int UNUSED (chan))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
drv_int_sum(void)209 int drv_int_sum(void) {
210 return mixer_get(MIXER_IRQ_STATUS) & 0x0F;
211 }
212
213
214
drv_int(int sub_dev)215 int drv_int(int sub_dev) {
216 return sub_dev == AUDIO && mixer_get(MIXER_IRQ_STATUS) & 0x03;
217 }
218
219
220
drv_pause(int chan)221 int drv_pause(int chan) {
222 drv_stop(chan);
223 return OK;
224 }
225
226
227
drv_resume(int UNUSED (chan))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
drv_io_ctl(unsigned long request,void * val,int * len,int sub_dev)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
drv_get_irq(char * irq)250 int drv_get_irq(char *irq) {
251 Dprint(("drv_get_irq():\n"));
252 *irq = SB_IRQ;
253 return OK;
254 }
255
256
257
drv_get_frag_size(u32_t * frag_size,int UNUSED (sub_dev))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
dsp_ioctl(unsigned long request,void * val,int * len)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
dsp_dma_setup(phys_bytes address,int count,int DmaMode)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
dsp_set_size(unsigned int size)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
dsp_set_speed(unsigned int speed)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
dsp_set_stereo(unsigned int stereo)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
dsp_set_bits(unsigned int bits)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
dsp_set_sign(unsigned int sign)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
dsp_get_max_frag_size(u32_t * val,int * len)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
dsp_command(int value)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
sb16_inb(int port)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
sb16_outb(int port,int value)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