diff options
Diffstat (limited to 'kernel/sound/core/jack.c')
-rw-r--r-- | kernel/sound/core/jack.c | 146 |
1 files changed, 130 insertions, 16 deletions
diff --git a/kernel/sound/core/jack.c b/kernel/sound/core/jack.c index 8658578eb..7237acbdc 100644 --- a/kernel/sound/core/jack.c +++ b/kernel/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); @@ -74,6 +87,10 @@ static int snd_jack_dev_register(struct snd_device *device) snprintf(jack->name, sizeof(jack->name), "%s %s", card->shortname, jack->id); + + if (!jack->input_dev) + return 0; + jack->input_dev->name = jack->name; /* Default to the sound card device. */ @@ -100,6 +117,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 +195,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 +204,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 +216,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; @@ -175,6 +282,8 @@ EXPORT_SYMBOL(snd_jack_new); void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) { WARN_ON(jack->registered); + if (!jack->input_dev) + return; jack->input_dev->dev.parent = parent; } @@ -230,11 +339,19 @@ 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) return; + list_for_each_entry(jack_kctl, &jack->kctl_list, list) + snd_kctl_jack_report(jack->card, jack_kctl->kctl, + status & jack_kctl->mask_bits); + + if (!jack->input_dev) + return; + for (i = 0; i < ARRAY_SIZE(jack->key); i++) { int testbit = SND_JACK_BTN_0 >> i; @@ -252,9 +369,6 @@ void snd_jack_report(struct snd_jack *jack, int status) } input_sync(jack->input_dev); + } EXPORT_SYMBOL(snd_jack_report); - -MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>"); -MODULE_DESCRIPTION("Jack detection support for ALSA"); -MODULE_LICENSE("GPL"); |