diff options
Diffstat (limited to 'sound/core')
-rw-r--r-- | sound/core/Kconfig | 3 | ||||
-rw-r--r-- | sound/core/Makefile | 3 | ||||
-rw-r--r-- | sound/core/ctljack.c | 41 | ||||
-rw-r--r-- | sound/core/jack.c | 133 |
4 files changed, 157 insertions, 23 deletions
diff --git a/sound/core/Kconfig b/sound/core/Kconfig index 313f22e9d929..63cc2e967099 100644 --- a/sound/core/Kconfig +++ b/sound/core/Kconfig @@ -221,9 +221,6 @@ config SND_PCM_XRUN_DEBUG config SND_VMASTER bool -config SND_KCTL_JACK - bool - config SND_DMA_SGBUF def_bool y depends on X86 diff --git a/sound/core/Makefile b/sound/core/Makefile index ae1d32b084fd..7dd17a365269 100644 --- a/sound/core/Makefile +++ b/sound/core/Makefile @@ -11,8 +11,7 @@ endif snd-$(CONFIG_ISA_DMA_API) += isadma.o snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o snd-$(CONFIG_SND_VMASTER) += vmaster.o -snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o -snd-$(CONFIG_SND_JACK) += jack.o +snd-$(CONFIG_SND_JACK) += ctljack.o jack.o snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \ pcm_memory.o memalloc.o diff --git a/sound/core/ctljack.c b/sound/core/ctljack.c index e4b38fbe51da..8f8d1033425c 100644 --- a/sound/core/ctljack.c +++ b/sound/core/ctljack.c @@ -31,19 +31,49 @@ static struct snd_kcontrol_new jack_detect_kctl = { .get = jack_detect_kctl_get, }; +static int get_available_index(struct snd_card *card, const char *name) +{ + struct snd_ctl_elem_id sid; + + memset(&sid, 0, sizeof(sid)); + + sid.index = 0; + sid.iface = SNDRV_CTL_ELEM_IFACE_CARD; + strlcpy(sid.name, name, sizeof(sid.name)); + + while (snd_ctl_find_id(card, &sid)) + sid.index++; + + return sid.index; +} + +static void jack_kctl_name_gen(char *name, const char *src_name, int size) +{ + size_t count = strlen(src_name); + bool need_cat = true; + + /* remove redundant " Jack" from src_name */ + if (count >= 5) + need_cat = strncmp(&src_name[count - 5], " Jack", 5) ? true : false; + + snprintf(name, size, need_cat ? "%s Jack" : "%s", src_name); + +} + struct snd_kcontrol * -snd_kctl_jack_new(const char *name, int idx, void *private_data) +snd_kctl_jack_new(const char *name, struct snd_card *card) { struct snd_kcontrol *kctl; - kctl = snd_ctl_new1(&jack_detect_kctl, private_data); + + kctl = snd_ctl_new1(&jack_detect_kctl, NULL); if (!kctl) return NULL; - snprintf(kctl->id.name, sizeof(kctl->id.name), "%s Jack", name); - kctl->id.index = idx; + + jack_kctl_name_gen(kctl->id.name, name, sizeof(kctl->id.name)); + kctl->id.index = get_available_index(card, name); kctl->private_value = 0; return kctl; } -EXPORT_SYMBOL_GPL(snd_kctl_jack_new); void snd_kctl_jack_report(struct snd_card *card, struct snd_kcontrol *kctl, bool status) @@ -53,4 +83,3 @@ void snd_kctl_jack_report(struct snd_card *card, kctl->private_value = status; snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); } -EXPORT_SYMBOL_GPL(snd_kctl_jack_report); diff --git a/sound/core/jack.c b/sound/core/jack.c index 8658578eb584..e8b51f52e7df 100644 --- a/sound/core/jack.c +++ b/sound/core/jack.c @@ -24,6 +24,13 @@ #include <linux/module.h> #include <sound/jack.h> #include <sound/core.h> +#include <sound/control.h> + +struct snd_jack_kctl { + struct snd_kcontrol *kctl; + struct list_head list; /* list of controls belong to the same jack */ + unsigned int mask_bits; /* only masked status bits are reported via kctl */ +}; static int jack_switch_types[SND_JACK_SWITCH_TYPES] = { SW_HEADPHONE_INSERT, @@ -54,7 +61,13 @@ static int snd_jack_dev_disconnect(struct snd_device *device) static int snd_jack_dev_free(struct snd_device *device) { struct snd_jack *jack = device->device_data; + struct snd_card *card = device->card; + struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl; + list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) { + list_del_init(&jack_kctl->list); + snd_ctl_remove(card, jack_kctl->kctl); + } if (jack->private_free) jack->private_free(jack); @@ -100,6 +113,77 @@ static int snd_jack_dev_register(struct snd_device *device) return err; } +static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl) +{ + struct snd_jack_kctl *jack_kctl; + + jack_kctl = kctl->private_data; + if (jack_kctl) { + list_del(&jack_kctl->list); + kfree(jack_kctl); + } +} + +static void snd_jack_kctl_add(struct snd_jack *jack, struct snd_jack_kctl *jack_kctl) +{ + list_add_tail(&jack_kctl->list, &jack->kctl_list); +} + +static struct snd_jack_kctl * snd_jack_kctl_new(struct snd_card *card, const char *name, unsigned int mask) +{ + struct snd_kcontrol *kctl; + struct snd_jack_kctl *jack_kctl; + int err; + + kctl = snd_kctl_jack_new(name, card); + if (!kctl) + return NULL; + + err = snd_ctl_add(card, kctl); + if (err < 0) + return NULL; + + jack_kctl = kzalloc(sizeof(*jack_kctl), GFP_KERNEL); + + if (!jack_kctl) + goto error; + + jack_kctl->kctl = kctl; + jack_kctl->mask_bits = mask; + + kctl->private_data = jack_kctl; + kctl->private_free = snd_jack_kctl_private_free; + + return jack_kctl; +error: + snd_ctl_free_one(kctl); + return NULL; +} + +/** + * snd_jack_add_new_kctl - Create a new snd_jack_kctl and add it to jack + * @jack: the jack instance which the kctl will attaching to + * @name: the name for the snd_kcontrol object + * @mask: a bitmask of enum snd_jack_type values that can be detected + * by this snd_jack_kctl object. + * + * Creates a new snd_kcontrol object and adds it to the jack kctl_list. + * + * Return: Zero if successful, or a negative error code on failure. + */ +int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask) +{ + struct snd_jack_kctl *jack_kctl; + + jack_kctl = snd_jack_kctl_new(jack->card, name, mask); + if (!jack_kctl) + return -ENOMEM; + + snd_jack_kctl_add(jack, jack_kctl); + return 0; +} +EXPORT_SYMBOL(snd_jack_add_new_kctl); + /** * snd_jack_new - Create a new jack * @card: the card instance @@ -107,6 +191,8 @@ static int snd_jack_dev_register(struct snd_device *device) * @type: a bitmask of enum snd_jack_type values that can be detected by * this jack * @jjack: Used to provide the allocated jack object to the caller. + * @initial_kctl: if true, create a kcontrol and add it to the jack list. + * @phantom_jack: Don't create a input device for phantom jacks. * * Creates a new jack object. * @@ -114,9 +200,10 @@ static int snd_jack_dev_register(struct snd_device *device) * On success @jjack will be initialised. */ int snd_jack_new(struct snd_card *card, const char *id, int type, - struct snd_jack **jjack) + struct snd_jack **jjack, bool initial_kctl, bool phantom_jack) { struct snd_jack *jack; + struct snd_jack_kctl *jack_kctl = NULL; int err; int i; static struct snd_device_ops ops = { @@ -125,31 +212,47 @@ int snd_jack_new(struct snd_card *card, const char *id, int type, .dev_disconnect = snd_jack_dev_disconnect, }; + if (initial_kctl) { + jack_kctl = snd_jack_kctl_new(card, id, type); + if (!jack_kctl) + return -ENOMEM; + } + jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); if (jack == NULL) return -ENOMEM; jack->id = kstrdup(id, GFP_KERNEL); - jack->input_dev = input_allocate_device(); - if (jack->input_dev == NULL) { - err = -ENOMEM; - goto fail_input; - } + /* don't creat input device for phantom jack */ + if (!phantom_jack) { + jack->input_dev = input_allocate_device(); + if (jack->input_dev == NULL) { + err = -ENOMEM; + goto fail_input; + } - jack->input_dev->phys = "ALSA"; + jack->input_dev->phys = "ALSA"; - jack->type = type; + jack->type = type; - for (i = 0; i < SND_JACK_SWITCH_TYPES; i++) - if (type & (1 << i)) - input_set_capability(jack->input_dev, EV_SW, - jack_switch_types[i]); + for (i = 0; i < SND_JACK_SWITCH_TYPES; i++) + if (type & (1 << i)) + input_set_capability(jack->input_dev, EV_SW, + jack_switch_types[i]); + + } err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); if (err < 0) goto fail_input; + jack->card = card; + INIT_LIST_HEAD(&jack->kctl_list); + + if (initial_kctl) + snd_jack_kctl_add(jack, jack_kctl); + *jjack = jack; return 0; @@ -230,6 +333,7 @@ EXPORT_SYMBOL(snd_jack_set_key); */ void snd_jack_report(struct snd_jack *jack, int status) { + struct snd_jack_kctl *jack_kctl; int i; if (!jack) @@ -252,6 +356,11 @@ void snd_jack_report(struct snd_jack *jack, int status) } input_sync(jack->input_dev); + + list_for_each_entry(jack_kctl, &jack->kctl_list, list) + snd_kctl_jack_report(jack->card, jack_kctl->kctl, + status & jack_kctl->mask_bits); + } EXPORT_SYMBOL(snd_jack_report); |