summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSudheer Papothi <spapothi@codeaurora.org>2016-01-29 00:36:30 +0530
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:09:50 -0700
commit93a336484a5e14711f62bc83f08cddd08ef3669e (patch)
tree56a533683a94b145370f759ee2dc4d7c7ac6a145
parent7ed3e4477179ea3db0639f740d191840a9a8b9f8 (diff)
ALSA: core: Expose sound card online/offline state
Expose sound card online/offline state to procfs so userspace application can poll and read sound card's state. Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org> Signed-off-by: Banajit Goswami <bgoswami@codeaurora.org> Signed-off-by: Sudheer Papothi <spapothi@codeaurora.org>
-rw-r--r--include/sound/core.h5
-rw-r--r--include/sound/soc.h3
-rw-r--r--sound/core/init.c75
-rw-r--r--sound/soc/soc-core.c11
-rw-r--r--sound/soc/soc-io.c11
5 files changed, 103 insertions, 2 deletions
diff --git a/include/sound/core.h b/include/sound/core.h
index cdfecafff0f4..7b05f88cacac 100644
--- a/include/sound/core.h
+++ b/include/sound/core.h
@@ -134,6 +134,9 @@ struct snd_card {
struct device card_dev; /* cardX object for sysfs */
const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */
bool registered; /* card_dev is registered? */
+ int offline; /* if this sound card is offline */
+ unsigned long offline_change;
+ wait_queue_head_t offline_poll_wait;
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
@@ -265,6 +268,8 @@ int snd_component_add(struct snd_card *card, const char *component);
int snd_card_file_add(struct snd_card *card, struct file *file);
int snd_card_file_remove(struct snd_card *card, struct file *file);
#define snd_card_unref(card) put_device(&(card)->card_dev)
+void snd_card_change_online_state(struct snd_card *card, int online);
+bool snd_card_is_online_state(struct snd_card *card);
#define snd_card_set_dev(card, devptr) ((card)->dev = (devptr))
diff --git a/include/sound/soc.h b/include/sound/soc.h
index d696c2f6bcbb..eb030bad423e 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -553,12 +553,13 @@ int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
unsigned int mask, unsigned int value);
+void snd_soc_card_change_online_state(struct snd_soc_card *soc_card,
+ int online);
#ifdef CONFIG_SND_SOC_AC97_BUS
struct snd_ac97 *snd_soc_alloc_ac97_codec(struct snd_soc_codec *codec);
struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
unsigned int id, unsigned int id_mask);
void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
-
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
struct platform_device *pdev);
diff --git a/sound/core/init.c b/sound/core/init.c
index 20f37fb3800e..f413963c414f 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -58,6 +58,8 @@ static char *slots[SNDRV_CARDS];
module_param_array(slots, charp, NULL, 0444);
MODULE_PARM_DESC(slots, "Module names assigned to the slots.");
+#define SND_CARD_STATE_MAX_LEN 16
+
/* return non-zero if the given index is reserved for the given
* module via slots option
*/
@@ -107,9 +109,39 @@ static void snd_card_id_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "%s\n", entry->card->id);
}
+static ssize_t snd_card_state_read(struct snd_info_entry *entry,
+ void *file_private_data, struct file *file,
+ char __user *buf, size_t count, loff_t pos)
+{
+ int len;
+ char buffer[SND_CARD_STATE_MAX_LEN];
+
+ /* make sure offline is updated prior to wake up */
+ rmb();
+ len = snprintf(buffer, sizeof(buffer), "%s\n",
+ entry->card->offline ? "OFFLINE" : "ONLINE");
+ return simple_read_from_buffer(buf, count, &pos, buffer, len);
+}
+
+static unsigned int snd_card_state_poll(struct snd_info_entry *entry,
+ void *private_data, struct file *file,
+ poll_table *wait)
+{
+ poll_wait(file, &entry->card->offline_poll_wait, wait);
+ if (xchg(&entry->card->offline_change, 0))
+ return POLLIN | POLLPRI | POLLRDNORM;
+ else
+ return 0;
+}
+
+static struct snd_info_entry_ops snd_card_state_proc_ops = {
+ .read = snd_card_state_read,
+ .poll = snd_card_state_poll,
+};
+
static int init_info_for_card(struct snd_card *card)
{
- struct snd_info_entry *entry;
+ struct snd_info_entry *entry, *entry_state;
entry = snd_info_create_card_entry(card, "id", card->proc_root);
if (!entry) {
@@ -119,6 +151,17 @@ static int init_info_for_card(struct snd_card *card)
entry->c.text.read = snd_card_id_read;
card->proc_id = entry;
+ entry_state = snd_info_create_card_entry(card, "state",
+ card->proc_root);
+ if (!entry_state) {
+ dev_dbg(card->dev, "unable to create card entry state\n");
+ card->proc_id = NULL;
+ return -ENOMEM;
+ }
+ entry_state->size = SND_CARD_STATE_MAX_LEN;
+ entry_state->content = SNDRV_INFO_CONTENT_DATA;
+ entry_state->c.ops = &snd_card_state_proc_ops;
+
return snd_info_card_register(card);
}
#else /* !CONFIG_SND_PROC_FS */
@@ -258,6 +301,7 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
init_waitqueue_head(&card->power_sleep);
#endif
+ init_waitqueue_head(&card->offline_poll_wait);
device_initialize(&card->card_dev);
card->card_dev.parent = parent;
card->card_dev.class = sound_class;
@@ -972,6 +1016,35 @@ int snd_card_file_remove(struct snd_card *card, struct file *file)
EXPORT_SYMBOL(snd_card_file_remove);
+/**
+ * snd_card_change_online_state - mark card's online/offline state
+ * @card: Card to mark
+ * @online: whether online of offline
+ *
+ * Mutes the DAI DAC.
+ */
+void snd_card_change_online_state(struct snd_card *card, int online)
+{
+ snd_printd("snd card %s state change %d -> %d\n",
+ card->shortname, !card->offline, online);
+ card->offline = !online;
+ /* make sure offline is updated prior to wake up */
+ wmb();
+ xchg(&card->offline_change, 1);
+ wake_up_interruptible(&card->offline_poll_wait);
+}
+EXPORT_SYMBOL(snd_card_change_online_state);
+
+/**
+ * snd_card_is_online_state - return true if card is online state
+ * @card: Card to query
+ */
+bool snd_card_is_online_state(struct snd_card *card)
+{
+ return !card->offline;
+}
+EXPORT_SYMBOL(snd_card_is_online_state);
+
#ifdef CONFIG_PM
/**
* snd_power_wait - wait until the power-state is changed.
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index 24cb33a9f5c8..e28f0f9e6e99 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -3039,6 +3039,17 @@ static int snd_soc_codec_set_bias_level(struct snd_soc_dapm_context *dapm,
}
/**
+ * snd_soc_card_change_online_state - Mark if soc card is online/offline
+ *
+ * @soc_card : soc_card to mark
+ */
+void snd_soc_card_change_online_state(struct snd_soc_card *soc_card, int online)
+{
+ snd_card_change_online_state(soc_card->snd_card, online);
+}
+EXPORT_SYMBOL(snd_soc_card_change_online_state);
+
+/**
* snd_soc_register_codec - Register a codec with the ASoC core
*
* @dev: The parent device for this codec
diff --git a/sound/soc/soc-io.c b/sound/soc/soc-io.c
index 9b3939049cef..a90a1630ab1c 100644
--- a/sound/soc/soc-io.c
+++ b/sound/soc/soc-io.c
@@ -195,9 +195,14 @@ EXPORT_SYMBOL_GPL(snd_soc_component_test_bits);
unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg)
{
+ struct snd_card *snd_card = codec->component.card->snd_card;
unsigned int val;
int ret;
+ if (unlikely(!snd_card_is_online_state(snd_card))) {
+ dev_err(codec->dev, "read 0x%02x while offline\n", reg);
+ return -ENODEV;
+ }
ret = snd_soc_component_read(&codec->component, reg, &val);
if (ret < 0)
return -1;
@@ -209,6 +214,12 @@ EXPORT_SYMBOL_GPL(snd_soc_read);
int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
+ struct snd_card *snd_card = codec->component.card->snd_card;
+
+ if (unlikely(!snd_card_is_online_state(snd_card))) {
+ dev_err(codec->dev, "write 0x%02x while offline\n", reg);
+ return -ENODEV;
+ }
return snd_soc_component_write(&codec->component, reg, val);
}
EXPORT_SYMBOL_GPL(snd_soc_write);