aboutsummaryrefslogtreecommitdiffstats
path: root/sound/core/jack.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/core/jack.c')
-rw-r--r--sound/core/jack.c146
1 files changed, 130 insertions, 16 deletions
diff --git a/sound/core/jack.c b/sound/core/jack.c
index 8658578eb584..7237acbdcbbc 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
@@ -74,6 +87,10 @@ static int snd_jack_dev_register(struct snd_device *device)
74 87
75 snprintf(jack->name, sizeof(jack->name), "%s %s", 88 snprintf(jack->name, sizeof(jack->name), "%s %s",
76 card->shortname, jack->id); 89 card->shortname, jack->id);
90
91 if (!jack->input_dev)
92 return 0;
93
77 jack->input_dev->name = jack->name; 94 jack->input_dev->name = jack->name;
78 95
79 /* Default to the sound card device. */ 96 /* Default to the sound card device. */
@@ -100,6 +117,77 @@ static int snd_jack_dev_register(struct snd_device *device)
100 return err; 117 return err;
101} 118}
102 119
120static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl)
121{
122 struct snd_jack_kctl *jack_kctl;
123
124 jack_kctl = kctl->private_data;
125 if (jack_kctl) {
126 list_del(&jack_kctl->list);
127 kfree(jack_kctl);
128 }
129}
130
131static void snd_jack_kctl_add(struct snd_jack *jack, struct snd_jack_kctl *jack_kctl)
132{
133 list_add_tail(&jack_kctl->list, &jack->kctl_list);
134}
135
136static struct snd_jack_kctl * snd_jack_kctl_new(struct snd_card *card, const char *name, unsigned int mask)
137{
138 struct snd_kcontrol *kctl;
139 struct snd_jack_kctl *jack_kctl;
140 int err;
141
142 kctl = snd_kctl_jack_new(name, card);
143 if (!kctl)
144 return NULL;
145
146 err = snd_ctl_add(card, kctl);
147 if (err < 0)
148 return NULL;
149
150 jack_kctl = kzalloc(sizeof(*jack_kctl), GFP_KERNEL);
151
152 if (!jack_kctl)
153 goto error;
154
155 jack_kctl->kctl = kctl;
156 jack_kctl->mask_bits = mask;
157
158 kctl->private_data = jack_kctl;
159 kctl->private_free = snd_jack_kctl_private_free;
160
161 return jack_kctl;
162error:
163 snd_ctl_free_one(kctl);
164 return NULL;
165}
166
167/**
168 * snd_jack_add_new_kctl - Create a new snd_jack_kctl and add it to jack
169 * @jack: the jack instance which the kctl will attaching to
170 * @name: the name for the snd_kcontrol object
171 * @mask: a bitmask of enum snd_jack_type values that can be detected
172 * by this snd_jack_kctl object.
173 *
174 * Creates a new snd_kcontrol object and adds it to the jack kctl_list.
175 *
176 * Return: Zero if successful, or a negative error code on failure.
177 */
178int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask)
179{
180 struct snd_jack_kctl *jack_kctl;
181
182 jack_kctl = snd_jack_kctl_new(jack->card, name, mask);
183 if (!jack_kctl)
184 return -ENOMEM;
185
186 snd_jack_kctl_add(jack, jack_kctl);
187 return 0;
188}
189EXPORT_SYMBOL(snd_jack_add_new_kctl);
190
103/** 191/**
104 * snd_jack_new - Create a new jack 192 * snd_jack_new - Create a new jack
105 * @card: the card instance 193 * @card: the card instance
@@ -107,6 +195,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 195 * @type: a bitmask of enum snd_jack_type values that can be detected by
108 * this jack 196 * this jack
109 * @jjack: Used to provide the allocated jack object to the caller. 197 * @jjack: Used to provide the allocated jack object to the caller.
198 * @initial_kctl: if true, create a kcontrol and add it to the jack list.
199 * @phantom_jack: Don't create a input device for phantom jacks.
110 * 200 *
111 * Creates a new jack object. 201 * Creates a new jack object.
112 * 202 *
@@ -114,9 +204,10 @@ static int snd_jack_dev_register(struct snd_device *device)
114 * On success @jjack will be initialised. 204 * On success @jjack will be initialised.
115 */ 205 */
116int snd_jack_new(struct snd_card *card, const char *id, int type, 206int snd_jack_new(struct snd_card *card, const char *id, int type,
117 struct snd_jack **jjack) 207 struct snd_jack **jjack, bool initial_kctl, bool phantom_jack)
118{ 208{
119 struct snd_jack *jack; 209 struct snd_jack *jack;
210 struct snd_jack_kctl *jack_kctl = NULL;
120 int err; 211 int err;
121 int i; 212 int i;
122 static struct snd_device_ops ops = { 213 static struct snd_device_ops ops = {
@@ -125,31 +216,47 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
125 .dev_disconnect = snd_jack_dev_disconnect, 216 .dev_disconnect = snd_jack_dev_disconnect,
126 }; 217 };
127 218
219 if (initial_kctl) {
220 jack_kctl = snd_jack_kctl_new(card, id, type);
221 if (!jack_kctl)
222 return -ENOMEM;
223 }
224
128 jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); 225 jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL);
129 if (jack == NULL) 226 if (jack == NULL)
130 return -ENOMEM; 227 return -ENOMEM;
131 228
132 jack->id = kstrdup(id, GFP_KERNEL); 229 jack->id = kstrdup(id, GFP_KERNEL);
133 230
134 jack->input_dev = input_allocate_device(); 231 /* don't creat input device for phantom jack */
135 if (jack->input_dev == NULL) { 232 if (!phantom_jack) {
136 err = -ENOMEM; 233 jack->input_dev = input_allocate_device();
137 goto fail_input; 234 if (jack->input_dev == NULL) {
138 } 235 err = -ENOMEM;
236 goto fail_input;
237 }
139 238
140 jack->input_dev->phys = "ALSA"; 239 jack->input_dev->phys = "ALSA";
141 240
142 jack->type = type; 241 jack->type = type;
143 242
144 for (i = 0; i < SND_JACK_SWITCH_TYPES; i++) 243 for (i = 0; i < SND_JACK_SWITCH_TYPES; i++)
145 if (type & (1 << i)) 244 if (type & (1 << i))
146 input_set_capability(jack->input_dev, EV_SW, 245 input_set_capability(jack->input_dev, EV_SW,
147 jack_switch_types[i]); 246 jack_switch_types[i]);
247
248 }
148 249
149 err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); 250 err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
150 if (err < 0) 251 if (err < 0)
151 goto fail_input; 252 goto fail_input;
152 253
254 jack->card = card;
255 INIT_LIST_HEAD(&jack->kctl_list);
256
257 if (initial_kctl)
258 snd_jack_kctl_add(jack, jack_kctl);
259
153 *jjack = jack; 260 *jjack = jack;
154 261
155 return 0; 262 return 0;
@@ -175,6 +282,8 @@ EXPORT_SYMBOL(snd_jack_new);
175void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) 282void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
176{ 283{
177 WARN_ON(jack->registered); 284 WARN_ON(jack->registered);
285 if (!jack->input_dev)
286 return;
178 287
179 jack->input_dev->dev.parent = parent; 288 jack->input_dev->dev.parent = parent;
180} 289}
@@ -230,11 +339,19 @@ EXPORT_SYMBOL(snd_jack_set_key);
230 */ 339 */
231void snd_jack_report(struct snd_jack *jack, int status) 340void snd_jack_report(struct snd_jack *jack, int status)
232{ 341{
342 struct snd_jack_kctl *jack_kctl;
233 int i; 343 int i;
234 344
235 if (!jack) 345 if (!jack)
236 return; 346 return;
237 347
348 list_for_each_entry(jack_kctl, &jack->kctl_list, list)
349 snd_kctl_jack_report(jack->card, jack_kctl->kctl,
350 status & jack_kctl->mask_bits);
351
352 if (!jack->input_dev)
353 return;
354
238 for (i = 0; i < ARRAY_SIZE(jack->key); i++) { 355 for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
239 int testbit = SND_JACK_BTN_0 >> i; 356 int testbit = SND_JACK_BTN_0 >> i;
240 357
@@ -252,9 +369,6 @@ void snd_jack_report(struct snd_jack *jack, int status)
252 } 369 }
253 370
254 input_sync(jack->input_dev); 371 input_sync(jack->input_dev);
372
255} 373}
256EXPORT_SYMBOL(snd_jack_report); 374EXPORT_SYMBOL(snd_jack_report);
257
258MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
259MODULE_DESCRIPTION("Jack detection support for ALSA");
260MODULE_LICENSE("GPL");