Commit | Line | Data |
---|---|---|
1a59d1b8 | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
e76d8cea MB |
2 | /* |
3 | * Jack abstraction layer | |
4 | * | |
5 | * Copyright 2008 Wolfson Microelectronics | |
e76d8cea MB |
6 | */ |
7 | ||
8 | #include <linux/input.h> | |
5a0e3ad6 | 9 | #include <linux/slab.h> |
da155d5b | 10 | #include <linux/module.h> |
2d670ea2 HW |
11 | #include <linux/ctype.h> |
12 | #include <linux/mm.h> | |
13 | #include <linux/debugfs.h> | |
e76d8cea MB |
14 | #include <sound/jack.h> |
15 | #include <sound/core.h> | |
9058cbe1 JY |
16 | #include <sound/control.h> |
17 | ||
18 | struct snd_jack_kctl { | |
19 | struct snd_kcontrol *kctl; | |
20 | struct list_head list; /* list of controls belong to the same jack */ | |
21 | unsigned int mask_bits; /* only masked status bits are reported via kctl */ | |
2d670ea2 HW |
22 | struct snd_jack *jack; /* pointer to struct snd_jack */ |
23 | bool sw_inject_enable; /* allow to inject plug event via debugfs */ | |
24 | #ifdef CONFIG_SND_JACK_INJECTION_DEBUG | |
25 | struct dentry *jack_debugfs_root; /* jack_kctl debugfs root */ | |
26 | #endif | |
9058cbe1 | 27 | }; |
e76d8cea | 28 | |
fe0d128c | 29 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
f98903fc | 30 | static const int jack_switch_types[SND_JACK_SWITCH_TYPES] = { |
bd8a71a7 MB |
31 | SW_HEADPHONE_INSERT, |
32 | SW_MICROPHONE_INSERT, | |
33 | SW_LINEOUT_INSERT, | |
34 | SW_JACK_PHYSICAL_INSERT, | |
d506fc32 | 35 | SW_VIDEOOUT_INSERT, |
7c2f8e40 | 36 | SW_LINEIN_INSERT, |
bd8a71a7 | 37 | }; |
fe0d128c | 38 | #endif /* CONFIG_SND_JACK_INPUT_DEV */ |
bd8a71a7 | 39 | |
32b85442 | 40 | static int snd_jack_dev_disconnect(struct snd_device *device) |
e76d8cea | 41 | { |
fe0d128c | 42 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
e76d8cea MB |
43 | struct snd_jack *jack = device->device_data; |
44 | ||
1b6a6fc5 AS |
45 | mutex_lock(&jack->input_dev_lock); |
46 | if (!jack->input_dev) { | |
47 | mutex_unlock(&jack->input_dev_lock); | |
32b85442 | 48 | return 0; |
1b6a6fc5 | 49 | } |
9d59065c | 50 | |
e76d8cea MB |
51 | /* If the input device is registered with the input subsystem |
52 | * then we need to use a different deallocator. */ | |
53 | if (jack->registered) | |
54 | input_unregister_device(jack->input_dev); | |
55 | else | |
56 | input_free_device(jack->input_dev); | |
32b85442 | 57 | jack->input_dev = NULL; |
1b6a6fc5 | 58 | mutex_unlock(&jack->input_dev_lock); |
fe0d128c | 59 | #endif /* CONFIG_SND_JACK_INPUT_DEV */ |
32b85442 TI |
60 | return 0; |
61 | } | |
62 | ||
63 | static int snd_jack_dev_free(struct snd_device *device) | |
64 | { | |
65 | struct snd_jack *jack = device->device_data; | |
9058cbe1 JY |
66 | struct snd_card *card = device->card; |
67 | struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl; | |
32b85442 | 68 | |
06764dc9 | 69 | down_write(&card->controls_rwsem); |
9058cbe1 JY |
70 | list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) { |
71 | list_del_init(&jack_kctl->list); | |
72 | snd_ctl_remove(card, jack_kctl->kctl); | |
73 | } | |
06764dc9 TI |
74 | up_write(&card->controls_rwsem); |
75 | ||
32b85442 TI |
76 | if (jack->private_free) |
77 | jack->private_free(jack); | |
78 | ||
79 | snd_jack_dev_disconnect(device); | |
e76d8cea | 80 | |
282cd76f | 81 | kfree(jack->id); |
e76d8cea MB |
82 | kfree(jack); |
83 | ||
84 | return 0; | |
85 | } | |
86 | ||
fe0d128c | 87 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
e76d8cea MB |
88 | static int snd_jack_dev_register(struct snd_device *device) |
89 | { | |
90 | struct snd_jack *jack = device->device_data; | |
91 | struct snd_card *card = device->card; | |
ebb812cb | 92 | int err, i; |
e76d8cea MB |
93 | |
94 | snprintf(jack->name, sizeof(jack->name), "%s %s", | |
2678f60d | 95 | card->shortname, jack->id); |
43b2cd54 | 96 | |
1b6a6fc5 AS |
97 | mutex_lock(&jack->input_dev_lock); |
98 | if (!jack->input_dev) { | |
99 | mutex_unlock(&jack->input_dev_lock); | |
43b2cd54 | 100 | return 0; |
1b6a6fc5 | 101 | } |
43b2cd54 | 102 | |
e76d8cea MB |
103 | jack->input_dev->name = jack->name; |
104 | ||
105 | /* Default to the sound card device. */ | |
106 | if (!jack->input_dev->dev.parent) | |
1f3fff7b | 107 | jack->input_dev->dev.parent = snd_card_get_device_link(card); |
e76d8cea | 108 | |
ebb812cb MB |
109 | /* Add capabilities for any keys that are enabled */ |
110 | for (i = 0; i < ARRAY_SIZE(jack->key); i++) { | |
111 | int testbit = SND_JACK_BTN_0 >> i; | |
112 | ||
113 | if (!(jack->type & testbit)) | |
114 | continue; | |
115 | ||
116 | if (!jack->key[i]) | |
117 | jack->key[i] = BTN_0 + i; | |
118 | ||
119 | input_set_capability(jack->input_dev, EV_KEY, jack->key[i]); | |
120 | } | |
121 | ||
e76d8cea MB |
122 | err = input_register_device(jack->input_dev); |
123 | if (err == 0) | |
124 | jack->registered = 1; | |
125 | ||
1b6a6fc5 | 126 | mutex_unlock(&jack->input_dev_lock); |
e76d8cea MB |
127 | return err; |
128 | } | |
fe0d128c | 129 | #endif /* CONFIG_SND_JACK_INPUT_DEV */ |
e76d8cea | 130 | |
2d670ea2 HW |
131 | #ifdef CONFIG_SND_JACK_INJECTION_DEBUG |
132 | static void snd_jack_inject_report(struct snd_jack_kctl *jack_kctl, int status) | |
133 | { | |
134 | struct snd_jack *jack; | |
135 | #ifdef CONFIG_SND_JACK_INPUT_DEV | |
136 | int i; | |
137 | #endif | |
138 | if (!jack_kctl) | |
139 | return; | |
140 | ||
141 | jack = jack_kctl->jack; | |
142 | ||
143 | if (jack_kctl->sw_inject_enable) | |
144 | snd_kctl_jack_report(jack->card, jack_kctl->kctl, | |
145 | status & jack_kctl->mask_bits); | |
146 | ||
147 | #ifdef CONFIG_SND_JACK_INPUT_DEV | |
148 | if (!jack->input_dev) | |
149 | return; | |
150 | ||
151 | for (i = 0; i < ARRAY_SIZE(jack->key); i++) { | |
152 | int testbit = ((SND_JACK_BTN_0 >> i) & jack_kctl->mask_bits); | |
153 | ||
154 | if (jack->type & testbit) | |
155 | input_report_key(jack->input_dev, jack->key[i], | |
156 | status & testbit); | |
157 | } | |
158 | ||
159 | for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) { | |
160 | int testbit = ((1 << i) & jack_kctl->mask_bits); | |
161 | ||
162 | if (jack->type & testbit) | |
163 | input_report_switch(jack->input_dev, | |
164 | jack_switch_types[i], | |
165 | status & testbit); | |
166 | } | |
167 | ||
168 | input_sync(jack->input_dev); | |
169 | #endif /* CONFIG_SND_JACK_INPUT_DEV */ | |
170 | } | |
171 | ||
172 | static ssize_t sw_inject_enable_read(struct file *file, | |
173 | char __user *to, size_t count, loff_t *ppos) | |
174 | { | |
175 | struct snd_jack_kctl *jack_kctl = file->private_data; | |
176 | int len, ret; | |
177 | char buf[128]; | |
178 | ||
179 | len = scnprintf(buf, sizeof(buf), "%s: %s\t\t%s: %i\n", "Jack", jack_kctl->kctl->id.name, | |
180 | "Inject Enabled", jack_kctl->sw_inject_enable); | |
181 | ret = simple_read_from_buffer(to, count, ppos, buf, len); | |
182 | ||
183 | return ret; | |
184 | } | |
185 | ||
186 | static ssize_t sw_inject_enable_write(struct file *file, | |
187 | const char __user *from, size_t count, loff_t *ppos) | |
188 | { | |
189 | struct snd_jack_kctl *jack_kctl = file->private_data; | |
190 | int ret, err; | |
191 | unsigned long enable; | |
192 | char buf[8] = { 0 }; | |
193 | ||
194 | ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, from, count); | |
195 | err = kstrtoul(buf, 0, &enable); | |
196 | if (err) | |
197 | return err; | |
198 | ||
199 | if (jack_kctl->sw_inject_enable == (!!enable)) | |
200 | return ret; | |
201 | ||
202 | jack_kctl->sw_inject_enable = !!enable; | |
203 | ||
204 | if (!jack_kctl->sw_inject_enable) | |
205 | snd_jack_report(jack_kctl->jack, jack_kctl->jack->hw_status_cache); | |
206 | ||
207 | return ret; | |
208 | } | |
209 | ||
210 | static ssize_t jackin_inject_write(struct file *file, | |
211 | const char __user *from, size_t count, loff_t *ppos) | |
212 | { | |
213 | struct snd_jack_kctl *jack_kctl = file->private_data; | |
214 | int ret, err; | |
215 | unsigned long enable; | |
216 | char buf[8] = { 0 }; | |
217 | ||
218 | if (!jack_kctl->sw_inject_enable) | |
219 | return -EINVAL; | |
220 | ||
221 | ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, from, count); | |
222 | err = kstrtoul(buf, 0, &enable); | |
223 | if (err) | |
224 | return err; | |
225 | ||
226 | snd_jack_inject_report(jack_kctl, !!enable ? jack_kctl->mask_bits : 0); | |
227 | ||
228 | return ret; | |
229 | } | |
230 | ||
231 | static ssize_t jack_kctl_id_read(struct file *file, | |
232 | char __user *to, size_t count, loff_t *ppos) | |
233 | { | |
234 | struct snd_jack_kctl *jack_kctl = file->private_data; | |
235 | char buf[64]; | |
236 | int len, ret; | |
237 | ||
238 | len = scnprintf(buf, sizeof(buf), "%s\n", jack_kctl->kctl->id.name); | |
239 | ret = simple_read_from_buffer(to, count, ppos, buf, len); | |
240 | ||
241 | return ret; | |
242 | } | |
243 | ||
244 | /* the bit definition is aligned with snd_jack_types in jack.h */ | |
245 | static const char * const jack_events_name[] = { | |
246 | "HEADPHONE(0x0001)", "MICROPHONE(0x0002)", "LINEOUT(0x0004)", | |
247 | "MECHANICAL(0x0008)", "VIDEOOUT(0x0010)", "LINEIN(0x0020)", | |
248 | "", "", "", "BTN_5(0x0200)", "BTN_4(0x0400)", "BTN_3(0x0800)", | |
249 | "BTN_2(0x1000)", "BTN_1(0x2000)", "BTN_0(0x4000)", "", | |
250 | }; | |
251 | ||
252 | /* the recommended buffer size is 256 */ | |
253 | static int parse_mask_bits(unsigned int mask_bits, char *buf, size_t buf_size) | |
254 | { | |
255 | int i; | |
256 | ||
257 | scnprintf(buf, buf_size, "0x%04x", mask_bits); | |
258 | ||
259 | for (i = 0; i < ARRAY_SIZE(jack_events_name); i++) | |
260 | if (mask_bits & (1 << i)) { | |
261 | strlcat(buf, " ", buf_size); | |
262 | strlcat(buf, jack_events_name[i], buf_size); | |
263 | } | |
264 | strlcat(buf, "\n", buf_size); | |
265 | ||
266 | return strlen(buf); | |
267 | } | |
268 | ||
269 | static ssize_t jack_kctl_mask_bits_read(struct file *file, | |
270 | char __user *to, size_t count, loff_t *ppos) | |
271 | { | |
272 | struct snd_jack_kctl *jack_kctl = file->private_data; | |
273 | char buf[256]; | |
274 | int len, ret; | |
275 | ||
276 | len = parse_mask_bits(jack_kctl->mask_bits, buf, sizeof(buf)); | |
277 | ret = simple_read_from_buffer(to, count, ppos, buf, len); | |
278 | ||
279 | return ret; | |
280 | } | |
281 | ||
282 | static ssize_t jack_kctl_status_read(struct file *file, | |
283 | char __user *to, size_t count, loff_t *ppos) | |
284 | { | |
285 | struct snd_jack_kctl *jack_kctl = file->private_data; | |
286 | char buf[16]; | |
287 | int len, ret; | |
288 | ||
289 | len = scnprintf(buf, sizeof(buf), "%s\n", jack_kctl->kctl->private_value ? | |
290 | "Plugged" : "Unplugged"); | |
291 | ret = simple_read_from_buffer(to, count, ppos, buf, len); | |
292 | ||
293 | return ret; | |
294 | } | |
295 | ||
296 | #ifdef CONFIG_SND_JACK_INPUT_DEV | |
297 | static ssize_t jack_type_read(struct file *file, | |
298 | char __user *to, size_t count, loff_t *ppos) | |
299 | { | |
300 | struct snd_jack_kctl *jack_kctl = file->private_data; | |
301 | char buf[256]; | |
302 | int len, ret; | |
303 | ||
304 | len = parse_mask_bits(jack_kctl->jack->type, buf, sizeof(buf)); | |
305 | ret = simple_read_from_buffer(to, count, ppos, buf, len); | |
306 | ||
307 | return ret; | |
308 | } | |
309 | ||
310 | static const struct file_operations jack_type_fops = { | |
311 | .open = simple_open, | |
312 | .read = jack_type_read, | |
313 | .llseek = default_llseek, | |
314 | }; | |
315 | #endif | |
316 | ||
317 | static const struct file_operations sw_inject_enable_fops = { | |
318 | .open = simple_open, | |
319 | .read = sw_inject_enable_read, | |
320 | .write = sw_inject_enable_write, | |
321 | .llseek = default_llseek, | |
322 | }; | |
323 | ||
324 | static const struct file_operations jackin_inject_fops = { | |
325 | .open = simple_open, | |
326 | .write = jackin_inject_write, | |
327 | .llseek = default_llseek, | |
328 | }; | |
329 | ||
330 | static const struct file_operations jack_kctl_id_fops = { | |
331 | .open = simple_open, | |
332 | .read = jack_kctl_id_read, | |
333 | .llseek = default_llseek, | |
334 | }; | |
335 | ||
336 | static const struct file_operations jack_kctl_mask_bits_fops = { | |
337 | .open = simple_open, | |
338 | .read = jack_kctl_mask_bits_read, | |
339 | .llseek = default_llseek, | |
340 | }; | |
341 | ||
342 | static const struct file_operations jack_kctl_status_fops = { | |
343 | .open = simple_open, | |
344 | .read = jack_kctl_status_read, | |
345 | .llseek = default_llseek, | |
346 | }; | |
347 | ||
348 | static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack, | |
349 | struct snd_jack_kctl *jack_kctl) | |
350 | { | |
351 | char *tname; | |
352 | int i; | |
353 | ||
354 | /* Don't create injection interface for Phantom jacks */ | |
355 | if (strstr(jack_kctl->kctl->id.name, "Phantom")) | |
356 | return 0; | |
357 | ||
358 | tname = kstrdup(jack_kctl->kctl->id.name, GFP_KERNEL); | |
359 | if (!tname) | |
360 | return -ENOMEM; | |
361 | ||
362 | /* replace the chars which are not suitable for folder's name with _ */ | |
363 | for (i = 0; tname[i]; i++) | |
364 | if (!isalnum(tname[i])) | |
365 | tname[i] = '_'; | |
366 | ||
367 | jack_kctl->jack_debugfs_root = debugfs_create_dir(tname, jack->card->debugfs_root); | |
368 | kfree(tname); | |
369 | ||
370 | debugfs_create_file("sw_inject_enable", 0644, jack_kctl->jack_debugfs_root, jack_kctl, | |
371 | &sw_inject_enable_fops); | |
372 | ||
373 | debugfs_create_file("jackin_inject", 0200, jack_kctl->jack_debugfs_root, jack_kctl, | |
374 | &jackin_inject_fops); | |
375 | ||
376 | debugfs_create_file("kctl_id", 0444, jack_kctl->jack_debugfs_root, jack_kctl, | |
377 | &jack_kctl_id_fops); | |
378 | ||
379 | debugfs_create_file("mask_bits", 0444, jack_kctl->jack_debugfs_root, jack_kctl, | |
380 | &jack_kctl_mask_bits_fops); | |
381 | ||
382 | debugfs_create_file("status", 0444, jack_kctl->jack_debugfs_root, jack_kctl, | |
383 | &jack_kctl_status_fops); | |
384 | ||
385 | #ifdef CONFIG_SND_JACK_INPUT_DEV | |
386 | debugfs_create_file("type", 0444, jack_kctl->jack_debugfs_root, jack_kctl, | |
387 | &jack_type_fops); | |
388 | #endif | |
389 | return 0; | |
390 | } | |
391 | ||
392 | static void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl) | |
393 | { | |
394 | debugfs_remove(jack_kctl->jack_debugfs_root); | |
395 | jack_kctl->jack_debugfs_root = NULL; | |
396 | } | |
397 | #else /* CONFIG_SND_JACK_INJECTION_DEBUG */ | |
398 | static int snd_jack_debugfs_add_inject_node(struct snd_jack *jack, | |
399 | struct snd_jack_kctl *jack_kctl) | |
400 | { | |
401 | return 0; | |
402 | } | |
403 | ||
404 | static void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl) | |
405 | { | |
406 | } | |
407 | #endif /* CONFIG_SND_JACK_INJECTION_DEBUG */ | |
408 | ||
9058cbe1 JY |
409 | static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl) |
410 | { | |
411 | struct snd_jack_kctl *jack_kctl; | |
412 | ||
413 | jack_kctl = kctl->private_data; | |
414 | if (jack_kctl) { | |
2d670ea2 | 415 | snd_jack_debugfs_clear_inject_node(jack_kctl); |
9058cbe1 JY |
416 | list_del(&jack_kctl->list); |
417 | kfree(jack_kctl); | |
418 | } | |
419 | } | |
420 | ||
421 | static void snd_jack_kctl_add(struct snd_jack *jack, struct snd_jack_kctl *jack_kctl) | |
422 | { | |
2d670ea2 | 423 | jack_kctl->jack = jack; |
9058cbe1 | 424 | list_add_tail(&jack_kctl->list, &jack->kctl_list); |
2d670ea2 | 425 | snd_jack_debugfs_add_inject_node(jack, jack_kctl); |
9058cbe1 JY |
426 | } |
427 | ||
428 | static struct snd_jack_kctl * snd_jack_kctl_new(struct snd_card *card, const char *name, unsigned int mask) | |
429 | { | |
430 | struct snd_kcontrol *kctl; | |
431 | struct snd_jack_kctl *jack_kctl; | |
432 | int err; | |
433 | ||
2ba2dfa1 | 434 | kctl = snd_kctl_jack_new(name, card); |
9058cbe1 JY |
435 | if (!kctl) |
436 | return NULL; | |
437 | ||
438 | err = snd_ctl_add(card, kctl); | |
439 | if (err < 0) | |
440 | return NULL; | |
441 | ||
442 | jack_kctl = kzalloc(sizeof(*jack_kctl), GFP_KERNEL); | |
443 | ||
444 | if (!jack_kctl) | |
445 | goto error; | |
446 | ||
447 | jack_kctl->kctl = kctl; | |
448 | jack_kctl->mask_bits = mask; | |
449 | ||
450 | kctl->private_data = jack_kctl; | |
451 | kctl->private_free = snd_jack_kctl_private_free; | |
452 | ||
453 | return jack_kctl; | |
454 | error: | |
455 | snd_ctl_free_one(kctl); | |
456 | return NULL; | |
457 | } | |
458 | ||
459 | /** | |
460 | * snd_jack_add_new_kctl - Create a new snd_jack_kctl and add it to jack | |
461 | * @jack: the jack instance which the kctl will attaching to | |
462 | * @name: the name for the snd_kcontrol object | |
463 | * @mask: a bitmask of enum snd_jack_type values that can be detected | |
464 | * by this snd_jack_kctl object. | |
465 | * | |
466 | * Creates a new snd_kcontrol object and adds it to the jack kctl_list. | |
467 | * | |
468 | * Return: Zero if successful, or a negative error code on failure. | |
469 | */ | |
470 | int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask) | |
471 | { | |
472 | struct snd_jack_kctl *jack_kctl; | |
473 | ||
474 | jack_kctl = snd_jack_kctl_new(jack->card, name, mask); | |
475 | if (!jack_kctl) | |
476 | return -ENOMEM; | |
477 | ||
478 | snd_jack_kctl_add(jack, jack_kctl); | |
479 | return 0; | |
480 | } | |
481 | EXPORT_SYMBOL(snd_jack_add_new_kctl); | |
482 | ||
e76d8cea MB |
483 | /** |
484 | * snd_jack_new - Create a new jack | |
485 | * @card: the card instance | |
486 | * @id: an identifying string for this jack | |
487 | * @type: a bitmask of enum snd_jack_type values that can be detected by | |
488 | * this jack | |
489 | * @jjack: Used to provide the allocated jack object to the caller. | |
4e3f0dc6 JY |
490 | * @initial_kctl: if true, create a kcontrol and add it to the jack list. |
491 | * @phantom_jack: Don't create a input device for phantom jacks. | |
e76d8cea MB |
492 | * |
493 | * Creates a new jack object. | |
494 | * | |
eb7c06e8 YB |
495 | * Return: Zero if successful, or a negative error code on failure. |
496 | * On success @jjack will be initialised. | |
e76d8cea MB |
497 | */ |
498 | int snd_jack_new(struct snd_card *card, const char *id, int type, | |
4e3f0dc6 | 499 | struct snd_jack **jjack, bool initial_kctl, bool phantom_jack) |
e76d8cea MB |
500 | { |
501 | struct snd_jack *jack; | |
4e3f0dc6 | 502 | struct snd_jack_kctl *jack_kctl = NULL; |
e76d8cea | 503 | int err; |
f15ee210 | 504 | static const struct snd_device_ops ops = { |
e76d8cea | 505 | .dev_free = snd_jack_dev_free, |
fe0d128c | 506 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
e76d8cea | 507 | .dev_register = snd_jack_dev_register, |
32b85442 | 508 | .dev_disconnect = snd_jack_dev_disconnect, |
fe0d128c | 509 | #endif /* CONFIG_SND_JACK_INPUT_DEV */ |
e76d8cea MB |
510 | }; |
511 | ||
4e3f0dc6 JY |
512 | if (initial_kctl) { |
513 | jack_kctl = snd_jack_kctl_new(card, id, type); | |
514 | if (!jack_kctl) | |
515 | return -ENOMEM; | |
516 | } | |
517 | ||
e76d8cea MB |
518 | jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); |
519 | if (jack == NULL) | |
520 | return -ENOMEM; | |
521 | ||
282cd76f | 522 | jack->id = kstrdup(id, GFP_KERNEL); |
c01c1db1 XW |
523 | if (jack->id == NULL) { |
524 | kfree(jack); | |
525 | return -ENOMEM; | |
526 | } | |
e76d8cea | 527 | |
fe0d128c | 528 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
1b6a6fc5 AS |
529 | mutex_init(&jack->input_dev_lock); |
530 | ||
531 | /* don't create input device for phantom jack */ | |
532 | if (!phantom_jack) { | |
fe0d128c TI |
533 | int i; |
534 | ||
4e3f0dc6 JY |
535 | jack->input_dev = input_allocate_device(); |
536 | if (jack->input_dev == NULL) { | |
537 | err = -ENOMEM; | |
538 | goto fail_input; | |
539 | } | |
e76d8cea | 540 | |
4e3f0dc6 | 541 | jack->input_dev->phys = "ALSA"; |
e76d8cea | 542 | |
4e3f0dc6 | 543 | jack->type = type; |
e76d8cea | 544 | |
4e3f0dc6 JY |
545 | for (i = 0; i < SND_JACK_SWITCH_TYPES; i++) |
546 | if (type & (1 << i)) | |
547 | input_set_capability(jack->input_dev, EV_SW, | |
548 | jack_switch_types[i]); | |
549 | ||
550 | } | |
1b6a6fc5 | 551 | #endif /* CONFIG_SND_JACK_INPUT_DEV */ |
e76d8cea MB |
552 | |
553 | err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); | |
554 | if (err < 0) | |
555 | goto fail_input; | |
556 | ||
9058cbe1 JY |
557 | jack->card = card; |
558 | INIT_LIST_HEAD(&jack->kctl_list); | |
559 | ||
4e3f0dc6 JY |
560 | if (initial_kctl) |
561 | snd_jack_kctl_add(jack, jack_kctl); | |
562 | ||
e76d8cea MB |
563 | *jjack = jack; |
564 | ||
565 | return 0; | |
566 | ||
567 | fail_input: | |
fe0d128c | 568 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
e76d8cea | 569 | input_free_device(jack->input_dev); |
fe0d128c | 570 | #endif |
eeda276b | 571 | kfree(jack->id); |
e76d8cea MB |
572 | kfree(jack); |
573 | return err; | |
574 | } | |
575 | EXPORT_SYMBOL(snd_jack_new); | |
576 | ||
fe0d128c | 577 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
e76d8cea MB |
578 | /** |
579 | * snd_jack_set_parent - Set the parent device for a jack | |
580 | * | |
581 | * @jack: The jack to configure | |
582 | * @parent: The device to set as parent for the jack. | |
583 | * | |
a2e888f0 | 584 | * Set the parent for the jack devices in the device tree. This |
e76d8cea MB |
585 | * function is only valid prior to registration of the jack. If no |
586 | * parent is configured then the parent device will be the sound card. | |
587 | */ | |
588 | void snd_jack_set_parent(struct snd_jack *jack, struct device *parent) | |
589 | { | |
590 | WARN_ON(jack->registered); | |
1b6a6fc5 AS |
591 | mutex_lock(&jack->input_dev_lock); |
592 | if (!jack->input_dev) { | |
593 | mutex_unlock(&jack->input_dev_lock); | |
43b2cd54 | 594 | return; |
1b6a6fc5 | 595 | } |
e76d8cea MB |
596 | |
597 | jack->input_dev->dev.parent = parent; | |
1b6a6fc5 | 598 | mutex_unlock(&jack->input_dev_lock); |
e76d8cea MB |
599 | } |
600 | EXPORT_SYMBOL(snd_jack_set_parent); | |
601 | ||
ebb812cb MB |
602 | /** |
603 | * snd_jack_set_key - Set a key mapping on a jack | |
604 | * | |
605 | * @jack: The jack to configure | |
606 | * @type: Jack report type for this key | |
607 | * @keytype: Input layer key type to be reported | |
608 | * | |
3f1185d6 | 609 | * Map a SND_JACK_BTN_* button type to an input layer key, allowing |
ebb812cb MB |
610 | * reporting of keys on accessories via the jack abstraction. If no |
611 | * mapping is provided but keys are enabled in the jack type then | |
612 | * BTN_n numeric buttons will be reported. | |
613 | * | |
a2e888f0 MB |
614 | * If jacks are not reporting via the input API this call will have no |
615 | * effect. | |
616 | * | |
ebb812cb MB |
617 | * Note that this is intended to be use by simple devices with small |
618 | * numbers of keys that can be reported. It is also possible to | |
619 | * access the input device directly - devices with complex input | |
620 | * capabilities on accessories should consider doing this rather than | |
621 | * using this abstraction. | |
622 | * | |
623 | * This function may only be called prior to registration of the jack. | |
eb7c06e8 YB |
624 | * |
625 | * Return: Zero if successful, or a negative error code on failure. | |
ebb812cb MB |
626 | */ |
627 | int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type, | |
628 | int keytype) | |
629 | { | |
630 | int key = fls(SND_JACK_BTN_0) - fls(type); | |
631 | ||
632 | WARN_ON(jack->registered); | |
633 | ||
634 | if (!keytype || key >= ARRAY_SIZE(jack->key)) | |
635 | return -EINVAL; | |
636 | ||
637 | jack->type |= type; | |
638 | jack->key[key] = keytype; | |
ebb812cb MB |
639 | return 0; |
640 | } | |
641 | EXPORT_SYMBOL(snd_jack_set_key); | |
fe0d128c | 642 | #endif /* CONFIG_SND_JACK_INPUT_DEV */ |
ebb812cb | 643 | |
e76d8cea MB |
644 | /** |
645 | * snd_jack_report - Report the current status of a jack | |
1b6a6fc5 AS |
646 | * Note: This function uses mutexes and should be called from a |
647 | * context which can sleep (such as a workqueue). | |
e76d8cea MB |
648 | * |
649 | * @jack: The jack to report status for | |
650 | * @status: The current status of the jack | |
651 | */ | |
652 | void snd_jack_report(struct snd_jack *jack, int status) | |
653 | { | |
9058cbe1 | 654 | struct snd_jack_kctl *jack_kctl; |
2d670ea2 | 655 | unsigned int mask_bits = 0; |
fe0d128c | 656 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
bd8a71a7 | 657 | int i; |
fe0d128c | 658 | #endif |
bd8a71a7 | 659 | |
9a3f371e MB |
660 | if (!jack) |
661 | return; | |
662 | ||
2d670ea2 HW |
663 | jack->hw_status_cache = status; |
664 | ||
6ed9495e | 665 | list_for_each_entry(jack_kctl, &jack->kctl_list, list) |
2d670ea2 HW |
666 | if (jack_kctl->sw_inject_enable) |
667 | mask_bits |= jack_kctl->mask_bits; | |
668 | else | |
669 | snd_kctl_jack_report(jack->card, jack_kctl->kctl, | |
670 | status & jack_kctl->mask_bits); | |
6ed9495e | 671 | |
fe0d128c | 672 | #ifdef CONFIG_SND_JACK_INPUT_DEV |
1b6a6fc5 AS |
673 | mutex_lock(&jack->input_dev_lock); |
674 | if (!jack->input_dev) { | |
675 | mutex_unlock(&jack->input_dev_lock); | |
6ed9495e | 676 | return; |
1b6a6fc5 | 677 | } |
6ed9495e | 678 | |
ebb812cb | 679 | for (i = 0; i < ARRAY_SIZE(jack->key); i++) { |
2d670ea2 | 680 | int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits); |
ebb812cb MB |
681 | |
682 | if (jack->type & testbit) | |
683 | input_report_key(jack->input_dev, jack->key[i], | |
684 | status & testbit); | |
685 | } | |
686 | ||
1c6e555c | 687 | for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) { |
2d670ea2 HW |
688 | int testbit = ((1 << i) & ~mask_bits); |
689 | ||
bd8a71a7 | 690 | if (jack->type & testbit) |
1c6e555c MB |
691 | input_report_switch(jack->input_dev, |
692 | jack_switch_types[i], | |
bd8a71a7 MB |
693 | status & testbit); |
694 | } | |
e76d8cea MB |
695 | |
696 | input_sync(jack->input_dev); | |
1b6a6fc5 | 697 | mutex_unlock(&jack->input_dev_lock); |
fe0d128c | 698 | #endif /* CONFIG_SND_JACK_INPUT_DEV */ |
e76d8cea MB |
699 | } |
700 | EXPORT_SYMBOL(snd_jack_report); |