Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / sound / isa / i386 / sound_switch.c
1 /*
2  * sound/sound_switch.c
3  * 
4  * The system call switch
5  * 
6  * Copyright by Hannu Savolainen 1993
7  * 
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are
10  * met: 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer. 2.
12  * Redistributions in binary form must reproduce the above copyright notice,
13  * this list of conditions and the following disclaimer in the documentation
14  * and/or other materials provided with the distribution.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
20  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
23  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  * 
28  */
29
30 #include <i386/isa/sound/sound_config.h>
31
32 #if NSND > 0
33
34 #define SNDSTAT_BUF_SIZE        4000
35
36 /*
37  * /dev/sndstatus -device
38  */
39 static char    *status_buf = NULL;
40 static int      status_len, status_ptr;
41 static int      status_busy = 0;
42
43 static int
44 put_status(char *s)
45 {
46     int             l = strlen(s);
47
48     if (status_len + l >= SNDSTAT_BUF_SIZE)
49         return 0;
50
51     bcopy(s, &status_buf[status_len], l);
52     status_len += l;
53
54     return 1;
55 }
56
57 /*
58  * in principle, we never overflow the buffer. But... if radix=2 ...
59  * and if smaller... lr970711
60  */
61
62 static int
63 put_status_int(u_int val, int radix)
64 {
65     int             l, v;
66     static char     hx[] = "0123456789abcdef";
67     char            buf[33]; /* int is 32 bit+null, in base 2 */
68
69     if (radix < 2 || radix > 16)        /* better than panic */
70         return put_status("???");
71
72     if (!val)
73         return put_status("0");
74
75     l = 0;
76     buf[10] = 0;
77
78     while (val) {
79         v = val % radix;
80         val = val / radix;
81
82         buf[9 - l] = hx[v];
83         l++;
84     }
85
86     if (status_len + l >= SNDSTAT_BUF_SIZE)
87         return 0;
88
89     bcopy(&buf[10 - l], &status_buf[status_len], l);
90     status_len += l;
91
92     return 1;
93 }
94
95 static void
96 init_status(void)
97 {
98     /*
99      * Write the status information to the status_buf and update
100      * status_len. There is a limit of SNDSTAT_BUF_SIZE bytes for the data.
101      * put_status handles this and returns 0 in case of failure. Since
102      * it never oveflows the buffer, we do not care to check.
103      */
104
105     int             i;
106
107     status_ptr = 0;
108
109 #ifdef SOUND_UNAME_A
110     put_status("VoxWare Sound Driver:" SOUND_VERSION_STRING
111                " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY ",\n"
112                SOUND_UNAME_A ")\n");
113 #else
114     put_status("VoxWare Sound Driver:" SOUND_VERSION_STRING
115                " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
116                SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")\n");
117 #endif
118
119     put_status("Config options: ") ;
120     /*   put_status_int(SELECTED_SOUND_OPTIONS, 16) ; */
121     put_status("\n\nInstalled drivers: \n") ;
122
123     for (i = 0; i < num_sound_drivers; i++)
124         if (sound_drivers[i].card_type != 0) {
125             put_status("Type ") ;
126             put_status_int(sound_drivers[i].card_type, 10);
127             put_status(": ") ;
128             put_status(sound_drivers[i].name) ;
129             put_status("\n") ;
130         }
131     put_status("\n\nCard config: \n") ;
132
133     for (i = 0; i < num_sound_cards; i++)
134         if (snd_installed_cards[i].card_type != 0) {
135             int             drv, tmp;
136
137             if (!snd_installed_cards[i].enabled)
138                 put_status("(") ;
139
140             if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1)
141                 put_status(sound_drivers[drv].name) ;
142
143             put_status(" at 0x") ;
144             put_status_int(snd_installed_cards[i].config.io_base, 16);
145
146             put_status(" irq ") ;
147             tmp = snd_installed_cards[i].config.irq;
148             if (tmp < 0)
149                 tmp = -tmp;
150             put_status_int(tmp, 10) ;
151
152             if (snd_installed_cards[i].config.dma != -1) {
153                 put_status(" drq ") ;
154                 put_status_int(snd_installed_cards[i].config.dma, 10) ;
155                 if (snd_installed_cards[i].config.dma2 != -1) {
156                     put_status(",") ;
157                     put_status_int(snd_installed_cards[i].config.dma2, 10) ;
158                 }
159             }
160             if (!snd_installed_cards[i].enabled)
161                 put_status(")") ;
162
163             put_status("\n") ;
164         }
165     if (!sound_started) {
166         put_status("\n\n***** Sound driver not started *****\n\n");
167         return;
168     }
169 #ifndef CONFIG_AUDIO
170     put_status("\nAudio devices: NOT ENABLED IN CONFIG\n") ;
171 #else
172     put_status("\nAudio devices:\n") ;
173
174     for (i = 0; i < num_audiodevs; i++) {
175         put_status_int(i, 10) ;
176         put_status(": ") ;
177         put_status(audio_devs[i]->name) ;
178
179         if (audio_devs[i]->flags & DMA_DUPLEX)
180             put_status(" (DUPLEX)") ;
181
182         put_status("\n") ;
183     }
184 #endif
185
186 #ifndef CONFIG_SEQUENCER
187     put_status("\nSynth devices: NOT ENABLED IN CONFIG\n");
188 #else
189     put_status("\nSynth devices:\n") ;
190
191     for (i = 0; i < num_synths; i++) {
192         put_status_int(i, 10) ;
193         put_status(": ") ;
194         put_status(synth_devs[i]->info->name) ;
195         put_status("\n") ;
196     }
197 #endif
198
199 #ifndef CONFIG_MIDI
200     put_status("\nMidi devices: NOT ENABLED IN CONFIG\n") ;
201 #else
202     put_status("\nMidi devices:\n") ;
203
204     for (i = 0; i < num_midis; i++) {
205         put_status_int(i, 10) ;
206         put_status(": ") ;
207         put_status(midi_devs[i]->info.name) ;
208         put_status("\n") ;
209     }
210 #endif
211
212     put_status("\nTimers:\n");
213
214     for (i = 0; i < num_sound_timers; i++) {
215         put_status_int(i, 10);
216         put_status(": ");
217         put_status(sound_timer_devs[i]->info.name);
218         put_status("\n");
219     }
220
221     put_status("\nMixers:\n");
222
223     for (i = 0; i < num_mixers; i++) {
224         put_status_int(i, 10);
225         put_status(": ");
226         put_status(mixer_devs[i]->name);
227         put_status("\n");
228     }
229 }
230
231 static int
232 read_status(snd_rw_buf * buf, int count)
233 {
234     /*
235      * Return at most 'count' bytes from the status_buf.
236      */
237     int             l, c;
238
239     l = count;
240     c = status_len - status_ptr;
241
242     if (l > c)
243         l = c;
244     if (l <= 0)
245         return 0;
246
247
248     if (uiomove(&status_buf[status_ptr], l, buf)) {
249         printf("sb: Bad copyout()!\n");
250     };
251     status_ptr += l;
252
253     return l;
254 }
255
256 int
257 sound_read_sw(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
258 {
259     DEB(printf("sound_read_sw(dev=%d, count=%d)\n", dev, count));
260
261     switch (dev & 0x0f) {
262     case SND_DEV_STATUS:
263         return read_status(buf, count);
264         break;
265
266 #ifdef CONFIG_AUDIO
267     case SND_DEV_DSP:
268     case SND_DEV_DSP16:
269     case SND_DEV_AUDIO:
270         return audio_read(dev, file, buf, count);
271         break;
272 #endif
273
274 #ifdef CONFIG_SEQUENCER
275     case SND_DEV_SEQ:
276     case SND_DEV_SEQ2:
277         return sequencer_read(dev, file, buf, count);
278         break;
279 #endif
280
281 #ifdef CONFIG_MIDI
282     case SND_DEV_MIDIN:
283         return MIDIbuf_read(dev, file, buf, count);
284 #endif
285
286     default:
287         printf("Sound: Undefined minor device %d\n", dev);
288     }
289
290     return -(EPERM);
291 }
292
293 int
294 sound_write_sw(int dev, struct fileinfo * file, snd_rw_buf * buf, int count)
295 {
296
297     DEB(printf("sound_write_sw(dev=%d, count=%d)\n", dev, count));
298
299     switch (dev & 0x0f) {
300
301 #ifdef CONFIG_SEQUENCER
302     case SND_DEV_SEQ:
303     case SND_DEV_SEQ2:
304         return sequencer_write(dev, file, buf, count);
305         break;
306 #endif
307
308 #ifdef CONFIG_AUDIO
309     case SND_DEV_DSP:
310     case SND_DEV_DSP16:
311     case SND_DEV_AUDIO:
312         return audio_write(dev, file, buf, count);
313         break;
314 #endif
315
316 #ifdef CONFIG_MIDI
317     case SND_DEV_MIDIN:
318         return MIDIbuf_write(dev, file, buf, count);
319 #endif
320
321     default:
322         return -(EPERM);
323     }
324
325     return count;
326 }
327
328 int
329 sound_open_sw(int dev, struct fileinfo * file)
330 {
331     int             retval;
332
333     DEB(printf("sound_open_sw(dev=%d)\n", dev));
334
335     if ((dev >= SND_NDEVS) || (dev < 0)) {
336         printf("Invalid minor device %d\n", dev);
337         return -(ENXIO);
338     }
339     switch (dev & 0x0f) {
340     case SND_DEV_STATUS:
341         if (status_busy)
342             return -(EBUSY);
343         status_busy = 1;
344         if ((status_buf = (char *) malloc(SNDSTAT_BUF_SIZE, M_TEMP, M_WAITOK)) == NULL)
345             return -(EIO);
346         status_len = status_ptr = 0;
347         init_status();
348         break;
349
350     case SND_DEV_CTL:
351         return 0;
352         break;
353
354 #ifdef CONFIG_SEQUENCER
355     case SND_DEV_SEQ:
356     case SND_DEV_SEQ2:
357         if ((retval = sequencer_open(dev, file)) < 0)
358             return retval;
359         break;
360 #endif
361
362 #ifdef CONFIG_MIDI
363     case SND_DEV_MIDIN:
364         if ((retval = MIDIbuf_open(dev, file)) < 0)
365             return retval;
366         break;
367 #endif
368
369 #ifdef CONFIG_AUDIO
370     case SND_DEV_DSP:
371     case SND_DEV_DSP16:
372     case SND_DEV_AUDIO:
373         if ((retval = audio_open(dev, file)) < 0)
374             return retval;
375         break;
376 #endif
377
378     default:
379         printf("Invalid minor device %d\n", dev);
380         return -(ENXIO);
381     }
382
383     return 0;
384 }
385
386 void
387 sound_release_sw(int dev, struct fileinfo * file)
388 {
389
390     DEB(printf("sound_release_sw(dev=%d)\n", dev));
391
392     switch (dev & 0x0f) {
393     case SND_DEV_STATUS:
394         if (status_buf)
395             free(status_buf, M_TEMP);
396         status_buf = NULL;
397         status_busy = 0;
398         break;
399
400     case SND_DEV_CTL:
401         break;
402
403 #ifdef CONFIG_SEQUENCER
404     case SND_DEV_SEQ:
405     case SND_DEV_SEQ2:
406         sequencer_release(dev, file);
407         break;
408 #endif
409
410 #ifdef CONFIG_MIDI
411     case SND_DEV_MIDIN:
412         MIDIbuf_release(dev, file);
413         break;
414 #endif
415
416 #ifdef CONFIG_AUDIO
417     case SND_DEV_DSP:
418     case SND_DEV_DSP16:
419     case SND_DEV_AUDIO:
420         audio_release(dev, file);
421         break;
422 #endif
423
424     default:
425         printf("Sound error: Releasing unknown device 0x%02x\n", dev);
426     }
427 }
428
429 int
430 sound_ioctl_sw(int dev, struct fileinfo * file, u_int cmd, ioctl_arg arg)
431 {
432     DEB(printf("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
433
434     if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0)   /* Mixer ioctl */
435         if ((dev & 0x0f) != SND_DEV_CTL) {
436             int             dtype = dev & 0x0f;
437             int             mixdev;
438
439             switch (dtype) {
440 #ifdef CONFIG_AUDIO
441             case SND_DEV_DSP:
442             case SND_DEV_DSP16:
443             case SND_DEV_AUDIO:
444                 mixdev = audio_devs[dev >> 4]->mixer_dev;
445                 if (mixdev < 0 || mixdev >= num_mixers)
446                     return -(ENXIO);
447                 return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg);
448                 break;
449 #endif
450
451             default:
452                 return mixer_devs[0]->ioctl(0, cmd, arg);
453             }
454         }
455     switch (dev & 0x0f) {
456
457     case SND_DEV_CTL:
458
459         if (!num_mixers)
460             return -(ENXIO);
461
462         dev = dev >> 4;
463
464         if (dev >= num_mixers)
465             return -(ENXIO);
466
467         return mixer_devs[dev]->ioctl(dev, cmd, arg);
468             break;
469
470 #ifdef CONFIG_SEQUENCER
471     case SND_DEV_SEQ:
472     case SND_DEV_SEQ2:
473         return sequencer_ioctl(dev, file, cmd, arg);
474         break;
475 #endif
476
477 #ifdef CONFIG_AUDIO
478     case SND_DEV_DSP:
479     case SND_DEV_DSP16:
480     case SND_DEV_AUDIO:
481         return audio_ioctl(dev, file, cmd, arg);
482         break;
483 #endif
484
485 #ifdef CONFIG_MIDI
486     case SND_DEV_MIDIN:
487         return MIDIbuf_ioctl(dev, file, cmd, arg);
488         break;
489 #endif
490
491     default:
492         return -(EPERM);
493         break;
494     }
495
496     return -(EPERM);
497 }
498
499 #endif