Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / sound / isa / i386 / sbxvi / sb16_dsp.c
1 /*
2  * sound/sb16_dsp.c
3  * 
4  * The low level driver for the SoundBlaster DSP chip.
5  * 
6  * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de)
7  * 
8  * based on SB-driver by (C) Hannu Savolainen
9  * 
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are
12  * met: 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer. 2.
14  * Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution.
17  * 
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
22  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD: src/sys/i386/isa/sound/sb16_dsp.c,v 1.33 1999/12/27 04:37:18 tanimura Exp $
31  * 
32  */
33
34 #define DEB(x)
35 #define DEB1(x)
36 #include <i386/isa/sound/sound_config.h>
37 #include "sb.h"
38 #include <i386/isa/sound/sb_mixer.h>
39 #include <i386/isa/sound/sbcard.h>
40
41 #if defined(CONFIG_SB16) && (NSB > 0) && defined(CONFIG_AUDIO) && defined(CONFIG_SBPRO)
42
43
44 extern sound_os_info *sb_osp;
45 extern int      sbc_base;
46
47 static int      sb16_dsp_ok = 0;
48 static int      dsp_16bit = 0;
49 static int      dsp_stereo = 0;
50 static int      dsp_current_speed = 8000;
51 static int      dsp_busy = 0;
52 static int      dma16, dma8;
53
54
55 static int      trigger_bits = 0;
56 static u_long dsp_count = 0;
57
58 static int      irq_mode = IMODE_NONE;
59 static int      my_dev = 0;
60
61 static volatile int intr_active = 0;
62
63 static int      sb16_dsp_open(int dev, int mode);
64 static void     sb16_dsp_close(int dev);
65 static void     sb16_dsp_output_block(int dev, u_long buf, int count, int intrflag, int dma_restart);
66 static void     sb16_dsp_start_input(int dev, u_long buf, int count, int intrflag, int dma_restart);
67 static int      sb16_dsp_ioctl(int dev, u_int cmd, ioctl_arg arg, int local);
68 static int      sb16_dsp_prepare_for_input(int dev, int bsize, int bcount);
69 static int      sb16_dsp_prepare_for_output(int dev, int bsize, int bcount);
70 static void     sb16_dsp_reset(int dev);
71 static void     sb16_dsp_halt(int dev);
72 static void     sb16_dsp_trigger(int dev, int bits);
73 static int      dsp_set_speed(int);
74 static int      dsp_set_stereo(int);
75 static void     dsp_cleanup(void);
76
77 static struct audio_operations sb16_dsp_operations =
78 {
79         "SoundBlaster 16",
80         DMA_AUTOMODE,
81         AFMT_U8 | AFMT_S16_LE,
82         NULL,
83         sb16_dsp_open,
84         sb16_dsp_close,
85         sb16_dsp_output_block,
86         sb16_dsp_start_input,
87         sb16_dsp_ioctl,
88         sb16_dsp_prepare_for_input,
89         sb16_dsp_prepare_for_output,
90         sb16_dsp_reset,
91         sb16_dsp_halt,
92         NULL,
93         NULL,
94         NULL,
95         NULL,
96         sb16_dsp_trigger
97 };
98
99 static int
100 sb_dsp_command01(u_char val)
101 {
102     int             i = 1 << 16;
103
104     while (--i & (!inb(DSP_STATUS) & 0x80));
105     if (!i)
106         printf("SB16 sb_dsp_command01 Timeout\n");
107     return sb_dsp_command(val);
108 }
109
110 static int
111 dsp_set_speed(int mode)
112 {
113     DEB(printf("dsp_set_speed(%d)\n", mode));
114     if (mode) {
115         RANGE (mode, 5000, 44100);
116         dsp_current_speed = mode;
117     }
118     return mode;
119 }
120
121 static int
122 dsp_set_stereo(int mode)
123 {
124     DEB(printf("dsp_set_stereo(%d)\n", mode));
125     dsp_stereo = mode;
126     return mode;
127 }
128
129 static int
130 dsp_set_bits(int arg)
131 {
132     DEB(printf("dsp_set_bits(%d)\n", arg));
133
134     if (arg)
135         dsp_16bit =  (arg == 16) ? 1 : 0 ;
136     return dsp_16bit ? 16 : 8;
137 }
138
139 static int
140 sb16_dsp_ioctl(int dev, u_int cmd, ioctl_arg arg, int local)
141 {
142     switch (cmd) {
143     case SOUND_PCM_WRITE_RATE:
144         if (local)
145             return dsp_set_speed((int) arg);
146         return *(int *) arg = dsp_set_speed((*(int *) arg));
147
148     case SOUND_PCM_READ_RATE:
149         if (local)
150             return dsp_current_speed;
151         return *(int *) arg = dsp_current_speed;
152
153     case SNDCTL_DSP_STEREO:
154         if (local)
155             return dsp_set_stereo((int) arg);
156         return *(int *) arg = dsp_set_stereo((*(int *) arg));
157
158     case SOUND_PCM_WRITE_CHANNELS:
159         if (local)
160             return dsp_set_stereo((int) arg - 1) + 1;
161         return *(int *) arg = dsp_set_stereo((*(int *) arg) - 1) + 1;
162
163     case SOUND_PCM_READ_CHANNELS:
164         if (local)
165             return dsp_stereo + 1;
166         return *(int *) arg = dsp_stereo + 1;
167
168     case SNDCTL_DSP_SETFMT:
169         if (local)
170             return dsp_set_bits((int) arg);
171         return *(int *) arg = dsp_set_bits((*(int *) arg));
172
173     case SOUND_PCM_READ_BITS:
174         if (local)
175             return dsp_16bit ? 16 : 8;
176         return *(int *) arg = dsp_16bit ? 16 : 8;
177
178     case SOUND_PCM_WRITE_FILTER:        /* NOT YET IMPLEMENTED */
179         if ((*(int *) arg) > 1)
180             return *(int *) arg = -(EINVAL);
181
182     case FIOASYNC:
183         if (local)
184             return 1;
185         return *(int *) arg = 1;
186
187     case FIONBIO:
188         if (local)
189             return 1;
190         return *(int *) arg = 1;
191
192     default:
193         return -(EINVAL);
194     }
195
196     return -(EINVAL);
197 }
198
199 static int
200 sb16_dsp_open(int dev, int mode)
201 {
202     DEB(printf("sb16_dsp_open()\n"));
203
204     if (!sb16_dsp_ok) {
205         printf("SB16 Error: SoundBlaster board not installed\n");
206         return -(ENXIO);
207     }
208     if (intr_active)
209         return -(EBUSY);
210
211     sb_reset_dsp();
212
213
214     irq_mode = IMODE_NONE;
215     dsp_busy = 1;
216     trigger_bits = 0;
217
218     return 0;
219 }
220
221 static void
222 sb16_dsp_close(int dev)
223 {
224     u_long   flags;
225
226     DEB(printf("sb16_dsp_close()\n"));
227     sb_dsp_command01(0xd9);
228     sb_dsp_command01(0xd5);
229
230     flags = splhigh();
231
232     audio_devs[dev]->dmachan1 = dma8;
233
234     dsp_cleanup();
235     dsp_busy = 0;
236
237
238     splx(flags);
239 }
240
241 static void
242 sb16_dsp_output_block(int dev, u_long buf, int count, int intrflag, int dma_restart)
243 {
244     u_long   flags, cnt;
245
246
247     cnt = count;
248     if (dsp_16bit)
249         cnt >>= 1;
250     cnt--;
251
252     if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt==dsp_count) {
253         irq_mode = IMODE_OUTPUT;
254         intr_active = 1;
255         return;         /* Auto mode on. No need to react */
256     }
257     flags = splhigh();
258
259     if (dma_restart) {
260
261         sb16_dsp_halt(dev);
262         DMAbuf_start_dma(dev, buf, count, 1);
263     }
264
265
266     sb_dsp_command(0x41);
267     sb_dsp_command((u_char) ((dsp_current_speed >> 8) & 0xff));
268     sb_dsp_command((u_char) (dsp_current_speed & 0xff));
269     sb_dsp_command((u_char) (dsp_16bit ? 0xb6 : 0xc6));
270     dsp_count = cnt;
271     sb_dsp_command((u_char) ((dsp_stereo ? 0x20 : 0) +
272                                 (dsp_16bit ? 0x10 : 0)));
273     sb_dsp_command((u_char) (cnt & 0xff));
274     sb_dsp_command((u_char) (cnt >> 8));
275
276     irq_mode = IMODE_OUTPUT;
277     intr_active = 1;
278     splx(flags);
279 }
280
281 static void
282 sb16_dsp_start_input(int dev, u_long buf, int count, int intrflag, int dma_restart)
283 {
284     u_long   flags, cnt;
285
286     cnt = count;
287     if (dsp_16bit)
288         cnt >>= 1;
289     cnt--;
290
291     if (audio_devs[dev]->flags & DMA_AUTOMODE && intrflag && cnt == dsp_count) {
292         irq_mode = IMODE_INPUT;
293         intr_active = 1;
294         return;         /* Auto mode on. No need to react */
295     }
296     flags = splhigh();
297
298     if (dma_restart) {
299         sb_reset_dsp();
300         DMAbuf_start_dma(dev, buf, count, 0);
301     }
302     sb_dsp_command(0x42);
303     sb_dsp_command((u_char) ((dsp_current_speed >> 8) & 0xff));
304     sb_dsp_command((u_char) (dsp_current_speed & 0xff));
305     sb_dsp_command((u_char) (dsp_16bit ? 0xbe : 0xce));
306     dsp_count = cnt;
307     sb_dsp_command((u_char) ((dsp_stereo ? 0x20 : 0) +
308                                     (dsp_16bit ? 0x10 : 0)));
309     sb_dsp_command01((u_char) (cnt & 0xff));
310     sb_dsp_command((u_char) (cnt >> 8));
311
312     irq_mode = IMODE_INPUT;
313     intr_active = 1;
314     splx(flags);
315 }
316
317 static int
318 sb16_dsp_prepare_for_input(int dev, int bsize, int bcount)
319 {
320     int fudge;
321     struct dma_buffparms *dmap =  audio_devs[dev]->dmap_in;
322
323     audio_devs[my_dev]->dmachan2 = dsp_16bit ? dma16 : dma8;
324
325
326     fudge =  audio_devs[my_dev]->dmachan2 ;
327
328     if (dmap->dma_chan != fudge ) {
329       isa_dma_release( dmap->dma_chan);
330       isa_dma_acquire(fudge);
331       dmap->dma_chan = fudge;
332     }
333
334     dsp_count = 0;
335     dsp_cleanup();
336     if (dsp_16bit) 
337         sb_dsp_command(0xd5);   /* Halt DMA until trigger() is called */
338     else
339         sb_dsp_command(0xd0);   /* Halt DMA until trigger() is called */
340
341     trigger_bits = 0;
342     return 0;
343 }
344
345 static int
346 sb16_dsp_prepare_for_output(int dev, int bsize, int bcount)
347 {
348     int fudge = dsp_16bit ? dma16 : dma8;
349     struct dma_buffparms *dmap =  audio_devs[dev]->dmap_out;
350
351     if (dmap->dma_chan != fudge ) {
352       isa_dma_release( dmap->dma_chan);
353       isa_dma_acquire(fudge);
354       dmap->dma_chan = fudge;
355     }
356
357     audio_devs[my_dev]->dmachan1 = fudge;
358
359     dsp_count = 0;
360     dsp_cleanup();
361     if (dsp_16bit) 
362         sb_dsp_command(0xd5);   /* Halt DMA until trigger() is called */
363     else
364         sb_dsp_command(0xd0);   /* Halt DMA until trigger() is called */
365
366     trigger_bits = 0;
367     return 0;
368 }
369
370 static void
371 sb16_dsp_trigger(int dev, int bits)
372 {
373     if (bits != 0)
374         bits = 1;
375
376     if (bits == trigger_bits)   /* No change */
377         return;
378
379     trigger_bits = bits;
380
381     if (!bits)
382         sb_dsp_command(0xd0);   /* Halt DMA */
383     else if (bits & irq_mode) {
384         if (dsp_16bit)
385             sb_dsp_command(0xd6);       /* Continue 16bit DMA */
386         else
387             sb_dsp_command(0xd4);       /* Continue 8bit DMA */
388     }
389 }
390
391 static void
392 dsp_cleanup(void)
393 {
394     irq_mode = IMODE_NONE;
395     intr_active = 0;
396 }
397
398 static void
399 sb16_dsp_reset(int dev)
400 {
401     u_long   flags;
402
403     flags = splhigh();
404
405     sb_reset_dsp();
406     dsp_cleanup();
407
408     splx(flags);
409 }
410
411 static void
412 sb16_dsp_halt(int dev)
413 {
414
415     if (dsp_16bit) {
416         sb_dsp_command01(0xd9);
417         sb_dsp_command01(0xd5);
418     } else {
419         sb_dsp_command01(0xda);
420         sb_dsp_command01(0xd0);
421     }
422
423
424 }
425
426 static void
427 set_irq_hw(int level)
428 {
429     int             ival;
430
431     switch (level) {
432 #ifdef PC98
433     case 5:
434         ival = 8;
435         break;
436     case 3:
437         ival = 1;
438         break;
439     case 10:
440         ival = 2;
441         break;  
442 #else
443     case 5:
444         ival = 2;
445         break;
446     case 7:
447         ival = 4;
448         break;
449     case 9:
450         ival = 1;
451         break;
452     case 10:
453         ival = 8;
454         break;
455 #endif
456     default:
457         printf("SB16_IRQ_LEVEL %d does not exist\n", level);
458         return;
459     }
460     sb_setmixer(IRQ_NR, ival);
461 }
462
463 void
464 sb16_dsp_init(struct address_info * hw_config)
465 {
466     if (sbc_major < 4)
467         return;         /* Not a SB16 */
468
469     snprintf(sb16_dsp_operations.name, sizeof(sb16_dsp_operations.name),
470         "SoundBlaster 16 %d.%d", sbc_major, sbc_minor);
471
472     conf_printf(sb16_dsp_operations.name, hw_config);
473
474     if (num_audiodevs < MAX_AUDIO_DEV) {
475         audio_devs[my_dev = num_audiodevs++] = &sb16_dsp_operations;
476         audio_devs[my_dev]->dmachan1 = dma8;
477         audio_devs[my_dev]->buffsize = DSP_BUFFSIZE;
478
479     } else
480         printf("SB: Too many DSP devices available\n");
481     sb16_dsp_ok = 1;
482     return;
483 }
484
485 int
486 sb16_dsp_detect(struct address_info * hw_config)
487 {
488     struct address_info *sb_config;
489
490     if (sb16_dsp_ok)
491         return 1;       /* Can't drive two cards */
492
493     if (!(sb_config = sound_getconf(SNDCARD_SB))) {
494         printf("SB16 Error: Plain SB not configured\n");
495         return 0;
496     }
497     /*
498      * sb_setmixer(OPSW,0xf); if(sb_getmixer(OPSW)!=0xf) return 0;
499      */
500
501     if (!sb_reset_dsp())
502         return 0;
503
504     if (sbc_major < 4)  /* Set by the plain SB driver */
505         return 0;       /* Not a SB16 */
506
507 #ifdef PC98
508     hw_config->dma = sb_config->dma;
509 #else 
510     if (hw_config->dma < 4)
511         if (hw_config->dma != sb_config->dma) {
512             printf("SB16 Error: Invalid DMA channel %d/%d\n",
513                    sb_config->dma, hw_config->dma);
514             return 0;
515         }
516 #endif
517     dma16 = hw_config->dma;
518     dma8 = sb_config->dma;
519     /*    hw_config->irq = 0;  sb_config->irq; 
520     hw_config->io_base = sb_config->io_base;
521     */
522     set_irq_hw(sb_config->irq);
523
524 #ifdef PC98
525     sb_setmixer (DMA_NR, hw_config->dma == 0 ? 1 : 2);
526 #else
527     sb_setmixer(DMA_NR, (1 << hw_config->dma) | (1 << sb_config->dma));
528 #endif
529
530     DEB(printf("SoundBlaster 16: IRQ %d DMA %d OK\n",
531                 sb_config->irq, hw_config->dma));
532
533     /*
534      * dsp_showmessage(0xe3,99);
535      */
536     sb16_dsp_ok = 1;
537     return 1;
538 }
539
540 void
541 sb16_dsp_interrupt(int unused)
542 {
543         int             data;
544
545         data = inb(DSP_DATA_AVL16);     /* Interrupt acknowledge */
546
547         if (intr_active)
548                 switch (irq_mode) {
549                 case IMODE_OUTPUT:
550                         DMAbuf_outputintr(my_dev, 1);
551                         break;
552
553                 case IMODE_INPUT:
554                         DMAbuf_inputintr(my_dev);
555                         break;
556
557                 default:
558                         printf("SoundBlaster: Unexpected interrupt\n");
559                 }
560 }
561 #endif