patch-2.1.77 linux/drivers/sound/soundcard.c
Next file: linux/drivers/sound/soundmodule.h
Previous file: linux/drivers/sound/sound_timer.c
Back to the patch index
Back to the overall index
- Lines: 802
- Date:
Tue Dec 30 11:02:39 1997
- Orig file:
v2.1.76/linux/drivers/sound/soundcard.c
- Orig date:
Sat Nov 29 11:25:11 1997
diff -u --recursive --new-file v2.1.76/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c
@@ -1,5 +1,5 @@
/*
- * linux/kernel/chr_drv/sound/soundcard.c
+ * linux/drivers/sound/soundcard.c
*
* Soundcard driver for Linux
*/
@@ -10,6 +10,11 @@
* Version 2 (June 1991). See the "COPYING" file distributed with this software
* for more info.
*/
+/*
+ * Thomas Sailer : ioctl code reworked (vmalloc/vfree removed)
+ * integrated sound_switch.c and made /proc/sound (equals to /dev/sndstat,
+ * which should disappear in the near future)
+ */
#include <linux/config.h>
@@ -27,6 +32,7 @@
#include <linux/ioport.h>
#endif /* __KERNEL__ */
#include <linux/delay.h>
+#include <linux/proc_fs.h>
#define SOUND_CORE
@@ -63,27 +69,342 @@
#define DMA_MAP_BUSY 2
+static int in_use = 0; /* Total # of open devices */
+unsigned long seq_time = 0; /* Time for /dev/sequencer */
-static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+/*
+ * Table for configurable mixer volume handling
+ */
+static mixer_vol_table mixer_vols[MAX_MIXER_DEV];
+static int num_mixer_volumes = 0;
+
+
+int *load_mixer_volumes(char *name, int *levels, int present)
+{
+ int i, n;
+
+ for (i = 0; i < num_mixer_volumes; i++)
+ if (strcmp(name, mixer_vols[i].name) == 0)
+ {
+ if (present)
+ mixer_vols[i].num = i;
+ return mixer_vols[i].levels;
+ }
+ if (num_mixer_volumes >= MAX_MIXER_DEV)
+ {
+ printk("Sound: Too many mixers (%s)\n", name);
+ return levels;
+ }
+ n = num_mixer_volumes++;
+
+ strcpy(mixer_vols[n].name, name);
+
+ if (present)
+ mixer_vols[n].num = n;
+ else
+ mixer_vols[n].num = -1;
+
+ for (i = 0; i < 32; i++)
+ mixer_vols[n].levels[i] = levels[i];
+ return mixer_vols[n].levels;
+}
+
+static int set_mixer_levels(caddr_t arg)
{
- int dev;
+ /* mixer_vol_table is 174 bytes, so IMHO no reason to not allocate it on the stack */
+ mixer_vol_table buf;
- dev = MINOR(file->f_dentry->d_inode->i_rdev);
+ if (__copy_from_user(&buf, arg, sizeof(buf)))
+ return -EFAULT;
+ load_mixer_volumes(buf.name, buf.levels, 0);
+ return __copy_to_user(arg, &buf, sizeof(buf));
+}
+
+static int get_mixer_levels(caddr_t arg)
+{
+ int n;
+
+ if (__get_user(n, (int *)(&(((mixer_vol_table *)arg)->num))))
+ return -EFAULT;
+ if (n < 0 || n >= num_mixer_volumes)
+ return -EINVAL;
+ return __copy_to_user(arg, &mixer_vols[n], sizeof(mixer_vol_table));
+}
+
+static int sound_proc_get_info(char *buffer, char **start, off_t offset, int length, int inout)
+{
+ int len, i, drv;
+ off_t pos = 0;
+ off_t begin = 0;
+
+#ifdef MODULE
+#define MODULEPROCSTRING "Driver loaded as a module"
+#else
+#define MODULEPROCSTRING "Driver compiled into kernel"
+#endif
+
+ len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"
+ "Load type: " MODULEPROCSTRING "\n"
+ "Kernel: %s %s %s %s %s\n"
+ "Config options: %x\n\nInstalled drivers: \n",
+ system_utsname.sysname, system_utsname.nodename, system_utsname.release,
+ system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);
+
+ for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) {
+ if (!sound_drivers[i].card_type)
+ continue;
+ len += sprintf(buffer + len, "Type %d: %s\n",
+ sound_drivers[i].card_type, sound_drivers[i].name);
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+ len += sprintf(buffer + len, "\nCard config: \n");
+
+ for (i = 0; (i < num_sound_cards) && (pos <= offset + length); i++) {
+ if (!snd_installed_cards[i].card_type)
+ continue;
+ if (!snd_installed_cards[i].enabled)
+ len += sprintf(buffer + len, "(");
+ if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1)
+ len += sprintf(buffer + len, "%s", sound_drivers[drv].name);
+ if (snd_installed_cards[i].config.io_base)
+ len += sprintf(buffer + len, " at 0x%x", snd_installed_cards[i].config.io_base);
+ if (snd_installed_cards[i].config.irq != 0)
+ len += sprintf(buffer + len, " irq %d", abs(snd_installed_cards[i].config.irq));
+ if (snd_installed_cards[i].config.dma != -1) {
+ len += sprintf(buffer + len, " drq %d", snd_installed_cards[i].config.dma);
+ if (snd_installed_cards[i].config.dma2 != -1)
+ len += sprintf(buffer + len, ",%d", snd_installed_cards[i].config.dma2);
+ }
+ if (!snd_installed_cards[i].enabled)
+ len += sprintf(buffer + len, ")");
+ len += sprintf(buffer + len, "\n");
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+ if (!sound_started)
+ len += sprintf(buffer + len, "\n\n***** Sound driver not started *****\n\n");
+#ifndef CONFIG_AUDIO
+ len += sprintf(buffer + len, "\nAudio devices: NOT ENABLED IN CONFIG\n");
+#else
+ len += sprintf(buffer + len, "\nAudio devices:\n");
+ for (i = 0; (i < num_audiodevs) && (pos <= offset + length); i++) {
+ if (audio_devs[i] == NULL)
+ continue;
+ len += sprintf(buffer + len, "%d: %s%s\n", i, audio_devs[i]->name,
+ audio_devs[i]->flags & DMA_DUPLEX ? " (DUPLEX)" : "");
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+#endif
+
+#ifndef CONFIG_SEQUENCER
+ len += sprintf(buffer + len, "\nSynth devices: NOT ENABLED IN CONFIG\n");
+#else
+ len += sprintf(buffer + len, "\nSynth devices:\n");
+ for (i = 0; (i < num_synths) && (pos <= offset + length); i++) {
+ if (synth_devs[i] == NULL)
+ continue;
+ len += sprintf(buffer + len, "%d: %s\n", i, synth_devs[i]->info->name);
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+#endif
+
+#ifndef CONFIG_MIDI
+ len += sprintf(buffer + len, "\nMidi devices: NOT ENABLED IN CONFIG\n");
+#else
+ len += sprintf(buffer + len, "\nMidi devices:\n");
+ for (i = 0; (i < num_midis) && (pos <= offset + length); i++) {
+ if (midi_devs[i] == NULL)
+ continue;
+ len += sprintf(buffer + len, "%d: %s\n", i, midi_devs[i]->info.name);
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+#endif
+
+#ifdef CONFIG_SEQUENCER
+ len += sprintf(buffer + len, "\nTimers:\n");
+
+ for (i = 0; (i < num_sound_timers) && (pos <= offset + length); i++) {
+ if (sound_timer_devs[i] == NULL)
+ continue;
+ len += sprintf(buffer + len, "%d: %s\n", i, sound_timer_devs[i]->info.name);
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+#endif
+
+ len += sprintf(buffer + len, "\nMixers:\n");
+ for (i = 0; (i < num_mixers) && (pos <= offset + length); i++) {
+ if (mixer_devs[i] == NULL)
+ continue;
+ len += sprintf(buffer + len, "%d: %s\n", i, mixer_devs[i]->name);
+ pos = begin + len;
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ }
+ *start = buffer + (offset - begin);
+ len -= (offset - begin);
+ if (len > length)
+ len = length;
+ return len;
+}
+
+static struct proc_dir_entry proc_root_sound = {
+ PROC_SOUND, 5, "sound",
+ S_IFREG | S_IRUGO, 1, 0, 0,
+ 0, NULL, sound_proc_get_info
+};
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/* 4K page size but our output routines use some slack for overruns */
+#define PROC_BLOCK_SIZE (3*1024)
+
+/*
+ * basically copied from fs/proc/generic.c:proc_file_read
+ * should be removed sometime in the future together with /dev/sndstat
+ * (a symlink /dev/sndstat -> /proc/sound will do as well)
+ */
+static ssize_t sndstat_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
+{
+ char *page;
+ ssize_t retval=0;
+ int eof=0;
+ ssize_t n, count;
+ char *start;
+
+ if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+
+ while ((nbytes > 0) && !eof)
+ {
+ count = MIN(PROC_BLOCK_SIZE, nbytes);
+
+ start = NULL;
+ n = sound_proc_get_info(page, &start, *ppos, count, 0);
+ if (n < count)
+ eof = 1;
+
+ if (!start) {
+ /*
+ * For proc files that are less than 4k
+ */
+ start = page + *ppos;
+ n -= *ppos;
+ if (n <= 0)
+ break;
+ if (n > count)
+ n = count;
+ }
+ if (n == 0)
+ break; /* End of file */
+ if (n < 0) {
+ if (retval == 0)
+ retval = n;
+ break;
+ }
+
+ n -= copy_to_user(buf, start, n); /* BUG ??? */
+ if (n == 0) {
+ if (retval == 0)
+ retval = -EFAULT;
+ break;
+ }
+
+ *ppos += n; /* Move down the file */
+ nbytes -= n;
+ buf += n;
+ retval += n;
+ }
+ free_page((unsigned long) page);
+ return retval;
+}
+
+
+static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+ int dev = MINOR(file->f_dentry->d_inode->i_rdev);
files[dev].flags = file->f_flags;
+ DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
+ switch (dev & 0x0f) {
+ case SND_DEV_STATUS:
+ return sndstat_file_read(file, buf, count, ppos);
+
+#ifdef CONFIG_AUDIO
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_read(dev, &files[dev], buf, count);
+#endif
- return sound_read_sw(dev, &files[dev], buf, count);
+#ifdef CONFIG_SEQUENCER
+ case SND_DEV_SEQ:
+ case SND_DEV_SEQ2:
+ return sequencer_read(dev, &files[dev], buf, count);
+#endif
+
+#ifdef CONFIG_MIDI
+ case SND_DEV_MIDIN:
+ return MIDIbuf_read(dev, &files[dev], buf, count);
+#endif
+
+ default:;
+ }
+ return -EINVAL;
}
static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
{
- int dev;
-
- dev = MINOR(file->f_dentry->d_inode->i_rdev);
+ int dev = MINOR(file->f_dentry->d_inode->i_rdev);
files[dev].flags = file->f_flags;
+ DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
+ switch (dev & 0x0f) {
+#ifdef CONFIG_SEQUENCER
+ case SND_DEV_SEQ:
+ case SND_DEV_SEQ2:
+ return sequencer_write(dev, &files[dev], buf, count);
+#endif
+
+#ifdef CONFIG_AUDIO
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_write(dev, &files[dev], buf, count);
+#endif
- return sound_write_sw(dev, &files[dev], buf, count);
+#ifdef CONFIG_MIDI
+ case SND_DEV_MIDIN:
+ return MIDIbuf_write(dev, &files[dev], buf, count);
+#endif
+ }
+ return -EINVAL;
}
static long long sound_lseek(struct file *file, long long offset, int orig)
@@ -93,20 +414,17 @@
static int sound_open(struct inode *inode, struct file *file)
{
- int dev, retval;
+ int dev, retval;
struct fileinfo tmp_file;
- if (is_unloading)
- {
-/* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/
- return -EBUSY;
+ if (is_unloading) {
+ /* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/
+ return -EBUSY;
}
dev = MINOR(inode->i_rdev);
-
- if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
- {
-/* printk("SoundCard Error: The soundcard system has not been configured\n");*/
- return -ENXIO;
+ if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) {
+ /* printk("SoundCard Error: The soundcard system has not been configured\n");*/
+ return -ENXIO;
}
tmp_file.mode = 0;
tmp_file.flags = file->f_flags;
@@ -117,130 +435,259 @@
tmp_file.mode = OPEN_READ;
if ((tmp_file.flags & O_ACCMODE) == O_WRONLY)
tmp_file.mode = OPEN_WRITE;
+ DEB(printk("sound_open(dev=%d)\n", dev));
+ if ((dev >= SND_NDEVS) || (dev < 0)) {
+ printk(KERN_ERR "Invalid minor device %d\n", dev);
+ return -ENXIO;
+ }
+ switch (dev & 0x0f) {
+ case SND_DEV_STATUS:
+ break;
+
+ case SND_DEV_CTL:
+ if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers)
+ return -ENXIO;
+ break;
+
+#ifdef CONFIG_SEQUENCER
+ case SND_DEV_SEQ:
+ case SND_DEV_SEQ2:
+ if ((retval = sequencer_open(dev, &tmp_file)) < 0)
+ return retval;
+ break;
+#endif
- if ((retval = sound_open_sw(dev, &tmp_file)) < 0)
- return retval;
+#ifdef CONFIG_MIDI
+ case SND_DEV_MIDIN:
+ if ((retval = MIDIbuf_open(dev, &tmp_file)) < 0)
+ return retval;
+ break;
+#endif
+#ifdef CONFIG_AUDIO
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ if ((retval = audio_open(dev, &tmp_file)) < 0)
+ return retval;
+ break;
+#endif
+
+ default:
+ printk(KERN_ERR "Invalid minor device %d\n", dev);
+ return -ENXIO;
+ }
+ in_use++;
#ifdef MODULE
SOUND_INC_USE_COUNT;
#endif
-
- memcpy((char *) &files[dev], (char *) &tmp_file, sizeof(tmp_file));
- return retval;
+ memcpy(&files[dev], &tmp_file, sizeof(tmp_file));
+ return 0;
}
static int sound_release(struct inode *inode, struct file *file)
{
- int dev;
-
- dev = MINOR(inode->i_rdev);
+ int dev = MINOR(inode->i_rdev);
files[dev].flags = file->f_flags;
+ DEB(printk("sound_release(dev=%d)\n", dev));
+ switch (dev & 0x0f) {
+ case SND_DEV_STATUS:
+ case SND_DEV_CTL:
+ break;
+
+#ifdef CONFIG_SEQUENCER
+ case SND_DEV_SEQ:
+ case SND_DEV_SEQ2:
+ sequencer_release(dev, &files[dev]);
+ break;
+#endif
- sound_release_sw(dev, &files[dev]);
+#ifdef CONFIG_MIDI
+ case SND_DEV_MIDIN:
+ MIDIbuf_release(dev, &files[dev]);
+ break;
+#endif
+
+#ifdef CONFIG_AUDIO
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ audio_release(dev, &files[dev]);
+ break;
+#endif
+
+ default:
+ printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
+ }
+ in_use--;
#ifdef MODULE
SOUND_DEC_USE_COUNT;
#endif
return 0;
}
-static int sound_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int get_mixer_info(int dev, caddr_t arg)
{
- int dev, err;
- int len = 0;
- int alloced = 0;
- char *ptr = (char *) arg;
+ mixer_info info;
+ int i;
- dev = MINOR(inode->i_rdev);
+ if (dev < 0 || dev >= num_mixers)
+ return -ENXIO;
+ strcpy(info.id, mixer_devs[dev]->id);
+ for (i = 0; i < 32 && mixer_devs[dev]->name; i++)
+ info.name[i] = mixer_devs[dev]->name[i];
+ info.name[i] = 0;
+ info.modify_counter = mixer_devs[dev]->modify_counter;
+ if (__copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+}
- files[dev].flags = file->f_flags;
+static int get_old_mixer_info(int dev, caddr_t arg)
+{
+ _old_mixer_info info;
+ int i;
- if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0)
- {
+ if (dev < 0 || dev >= num_mixers)
+ return -ENXIO;
+ strcpy(info.id, mixer_devs[dev]->id);
+ for (i = 0; i < 32 && mixer_devs[dev]->name; i++)
+ info.name[i] = mixer_devs[dev]->name[i];
+ info.name[i] = 0;
+ if (__copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+ return 0;
+}
+
+static int sound_mixer_ioctl(int mixdev, unsigned int cmd, caddr_t arg)
+{
+ if (cmd == SOUND_MIXER_INFO)
+ return get_mixer_info(mixdev, arg);
+ if (cmd == SOUND_OLD_MIXER_INFO)
+ return get_old_mixer_info(mixdev, arg);
+ if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+ mixer_devs[mixdev]->modify_counter++;
+ if (!mixer_devs[mixdev]->ioctl)
+ return -EINVAL;
+ return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg);
+}
+
+static int sound_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ int err, len = 0, dtype, mixdev;
+ int dev = MINOR(inode->i_rdev);
+
+ files[dev].flags = file->f_flags;
+ if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) {
/*
* Have to validate the address given by the process.
*/
-
len = _SIOC_SIZE(cmd);
if (len < 1 || len > 65536 || arg == 0)
return -EFAULT;
-
- ptr = vmalloc(len);
- alloced = 1;
- if (ptr == NULL)
- return -EFAULT;
-
if (_SIOC_DIR(cmd) & _SIOC_WRITE)
- {
- if ((err = verify_area(VERIFY_READ, (void *) arg, len)) < 0)
+ if ((err = verify_area(VERIFY_READ, (void *)arg, len)) < 0)
return err;
- copy_from_user(ptr, (char *) arg, len);
- }
if (_SIOC_DIR(cmd) & _SIOC_READ)
- {
- if ((err = verify_area(VERIFY_WRITE, (void *) arg, len)) < 0)
+ if ((err = verify_area(VERIFY_WRITE, (void *)arg, len)) < 0)
return err;
- }
}
- err = sound_ioctl_sw(dev, &files[dev], cmd, (caddr_t) ptr);
+ DEB(printk("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
+ if (cmd == OSS_GETVERSION)
+ return __put_user(SOUND_VERSION, (int *)arg);
+
+ if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0) /* Mixer ioctl */
+ if ((dev & 0x0f) != SND_DEV_CTL) {
+ dtype = dev & 0x0f;
+ switch (dtype) {
+#ifdef CONFIG_AUDIO
+ 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 -ENXIO;
+ return sound_mixer_ioctl(mixdev, cmd, (caddr_t)arg);
+#endif
+
+ default:
+ return sound_mixer_ioctl(dev, cmd, (caddr_t)arg);
+ }
+ }
+ switch (dev & 0x0f) {
+ case SND_DEV_CTL:
+ if (cmd == SOUND_MIXER_GETLEVELS)
+ return get_mixer_levels((caddr_t)arg);
+ if (cmd == SOUND_MIXER_SETLEVELS)
+ return set_mixer_levels((caddr_t)arg);
+ if (!num_mixers)
+ return -ENXIO;
+ dev = dev >> 4;
+ if (dev >= num_mixers)
+ return -ENXIO;
+ return sound_mixer_ioctl(dev, cmd, (caddr_t)arg);
+ break;
+
+#ifdef CONFIG_SEQUENCER
+ case SND_DEV_SEQ:
+ case SND_DEV_SEQ2:
+ return sequencer_ioctl(dev, &files[dev], cmd, (caddr_t)arg);
+#endif
- if (_SIOC_DIR(cmd) & _SIOC_READ)
- copy_to_user((char *) arg, ptr, len);
+#ifdef CONFIG_AUDIO
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return audio_ioctl(dev, &files[dev], cmd, (caddr_t)arg);
+ break;
+#endif
- if (ptr != NULL && alloced)
- vfree(ptr);
+#ifdef CONFIG_MIDI
+ case SND_DEV_MIDIN:
+ return MIDIbuf_ioctl(dev, &files[dev], cmd, (caddr_t)arg);
+ break;
+#endif
- return ((err < 0) ? err : 0);
+ }
+ return -EINVAL;
}
static int sound_select(struct inode *inode, struct file *file, int sel_type, poll_table * wait)
{
- int dev;
-
- dev = MINOR(inode->i_rdev);
+ int dev = MINOR(inode->i_rdev);
files[dev].flags = file->f_flags;
-
DEB(printk("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
-
- switch (dev & 0x0f)
- {
+ switch (dev & 0x0f) {
#if defined(CONFIG_SEQUENCER) || defined(MODULE)
- case SND_DEV_SEQ:
- case SND_DEV_SEQ2:
- return sequencer_select(dev, &files[dev], sel_type, wait);
- break;
+ case SND_DEV_SEQ:
+ case SND_DEV_SEQ2:
+ return sequencer_select(dev, &files[dev], sel_type, wait);
#endif
#if defined(CONFIG_MIDI)
- case SND_DEV_MIDIN:
- return MIDIbuf_select(dev, &files[dev], sel_type, wait);
- break;
+ case SND_DEV_MIDIN:
+ return MIDIbuf_select(dev, &files[dev], sel_type, wait);
#endif
#if defined(CONFIG_AUDIO) || defined(MODULE)
- case SND_DEV_DSP:
- case SND_DEV_DSP16:
- case SND_DEV_AUDIO:
- return DMAbuf_select(dev >> 4, &files[dev], sel_type, wait);
- break;
+ case SND_DEV_DSP:
+ case SND_DEV_DSP16:
+ case SND_DEV_AUDIO:
+ return DMAbuf_select(dev >> 4, &files[dev], sel_type, wait);
#endif
-
- default:
- return 0;
}
-
return 0;
}
static unsigned int sound_poll(struct file *file, poll_table * wait)
{
- struct inode *inode;
- int ret = 0;
+ struct inode *inode;
+ int ret = 0;
inode = file->f_dentry->d_inode;
-
if (sound_select(inode, file, SEL_IN, wait))
ret |= POLLIN;
if (sound_select(inode, file, SEL_OUT, wait))
@@ -250,11 +697,10 @@
static int sound_mmap(struct file *file, struct vm_area_struct *vma)
{
- int dev, dev_class;
- unsigned long size;
+ int dev_class;
+ unsigned long size;
struct dma_buffparms *dmap = NULL;
-
- dev = MINOR(file->f_dentry->d_inode->i_rdev);
+ int dev = MINOR(file->f_dentry->d_inode->i_rdev);
files[dev].flags = file->f_flags;
@@ -418,7 +864,9 @@
if (sound_nblocks >= 1024)
printk(KERN_ERR "Sound warning: Deallocation table was too small.\n");
-
+
+ if (proc_register(&proc_root, &proc_root_sound))
+ printk(KERN_ERR "sound: registering /proc/sound failed\n");
return 0;
}
@@ -433,6 +881,8 @@
{
return;
}
+ if (proc_unregister(&proc_root, PROC_SOUND))
+ printk(KERN_ERR "sound: unregistering /proc/sound failed\n");
if (chrdev_registered)
unregister_chrdev(sound_major, "sound");
@@ -779,3 +1229,35 @@
}
printk("\n");
}
+
+/*
+ * Module and lock management
+ */
+
+struct notifier_block *sound_locker=(struct notifier_block *)0;
+static int lock_depth = 0;
+
+#define SOUND_INC_USE_COUNT do { notifier_call_chain(&sound_locker, 1, 0); lock_depth++; } while(0);
+#define SOUND_DEC_USE_COUNT do { notifier_call_chain(&sound_locker, 0, 0); lock_depth--; } while(0);
+
+/*
+ * When a sound module is registered we need to bring it to the current
+ * lock level...
+ */
+
+void sound_notifier_chain_register(struct notifier_block *bl)
+{
+ int ct=0;
+
+ notifier_chain_register(&sound_locker, bl);
+ /*
+ * Normalise the lock count by calling the entry directly. We
+ * have to call the module as it owns its own use counter
+ */
+ while(ct<lock_depth)
+ {
+ bl->notifier_call(bl, 1, 0);
+ ct++;
+ }
+}
+
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov