~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/virtio/virtio_jack.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0+
  2 /*
  3  * virtio-snd: Virtio sound device
  4  * Copyright (C) 2021 OpenSynergy GmbH
  5  */
  6 #include <linux/virtio_config.h>
  7 #include <sound/jack.h>
  8 #include <sound/hda_verbs.h>
  9 
 10 #include "virtio_card.h"
 11 
 12 /**
 13  * DOC: Implementation Status
 14  *
 15  * At the moment jacks have a simple implementation and can only be used to
 16  * receive notifications about a plugged in/out device.
 17  *
 18  * VIRTIO_SND_R_JACK_REMAP
 19  *   is not supported
 20  */
 21 
 22 /**
 23  * struct virtio_jack - VirtIO jack.
 24  * @jack: Kernel jack control.
 25  * @nid: Functional group node identifier.
 26  * @features: Jack virtio feature bit map (1 << VIRTIO_SND_JACK_F_XXX).
 27  * @defconf: Pin default configuration value.
 28  * @caps: Pin capabilities value.
 29  * @connected: Current jack connection status.
 30  * @type: Kernel jack type (SND_JACK_XXX).
 31  */
 32 struct virtio_jack {
 33         struct snd_jack *jack;
 34         u32 nid;
 35         u32 features;
 36         u32 defconf;
 37         u32 caps;
 38         bool connected;
 39         int type;
 40 };
 41 
 42 /**
 43  * virtsnd_jack_get_label() - Get the name string for the jack.
 44  * @vjack: VirtIO jack.
 45  *
 46  * Returns the jack name based on the default pin configuration value (see HDA
 47  * specification).
 48  *
 49  * Context: Any context.
 50  * Return: Name string.
 51  */
 52 static const char *virtsnd_jack_get_label(struct virtio_jack *vjack)
 53 {
 54         unsigned int defconf = vjack->defconf;
 55         unsigned int device =
 56                 (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT;
 57         unsigned int location =
 58                 (defconf & AC_DEFCFG_LOCATION) >> AC_DEFCFG_LOCATION_SHIFT;
 59 
 60         switch (device) {
 61         case AC_JACK_LINE_OUT:
 62                 return "Line Out";
 63         case AC_JACK_SPEAKER:
 64                 return "Speaker";
 65         case AC_JACK_HP_OUT:
 66                 return "Headphone";
 67         case AC_JACK_CD:
 68                 return "CD";
 69         case AC_JACK_SPDIF_OUT:
 70         case AC_JACK_DIG_OTHER_OUT:
 71                 if (location == AC_JACK_LOC_HDMI)
 72                         return "HDMI Out";
 73                 else
 74                         return "SPDIF Out";
 75         case AC_JACK_LINE_IN:
 76                 return "Line";
 77         case AC_JACK_AUX:
 78                 return "Aux";
 79         case AC_JACK_MIC_IN:
 80                 return "Mic";
 81         case AC_JACK_SPDIF_IN:
 82                 return "SPDIF In";
 83         case AC_JACK_DIG_OTHER_IN:
 84                 return "Digital In";
 85         default:
 86                 return "Misc";
 87         }
 88 }
 89 
 90 /**
 91  * virtsnd_jack_get_type() - Get the type for the jack.
 92  * @vjack: VirtIO jack.
 93  *
 94  * Returns the jack type based on the default pin configuration value (see HDA
 95  * specification).
 96  *
 97  * Context: Any context.
 98  * Return: SND_JACK_XXX value.
 99  */
100 static int virtsnd_jack_get_type(struct virtio_jack *vjack)
101 {
102         unsigned int defconf = vjack->defconf;
103         unsigned int device =
104                 (defconf & AC_DEFCFG_DEVICE) >> AC_DEFCFG_DEVICE_SHIFT;
105 
106         switch (device) {
107         case AC_JACK_LINE_OUT:
108         case AC_JACK_SPEAKER:
109                 return SND_JACK_LINEOUT;
110         case AC_JACK_HP_OUT:
111                 return SND_JACK_HEADPHONE;
112         case AC_JACK_SPDIF_OUT:
113         case AC_JACK_DIG_OTHER_OUT:
114                 return SND_JACK_AVOUT;
115         case AC_JACK_MIC_IN:
116                 return SND_JACK_MICROPHONE;
117         default:
118                 return SND_JACK_LINEIN;
119         }
120 }
121 
122 /**
123  * virtsnd_jack_parse_cfg() - Parse the jack configuration.
124  * @snd: VirtIO sound device.
125  *
126  * This function is called during initial device initialization.
127  *
128  * Context: Any context that permits to sleep.
129  * Return: 0 on success, -errno on failure.
130  */
131 int virtsnd_jack_parse_cfg(struct virtio_snd *snd)
132 {
133         struct virtio_device *vdev = snd->vdev;
134         struct virtio_snd_jack_info *info;
135         u32 i;
136         int rc;
137 
138         virtio_cread_le(vdev, struct virtio_snd_config, jacks, &snd->njacks);
139         if (!snd->njacks)
140                 return 0;
141 
142         snd->jacks = devm_kcalloc(&vdev->dev, snd->njacks, sizeof(*snd->jacks),
143                                   GFP_KERNEL);
144         if (!snd->jacks)
145                 return -ENOMEM;
146 
147         info = kcalloc(snd->njacks, sizeof(*info), GFP_KERNEL);
148         if (!info)
149                 return -ENOMEM;
150 
151         rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_JACK_INFO, 0, snd->njacks,
152                                     sizeof(*info), info);
153         if (rc)
154                 goto on_exit;
155 
156         for (i = 0; i < snd->njacks; ++i) {
157                 struct virtio_jack *vjack = &snd->jacks[i];
158 
159                 vjack->nid = le32_to_cpu(info[i].hdr.hda_fn_nid);
160                 vjack->features = le32_to_cpu(info[i].features);
161                 vjack->defconf = le32_to_cpu(info[i].hda_reg_defconf);
162                 vjack->caps = le32_to_cpu(info[i].hda_reg_caps);
163                 vjack->connected = info[i].connected;
164         }
165 
166 on_exit:
167         kfree(info);
168 
169         return rc;
170 }
171 
172 /**
173  * virtsnd_jack_build_devs() - Build ALSA controls for jacks.
174  * @snd: VirtIO sound device.
175  *
176  * Context: Any context that permits to sleep.
177  * Return: 0 on success, -errno on failure.
178  */
179 int virtsnd_jack_build_devs(struct virtio_snd *snd)
180 {
181         u32 i;
182         int rc;
183 
184         for (i = 0; i < snd->njacks; ++i) {
185                 struct virtio_jack *vjack = &snd->jacks[i];
186 
187                 vjack->type = virtsnd_jack_get_type(vjack);
188 
189                 rc = snd_jack_new(snd->card, virtsnd_jack_get_label(vjack),
190                                   vjack->type, &vjack->jack, true, true);
191                 if (rc)
192                         return rc;
193 
194                 if (vjack->jack)
195                         vjack->jack->private_data = vjack;
196 
197                 snd_jack_report(vjack->jack,
198                                 vjack->connected ? vjack->type : 0);
199         }
200 
201         return 0;
202 }
203 
204 /**
205  * virtsnd_jack_event() - Handle the jack event notification.
206  * @snd: VirtIO sound device.
207  * @event: VirtIO sound event.
208  *
209  * Context: Interrupt context.
210  */
211 void virtsnd_jack_event(struct virtio_snd *snd, struct virtio_snd_event *event)
212 {
213         u32 jack_id = le32_to_cpu(event->data);
214         struct virtio_jack *vjack;
215 
216         if (jack_id >= snd->njacks)
217                 return;
218 
219         vjack = &snd->jacks[jack_id];
220 
221         switch (le32_to_cpu(event->hdr.code)) {
222         case VIRTIO_SND_EVT_JACK_CONNECTED:
223                 vjack->connected = true;
224                 break;
225         case VIRTIO_SND_EVT_JACK_DISCONNECTED:
226                 vjack->connected = false;
227                 break;
228         default:
229                 return;
230         }
231 
232         snd_jack_report(vjack->jack, vjack->connected ? vjack->type : 0);
233 }
234 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php