1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Helper functions for jack-detection kcontrols 4 * 5 * Copyright (c) 2011 Takashi Iwai <tiwai@suse.de> 6 */ 7 8 #include <linux/kernel.h> 9 #include <linux/export.h> 10 #include <sound/core.h> 11 #include <sound/control.h> 12 13 #define jack_detect_kctl_info snd_ctl_boolean_mono_info 14 15 static int jack_detect_kctl_get(struct snd_kcontrol *kcontrol, 16 struct snd_ctl_elem_value *ucontrol) 17 { 18 ucontrol->value.integer.value[0] = kcontrol->private_value; 19 return 0; 20 } 21 22 static const struct snd_kcontrol_new jack_detect_kctl = { 23 /* name is filled later */ 24 .iface = SNDRV_CTL_ELEM_IFACE_CARD, 25 .access = SNDRV_CTL_ELEM_ACCESS_READ, 26 .info = jack_detect_kctl_info, 27 .get = jack_detect_kctl_get, 28 }; 29 30 static int get_available_index(struct snd_card *card, const char *name) 31 { 32 struct snd_ctl_elem_id sid; 33 34 memset(&sid, 0, sizeof(sid)); 35 36 sid.index = 0; 37 sid.iface = SNDRV_CTL_ELEM_IFACE_CARD; 38 strscpy(sid.name, name, sizeof(sid.name)); 39 40 while (snd_ctl_find_id(card, &sid)) { 41 sid.index++; 42 /* reset numid; otherwise snd_ctl_find_id() hits this again */ 43 sid.numid = 0; 44 } 45 46 return sid.index; 47 } 48 49 static void jack_kctl_name_gen(char *name, const char *src_name, int size) 50 { 51 size_t count = strlen(src_name); 52 bool need_cat = true; 53 54 /* remove redundant " Jack" from src_name */ 55 if (count >= 5) 56 need_cat = strncmp(&src_name[count - 5], " Jack", 5) ? true : false; 57 58 snprintf(name, size, need_cat ? "%s Jack" : "%s", src_name); 59 60 } 61 62 struct snd_kcontrol * 63 snd_kctl_jack_new(const char *name, struct snd_card *card) 64 { 65 struct snd_kcontrol *kctl; 66 67 kctl = snd_ctl_new1(&jack_detect_kctl, NULL); 68 if (!kctl) 69 return NULL; 70 71 jack_kctl_name_gen(kctl->id.name, name, sizeof(kctl->id.name)); 72 kctl->id.index = get_available_index(card, kctl->id.name); 73 kctl->private_value = 0; 74 return kctl; 75 } 76 77 void snd_kctl_jack_report(struct snd_card *card, 78 struct snd_kcontrol *kctl, bool status) 79 { 80 if (kctl->private_value == status) 81 return; 82 kctl->private_value = status; 83 snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id); 84 } 85