aboutsummaryrefslogtreecommitdiff
path: root/sound/core
diff options
context:
space:
mode:
authorAlexander Graf <agraf@suse.de>2013-08-29 00:41:59 +0200
committerAlexander Graf <agraf@suse.de>2013-08-29 00:41:59 +0200
commitbf550fc93d9855872a95e69e4002256110d89858 (patch)
tree10876bb4304bffe54c4160a132e7b8de6577ac4e /sound/core
parent7e48c101e0c53e6095c5f4f5e63d14df50aae8fc (diff)
parentcc2df20c7c4ce594c3e17e9cc260c330646012c8 (diff)
Merge remote-tracking branch 'origin/next' into kvm-ppc-next
Conflicts: mm/Kconfig CMA DMA split and ZSWAP introduction were conflicting, fix up manually.
Diffstat (limited to 'sound/core')
-rw-r--r--sound/core/Kconfig9
-rw-r--r--sound/core/init.c55
-rw-r--r--sound/core/pcm_lib.c3
-rw-r--r--sound/core/vmaster.c65
4 files changed, 85 insertions, 47 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig
index b413ed05e74..c0c2f57a0d6 100644
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -157,6 +157,15 @@ config SND_DYNAMIC_MINORS
If you are unsure about this, say N here.
+config SND_MAX_CARDS
+ int "Max number of sound cards"
+ range 4 256
+ default 32
+ depends on SND_DYNAMIC_MINORS
+ help
+ Specify the max number of sound cards that can be assigned
+ on a single machine.
+
config SND_SUPPORT_OLD_API
bool "Support old ALSA API"
default y
diff --git a/sound/core/init.c b/sound/core/init.c
index 6ef06400dfc..6b9087115da 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -46,7 +46,8 @@ static LIST_HEAD(shutdown_files);
static const struct file_operations snd_shutdown_f_ops;
-static unsigned int snd_cards_lock; /* locked for registering/using */
+/* locked for registering/using */
+static DECLARE_BITMAP(snd_cards_lock, SNDRV_CARDS);
struct snd_card *snd_cards[SNDRV_CARDS];
EXPORT_SYMBOL(snd_cards);
@@ -167,29 +168,35 @@ int snd_card_create(int idx, const char *xid,
err = 0;
mutex_lock(&snd_card_mutex);
if (idx < 0) {
- for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+ for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
/* idx == -1 == 0xffff means: take any free slot */
- if (~snd_cards_lock & idx & 1<<idx2) {
+ if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
+ continue;
+ if (!test_bit(idx2, snd_cards_lock)) {
if (module_slot_match(module, idx2)) {
idx = idx2;
break;
}
}
+ }
}
if (idx < 0) {
- for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++)
+ for (idx2 = 0; idx2 < SNDRV_CARDS; idx2++) {
/* idx == -1 == 0xffff means: take any free slot */
- if (~snd_cards_lock & idx & 1<<idx2) {
+ if (idx2 < sizeof(int) && !(idx & (1U << idx2)))
+ continue;
+ if (!test_bit(idx2, snd_cards_lock)) {
if (!slots[idx2] || !*slots[idx2]) {
idx = idx2;
break;
}
}
+ }
}
if (idx < 0)
err = -ENODEV;
else if (idx < snd_ecards_limit) {
- if (snd_cards_lock & (1 << idx))
+ if (test_bit(idx, snd_cards_lock))
err = -EBUSY; /* invalid */
} else if (idx >= SNDRV_CARDS)
err = -ENODEV;
@@ -199,7 +206,7 @@ int snd_card_create(int idx, const char *xid,
idx, snd_ecards_limit - 1, err);
goto __error;
}
- snd_cards_lock |= 1 << idx; /* lock it */
+ set_bit(idx, snd_cards_lock); /* lock it */
if (idx >= snd_ecards_limit)
snd_ecards_limit = idx + 1; /* increase the limit */
mutex_unlock(&snd_card_mutex);
@@ -249,7 +256,7 @@ int snd_card_locked(int card)
int locked;
mutex_lock(&snd_card_mutex);
- locked = snd_cards_lock & (1 << card);
+ locked = test_bit(card, snd_cards_lock);
mutex_unlock(&snd_card_mutex);
return locked;
}
@@ -361,7 +368,7 @@ int snd_card_disconnect(struct snd_card *card)
/* phase 1: disable fops (user space) operations for ALSA API */
mutex_lock(&snd_card_mutex);
snd_cards[card->number] = NULL;
- snd_cards_lock &= ~(1 << card->number);
+ clear_bit(card->number, snd_cards_lock);
mutex_unlock(&snd_card_mutex);
/* phase 2: replace file->f_op with special dummy operations */
@@ -549,7 +556,6 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
const char *nid)
{
int len, loops;
- bool with_suffix;
bool is_default = false;
char *id;
@@ -565,26 +571,23 @@ static void snd_card_set_id_no_lock(struct snd_card *card, const char *src,
is_default = true;
}
- with_suffix = false;
+ len = strlen(id);
for (loops = 0; loops < SNDRV_CARDS; loops++) {
+ char *spos;
+ char sfxstr[5]; /* "_012" */
+ int sfxlen;
+
if (card_id_ok(card, id))
return; /* OK */
- len = strlen(id);
- if (!with_suffix) {
- /* add the "_X" suffix */
- char *spos = id + len;
- if (len > sizeof(card->id) - 3)
- spos = id + sizeof(card->id) - 3;
- strcpy(spos, "_1");
- with_suffix = true;
- } else {
- /* modify the existing suffix */
- if (id[len - 1] != '9')
- id[len - 1]++;
- else
- id[len - 1] = 'A';
- }
+ /* Add _XYZ suffix */
+ sprintf(sfxstr, "_%X", loops + 1);
+ sfxlen = strlen(sfxstr);
+ if (len + sfxlen >= sizeof(card->id))
+ spos = id + sizeof(card->id) - sfxlen - 1;
+ else
+ spos = id + len;
+ strcpy(spos, sfxstr);
}
/* fallback to the default id */
if (!is_default) {
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index 41b3dfe6869..82bb029d441 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -568,7 +568,8 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream)
*
* Sets the given PCM operators to the pcm instance.
*/
-void snd_pcm_set_ops(struct snd_pcm *pcm, int direction, struct snd_pcm_ops *ops)
+void snd_pcm_set_ops(struct snd_pcm *pcm, int direction,
+ const struct snd_pcm_ops *ops)
{
struct snd_pcm_str *stream = &pcm->streams[direction];
struct snd_pcm_substream *substream;
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c
index 02f90b4f8b8..842a97d5fc3 100644
--- a/sound/core/vmaster.c
+++ b/sound/core/vmaster.c
@@ -310,20 +310,10 @@ static int master_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int master_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int sync_slaves(struct link_master *master, int old_val, int new_val)
{
- struct link_master *master = snd_kcontrol_chip(kcontrol);
struct link_slave *slave;
struct snd_ctl_elem_value *uval;
- int err, old_val;
-
- err = master_init(master);
- if (err < 0)
- return err;
- old_val = master->val;
- if (ucontrol->value.integer.value[0] == old_val)
- return 0;
uval = kmalloc(sizeof(*uval), GFP_KERNEL);
if (!uval)
@@ -332,11 +322,33 @@ static int master_put(struct snd_kcontrol *kcontrol,
master->val = old_val;
uval->id = slave->slave.id;
slave_get_val(slave, uval);
- master->val = ucontrol->value.integer.value[0];
+ master->val = new_val;
slave_put_val(slave, uval);
}
kfree(uval);
- if (master->hook && !err)
+ return 0;
+}
+
+static int master_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct link_master *master = snd_kcontrol_chip(kcontrol);
+ int err, new_val, old_val;
+ bool first_init;
+
+ err = master_init(master);
+ if (err < 0)
+ return err;
+ first_init = err;
+ old_val = master->val;
+ new_val = ucontrol->value.integer.value[0];
+ if (new_val == old_val)
+ return 0;
+
+ err = sync_slaves(master, old_val, new_val);
+ if (err < 0)
+ return err;
+ if (master->hook && !first_init)
master->hook(master->hook_private_data, master->val);
return 1;
}
@@ -442,20 +454,33 @@ int snd_ctl_add_vmaster_hook(struct snd_kcontrol *kcontrol,
EXPORT_SYMBOL_GPL(snd_ctl_add_vmaster_hook);
/**
- * snd_ctl_sync_vmaster_hook - Sync the vmaster hook
+ * snd_ctl_sync_vmaster - Sync the vmaster slaves and hook
* @kcontrol: vmaster kctl element
+ * @hook_only: sync only the hook
*
- * Call the hook function to synchronize with the current value of the given
- * vmaster element. NOP when NULL is passed to @kcontrol or the hook doesn't
- * exist.
+ * Forcibly call the put callback of each slave and call the hook function
+ * to synchronize with the current value of the given vmaster element.
+ * NOP when NULL is passed to @kcontrol.
*/
-void snd_ctl_sync_vmaster_hook(struct snd_kcontrol *kcontrol)
+void snd_ctl_sync_vmaster(struct snd_kcontrol *kcontrol, bool hook_only)
{
struct link_master *master;
+ bool first_init = false;
+
if (!kcontrol)
return;
master = snd_kcontrol_chip(kcontrol);
- if (master->hook)
+ if (!hook_only) {
+ int err = master_init(master);
+ if (err < 0)
+ return;
+ first_init = err;
+ err = sync_slaves(master, master->val, master->val);
+ if (err < 0)
+ return;
+ }
+
+ if (master->hook && !first_init)
master->hook(master->hook_private_data, master->val);
}
-EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster_hook);
+EXPORT_SYMBOL_GPL(snd_ctl_sync_vmaster);