Commit | Line | Data |
---|---|---|
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 | ||
37 | int __timeout_val = 0; | |
38 | int __process_aborting = 0; | |
39 | ||
40 | u_int snd1mask; | |
41 | u_int snd2mask; | |
42 | u_int snd3mask; | |
43 | u_int snd4mask; | |
44 | u_int snd5mask; | |
45 | ||
46 | struct sbc_device | |
47 | { | |
48 | int usecount; | |
49 | }; | |
50 | ||
51 | #define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;} | |
52 | ||
53 | static struct sbc_device sbc_devices[SND_NDEVS]; | |
54 | static int timer_running = 0; | |
55 | ||
56 | static int in_use = 0; /* Total # of open device files (excluding | |
57 | * minor 0) */ | |
58 | ||
59 | static int soundcards_installed = 0; /* Number of installed | |
60 | * soundcards */ | |
61 | static int soundcard_configured = 0; | |
62 | extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT]; | |
63 | extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT]; | |
64 | extern int snd_raw_count[MAX_DSP_DEV]; | |
65 | ||
66 | static struct fileinfo files[SND_NDEVS]; | |
67 | ||
68 | int sndprobe (struct isa_device *dev); | |
69 | int sndattach (struct isa_device *dev); | |
70 | int sndopen (dev_t dev, int flags); | |
71 | int sndclose (dev_t dev, int flags); | |
72 | int sndioctl (dev_t dev, int cmd, caddr_t arg, int mode); | |
73 | int sndread (int dev, struct uio *uio); | |
74 | int sndwrite (int dev, struct uio *uio); | |
75 | int sndselect (int dev, int rw); | |
76 | static void sound_mem_init(void); | |
77 | ||
78 | int | |
79 | get_time() | |
80 | { | |
81 | extern struct timeval time; | |
82 | ||
83 | return(time.tv_usec + (time.tv_sec*1000000)); | |
84 | } | |
85 | ||
86 | ||
87 | int | |
88 | sndread (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 | ||
131 | int | |
132 | sndwrite (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 | ||
169 | int | |
170 | sndopen (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 | ||
259 | int | |
260 | sndclose (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 | ||
303 | int | |
304 | sndioctl (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 | ||
350 | int | |
351 | sndselect (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 | 360 | static unsigned short |
1d43110e | 361 | ipri_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 | ||
375 | int | |
376 | sndprobe (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 | ||
388 | int | |
389 | sndattach (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 | ||
470 | void | |
471 | tenmicrosec (void) | |
472 | { | |
473 | int i; | |
474 | ||
475 | for (i = 0; i < 16; i++) | |
476 | inb (0x80); | |
477 | } | |
478 | ||
479 | #ifdef EXCLUDE_GUS | |
480 | void | |
481 | gusintr (int unit) | |
482 | { | |
483 | return (0); | |
484 | } | |
485 | #endif | |
486 | ||
487 | void | |
488 | request_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 | ||
513 | void | |
514 | sound_stop_timer (void) | |
515 | { | |
516 | if (timer_running) | |
517 | untimeout (sequencer_timer, 0); | |
518 | timer_running = 0; | |
519 | } | |
520 | ||
521 | #ifndef EXCLUDE_AUDIO | |
522 | static void | |
523 | sound_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 | ||
604 | struct isa_driver snddriver = | |
605 | {sndprobe, sndattach, "snd"}; | |
606 | ||
607 | int | |
608 | snd_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 |