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