This commit was generated by cvs2svn to track changes on a CVS vendor
[unix-history] / sys / i386 / isa / sound / soundcard.c
CommitLineData
1b261ae5
JH
1/*
2 * sound/386bsd/soundcard.c
3 *
1d43110e 4 * Soundcard driver for FreeBSD.
1b261ae5 5 *
1d43110e
JH
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
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
1b261ae5
JH
29 */
30
31#include "sound_config.h"
32
33#ifdef CONFIGURE_SOUNDCARD
34
35#include "dev_table.h"
36
37int __timeout_val = 0;
38int __process_aborting = 0;
39
40u_int snd1mask;
41u_int snd2mask;
42u_int snd3mask;
43u_int snd4mask;
44u_int snd5mask;
45
46struct sbc_device
47{
48 int usecount;
49};
50
51#define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
52
53static struct sbc_device sbc_devices[SND_NDEVS];
54static int timer_running = 0;
55
56static int in_use = 0; /* Total # of open device files (excluding
57 * minor 0) */
58
59static int soundcards_installed = 0; /* Number of installed
60 * soundcards */
61static int soundcard_configured = 0;
62extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
63extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
64extern int snd_raw_count[MAX_DSP_DEV];
65
66static struct fileinfo files[SND_NDEVS];
67
68int sndprobe (struct isa_device *dev);
69int sndattach (struct isa_device *dev);
70int sndopen (dev_t dev, int flags);
71int sndclose (dev_t dev, int flags);
72int sndioctl (dev_t dev, int cmd, caddr_t arg, int mode);
73int sndread (int dev, struct uio *uio);
74int sndwrite (int dev, struct uio *uio);
75int sndselect (int dev, int rw);
76static void sound_mem_init(void);
77
78int
79get_time()
80{
81extern struct timeval time;
82
83 return(time.tv_usec + (time.tv_sec*1000000));
84}
85
86
87int
88sndread (int dev, struct uio *buf)
89{
90 int count = buf->uio_resid;
91
92 dev = minor (dev);
93
94 DEB (printk ("sound_read(dev=%d, count=%d)\n", dev, count));
95
1d43110e 96 switch (dev & 0x0f) /* It really has to be 0x0f */
1b261ae5
JH
97 {
98 case SND_DEV_AUDIO:
99 FIX_RETURN (audio_read (dev, &files[dev], buf, count));
100 break;
101
102 case SND_DEV_DSP:
103 case SND_DEV_DSP16:
104 FIX_RETURN (dsp_read (dev, &files[dev], buf, count));
105 break;
106
107 case SND_DEV_SEQ:
108 FIX_RETURN (sequencer_read (dev, &files[dev], buf, count));
109 break;
110
111#ifndef EXCLUDE_CHIP_MIDI
112 case CMIDI_DEV_PRO:
113 FIX_RETURN (CMIDI_read (dev, &files[dev], buf, count));
114
115 break;
116#endif
117
118
119#ifndef EXCLUDE_MPU401
120 case SND_DEV_MIDIN:
121 FIX_RETURN (MIDIbuf_read (dev, &files[dev], buf, count));
122#endif
123
124 default:
125 ;
126 }
127
128 FIX_RETURN (-EPERM);
129}
130
131int
132sndwrite (int dev, struct uio *buf)
133{
134 int count = buf->uio_resid;
135
136 DEB (printk ("sound_write(dev=%d, count=%d)\n", dev, count));
137
138 dev = minor (dev);
139
1d43110e 140 switch (dev & 0x0f) /* It really has to be 0x0f */
1b261ae5
JH
141 {
142
143 case SND_DEV_SEQ:
144 FIX_RETURN (sequencer_write (dev, &files[dev], buf, count));
145 break;
146
147 case SND_DEV_AUDIO:
148 FIX_RETURN (audio_write (dev, &files[dev], buf, count));
149 break;
150
151 case SND_DEV_DSP:
152 case SND_DEV_DSP16:
153 FIX_RETURN (dsp_write (dev, &files[dev], buf, count));
154 break;
155
156#ifndef EXCLUDE_CHIP_MIDI
157 case CMIDI_DEV_PRO:
158 FIX_RETURN (CMIDI_write (dev, &files[dev], buf, count));
159 break;
160#endif
161
162 default:
163 FIX_RETURN (-EPERM);
164 }
165
166 FIX_RETURN (count);
167}
168
169int
170sndopen (dev_t dev, int flags)
171{
172 int retval;
173
174 dev = minor (dev);
175
176 /* printf("SND: Minor number is now : %ld\n",dev); */
177
178 DEB (printk ("sound_open(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount));
179
180 if ((dev >= SND_NDEVS) || (dev < 0))
181 {
182 printk ("Invalid minor device %d\n", dev);
183 FIX_RETURN (-ENODEV);
184 }
185
186 if (!soundcard_configured && dev)
187 {
188 printk ("SoundCard Error: The soundcard system has not been configured\n");
189 FIX_RETURN (-ENODEV);
190 }
191
192 files[dev].mode = 0;
193
194 if (flags & FREAD && flags & FWRITE)
195 files[dev].mode = OPEN_READWRITE;
196 else if (flags & FREAD)
197 files[dev].mode = OPEN_READ;
198 else if (flags & FWRITE)
199 files[dev].mode = OPEN_WRITE;
200
1d43110e 201 switch (dev & 0x0f) /* It has to be 0x0f. Trust me */
1b261ae5
JH
202 {
203 case SND_DEV_CTL:
204 if (!soundcards_installed)
205 if (soundcard_configured)
206 {
207 printk ("Soundcard not installed\n");
208 FIX_RETURN (-ENODEV);
209 }
210 break;
211
212 case SND_DEV_SEQ:
213 if ((retval = sequencer_open (dev, &files[dev])) < 0)
214 FIX_RETURN (retval);
215 break;
216
217/** UWM stuff **/
218
219#ifndef EXCLUDE_CHIP_MIDI
220 case CMIDI_DEV_PRO:
221 FIX_RETURN ( CMIDI_open (dev, &files[dev]) );
222 break;
223#endif
224
225
226#ifndef EXCLUDE_MPU401
227 case SND_DEV_MIDIN:
228 if ((retval = MIDIbuf_open (dev, &files[dev])) < 0)
229 FIX_RETURN (retval);
230 break;
231#endif
232
233 case SND_DEV_AUDIO:
234 if ((retval = audio_open (dev, &files[dev])) < 0)
235 FIX_RETURN (retval);
236 break;
237
238 case SND_DEV_DSP:
239 if ((retval = dsp_open (dev, &files[dev], 8)) < 0)
240 FIX_RETURN (retval);
241 break;
242
243 case SND_DEV_DSP16:
244 if ((retval = dsp_open (dev, &files[dev], 16)) < 0)
245 FIX_RETURN (retval);
246 break;
247
248 default:
249 printk ("Invalid minor device %d\n", dev);
250 FIX_RETURN (-ENODEV);
251 }
252
253 sbc_devices[dev].usecount++;
254 in_use++;
255
256 FIX_RETURN (0);
257}
258
259int
260sndclose (dev_t dev, int flags)
261{
262
263 dev = minor (dev);
264
265 DEB (printk ("sound_release(dev=%d)\n", dev));
266
1d43110e 267 switch (dev & 0x0f) /* Has to be 0x0f */
1b261ae5
JH
268 {
269 case SND_DEV_SEQ:
270 sequencer_release (dev, &files[dev]);
271 break;
272
273#ifndef EXCLUDE_CHIP_MIDI
274 case CMIDI_DEV_PRO:
275 CMIDI_close (dev, &files[dev]);
276 break;
277#endif
278
279#ifndef EXCLUDE_MPU401
280 case SND_DEV_MIDIN:
281 MIDIbuf_release (dev, &files[dev]);
282 break;
283#endif
284
285 case SND_DEV_AUDIO:
286 audio_release (dev, &files[dev]);
287 break;
288
289 case SND_DEV_DSP:
290 case SND_DEV_DSP16:
291 dsp_release (dev, &files[dev]);
292 break;
293
294 default:;
295 }
296
297 sbc_devices[dev].usecount--;
298 in_use--; /* If not control port */
299
300 FIX_RETURN (0);
301}
302
303int
304sndioctl (dev_t dev, int cmd, caddr_t arg, int mode)
305{
306 dev = minor (dev);
307
308 DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
309
310 switch (dev & 0x0f)
311 {
312
313 case SND_DEV_CTL:
314 if (!num_mixers)
315 FIX_RETURN (-ENODEV);
316
317 if (dev >= num_mixers)
318 FIX_RETURN (-ENODEV);
319
320 FIX_RETURN (mixer_devs[dev]->ioctl (dev, cmd, (unsigned int) arg));
321 break;
322
323 case SND_DEV_SEQ:
324 FIX_RETURN (sequencer_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
325 break;
326
327 case SND_DEV_AUDIO:
328 FIX_RETURN (audio_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
329 break;
330
331 case SND_DEV_DSP:
332 case SND_DEV_DSP16:
333 FIX_RETURN (dsp_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
334 break;
335
336#ifndef EXCLUDE_MPU401
337 case SND_DEV_MIDIN:
338 FIX_RETURN (MIDIbuf_ioctl (dev, &files[dev], cmd, (unsigned int) arg));
339 break;
340#endif
341
342 default:
343 FIX_RETURN (-EPERM);
344 break;
345 }
346
347 FIX_RETURN (-EPERM);
348}
349
350int
351sndselect (int dev, int rw)
352{
353 dev = minor (dev);
354
355 DEB (printk ("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
356
357 FIX_RETURN (0);
358}
359
46c2d4f5 360static unsigned short
1d43110e 361ipri_to_irq (unsigned short ipri)
1b261ae5
JH
362{
363 /*
364 * Converts the ipri (bitmask) to the corresponding irq number
365 */
366 int irq;
367
368 for (irq = 0; irq < 16; irq++)
369 if (ipri == (1 << irq))
370 return irq;
371
372 return -1; /* Invalid argument */
373}
374
375int
376sndprobe (struct isa_device *dev)
377{
378 struct address_info hw_config;
379
380 hw_config.io_base = dev->id_iobase;
381 hw_config.irq = ipri_to_irq (dev->id_irq);
382 hw_config.dma = dev->id_drq;
383
384
385 return sndtable_probe (dev->id_unit, &hw_config);
386}
387
388int
389sndattach (struct isa_device *dev)
390{
391 int i;
392 static int dsp_initialized = 0;
393 static int midi_initialized = 0;
394 static int seq_initialized = 0;
395 static int generic_midi_initialized = 0;
396 unsigned long mem_start = 0xefffffff;
397 struct address_info hw_config;
398
399 hw_config.io_base = dev->id_iobase;
400 hw_config.irq = ipri_to_irq (dev->id_irq);
401 hw_config.dma = dev->id_drq;
402
403 if (dev->id_unit) /* Card init */
404 if (!sndtable_init_card (dev->id_unit, &hw_config))
405 {
406 printf (" <Driver not configured>");
407 return FALSE;
408 }
409
410 /*
411 * Init the high level sound driver
412 */
413
414 if (!(soundcards_installed = sndtable_get_cardcount ()))
415 {
416 printf (" <No such hardware>");
417 return FALSE; /* No cards detected */
418 }
419
1d43110e
JH
420 printf("\n");
421
1b261ae5
JH
422#ifndef EXCLUDE_AUDIO
423 soundcard_configured = 1;
424 if (num_dspdevs)
425 sound_mem_init ();
426#endif
427
428 if (num_dspdevs && !dsp_initialized) /* Audio devices present */
429 {
430 dsp_initialized = 1;
431 mem_start = DMAbuf_init (mem_start);
432 mem_start = audio_init (mem_start);
433 mem_start = dsp_init (mem_start);
434 }
435
436/** UWM stuff **/
437
438#ifndef EXCLUDE_CHIP_MIDI
439
440 if (!generic_midi_initialized)
441 {
442 generic_midi_initialized = 1;
443 mem_start = CMIDI_init (mem_start);
444 }
445
446#endif
447
448#ifndef EXCLUDE_MPU401
449 if (num_midis && !midi_initialized)
450 {
451 midi_initialized = 1;
452 mem_start = MIDIbuf_init (mem_start);
453 }
454#endif
455
456 if ((num_midis + num_synths) && !seq_initialized)
457 {
458 seq_initialized = 1;
459 mem_start = sequencer_init (mem_start);
460 }
461
462 for (i = 0; i < SND_NDEVS; i++)
463 {
464 sbc_devices[i].usecount = 0;
465 }
466
467 return TRUE;
468}
469
470void
471tenmicrosec (void)
472{
473 int i;
474
475 for (i = 0; i < 16; i++)
476 inb (0x80);
477}
478
479#ifdef EXCLUDE_GUS
480void
481gusintr (int unit)
482{
483 return (0);
484}
485#endif
486
487void
488request_sound_timer (int count)
489{
490 static int current = 0;
491 int tmp = count;
492
493 if (count < 0)
494 timeout (sequencer_timer, 0, -count);
495 else
496 {
497
498 if (count < current)
499 current = 0; /* Timer restarted */
500
501 count = count - current;
502
503 current = tmp;
504
505 if (!count)
506 count = 1;
507
508 timeout (sequencer_timer, 0, count);
509 }
510 timer_running = 1;
511}
512
513void
514sound_stop_timer (void)
515{
516 if (timer_running)
517 untimeout (sequencer_timer, 0);
518 timer_running = 0;
519}
520
521#ifndef EXCLUDE_AUDIO
522static void
523sound_mem_init (void)
524{
525 int i, dev;
526 unsigned long dma_pagesize;
527 static unsigned long dsp_init_mask = 0;
528
529 for (dev = 0; dev < num_dspdevs; dev++) /* Enumerate devices */
530 if (!(dsp_init_mask & (1 << dev))) /* Not already done */
531 if (sound_buffcounts[dev] > 0 && sound_dsp_dmachan[dev] > 0)
532 {
533 dsp_init_mask |= (1 << dev);
534
535 if (sound_dma_automode[dev])
536 {
1d43110e 537 sound_dma_automode[dev] = 0; /* Not possible with FreeBSD */
1b261ae5
JH
538 }
539
540 if (sound_buffcounts[dev] == 1)
541 {
542 sound_buffcounts[dev] = 2;
543 sound_buffsizes[dev] /= 2;
544 }
545
546 if (sound_buffsizes[dev] > 65536) /* Larger is not possible (yet) */
547 sound_buffsizes[dev] = 65536;
548
549 if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536)
550 dma_pagesize = 131072; /* 128k */
551 else
552 dma_pagesize = 65536;
553
554 /* More sanity checks */
555
556 if (sound_buffsizes[dev] > dma_pagesize)
557 sound_buffsizes[dev] = dma_pagesize;
558 sound_buffsizes[dev] &= 0xfffff000; /* Truncate to n*4k */
559 if (sound_buffsizes[dev] < 4096)
560 sound_buffsizes[dev] = 4096;
561
562 /* Now allocate the buffers */
563
564 for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++)
565 {
566 /*
567 * The DMA buffer allocation algorithm hogs memory. We allocate
568 * a memory area which is two times the requires size. This
569 * guarantees that it contains at least one valid DMA buffer.
570 *
571 * This really needs some kind of finetuning.
572 */
573 char *tmpbuf = malloc (2*sound_buffsizes[dev], M_DEVBUF, M_NOWAIT);
574 unsigned long addr, rounded;
575
576 if (tmpbuf == NULL)
577 {
578 printk ("snd: Unable to allocate %d bytes of buffer\n",
579 2 * sound_buffsizes[dev]);
580 return;
581 }
582
583 addr = kvtop (tmpbuf);
584 /*
585 * Align the start address
586 */
587 rounded = (addr & ~(dma_pagesize - 1)) + dma_pagesize;
588
589 snd_raw_buf[dev][snd_raw_count[dev]] =
590 &tmpbuf[rounded - addr]; /* Compute offset */
591 /*
592 * Use virtual address as the physical address, since
593 * isa_dmastart performs the phys address computation.
594 */
595 snd_raw_buf_phys[dev][snd_raw_count[dev]] =
596 (unsigned long) snd_raw_buf[dev][snd_raw_count[dev]];
597 }
598 } /* for dev */
599
600}
601
602#endif
603
604struct isa_driver snddriver =
605{sndprobe, sndattach, "snd"};
606
607int
608snd_ioctl_return (int *addr, int value)
609{
610 if (value < 0)
611 return value; /* Error */
612 suword (addr, value);
613 return 0;
614}
615
616#endif