/* * sound/sound_switch.c * * The system call switch * * Copyright by Hannu Savolainen 1993 * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. 2. * Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sound_config.h" #ifdef CONFIGURE_SOUNDCARD struct sbc_device { int usecount; }; static struct sbc_device sbc_devices[SND_NDEVS] = { {0}}; static int in_use = 0; /* * * * * Total # of open device files * (excluding * * * minor 0) */ /* * /dev/sndstatus -device */ static char *status_buf = NULL; static int status_len, status_ptr; static int status_busy = 0; static int put_status (char *s) { int l; for (l = 0; l < 256, s[l]; l++); /* * l=strlen(s); */ if (status_len + l >= 4000) return 0; memcpy (&status_buf[status_len], s, l); status_len += l; return 1; } static int put_status_int (unsigned int val, int radix) { int l, v; static char hx[] = "0123456789abcdef"; char buf[11]; if (!val) return put_status ("0"); l = 0; buf[10] = 0; while (val) { v = val % radix; val = val / radix; buf[9 - l] = hx[v]; l++; } if (status_len + l >= 4000) return 0; memcpy (&status_buf[status_len], &buf[10 - l], l); status_len += l; return 1; } static void init_status (void) { /* * Write the status information to the status_buf and update status_len. * There is a limit of 4000 bytes for the data. */ int i; status_ptr = 0; put_status ("VoxWare Sound Driver:" SOUND_VERSION_STRING " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" "\n"); if (!put_status ("Config options: ")) return; if (!put_status_int (SELECTED_SOUND_OPTIONS, 16)) return; if (!put_status ("\n\nInstalled drivers: \n")) return; for (i = 0; i < (num_sound_drivers - 1); i++) { if (!put_status ("Type ")) return; if (!put_status_int (sound_drivers[i].card_type, 10)) return; if (!put_status (": ")) return; if (!put_status (sound_drivers[i].name)) return; if (!put_status ("\n")) return; } if (!put_status ("\n\nCard config: \n")) return; for (i = 0; i < (num_sound_cards - 1); i++) { int drv; if (!snd_installed_cards[i].enabled) if (!put_status ("(")) return; /* * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return; * if (!put_status (": ")) return; */ if ((drv = snd_find_driver (snd_installed_cards[i].card_type)) != -1) if (!put_status (sound_drivers[drv].name)) return; if (!put_status (" at 0x")) return; if (!put_status_int (snd_installed_cards[i].config.io_base, 16)) return; if (!put_status (" irq ")) return; if (!put_status_int (snd_installed_cards[i].config.irq, 10)) return; if (!put_status (" drq ")) return; if (!put_status_int (snd_installed_cards[i].config.dma, 10)) return; if (!snd_installed_cards[i].enabled) if (!put_status (")")) return; if (!put_status ("\n")) return; } #ifdef EXCLUDE_AUDIO if (!put_status ("\nAudio devices: NOT ENABLED IN CONFIG\n")) return; #else if (!put_status ("\nAudio devices:\n")) return; for (i = 0; i < num_audiodevs; i++) { if (!put_status_int (i, 10)) return; if (!put_status (": ")) return; if (!put_status (audio_devs[i]->name)) return; if (!put_status ("\n")) return; } #endif #ifdef EXCLUDE_SEQUENCER if (!put_status ("\nSynth devices: NOT ENABLED IN CONFIG\n")) return; #else if (!put_status ("\nSynth devices:\n")) return; for (i = 0; i < num_synths; i++) { if (!put_status_int (i, 10)) return; if (!put_status (": ")) return; if (!put_status (synth_devs[i]->info->name)) return; if (!put_status ("\n")) return; } #endif #ifdef EXCLUDE_MIDI if (!put_status ("\nMidi devices: NOT ENABLED IN CONFIG\n")) return; #else if (!put_status ("\nMidi devices:\n")) return; for (i = 0; i < num_midis; i++) { if (!put_status_int (i, 10)) return; if (!put_status (": ")) return; if (!put_status (midi_devs[i]->info.name)) return; if (!put_status ("\n")) return; } #endif if (!put_status ("\nTimers:\n")) return; for (i = 0; i < num_sound_timers; i++) { if (!put_status_int (i, 10)) return; if (!put_status (": ")) return; if (!put_status (sound_timer_devs[i]->info.name)) return; if (!put_status ("\n")) return; } if (!put_status ("\nMixers:\n")) return; for (i = 0; i < num_mixers; i++) { if (!put_status_int (i, 10)) return; if (!put_status (": ")) return; if (!put_status (mixer_devs[i]->name)) return; if (!put_status ("\n")) return; } } static int read_status (snd_rw_buf * buf, int count) { /* * Return at most 'count' bytes from the status_buf. */ int l, c; l = count; c = status_len - status_ptr; if (l > c) l = c; if (l <= 0) return 0; COPY_TO_USER (buf, 0, &status_buf[status_ptr], l); status_ptr += l; return l; } int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { case SND_DEV_STATUS: return read_status (buf, count); break; case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return audio_read (dev, file, buf, count); break; case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_read (dev, file, buf, count); break; #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: return MIDIbuf_read (dev, file, buf, count); #endif default: printk ("Sound: Undefined minor device %d\n", dev); } return RET_ERROR (EPERM); } int sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) { DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count)); switch (dev & 0x0f) { case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_write (dev, file, buf, count); break; case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return audio_write (dev, file, buf, count); break; #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: return MIDIbuf_write (dev, file, buf, count); #endif default: return RET_ERROR (EPERM); } return count; } int sound_open_sw (int dev, struct fileinfo *file) { int retval; DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount)); if ((dev >= SND_NDEVS) || (dev < 0)) { printk ("Invalid minor device %d\n", dev); return RET_ERROR (ENXIO); } switch (dev & 0x0f) { case SND_DEV_STATUS: if (status_busy) return RET_ERROR (EBUSY); status_busy = 1; if ((status_buf = (char *) KERNEL_MALLOC (4000)) == NULL) return RET_ERROR (EIO); status_len = status_ptr = 0; init_status (); break; case SND_DEV_CTL: return 0; break; case SND_DEV_SEQ: case SND_DEV_SEQ2: if ((retval = sequencer_open (dev, file)) < 0) return retval; break; #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: if ((retval = MIDIbuf_open (dev, file)) < 0) return retval; break; #endif case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: if ((retval = audio_open (dev, file)) < 0) return retval; break; default: printk ("Invalid minor device %d\n", dev); return RET_ERROR (ENXIO); } sbc_devices[dev].usecount++; in_use++; return 0; } void sound_release_sw (int dev, struct fileinfo *file) { DEB (printk ("sound_release_sw(dev=%d)\n", dev)); switch (dev & 0x0f) { case SND_DEV_STATUS: if (status_buf) KERNEL_FREE (status_buf); status_buf = NULL; status_busy = 0; break; case SND_DEV_CTL: break; case SND_DEV_SEQ: case SND_DEV_SEQ2: sequencer_release (dev, file); break; #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: MIDIbuf_release (dev, file); break; #endif case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: audio_release (dev, file); break; default: printk ("Sound error: Releasing unknown device 0x%02x\n", dev); } sbc_devices[dev].usecount--; in_use--; } int sound_ioctl_sw (int dev, struct fileinfo *file, unsigned int cmd, unsigned long arg) { DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); if ((cmd >> 8) & 0xff == 'M' && num_mixers > 0) /* Mixer ioctl */ if ((dev & 0x0f) != SND_DEV_CTL) { int dtype = dev & 0x0f; int mixdev; switch (dtype) { case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: mixdev = audio_devs[dev >> 4]->mixer_dev; if (mixdev < 0 || mixdev >= num_mixers) return RET_ERROR (ENXIO); return mixer_devs[mixdev]->ioctl (mixdev, cmd, arg); break; default: return mixer_devs[0]->ioctl (0, cmd, arg); } } switch (dev & 0x0f) { case SND_DEV_CTL: if (!num_mixers) return RET_ERROR (ENXIO); dev = dev >> 4; if (dev >= num_mixers) return RET_ERROR (ENXIO); return mixer_devs[dev]->ioctl (dev, cmd, arg); break; case SND_DEV_SEQ: case SND_DEV_SEQ2: return sequencer_ioctl (dev, file, cmd, arg); break; case SND_DEV_DSP: case SND_DEV_DSP16: case SND_DEV_AUDIO: return audio_ioctl (dev, file, cmd, arg); break; #ifndef EXCLUDE_MIDI case SND_DEV_MIDIN: return MIDIbuf_ioctl (dev, file, cmd, arg); break; #endif default: return RET_ERROR (EPERM); break; } return RET_ERROR (EPERM); } #endif