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.
Change-Id: Icafb2a8b970fb53ebc3eb7c44d075f1c01985072
Signed-off-by: Joonwoo Park <joonwoop@codeaurora.org>
diff --git a/sound/core/init.c b/sound/core/init.c
index f300bd3..6559a40 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -55,6 +55,8 @@
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
*/
@@ -104,10 +106,40 @@
snd_iprintf(buffer, "%s\n", entry->card->id);
}
+static int 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 inline int init_info_for_card(struct snd_card *card)
{
int err;
- struct snd_info_entry *entry;
+ struct snd_info_entry *entry, *entry_state;
if ((err = snd_info_card_register(card)) < 0) {
snd_printd("unable to create card info\n");
@@ -123,6 +155,24 @@
entry = NULL;
}
card->proc_id = entry;
+
+ entry_state = snd_info_create_card_entry(card, "state",
+ card->proc_root);
+ if (entry_state == NULL) {
+ snd_printd("unable to create card entry state\n");
+ card->proc_id = NULL;
+ return err;
+ }
+ entry_state->size = SND_CARD_STATE_MAX_LEN;
+ entry_state->content = SNDRV_INFO_CONTENT_DATA;
+ entry_state->c.ops = &snd_card_state_proc_ops;
+ err = snd_info_register(entry_state);
+ if (err < 0) {
+ snd_printd("unable to register card entry state\n");
+ card->proc_id = NULL;
+ return err;
+ }
+
return 0;
}
#else /* !CONFIG_PROC_FS */
@@ -216,6 +266,7 @@
mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
#endif
+ init_waitqueue_head(&card->offline_poll_wait);
/* the control interface cannot be accessed from the user space until */
/* snd_cards_bitmask and snd_cards are set with snd_card_register */
err = snd_ctl_create(card);
@@ -909,6 +960,35 @@
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.