These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / sound / core / jack.c
index 8658578..7237acb 100644 (file)
 #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");