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