This is the Linux generic soundcard driver, version 1.0c. Supports
[unix-history] / sys / i386 / isa / sound / soundcard.c
CommitLineData
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
16int __timeout_val = 0;
17int __process_aborting = 0;
18
19u_int snd1mask;
20u_int snd2mask;
21u_int snd3mask;
22u_int snd4mask;
23u_int snd5mask;
24
25struct sbc_device
26{
27 int usecount;
28};
29
30#define FIX_RETURN(ret) {if ((ret)<0) return -(ret); else return 0;}
31
32static struct sbc_device sbc_devices[SND_NDEVS];
33static int timer_running = 0;
34
35static int in_use = 0; /* Total # of open device files (excluding
36 * minor 0) */
37
38static int soundcards_installed = 0; /* Number of installed
39 * soundcards */
40static int soundcard_configured = 0;
41extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT];
42extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT];
43extern int snd_raw_count[MAX_DSP_DEV];
44
45static struct fileinfo files[SND_NDEVS];
46
47int sndprobe (struct isa_device *dev);
48int sndattach (struct isa_device *dev);
49int sndopen (dev_t dev, int flags);
50int sndclose (dev_t dev, int flags);
51int sndioctl (dev_t dev, int cmd, caddr_t arg, int mode);
52int sndread (int dev, struct uio *uio);
53int sndwrite (int dev, struct uio *uio);
54int sndselect (int dev, int rw);
55static void sound_mem_init(void);
56
57int
58get_time()
59{
60extern struct timeval time;
61
62 return(time.tv_usec + (time.tv_sec*1000000));
63}
64
65
66int
67sndread (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
110int
111sndwrite (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
148int
149sndopen (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
238int
239sndclose (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
282int
283sndioctl (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
329int
330sndselect (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
339static short
340ipri_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
354int
355sndprobe (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
367int
368sndattach (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
447void
448tenmicrosec (void)
449{
450 int i;
451
452 for (i = 0; i < 16; i++)
453 inb (0x80);
454}
455
456#ifdef EXCLUDE_GUS
457void
458gusintr (int unit)
459{
460 return (0);
461}
462#endif
463
464void
465request_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
490void
491sound_stop_timer (void)
492{
493 if (timer_running)
494 untimeout (sequencer_timer, 0);
495 timer_running = 0;
496}
497
498#ifndef EXCLUDE_AUDIO
499static void
500sound_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
581struct isa_driver snddriver =
582{sndprobe, sndattach, "snd"};
583
584int
585snd_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