Merge branch 'for-2.6.29' of git://linux-nfs.org/~bfields/linux
[safe/jmp/linux-2.6] / sound / core / oss / mixer_oss.c
index 2dd6bf9..e570649 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  OSS emulation layer for the mixer interface
- *  Copyright (c) by Jaroslav Kysela <perex@suse.cz>
+ *  Copyright (c) by Jaroslav Kysela <perex@perex.cz>
  *
  *
  *   This program is free software; you can redistribute it and/or modify
@@ -19,9 +19,7 @@
  *
  */
 
-#include <sound/driver.h>
 #include <linux/init.h>
-#include <linux/smp_lock.h>
 #include <linux/slab.h>
 #include <linux/time.h>
 #include <linux/string.h>
 
 #define OSS_ALSAEMULVER         _SIOR ('M', 249, int)
 
-MODULE_AUTHOR("Jaroslav Kysela <perex@suse.cz>");
+MODULE_AUTHOR("Jaroslav Kysela <perex@perex.cz>");
 MODULE_DESCRIPTION("Mixer OSS emulation for ALSA.");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MIXER);
 
 static int snd_mixer_oss_open(struct inode *inode, struct file *file)
 {
-       int cardnum = SNDRV_MINOR_OSS_CARD(iminor(inode));
        struct snd_card *card;
        struct snd_mixer_oss_file *fmixer;
        int err;
 
-       if ((card = snd_cards[cardnum]) == NULL)
+       card = snd_lookup_oss_minor_data(iminor(inode),
+                                        SNDRV_OSS_DEVICE_TYPE_MIXER);
+       if (card == NULL)
                return -ENODEV;
        if (card->mixer_oss == NULL)
                return -ENODEV;
@@ -258,8 +257,10 @@ static int snd_mixer_oss_get_volume(struct snd_mixer_oss_file *fmixer, int slot)
                result = pslot->get_volume(fmixer, pslot, &left, &right);
        if (!pslot->stereo)
                right = left;
-       snd_assert(left >= 0 && left <= 100, return -EIO);
-       snd_assert(right >= 0 && right <= 100, return -EIO);
+       if (snd_BUG_ON(left < 0 || left > 100))
+               return -EIO;
+       if (snd_BUG_ON(right < 0 || right > 100))
+               return -EIO;
        if (result >= 0) {
                pslot->volume[0] = left;
                pslot->volume[1] = right;
@@ -299,7 +300,8 @@ static int snd_mixer_oss_ioctl1(struct snd_mixer_oss_file *fmixer, unsigned int
        int __user *p = argp;
        int tmp;
 
-       snd_assert(fmixer != NULL, return -ENXIO);
+       if (snd_BUG_ON(!fmixer))
+               return -ENXIO;
        if (((cmd >> 8) & 0xff) == 'M') {
                switch (cmd) {
                case SOUND_MIXER_INFO:
@@ -369,7 +371,8 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l
 {
        struct snd_mixer_oss_file fmixer;
        
-       snd_assert(card != NULL, return -ENXIO);
+       if (snd_BUG_ON(!card))
+               return -ENXIO;
        if (card->mixer_oss == NULL)
                return -ENXIO;
        memset(&fmixer, 0, sizeof(fmixer));
@@ -389,7 +392,7 @@ int snd_mixer_oss_ioctl_card(struct snd_card *card, unsigned int cmd, unsigned l
  *  REGISTRATION PART
  */
 
-static struct file_operations snd_mixer_oss_f_ops =
+static const struct file_operations snd_mixer_oss_f_ops =
 {
        .owner =        THIS_MODULE,
        .open =         snd_mixer_oss_open,
@@ -689,6 +692,9 @@ static int snd_mixer_oss_put_volume1(struct snd_mixer_oss_file *fmixer,
                snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_PVOLUME], left, right);
                if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME)
                        snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
+       } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_CVOLUME) {
+               snd_mixer_oss_put_volume1_vol(fmixer, pslot,
+                       slot->numid[SNDRV_MIXER_OSS_ITEM_CVOLUME], left, right);
        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GVOLUME) {
                snd_mixer_oss_put_volume1_vol(fmixer, pslot, slot->numid[SNDRV_MIXER_OSS_ITEM_GVOLUME], left, right);
        } else if (slot->present & SNDRV_MIXER_OSS_PRESENT_GLOBAL) {
@@ -925,6 +931,68 @@ static void mixer_slot_clear(struct snd_mixer_oss_slot *rslot)
        rslot->number = idx;
 }
 
+/* In a separate function to keep gcc 3.2 happy - do NOT merge this in
+   snd_mixer_oss_build_input! */
+static int snd_mixer_oss_build_test_all(struct snd_mixer_oss *mixer,
+                                       struct snd_mixer_oss_assign_table *ptr,
+                                       struct slot *slot)
+{
+       char str[64];
+       int err;
+
+       err = snd_mixer_oss_build_test(mixer, slot, ptr->name, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_GLOBAL);
+       if (err)
+               return err;
+       sprintf(str, "%s Switch", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_GSWITCH);
+       if (err)
+               return err;
+       sprintf(str, "%s Route", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_GROUTE);
+       if (err)
+               return err;
+       sprintf(str, "%s Volume", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_GVOLUME);
+       if (err)
+               return err;
+       sprintf(str, "%s Playback Switch", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_PSWITCH);
+       if (err)
+               return err;
+       sprintf(str, "%s Playback Route", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_PROUTE);
+       if (err)
+               return err;
+       sprintf(str, "%s Playback Volume", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_PVOLUME);
+       if (err)
+               return err;
+       sprintf(str, "%s Capture Switch", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_CSWITCH);
+       if (err)
+               return err;
+       sprintf(str, "%s Capture Route", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_CROUTE);
+       if (err)
+               return err;
+       sprintf(str, "%s Capture Volume", ptr->name);
+       err = snd_mixer_oss_build_test(mixer, slot, str, ptr->index,
+                                      SNDRV_MIXER_OSS_ITEM_CVOLUME);
+       if (err)
+               return err;
+
+       return 0;
+}
+
 /*
  * build an OSS mixer element.
  * ptr_allocated means the entry is dynamically allocated (change via proc file).
@@ -944,56 +1012,18 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
 
        memset(&slot, 0, sizeof(slot));
        memset(slot.numid, 0xff, sizeof(slot.numid)); /* ID_UNKNOWN */
-       if (snd_mixer_oss_build_test(mixer, &slot, ptr->name, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_GLOBAL))
-               return 0;
-       sprintf(str, "%s Switch", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_GSWITCH))
-               return 0;
-       sprintf(str, "%s Route", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_GROUTE))
-               return 0;
-       sprintf(str, "%s Volume", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_GVOLUME))
-               return 0;
-       sprintf(str, "%s Playback Switch", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_PSWITCH))
-               return 0;
-       sprintf(str, "%s Playback Route", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_PROUTE))
-               return 0;
-       sprintf(str, "%s Playback Volume", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_PVOLUME))
-               return 0;
-       sprintf(str, "%s Capture Switch", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_CSWITCH))
-               return 0;
-       sprintf(str, "%s Capture Route", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_CROUTE))
-               return 0;
-       sprintf(str, "%s Capture Volume", ptr->name);
-       if (snd_mixer_oss_build_test(mixer, &slot, str, ptr->index,
-                                    SNDRV_MIXER_OSS_ITEM_CVOLUME))
+       if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
                return 0;
        down_read(&mixer->card->controls_rwsem);
        if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
                struct snd_ctl_elem_info *uinfo;
 
-               uinfo = kmalloc(sizeof(*uinfo), GFP_KERNEL);
+               uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
                if (! uinfo) {
                        up_read(&mixer->card->controls_rwsem);
                        return -ENOMEM;
                }
                        
-               memset(uinfo, 0, sizeof(*uinfo));
                if (kctl->info(kctl, uinfo)) {
                        up_read(&mixer->card->controls_rwsem);
                        return 0;
@@ -1023,7 +1053,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
        }
        up_read(&mixer->card->controls_rwsem);
        if (slot.present != 0) {
-               pslot = (struct slot *)kmalloc(sizeof(slot), GFP_KERNEL);
+               pslot = kmalloc(sizeof(slot), GFP_KERNEL);
                if (! pslot)
                        return -ENOMEM;
                *pslot = slot;
@@ -1052,6 +1082,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
        return 0;
 }
 
+#ifdef CONFIG_PROC_FS
 /*
  */
 #define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
@@ -1093,7 +1124,7 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
        struct snd_mixer_oss *mixer = entry->private_data;
        int i;
 
-       down(&mixer->reg_mutex);
+       mutex_lock(&mixer->reg_mutex);
        for (i = 0; i < SNDRV_OSS_MAX_MIXERS; i++) {
                struct slot *p;
 
@@ -1108,7 +1139,7 @@ static void snd_mixer_oss_proc_read(struct snd_info_entry *entry,
                else
                        snd_iprintf(buffer, "\"\" 0\n");
        }
-       up(&mixer->reg_mutex);
+       mutex_unlock(&mixer->reg_mutex);
 }
 
 static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
@@ -1132,9 +1163,9 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                cptr = snd_info_get_str(str, cptr, sizeof(str));
                if (! *str) {
                        /* remove the entry */
-                       down(&mixer->reg_mutex);
+                       mutex_lock(&mixer->reg_mutex);
                        mixer_slot_clear(&mixer->slots[ch]);
-                       up(&mixer->reg_mutex);
+                       mutex_unlock(&mixer->reg_mutex);
                        continue;
                }
                snd_info_get_str(idxstr, cptr, sizeof(idxstr));
@@ -1143,7 +1174,7 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                        snd_printk(KERN_ERR "mixer_oss: invalid index %d\n", idx);
                        continue;
                }
-               down(&mixer->reg_mutex);
+               mutex_lock(&mixer->reg_mutex);
                slot = (struct slot *)mixer->slots[ch].private_data;
                if (slot && slot->assigned &&
                    slot->assigned->index == idx && ! strcmp(slot->assigned->name, str))
@@ -1166,7 +1197,7 @@ static void snd_mixer_oss_proc_write(struct snd_info_entry *entry,
                        kfree(tbl);
                }
        __unlock:
-               up(&mixer->reg_mutex);
+               mutex_unlock(&mixer->reg_mutex);
        }
 }
 
@@ -1180,9 +1211,7 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
                return;
        entry->content = SNDRV_INFO_CONTENT_TEXT;
        entry->mode = S_IFREG | S_IRUGO | S_IWUSR;
-       entry->c.text.read_size = 8192;
        entry->c.text.read = snd_mixer_oss_proc_read;
-       entry->c.text.write_size = 8192;
        entry->c.text.write = snd_mixer_oss_proc_write;
        entry->private_data = mixer;
        if (snd_info_register(entry) < 0) {
@@ -1194,11 +1223,13 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer)
 
 static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
 {
-       if (mixer->proc_entry) {
-               snd_info_unregister(mixer->proc_entry);
-               mixer->proc_entry = NULL;
-       }
+       snd_info_free_entry(mixer->proc_entry);
+       mixer->proc_entry = NULL;
 }
+#else /* !CONFIG_PROC_FS */
+#define snd_mixer_oss_proc_init(mix)
+#define snd_mixer_oss_proc_done(mix)
+#endif /* CONFIG_PROC_FS */
 
 static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
 {
@@ -1233,6 +1264,8 @@ static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
                { SOUND_MIXER_DIGITAL3, "Digital",              2 },
                { SOUND_MIXER_PHONEIN,  "Phone",                0 },
                { SOUND_MIXER_PHONEOUT, "Master Mono",          0 },
+               { SOUND_MIXER_PHONEOUT, "Speaker",              0 }, /*fallback*/
+               { SOUND_MIXER_PHONEOUT, "Mono",                 0 }, /*fallback*/
                { SOUND_MIXER_PHONEOUT, "Phone",                0 }, /* fallback */
                { SOUND_MIXER_VIDEO,    "Video",                0 },
                { SOUND_MIXER_RADIO,    "Radio",                0 },
@@ -1258,9 +1291,11 @@ static int snd_mixer_oss_free1(void *private)
        struct snd_card *card;
        int idx;
  
-       snd_assert(mixer != NULL, return -ENXIO);
+       if (!mixer)
+               return 0;
        card = mixer->card;
-       snd_assert(mixer == card->mixer_oss, return -ENXIO);
+       if (snd_BUG_ON(mixer != card->mixer_oss))
+               return -ENXIO;
        card->mixer_oss = NULL;
        for (idx = 0; idx < SNDRV_OSS_MAX_MIXERS; idx++) {
                struct snd_mixer_oss_slot *chn = &mixer->slots[idx];
@@ -1282,11 +1317,11 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
                mixer = kcalloc(2, sizeof(*mixer), GFP_KERNEL);
                if (mixer == NULL)
                        return -ENOMEM;
-               init_MUTEX(&mixer->reg_mutex);
+               mutex_init(&mixer->reg_mutex);
                sprintf(name, "mixer%i%i", card->number, 0);
                if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
                                                   card, 0,
-                                                  &snd_mixer_oss_f_ops,
+                                                  &snd_mixer_oss_f_ops, card,
                                                   name)) < 0) {
                        snd_printk(KERN_ERR "unable to register OSS mixer device %i:%i\n",
                                   card->number, 0);
@@ -1309,21 +1344,19 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
                card->mixer_oss = mixer;
                snd_mixer_oss_build(mixer);
                snd_mixer_oss_proc_init(mixer);
-       } else if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT) {
-               mixer = card->mixer_oss;
-               if (mixer == NULL || !mixer->oss_dev_alloc)
-                       return 0;
-               snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
-               mixer->oss_dev_alloc = 0;
-       } else {                /* free */
+       } else {
                mixer = card->mixer_oss;
                if (mixer == NULL)
                        return 0;
+               if (mixer->oss_dev_alloc) {
 #ifdef SNDRV_OSS_INFO_DEV_MIXERS
-               snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
+                       snd_oss_info_unregister(SNDRV_OSS_INFO_DEV_MIXERS, mixer->card->number);
 #endif
-               if (mixer->oss_dev_alloc)
                        snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER, mixer->card, 0);
+                       mixer->oss_dev_alloc = 0;
+               }
+               if (cmd == SND_MIXER_OSS_NOTIFY_DISCONNECT)
+                       return 0;
                snd_mixer_oss_proc_done(mixer);
                return snd_mixer_oss_free1(mixer);
        }