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