aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/jack.c
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2015-04-28 02:31:31 -0400
committerTakashi Iwai <tiwai@suse.de>2015-04-28 02:31:31 -0400
commit1962fcab4ee80e555bcc9d0f50e416800d474fa2 (patch)
tree945ba95f11016871f9d5241b7da2712f9367081a /sound/core/jack.c
parentf1a77547c21fe942e95ebaadbc9200f26d138574 (diff)
parent12e180a27f3e066a4ed4a446d428fd117f168beb (diff)
Merge branch 'topic/jack' into for-next
Diffstat (limited to 'sound/core/jack.c')
-rw-r--r--sound/core/jack.c133
1 files changed, 121 insertions, 12 deletions
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 @@
24#include <linux/module.h> 24#include <linux/module.h>
25#include <sound/jack.h> 25#include <sound/jack.h>
26#include <sound/core.h> 26#include <sound/core.h>
27#include <sound/control.h>
28
29struct snd_jack_kctl {
30 struct snd_kcontrol *kctl;
31 struct list_head list; /* list of controls belong to the same jack */
32 unsigned int mask_bits; /* only masked status bits are reported via kctl */
33};
27 34
28static int jack_switch_types[SND_JACK_SWITCH_TYPES] = { 35static int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
29 SW_HEADPHONE_INSERT, 36 SW_HEADPHONE_INSERT,
@@ -54,7 +61,13 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
54static int snd_jack_dev_free(struct snd_device *device) 61static int snd_jack_dev_free(struct snd_device *device)
55{ 62{
56 struct snd_jack *jack = device->device_data; 63 struct snd_jack *jack = device->device_data;
64 struct snd_card *card = device->card;
65 struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl;
57 66
67 list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) {
68 list_del_init(&jack_kctl->list);
69 snd_ctl_remove(card, jack_kctl->kctl);
70 }
58 if (jack->private_free) 71 if (jack->private_free)
59 jack->private_free(jack); 72 jack->private_free(jack);
60 73
@@ -100,6 +113,77 @@ static int snd_jack_dev_register(struct snd_device *device)
100 return err; 113 return err;
101} 114}
102 115
116static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl)
117{
118 struct snd_jack_kctl *jack_kctl;
119
120 jack_kctl = kctl->private_data;
121 if (jack_kctl) {
122 list_del(&jack_kctl->list);
123 kfree(jack_kctl);
124 }
125}
126
127static void snd_jack_kctl_add(struct snd_jack *jack, struct snd_jack_kctl *jack_kctl)
128{
129 list_add_tail(&jack_kctl->list, &jack->kctl_list);
130}
131
132static struct snd_jack_kctl * snd_jack_kctl_new(struct snd_card *card, const char *name, unsigned int mask)
133{
134 struct snd_kcontrol *kctl;
135 struct snd_jack_kctl *jack_kctl;
136 int err;
137
138 kctl = snd_kctl_jack_new(name, card);
139 if (!kctl)
140 return NULL;
141
142 err = snd_ctl_add(card, kctl);
143 if (err < 0)
144 return NULL;
145
146 jack_kctl = kzalloc(sizeof(*jack_kctl), GFP_KERNEL);
147
148 if (!jack_kctl)
149 goto error;
150
151 jack_kctl->kctl = kctl;
152 jack_kctl->mask_bits = mask;
153
154 kctl->private_data = jack_kctl;
155 kctl->private_free = snd_jack_kctl_private_free;
156
157 return jack_kctl;
158error:
159 snd_ctl_free_one(kctl);
160 return NULL;
161}
162
163/**
164 * snd_jack_add_new_kctl - Create a new snd_jack_kctl and add it to jack
165 * @jack: the jack instance which the kctl will attaching to
166 * @name: the name for the snd_kcontrol object
167 * @mask: a bitmask of enum snd_jack_type values that can be detected
168 * by this snd_jack_kctl object.
169 *
170 * Creates a new snd_kcontrol object and adds it to the jack kctl_list.
171 *
172 * Return: Zero if successful, or a negative error code on failure.
173 */
174int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask)
175{
176 struct snd_jack_kctl *jack_kctl;
177
178 jack_kctl = snd_jack_kctl_new(jack->card, name, mask);
179 if (!jack_kctl)
180 return -ENOMEM;
181
182 snd_jack_kctl_add(jack, jack_kctl);
183 return 0;
184}
185EXPORT_SYMBOL(snd_jack_add_new_kctl);
186
103/** 187/**
104 * snd_jack_new - Create a new jack 188 * snd_jack_new - Create a new jack
105 * @card: the card instance 189 * @card: the card instance
@@ -107,6 +191,8 @@ static int snd_jack_dev_register(struct snd_device *device)
107 * @type: a bitmask of enum snd_jack_type values that can be detected by 191 * @type: a bitmask of enum snd_jack_type values that can be detected by
108 * this jack 192 * this jack
109 * @jjack: Used to provide the allocated jack object to the caller. 193 * @jjack: Used to provide the allocated jack object to the caller.
194 * @initial_kctl: if true, create a kcontrol and add it to the jack list.
195 * @phantom_jack: Don't create a input device for phantom jacks.
110 * 196 *
111 * Creates a new jack object. 197 * Creates a new jack object.
112 * 198 *
@@ -114,9 +200,10 @@ static int snd_jack_dev_register(struct snd_device *device)
114 * On success @jjack will be initialised. 200 * On success @jjack will be initialised.
115 */ 201 */
116int snd_jack_new(struct snd_card *card, const char *id, int type, 202int snd_jack_new(struct snd_card *card, const char *id, int type,
117 struct snd_jack **jjack) 203 struct snd_jack **jjack, bool initial_kctl, bool phantom_jack)
118{ 204{
119 struct snd_jack *jack; 205 struct snd_jack *jack;
206 struct snd_jack_kctl *jack_kctl = NULL;
120 int err; 207 int err;
121 int i; 208 int i;
122 static struct snd_device_ops ops = { 209 static struct snd_device_ops ops = {
@@ -125,31 +212,47 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
125 .dev_disconnect = snd_jack_dev_disconnect, 212 .dev_disconnect = snd_jack_dev_disconnect,
126 }; 213 };
127 214
215 if (initial_kctl) {
216 jack_kctl = snd_jack_kctl_new(card, id, type);
217 if (!jack_kctl)
218 return -ENOMEM;
219 }
220
128 jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); 221 jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL);
129 if (jack == NULL) 222 if (jack == NULL)
130 return -ENOMEM; 223 return -ENOMEM;
131 224
132 jack->id = kstrdup(id, GFP_KERNEL); 225 jack->id = kstrdup(id, GFP_KERNEL);
133 226
134 jack->input_dev = input_allocate_device(); 227 /* don't creat input device for phantom jack */
135 if (jack->input_dev == NULL) { 228 if (!phantom_jack) {
136 err = -ENOMEM; 229 jack->input_dev = input_allocate_device();
137 goto fail_input; 230 if (jack->input_dev == NULL) {
138 } 231 err = -ENOMEM;
232 goto fail_input;
233 }
139 234
140 jack->input_dev->phys = "ALSA"; 235 jack->input_dev->phys = "ALSA";
141 236
142 jack->type = type; 237 jack->type = type;
143 238
144 for (i = 0; i < SND_JACK_SWITCH_TYPES; i++) 239 for (i = 0; i < SND_JACK_SWITCH_TYPES; i++)
145 if (type & (1 << i)) 240 if (type & (1 << i))
146 input_set_capability(jack->input_dev, EV_SW, 241 input_set_capability(jack->input_dev, EV_SW,
147 jack_switch_types[i]); 242 jack_switch_types[i]);
243
244 }
148 245
149 err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); 246 err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
150 if (err < 0) 247 if (err < 0)
151 goto fail_input; 248 goto fail_input;
152 249
250 jack->card = card;
251 INIT_LIST_HEAD(&jack->kctl_list);
252
253 if (initial_kctl)
254 snd_jack_kctl_add(jack, jack_kctl);
255
153 *jjack = jack; 256 *jjack = jack;
154 257
155 return 0; 258 return 0;
@@ -230,6 +333,7 @@ EXPORT_SYMBOL(snd_jack_set_key);
230 */ 333 */
231void snd_jack_report(struct snd_jack *jack, int status) 334void snd_jack_report(struct snd_jack *jack, int status)
232{ 335{
336 struct snd_jack_kctl *jack_kctl;
233 int i; 337 int i;
234 338
235 if (!jack) 339 if (!jack)
@@ -252,6 +356,11 @@ void snd_jack_report(struct snd_jack *jack, int status)
252 } 356 }
253 357
254 input_sync(jack->input_dev); 358 input_sync(jack->input_dev);
359
360 list_for_each_entry(jack_kctl, &jack->kctl_list, list)
361 snd_kctl_jack_report(jack->card, jack_kctl->kctl,
362 status & jack_kctl->mask_bits);
363
255} 364}
256EXPORT_SYMBOL(snd_jack_report); 365EXPORT_SYMBOL(snd_jack_report);
257 366