162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Jack abstraction layer 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2008 Wolfson Microelectronics 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/input.h> 962306a36Sopenharmony_ci#include <linux/slab.h> 1062306a36Sopenharmony_ci#include <linux/module.h> 1162306a36Sopenharmony_ci#include <linux/ctype.h> 1262306a36Sopenharmony_ci#include <linux/mm.h> 1362306a36Sopenharmony_ci#include <linux/debugfs.h> 1462306a36Sopenharmony_ci#include <sound/jack.h> 1562306a36Sopenharmony_ci#include <sound/core.h> 1662306a36Sopenharmony_ci#include <sound/control.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_cistruct snd_jack_kctl { 1962306a36Sopenharmony_ci struct snd_kcontrol *kctl; 2062306a36Sopenharmony_ci struct list_head list; /* list of controls belong to the same jack */ 2162306a36Sopenharmony_ci unsigned int mask_bits; /* only masked status bits are reported via kctl */ 2262306a36Sopenharmony_ci struct snd_jack *jack; /* pointer to struct snd_jack */ 2362306a36Sopenharmony_ci bool sw_inject_enable; /* allow to inject plug event via debugfs */ 2462306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INJECTION_DEBUG 2562306a36Sopenharmony_ci struct dentry *jack_debugfs_root; /* jack_kctl debugfs root */ 2662306a36Sopenharmony_ci#endif 2762306a36Sopenharmony_ci}; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 3062306a36Sopenharmony_cistatic const int jack_switch_types[SND_JACK_SWITCH_TYPES] = { 3162306a36Sopenharmony_ci SW_HEADPHONE_INSERT, 3262306a36Sopenharmony_ci SW_MICROPHONE_INSERT, 3362306a36Sopenharmony_ci SW_LINEOUT_INSERT, 3462306a36Sopenharmony_ci SW_JACK_PHYSICAL_INSERT, 3562306a36Sopenharmony_ci SW_VIDEOOUT_INSERT, 3662306a36Sopenharmony_ci SW_LINEIN_INSERT, 3762306a36Sopenharmony_ci}; 3862306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INPUT_DEV */ 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_cistatic int snd_jack_dev_disconnect(struct snd_device *device) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 4362306a36Sopenharmony_ci struct snd_jack *jack = device->device_data; 4462306a36Sopenharmony_ci 4562306a36Sopenharmony_ci mutex_lock(&jack->input_dev_lock); 4662306a36Sopenharmony_ci if (!jack->input_dev) { 4762306a36Sopenharmony_ci mutex_unlock(&jack->input_dev_lock); 4862306a36Sopenharmony_ci return 0; 4962306a36Sopenharmony_ci } 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* If the input device is registered with the input subsystem 5262306a36Sopenharmony_ci * then we need to use a different deallocator. */ 5362306a36Sopenharmony_ci if (jack->registered) 5462306a36Sopenharmony_ci input_unregister_device(jack->input_dev); 5562306a36Sopenharmony_ci else 5662306a36Sopenharmony_ci input_free_device(jack->input_dev); 5762306a36Sopenharmony_ci jack->input_dev = NULL; 5862306a36Sopenharmony_ci mutex_unlock(&jack->input_dev_lock); 5962306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INPUT_DEV */ 6062306a36Sopenharmony_ci return 0; 6162306a36Sopenharmony_ci} 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic int snd_jack_dev_free(struct snd_device *device) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct snd_jack *jack = device->device_data; 6662306a36Sopenharmony_ci struct snd_card *card = device->card; 6762306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl; 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) { 7062306a36Sopenharmony_ci list_del_init(&jack_kctl->list); 7162306a36Sopenharmony_ci snd_ctl_remove(card, jack_kctl->kctl); 7262306a36Sopenharmony_ci } 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci if (jack->private_free) 7562306a36Sopenharmony_ci jack->private_free(jack); 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci snd_jack_dev_disconnect(device); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci kfree(jack->id); 8062306a36Sopenharmony_ci kfree(jack); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci return 0; 8362306a36Sopenharmony_ci} 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 8662306a36Sopenharmony_cistatic int snd_jack_dev_register(struct snd_device *device) 8762306a36Sopenharmony_ci{ 8862306a36Sopenharmony_ci struct snd_jack *jack = device->device_data; 8962306a36Sopenharmony_ci struct snd_card *card = device->card; 9062306a36Sopenharmony_ci int err, i; 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci snprintf(jack->name, sizeof(jack->name), "%s %s", 9362306a36Sopenharmony_ci card->shortname, jack->id); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci mutex_lock(&jack->input_dev_lock); 9662306a36Sopenharmony_ci if (!jack->input_dev) { 9762306a36Sopenharmony_ci mutex_unlock(&jack->input_dev_lock); 9862306a36Sopenharmony_ci return 0; 9962306a36Sopenharmony_ci } 10062306a36Sopenharmony_ci 10162306a36Sopenharmony_ci jack->input_dev->name = jack->name; 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_ci /* Default to the sound card device. */ 10462306a36Sopenharmony_ci if (!jack->input_dev->dev.parent) 10562306a36Sopenharmony_ci jack->input_dev->dev.parent = snd_card_get_device_link(card); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* Add capabilities for any keys that are enabled */ 10862306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(jack->key); i++) { 10962306a36Sopenharmony_ci int testbit = SND_JACK_BTN_0 >> i; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci if (!(jack->type & testbit)) 11262306a36Sopenharmony_ci continue; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci if (!jack->key[i]) 11562306a36Sopenharmony_ci jack->key[i] = BTN_0 + i; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci input_set_capability(jack->input_dev, EV_KEY, jack->key[i]); 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci err = input_register_device(jack->input_dev); 12162306a36Sopenharmony_ci if (err == 0) 12262306a36Sopenharmony_ci jack->registered = 1; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci mutex_unlock(&jack->input_dev_lock); 12562306a36Sopenharmony_ci return err; 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INPUT_DEV */ 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INJECTION_DEBUG 13062306a36Sopenharmony_cistatic void snd_jack_inject_report(struct snd_jack_kctl *jack_kctl, int status) 13162306a36Sopenharmony_ci{ 13262306a36Sopenharmony_ci struct snd_jack *jack; 13362306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 13462306a36Sopenharmony_ci int i; 13562306a36Sopenharmony_ci#endif 13662306a36Sopenharmony_ci if (!jack_kctl) 13762306a36Sopenharmony_ci return; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci jack = jack_kctl->jack; 14062306a36Sopenharmony_ci 14162306a36Sopenharmony_ci if (jack_kctl->sw_inject_enable) 14262306a36Sopenharmony_ci snd_kctl_jack_report(jack->card, jack_kctl->kctl, 14362306a36Sopenharmony_ci status & jack_kctl->mask_bits); 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 14662306a36Sopenharmony_ci if (!jack->input_dev) 14762306a36Sopenharmony_ci return; 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(jack->key); i++) { 15062306a36Sopenharmony_ci int testbit = ((SND_JACK_BTN_0 >> i) & jack_kctl->mask_bits); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci if (jack->type & testbit) 15362306a36Sopenharmony_ci input_report_key(jack->input_dev, jack->key[i], 15462306a36Sopenharmony_ci status & testbit); 15562306a36Sopenharmony_ci } 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) { 15862306a36Sopenharmony_ci int testbit = ((1 << i) & jack_kctl->mask_bits); 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci if (jack->type & testbit) 16162306a36Sopenharmony_ci input_report_switch(jack->input_dev, 16262306a36Sopenharmony_ci jack_switch_types[i], 16362306a36Sopenharmony_ci status & testbit); 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci input_sync(jack->input_dev); 16762306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INPUT_DEV */ 16862306a36Sopenharmony_ci} 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_cistatic ssize_t sw_inject_enable_read(struct file *file, 17162306a36Sopenharmony_ci char __user *to, size_t count, loff_t *ppos) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl = file->private_data; 17462306a36Sopenharmony_ci int len, ret; 17562306a36Sopenharmony_ci char buf[128]; 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%s: %s\t\t%s: %i\n", "Jack", jack_kctl->kctl->id.name, 17862306a36Sopenharmony_ci "Inject Enabled", jack_kctl->sw_inject_enable); 17962306a36Sopenharmony_ci ret = simple_read_from_buffer(to, count, ppos, buf, len); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci return ret; 18262306a36Sopenharmony_ci} 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_cistatic ssize_t sw_inject_enable_write(struct file *file, 18562306a36Sopenharmony_ci const char __user *from, size_t count, loff_t *ppos) 18662306a36Sopenharmony_ci{ 18762306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl = file->private_data; 18862306a36Sopenharmony_ci int ret, err; 18962306a36Sopenharmony_ci unsigned long enable; 19062306a36Sopenharmony_ci char buf[8] = { 0 }; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, from, count); 19362306a36Sopenharmony_ci err = kstrtoul(buf, 0, &enable); 19462306a36Sopenharmony_ci if (err) 19562306a36Sopenharmony_ci return err; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (jack_kctl->sw_inject_enable == (!!enable)) 19862306a36Sopenharmony_ci return ret; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci jack_kctl->sw_inject_enable = !!enable; 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci if (!jack_kctl->sw_inject_enable) 20362306a36Sopenharmony_ci snd_jack_report(jack_kctl->jack, jack_kctl->jack->hw_status_cache); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci return ret; 20662306a36Sopenharmony_ci} 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_cistatic ssize_t jackin_inject_write(struct file *file, 20962306a36Sopenharmony_ci const char __user *from, size_t count, loff_t *ppos) 21062306a36Sopenharmony_ci{ 21162306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl = file->private_data; 21262306a36Sopenharmony_ci int ret, err; 21362306a36Sopenharmony_ci unsigned long enable; 21462306a36Sopenharmony_ci char buf[8] = { 0 }; 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci if (!jack_kctl->sw_inject_enable) 21762306a36Sopenharmony_ci return -EINVAL; 21862306a36Sopenharmony_ci 21962306a36Sopenharmony_ci ret = simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, from, count); 22062306a36Sopenharmony_ci err = kstrtoul(buf, 0, &enable); 22162306a36Sopenharmony_ci if (err) 22262306a36Sopenharmony_ci return err; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci snd_jack_inject_report(jack_kctl, !!enable ? jack_kctl->mask_bits : 0); 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return ret; 22762306a36Sopenharmony_ci} 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_cistatic ssize_t jack_kctl_id_read(struct file *file, 23062306a36Sopenharmony_ci char __user *to, size_t count, loff_t *ppos) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl = file->private_data; 23362306a36Sopenharmony_ci char buf[64]; 23462306a36Sopenharmony_ci int len, ret; 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%s\n", jack_kctl->kctl->id.name); 23762306a36Sopenharmony_ci ret = simple_read_from_buffer(to, count, ppos, buf, len); 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci return ret; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* the bit definition is aligned with snd_jack_types in jack.h */ 24362306a36Sopenharmony_cistatic const char * const jack_events_name[] = { 24462306a36Sopenharmony_ci "HEADPHONE(0x0001)", "MICROPHONE(0x0002)", "LINEOUT(0x0004)", 24562306a36Sopenharmony_ci "MECHANICAL(0x0008)", "VIDEOOUT(0x0010)", "LINEIN(0x0020)", 24662306a36Sopenharmony_ci "", "", "", "BTN_5(0x0200)", "BTN_4(0x0400)", "BTN_3(0x0800)", 24762306a36Sopenharmony_ci "BTN_2(0x1000)", "BTN_1(0x2000)", "BTN_0(0x4000)", "", 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* the recommended buffer size is 256 */ 25162306a36Sopenharmony_cistatic int parse_mask_bits(unsigned int mask_bits, char *buf, size_t buf_size) 25262306a36Sopenharmony_ci{ 25362306a36Sopenharmony_ci int i; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_ci scnprintf(buf, buf_size, "0x%04x", mask_bits); 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(jack_events_name); i++) 25862306a36Sopenharmony_ci if (mask_bits & (1 << i)) { 25962306a36Sopenharmony_ci strlcat(buf, " ", buf_size); 26062306a36Sopenharmony_ci strlcat(buf, jack_events_name[i], buf_size); 26162306a36Sopenharmony_ci } 26262306a36Sopenharmony_ci strlcat(buf, "\n", buf_size); 26362306a36Sopenharmony_ci 26462306a36Sopenharmony_ci return strlen(buf); 26562306a36Sopenharmony_ci} 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_cistatic ssize_t jack_kctl_mask_bits_read(struct file *file, 26862306a36Sopenharmony_ci char __user *to, size_t count, loff_t *ppos) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl = file->private_data; 27162306a36Sopenharmony_ci char buf[256]; 27262306a36Sopenharmony_ci int len, ret; 27362306a36Sopenharmony_ci 27462306a36Sopenharmony_ci len = parse_mask_bits(jack_kctl->mask_bits, buf, sizeof(buf)); 27562306a36Sopenharmony_ci ret = simple_read_from_buffer(to, count, ppos, buf, len); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci return ret; 27862306a36Sopenharmony_ci} 27962306a36Sopenharmony_ci 28062306a36Sopenharmony_cistatic ssize_t jack_kctl_status_read(struct file *file, 28162306a36Sopenharmony_ci char __user *to, size_t count, loff_t *ppos) 28262306a36Sopenharmony_ci{ 28362306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl = file->private_data; 28462306a36Sopenharmony_ci char buf[16]; 28562306a36Sopenharmony_ci int len, ret; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci len = scnprintf(buf, sizeof(buf), "%s\n", jack_kctl->kctl->private_value ? 28862306a36Sopenharmony_ci "Plugged" : "Unplugged"); 28962306a36Sopenharmony_ci ret = simple_read_from_buffer(to, count, ppos, buf, len); 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci return ret; 29262306a36Sopenharmony_ci} 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 29562306a36Sopenharmony_cistatic ssize_t jack_type_read(struct file *file, 29662306a36Sopenharmony_ci char __user *to, size_t count, loff_t *ppos) 29762306a36Sopenharmony_ci{ 29862306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl = file->private_data; 29962306a36Sopenharmony_ci char buf[256]; 30062306a36Sopenharmony_ci int len, ret; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci len = parse_mask_bits(jack_kctl->jack->type, buf, sizeof(buf)); 30362306a36Sopenharmony_ci ret = simple_read_from_buffer(to, count, ppos, buf, len); 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic const struct file_operations jack_type_fops = { 30962306a36Sopenharmony_ci .open = simple_open, 31062306a36Sopenharmony_ci .read = jack_type_read, 31162306a36Sopenharmony_ci .llseek = default_llseek, 31262306a36Sopenharmony_ci}; 31362306a36Sopenharmony_ci#endif 31462306a36Sopenharmony_ci 31562306a36Sopenharmony_cistatic const struct file_operations sw_inject_enable_fops = { 31662306a36Sopenharmony_ci .open = simple_open, 31762306a36Sopenharmony_ci .read = sw_inject_enable_read, 31862306a36Sopenharmony_ci .write = sw_inject_enable_write, 31962306a36Sopenharmony_ci .llseek = default_llseek, 32062306a36Sopenharmony_ci}; 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_cistatic const struct file_operations jackin_inject_fops = { 32362306a36Sopenharmony_ci .open = simple_open, 32462306a36Sopenharmony_ci .write = jackin_inject_write, 32562306a36Sopenharmony_ci .llseek = default_llseek, 32662306a36Sopenharmony_ci}; 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_cistatic const struct file_operations jack_kctl_id_fops = { 32962306a36Sopenharmony_ci .open = simple_open, 33062306a36Sopenharmony_ci .read = jack_kctl_id_read, 33162306a36Sopenharmony_ci .llseek = default_llseek, 33262306a36Sopenharmony_ci}; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic const struct file_operations jack_kctl_mask_bits_fops = { 33562306a36Sopenharmony_ci .open = simple_open, 33662306a36Sopenharmony_ci .read = jack_kctl_mask_bits_read, 33762306a36Sopenharmony_ci .llseek = default_llseek, 33862306a36Sopenharmony_ci}; 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic const struct file_operations jack_kctl_status_fops = { 34162306a36Sopenharmony_ci .open = simple_open, 34262306a36Sopenharmony_ci .read = jack_kctl_status_read, 34362306a36Sopenharmony_ci .llseek = default_llseek, 34462306a36Sopenharmony_ci}; 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_cistatic int snd_jack_debugfs_add_inject_node(struct snd_jack *jack, 34762306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl) 34862306a36Sopenharmony_ci{ 34962306a36Sopenharmony_ci char *tname; 35062306a36Sopenharmony_ci int i; 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci /* Don't create injection interface for Phantom jacks */ 35362306a36Sopenharmony_ci if (strstr(jack_kctl->kctl->id.name, "Phantom")) 35462306a36Sopenharmony_ci return 0; 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_ci tname = kstrdup(jack_kctl->kctl->id.name, GFP_KERNEL); 35762306a36Sopenharmony_ci if (!tname) 35862306a36Sopenharmony_ci return -ENOMEM; 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci /* replace the chars which are not suitable for folder's name with _ */ 36162306a36Sopenharmony_ci for (i = 0; tname[i]; i++) 36262306a36Sopenharmony_ci if (!isalnum(tname[i])) 36362306a36Sopenharmony_ci tname[i] = '_'; 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci jack_kctl->jack_debugfs_root = debugfs_create_dir(tname, jack->card->debugfs_root); 36662306a36Sopenharmony_ci kfree(tname); 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci debugfs_create_file("sw_inject_enable", 0644, jack_kctl->jack_debugfs_root, jack_kctl, 36962306a36Sopenharmony_ci &sw_inject_enable_fops); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci debugfs_create_file("jackin_inject", 0200, jack_kctl->jack_debugfs_root, jack_kctl, 37262306a36Sopenharmony_ci &jackin_inject_fops); 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci debugfs_create_file("kctl_id", 0444, jack_kctl->jack_debugfs_root, jack_kctl, 37562306a36Sopenharmony_ci &jack_kctl_id_fops); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci debugfs_create_file("mask_bits", 0444, jack_kctl->jack_debugfs_root, jack_kctl, 37862306a36Sopenharmony_ci &jack_kctl_mask_bits_fops); 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_ci debugfs_create_file("status", 0444, jack_kctl->jack_debugfs_root, jack_kctl, 38162306a36Sopenharmony_ci &jack_kctl_status_fops); 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 38462306a36Sopenharmony_ci debugfs_create_file("type", 0444, jack_kctl->jack_debugfs_root, jack_kctl, 38562306a36Sopenharmony_ci &jack_type_fops); 38662306a36Sopenharmony_ci#endif 38762306a36Sopenharmony_ci return 0; 38862306a36Sopenharmony_ci} 38962306a36Sopenharmony_ci 39062306a36Sopenharmony_cistatic void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl) 39162306a36Sopenharmony_ci{ 39262306a36Sopenharmony_ci debugfs_remove(jack_kctl->jack_debugfs_root); 39362306a36Sopenharmony_ci jack_kctl->jack_debugfs_root = NULL; 39462306a36Sopenharmony_ci} 39562306a36Sopenharmony_ci#else /* CONFIG_SND_JACK_INJECTION_DEBUG */ 39662306a36Sopenharmony_cistatic int snd_jack_debugfs_add_inject_node(struct snd_jack *jack, 39762306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl) 39862306a36Sopenharmony_ci{ 39962306a36Sopenharmony_ci return 0; 40062306a36Sopenharmony_ci} 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_cistatic void snd_jack_debugfs_clear_inject_node(struct snd_jack_kctl *jack_kctl) 40362306a36Sopenharmony_ci{ 40462306a36Sopenharmony_ci} 40562306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INJECTION_DEBUG */ 40662306a36Sopenharmony_ci 40762306a36Sopenharmony_cistatic void snd_jack_kctl_private_free(struct snd_kcontrol *kctl) 40862306a36Sopenharmony_ci{ 40962306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl; 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci jack_kctl = kctl->private_data; 41262306a36Sopenharmony_ci if (jack_kctl) { 41362306a36Sopenharmony_ci snd_jack_debugfs_clear_inject_node(jack_kctl); 41462306a36Sopenharmony_ci list_del(&jack_kctl->list); 41562306a36Sopenharmony_ci kfree(jack_kctl); 41662306a36Sopenharmony_ci } 41762306a36Sopenharmony_ci} 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_cistatic void snd_jack_kctl_add(struct snd_jack *jack, struct snd_jack_kctl *jack_kctl) 42062306a36Sopenharmony_ci{ 42162306a36Sopenharmony_ci jack_kctl->jack = jack; 42262306a36Sopenharmony_ci list_add_tail(&jack_kctl->list, &jack->kctl_list); 42362306a36Sopenharmony_ci snd_jack_debugfs_add_inject_node(jack, jack_kctl); 42462306a36Sopenharmony_ci} 42562306a36Sopenharmony_ci 42662306a36Sopenharmony_cistatic struct snd_jack_kctl * snd_jack_kctl_new(struct snd_card *card, const char *name, unsigned int mask) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct snd_kcontrol *kctl; 42962306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl; 43062306a36Sopenharmony_ci int err; 43162306a36Sopenharmony_ci 43262306a36Sopenharmony_ci kctl = snd_kctl_jack_new(name, card); 43362306a36Sopenharmony_ci if (!kctl) 43462306a36Sopenharmony_ci return NULL; 43562306a36Sopenharmony_ci 43662306a36Sopenharmony_ci err = snd_ctl_add(card, kctl); 43762306a36Sopenharmony_ci if (err < 0) 43862306a36Sopenharmony_ci return NULL; 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_ci jack_kctl = kzalloc(sizeof(*jack_kctl), GFP_KERNEL); 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (!jack_kctl) 44362306a36Sopenharmony_ci goto error; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci jack_kctl->kctl = kctl; 44662306a36Sopenharmony_ci jack_kctl->mask_bits = mask; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci kctl->private_data = jack_kctl; 44962306a36Sopenharmony_ci kctl->private_free = snd_jack_kctl_private_free; 45062306a36Sopenharmony_ci 45162306a36Sopenharmony_ci return jack_kctl; 45262306a36Sopenharmony_cierror: 45362306a36Sopenharmony_ci snd_ctl_free_one(kctl); 45462306a36Sopenharmony_ci return NULL; 45562306a36Sopenharmony_ci} 45662306a36Sopenharmony_ci 45762306a36Sopenharmony_ci/** 45862306a36Sopenharmony_ci * snd_jack_add_new_kctl - Create a new snd_jack_kctl and add it to jack 45962306a36Sopenharmony_ci * @jack: the jack instance which the kctl will attaching to 46062306a36Sopenharmony_ci * @name: the name for the snd_kcontrol object 46162306a36Sopenharmony_ci * @mask: a bitmask of enum snd_jack_type values that can be detected 46262306a36Sopenharmony_ci * by this snd_jack_kctl object. 46362306a36Sopenharmony_ci * 46462306a36Sopenharmony_ci * Creates a new snd_kcontrol object and adds it to the jack kctl_list. 46562306a36Sopenharmony_ci * 46662306a36Sopenharmony_ci * Return: Zero if successful, or a negative error code on failure. 46762306a36Sopenharmony_ci */ 46862306a36Sopenharmony_ciint snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask) 46962306a36Sopenharmony_ci{ 47062306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl; 47162306a36Sopenharmony_ci 47262306a36Sopenharmony_ci jack_kctl = snd_jack_kctl_new(jack->card, name, mask); 47362306a36Sopenharmony_ci if (!jack_kctl) 47462306a36Sopenharmony_ci return -ENOMEM; 47562306a36Sopenharmony_ci 47662306a36Sopenharmony_ci snd_jack_kctl_add(jack, jack_kctl); 47762306a36Sopenharmony_ci return 0; 47862306a36Sopenharmony_ci} 47962306a36Sopenharmony_ciEXPORT_SYMBOL(snd_jack_add_new_kctl); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_ci/** 48262306a36Sopenharmony_ci * snd_jack_new - Create a new jack 48362306a36Sopenharmony_ci * @card: the card instance 48462306a36Sopenharmony_ci * @id: an identifying string for this jack 48562306a36Sopenharmony_ci * @type: a bitmask of enum snd_jack_type values that can be detected by 48662306a36Sopenharmony_ci * this jack 48762306a36Sopenharmony_ci * @jjack: Used to provide the allocated jack object to the caller. 48862306a36Sopenharmony_ci * @initial_kctl: if true, create a kcontrol and add it to the jack list. 48962306a36Sopenharmony_ci * @phantom_jack: Don't create a input device for phantom jacks. 49062306a36Sopenharmony_ci * 49162306a36Sopenharmony_ci * Creates a new jack object. 49262306a36Sopenharmony_ci * 49362306a36Sopenharmony_ci * Return: Zero if successful, or a negative error code on failure. 49462306a36Sopenharmony_ci * On success @jjack will be initialised. 49562306a36Sopenharmony_ci */ 49662306a36Sopenharmony_ciint snd_jack_new(struct snd_card *card, const char *id, int type, 49762306a36Sopenharmony_ci struct snd_jack **jjack, bool initial_kctl, bool phantom_jack) 49862306a36Sopenharmony_ci{ 49962306a36Sopenharmony_ci struct snd_jack *jack; 50062306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl = NULL; 50162306a36Sopenharmony_ci int err; 50262306a36Sopenharmony_ci static const struct snd_device_ops ops = { 50362306a36Sopenharmony_ci .dev_free = snd_jack_dev_free, 50462306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 50562306a36Sopenharmony_ci .dev_register = snd_jack_dev_register, 50662306a36Sopenharmony_ci .dev_disconnect = snd_jack_dev_disconnect, 50762306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INPUT_DEV */ 50862306a36Sopenharmony_ci }; 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci if (initial_kctl) { 51162306a36Sopenharmony_ci jack_kctl = snd_jack_kctl_new(card, id, type); 51262306a36Sopenharmony_ci if (!jack_kctl) 51362306a36Sopenharmony_ci return -ENOMEM; 51462306a36Sopenharmony_ci } 51562306a36Sopenharmony_ci 51662306a36Sopenharmony_ci jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL); 51762306a36Sopenharmony_ci if (jack == NULL) 51862306a36Sopenharmony_ci return -ENOMEM; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci jack->id = kstrdup(id, GFP_KERNEL); 52162306a36Sopenharmony_ci if (jack->id == NULL) { 52262306a36Sopenharmony_ci kfree(jack); 52362306a36Sopenharmony_ci return -ENOMEM; 52462306a36Sopenharmony_ci } 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 52762306a36Sopenharmony_ci mutex_init(&jack->input_dev_lock); 52862306a36Sopenharmony_ci 52962306a36Sopenharmony_ci /* don't create input device for phantom jack */ 53062306a36Sopenharmony_ci if (!phantom_jack) { 53162306a36Sopenharmony_ci int i; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci jack->input_dev = input_allocate_device(); 53462306a36Sopenharmony_ci if (jack->input_dev == NULL) { 53562306a36Sopenharmony_ci err = -ENOMEM; 53662306a36Sopenharmony_ci goto fail_input; 53762306a36Sopenharmony_ci } 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci jack->input_dev->phys = "ALSA"; 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_ci jack->type = type; 54262306a36Sopenharmony_ci 54362306a36Sopenharmony_ci for (i = 0; i < SND_JACK_SWITCH_TYPES; i++) 54462306a36Sopenharmony_ci if (type & (1 << i)) 54562306a36Sopenharmony_ci input_set_capability(jack->input_dev, EV_SW, 54662306a36Sopenharmony_ci jack_switch_types[i]); 54762306a36Sopenharmony_ci 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INPUT_DEV */ 55062306a36Sopenharmony_ci 55162306a36Sopenharmony_ci err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops); 55262306a36Sopenharmony_ci if (err < 0) 55362306a36Sopenharmony_ci goto fail_input; 55462306a36Sopenharmony_ci 55562306a36Sopenharmony_ci jack->card = card; 55662306a36Sopenharmony_ci INIT_LIST_HEAD(&jack->kctl_list); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ci if (initial_kctl) 55962306a36Sopenharmony_ci snd_jack_kctl_add(jack, jack_kctl); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci *jjack = jack; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci return 0; 56462306a36Sopenharmony_ci 56562306a36Sopenharmony_cifail_input: 56662306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 56762306a36Sopenharmony_ci input_free_device(jack->input_dev); 56862306a36Sopenharmony_ci#endif 56962306a36Sopenharmony_ci kfree(jack->id); 57062306a36Sopenharmony_ci kfree(jack); 57162306a36Sopenharmony_ci return err; 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ciEXPORT_SYMBOL(snd_jack_new); 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 57662306a36Sopenharmony_ci/** 57762306a36Sopenharmony_ci * snd_jack_set_parent - Set the parent device for a jack 57862306a36Sopenharmony_ci * 57962306a36Sopenharmony_ci * @jack: The jack to configure 58062306a36Sopenharmony_ci * @parent: The device to set as parent for the jack. 58162306a36Sopenharmony_ci * 58262306a36Sopenharmony_ci * Set the parent for the jack devices in the device tree. This 58362306a36Sopenharmony_ci * function is only valid prior to registration of the jack. If no 58462306a36Sopenharmony_ci * parent is configured then the parent device will be the sound card. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_civoid snd_jack_set_parent(struct snd_jack *jack, struct device *parent) 58762306a36Sopenharmony_ci{ 58862306a36Sopenharmony_ci WARN_ON(jack->registered); 58962306a36Sopenharmony_ci mutex_lock(&jack->input_dev_lock); 59062306a36Sopenharmony_ci if (!jack->input_dev) { 59162306a36Sopenharmony_ci mutex_unlock(&jack->input_dev_lock); 59262306a36Sopenharmony_ci return; 59362306a36Sopenharmony_ci } 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci jack->input_dev->dev.parent = parent; 59662306a36Sopenharmony_ci mutex_unlock(&jack->input_dev_lock); 59762306a36Sopenharmony_ci} 59862306a36Sopenharmony_ciEXPORT_SYMBOL(snd_jack_set_parent); 59962306a36Sopenharmony_ci 60062306a36Sopenharmony_ci/** 60162306a36Sopenharmony_ci * snd_jack_set_key - Set a key mapping on a jack 60262306a36Sopenharmony_ci * 60362306a36Sopenharmony_ci * @jack: The jack to configure 60462306a36Sopenharmony_ci * @type: Jack report type for this key 60562306a36Sopenharmony_ci * @keytype: Input layer key type to be reported 60662306a36Sopenharmony_ci * 60762306a36Sopenharmony_ci * Map a SND_JACK_BTN_* button type to an input layer key, allowing 60862306a36Sopenharmony_ci * reporting of keys on accessories via the jack abstraction. If no 60962306a36Sopenharmony_ci * mapping is provided but keys are enabled in the jack type then 61062306a36Sopenharmony_ci * BTN_n numeric buttons will be reported. 61162306a36Sopenharmony_ci * 61262306a36Sopenharmony_ci * If jacks are not reporting via the input API this call will have no 61362306a36Sopenharmony_ci * effect. 61462306a36Sopenharmony_ci * 61562306a36Sopenharmony_ci * Note that this is intended to be use by simple devices with small 61662306a36Sopenharmony_ci * numbers of keys that can be reported. It is also possible to 61762306a36Sopenharmony_ci * access the input device directly - devices with complex input 61862306a36Sopenharmony_ci * capabilities on accessories should consider doing this rather than 61962306a36Sopenharmony_ci * using this abstraction. 62062306a36Sopenharmony_ci * 62162306a36Sopenharmony_ci * This function may only be called prior to registration of the jack. 62262306a36Sopenharmony_ci * 62362306a36Sopenharmony_ci * Return: Zero if successful, or a negative error code on failure. 62462306a36Sopenharmony_ci */ 62562306a36Sopenharmony_ciint snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type, 62662306a36Sopenharmony_ci int keytype) 62762306a36Sopenharmony_ci{ 62862306a36Sopenharmony_ci int key = fls(SND_JACK_BTN_0) - fls(type); 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ci WARN_ON(jack->registered); 63162306a36Sopenharmony_ci 63262306a36Sopenharmony_ci if (!keytype || key >= ARRAY_SIZE(jack->key)) 63362306a36Sopenharmony_ci return -EINVAL; 63462306a36Sopenharmony_ci 63562306a36Sopenharmony_ci jack->type |= type; 63662306a36Sopenharmony_ci jack->key[key] = keytype; 63762306a36Sopenharmony_ci return 0; 63862306a36Sopenharmony_ci} 63962306a36Sopenharmony_ciEXPORT_SYMBOL(snd_jack_set_key); 64062306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INPUT_DEV */ 64162306a36Sopenharmony_ci 64262306a36Sopenharmony_ci/** 64362306a36Sopenharmony_ci * snd_jack_report - Report the current status of a jack 64462306a36Sopenharmony_ci * Note: This function uses mutexes and should be called from a 64562306a36Sopenharmony_ci * context which can sleep (such as a workqueue). 64662306a36Sopenharmony_ci * 64762306a36Sopenharmony_ci * @jack: The jack to report status for 64862306a36Sopenharmony_ci * @status: The current status of the jack 64962306a36Sopenharmony_ci */ 65062306a36Sopenharmony_civoid snd_jack_report(struct snd_jack *jack, int status) 65162306a36Sopenharmony_ci{ 65262306a36Sopenharmony_ci struct snd_jack_kctl *jack_kctl; 65362306a36Sopenharmony_ci unsigned int mask_bits = 0; 65462306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 65562306a36Sopenharmony_ci struct input_dev *idev; 65662306a36Sopenharmony_ci int i; 65762306a36Sopenharmony_ci#endif 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (!jack) 66062306a36Sopenharmony_ci return; 66162306a36Sopenharmony_ci 66262306a36Sopenharmony_ci jack->hw_status_cache = status; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci list_for_each_entry(jack_kctl, &jack->kctl_list, list) 66562306a36Sopenharmony_ci if (jack_kctl->sw_inject_enable) 66662306a36Sopenharmony_ci mask_bits |= jack_kctl->mask_bits; 66762306a36Sopenharmony_ci else 66862306a36Sopenharmony_ci snd_kctl_jack_report(jack->card, jack_kctl->kctl, 66962306a36Sopenharmony_ci status & jack_kctl->mask_bits); 67062306a36Sopenharmony_ci 67162306a36Sopenharmony_ci#ifdef CONFIG_SND_JACK_INPUT_DEV 67262306a36Sopenharmony_ci idev = input_get_device(jack->input_dev); 67362306a36Sopenharmony_ci if (!idev) 67462306a36Sopenharmony_ci return; 67562306a36Sopenharmony_ci 67662306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(jack->key); i++) { 67762306a36Sopenharmony_ci int testbit = ((SND_JACK_BTN_0 >> i) & ~mask_bits); 67862306a36Sopenharmony_ci 67962306a36Sopenharmony_ci if (jack->type & testbit) 68062306a36Sopenharmony_ci input_report_key(idev, jack->key[i], 68162306a36Sopenharmony_ci status & testbit); 68262306a36Sopenharmony_ci } 68362306a36Sopenharmony_ci 68462306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(jack_switch_types); i++) { 68562306a36Sopenharmony_ci int testbit = ((1 << i) & ~mask_bits); 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (jack->type & testbit) 68862306a36Sopenharmony_ci input_report_switch(idev, 68962306a36Sopenharmony_ci jack_switch_types[i], 69062306a36Sopenharmony_ci status & testbit); 69162306a36Sopenharmony_ci } 69262306a36Sopenharmony_ci 69362306a36Sopenharmony_ci input_sync(idev); 69462306a36Sopenharmony_ci input_put_device(idev); 69562306a36Sopenharmony_ci#endif /* CONFIG_SND_JACK_INPUT_DEV */ 69662306a36Sopenharmony_ci} 69762306a36Sopenharmony_ciEXPORT_SYMBOL(snd_jack_report); 698