diff --git a/include/sound/core.h b/include/sound/core.h index ee238f100f73..2ad852853074 100644 --- a/include/sound/core.h +++ b/include/sound/core.h @@ -118,6 +118,11 @@ struct snd_card { const struct attribute_group *dev_groups[4]; /* assigned sysfs attr */ bool registered; /* card_dev is registered? */ wait_queue_head_t remove_sleep; +#ifdef CONFIG_AUDIO_QGKI + int offline; /* if this sound card is offline */ + unsigned long offline_change; + wait_queue_head_t offline_poll_wait; +#endif #ifdef CONFIG_PM unsigned int power_state; /* power state */ @@ -250,6 +255,11 @@ static inline void snd_card_unref(struct snd_card *card) put_device(&card->card_dev); } +#ifdef CONFIG_AUDIO_QGKI +void snd_card_change_online_state(struct snd_card *card, int online); +bool snd_card_is_online_state(struct snd_card *card); +#endif + #define snd_card_set_dev(card, devptr) ((card)->dev = (devptr)) /* device.c */ diff --git a/include/sound/soc.h b/include/sound/soc.h index f264c6509f00..f2daadd33661 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -534,6 +534,11 @@ static inline void snd_soc_jack_free_gpios(struct snd_soc_jack *jack, int count, } #endif +#ifdef CONFIG_AUDIO_QGKI +void snd_soc_card_change_online_state(struct snd_soc_card *soc_card, + int online); +#endif + struct snd_ac97 *snd_soc_alloc_ac97_component(struct snd_soc_component *component); struct snd_ac97 *snd_soc_new_ac97_component(struct snd_soc_component *component, unsigned int id, unsigned int id_mask); diff --git a/sound/core/info.c b/sound/core/info.c index e051a029ccfb..3b300358f8c4 100644 --- a/sound/core/info.c +++ b/sound/core/info.c @@ -71,6 +71,43 @@ EXPORT_SYMBOL(snd_seq_root); struct snd_info_entry *snd_oss_root; #endif +#ifdef CONFIG_AUDIO_QGKI +#define SND_CARD_STATE_MAX_LEN 16 + +static ssize_t snd_info_card_state_read(struct snd_info_entry *entry, + void *file_private_data, struct file *file, + char __user *buf, size_t count, loff_t pos) +{ + struct snd_card *card = entry->private_data; + 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", + card->offline ? "OFFLINE" : "ONLINE"); + return simple_read_from_buffer(buf, count, &pos, buffer, len); +} + +static unsigned int snd_info_card_state_poll(struct snd_info_entry *entry, + void *private_data, struct file *file, + poll_table *wait) +{ + struct snd_card *card = entry->private_data; + + poll_wait(file, &card->offline_poll_wait, wait); + if (xchg(&card->offline_change, 0)) + return POLLIN | POLLPRI | POLLRDNORM; + else + return 0; +} + +static struct snd_info_entry_ops snd_info_card_state_proc_ops = { + .read = snd_info_card_state_read, + .poll = snd_info_card_state_poll, +}; +#endif + static int alloc_info_private(struct snd_info_entry *entry, struct snd_info_private_data **ret) { @@ -505,6 +542,10 @@ int snd_info_card_create(struct snd_card *card) { char str[8]; struct snd_info_entry *entry; +#ifdef CONFIG_AUDIO_QGKI + struct snd_info_entry *entry_state; +#endif + int ret; if (snd_BUG_ON(!card)) return -ENXIO; @@ -515,7 +556,23 @@ int snd_info_card_create(struct snd_card *card) return -ENOMEM; card->proc_root = entry; - return snd_card_ro_proc_new(card, "id", card, snd_card_id_read); + ret = snd_card_ro_proc_new(card, "id", card, snd_card_id_read); + if (ret) + return ret; + +#ifdef CONFIG_AUDIO_QGKI + 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_root = NULL; + return -ENOMEM; + } + entry_state->size = SND_CARD_STATE_MAX_LEN; + entry_state->content = SNDRV_INFO_CONTENT_DATA; + entry_state->c.ops = &snd_info_card_state_proc_ops; +#endif + return 0; } /* diff --git a/sound/core/init.c b/sound/core/init.c index db99b7fad6ad..c2b70bb09b42 100644 --- a/sound/core/init.c +++ b/sound/core/init.c @@ -215,7 +215,9 @@ int snd_card_new(struct device *parent, int idx, const char *xid, init_waitqueue_head(&card->power_sleep); #endif init_waitqueue_head(&card->remove_sleep); - +#ifdef CONFIG_AUDIO_QGKI + init_waitqueue_head(&card->offline_poll_wait); +#endif device_initialize(&card->card_dev); card->card_dev.parent = parent; card->card_dev.class = sound_class; @@ -981,6 +983,37 @@ int snd_card_file_remove(struct snd_card *card, struct file *file) } EXPORT_SYMBOL(snd_card_file_remove); +#ifdef CONFIG_AUDIO_QGKI +/** + * 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); +#endif + #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 88978a3036c4..1af19d296089 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2921,6 +2921,19 @@ struct snd_soc_component *snd_soc_lookup_component(struct device *dev, } EXPORT_SYMBOL_GPL(snd_soc_lookup_component); +#ifdef CONFIG_AUDIO_QGKI +/** + * 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); +#endif + /* Retrieve a card's name from device tree */ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname)