1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * virtio-snd: Virtio sound device
4 * Copyright (C) 2022 OpenSynergy GmbH
5 */
6#include <sound/control.h>
7#include <linux/virtio_config.h>
8
9#include "virtio_card.h"
10
11/* Map for converting VirtIO types to ALSA types. */
12static const snd_ctl_elem_type_t g_v2a_type_map[] = {
13 [VIRTIO_SND_CTL_TYPE_BOOLEAN] = SNDRV_CTL_ELEM_TYPE_BOOLEAN,
14 [VIRTIO_SND_CTL_TYPE_INTEGER] = SNDRV_CTL_ELEM_TYPE_INTEGER,
15 [VIRTIO_SND_CTL_TYPE_INTEGER64] = SNDRV_CTL_ELEM_TYPE_INTEGER64,
16 [VIRTIO_SND_CTL_TYPE_ENUMERATED] = SNDRV_CTL_ELEM_TYPE_ENUMERATED,
17 [VIRTIO_SND_CTL_TYPE_BYTES] = SNDRV_CTL_ELEM_TYPE_BYTES,
18 [VIRTIO_SND_CTL_TYPE_IEC958] = SNDRV_CTL_ELEM_TYPE_IEC958
19};
20
21/* Map for converting VirtIO access rights to ALSA access rights. */
22static const unsigned int g_v2a_access_map[] = {
23 [VIRTIO_SND_CTL_ACCESS_READ] = SNDRV_CTL_ELEM_ACCESS_READ,
24 [VIRTIO_SND_CTL_ACCESS_WRITE] = SNDRV_CTL_ELEM_ACCESS_WRITE,
25 [VIRTIO_SND_CTL_ACCESS_VOLATILE] = SNDRV_CTL_ELEM_ACCESS_VOLATILE,
26 [VIRTIO_SND_CTL_ACCESS_INACTIVE] = SNDRV_CTL_ELEM_ACCESS_INACTIVE,
27 [VIRTIO_SND_CTL_ACCESS_TLV_READ] = SNDRV_CTL_ELEM_ACCESS_TLV_READ,
28 [VIRTIO_SND_CTL_ACCESS_TLV_WRITE] = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE,
29 [VIRTIO_SND_CTL_ACCESS_TLV_COMMAND] = SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND
30};
31
32/* Map for converting VirtIO event masks to ALSA event masks. */
33static const unsigned int g_v2a_mask_map[] = {
34 [VIRTIO_SND_CTL_EVT_MASK_VALUE] = SNDRV_CTL_EVENT_MASK_VALUE,
35 [VIRTIO_SND_CTL_EVT_MASK_INFO] = SNDRV_CTL_EVENT_MASK_INFO,
36 [VIRTIO_SND_CTL_EVT_MASK_TLV] = SNDRV_CTL_EVENT_MASK_TLV
37};
38
39/**
40 * virtsnd_kctl_info() - Returns information about the control.
41 * @kcontrol: ALSA control element.
42 * @uinfo: Element information.
43 *
44 * Context: Process context.
45 * Return: 0 on success, -errno on failure.
46 */
47static int virtsnd_kctl_info(struct snd_kcontrol *kcontrol,
48 struct snd_ctl_elem_info *uinfo)
49{
50 struct virtio_snd *snd = kcontrol->private_data;
51 struct virtio_kctl *kctl = &snd->kctls[kcontrol->private_value];
52 struct virtio_snd_ctl_info *kinfo =
53 &snd->kctl_infos[kcontrol->private_value];
54 unsigned int i;
55
56 uinfo->type = g_v2a_type_map[le32_to_cpu(kinfo->type)];
57 uinfo->count = le32_to_cpu(kinfo->count);
58
59 switch (uinfo->type) {
60 case SNDRV_CTL_ELEM_TYPE_INTEGER:
61 uinfo->value.integer.min =
62 le32_to_cpu(kinfo->value.integer.min);
63 uinfo->value.integer.max =
64 le32_to_cpu(kinfo->value.integer.max);
65 uinfo->value.integer.step =
66 le32_to_cpu(kinfo->value.integer.step);
67
68 break;
69 case SNDRV_CTL_ELEM_TYPE_INTEGER64:
70 uinfo->value.integer64.min =
71 le64_to_cpu(kinfo->value.integer64.min);
72 uinfo->value.integer64.max =
73 le64_to_cpu(kinfo->value.integer64.max);
74 uinfo->value.integer64.step =
75 le64_to_cpu(kinfo->value.integer64.step);
76
77 break;
78 case SNDRV_CTL_ELEM_TYPE_ENUMERATED:
79 uinfo->value.enumerated.items =
80 le32_to_cpu(kinfo->value.enumerated.items);
81 i = uinfo->value.enumerated.item;
82 if (i >= uinfo->value.enumerated.items)
83 return -EINVAL;
84
85 strscpy(uinfo->value.enumerated.name, kctl->items[i].item,
86 sizeof(uinfo->value.enumerated.name));
87
88 break;
89 }
90
91 return 0;
92}
93
94/**
95 * virtsnd_kctl_get() - Read the value from the control.
96 * @kcontrol: ALSA control element.
97 * @uvalue: Element value.
98 *
99 * Context: Process context.
100 * Return: 0 on success, -errno on failure.
101 */
102static int virtsnd_kctl_get(struct snd_kcontrol *kcontrol,
103 struct snd_ctl_elem_value *uvalue)
104{
105 struct virtio_snd *snd = kcontrol->private_data;
106 struct virtio_snd_ctl_info *kinfo =
107 &snd->kctl_infos[kcontrol->private_value];
108 unsigned int type = le32_to_cpu(kinfo->type);
109 unsigned int count = le32_to_cpu(kinfo->count);
110 struct virtio_snd_msg *msg;
111 struct virtio_snd_ctl_hdr *hdr;
112 struct virtio_snd_ctl_value *kvalue;
113 size_t request_size = sizeof(*hdr);
114 size_t response_size = sizeof(struct virtio_snd_hdr) + sizeof(*kvalue);
115 unsigned int i;
116 int rc;
117
118 msg = virtsnd_ctl_msg_alloc(request_size, response_size, GFP_KERNEL);
119 if (!msg)
120 return -ENOMEM;
121
122 virtsnd_ctl_msg_ref(msg);
123
124 hdr = virtsnd_ctl_msg_request(msg);
125 hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_READ);
126 hdr->control_id = cpu_to_le32(kcontrol->private_value);
127
128 rc = virtsnd_ctl_msg_send_sync(snd, msg);
129 if (rc)
130 goto on_failure;
131
132 kvalue = (void *)((u8 *)virtsnd_ctl_msg_response(msg) +
133 sizeof(struct virtio_snd_hdr));
134
135 switch (type) {
136 case VIRTIO_SND_CTL_TYPE_BOOLEAN:
137 case VIRTIO_SND_CTL_TYPE_INTEGER:
138 for (i = 0; i < count; ++i)
139 uvalue->value.integer.value[i] =
140 le32_to_cpu(kvalue->value.integer[i]);
141 break;
142 case VIRTIO_SND_CTL_TYPE_INTEGER64:
143 for (i = 0; i < count; ++i)
144 uvalue->value.integer64.value[i] =
145 le64_to_cpu(kvalue->value.integer64[i]);
146 break;
147 case VIRTIO_SND_CTL_TYPE_ENUMERATED:
148 for (i = 0; i < count; ++i)
149 uvalue->value.enumerated.item[i] =
150 le32_to_cpu(kvalue->value.enumerated[i]);
151 break;
152 case VIRTIO_SND_CTL_TYPE_BYTES:
153 memcpy(uvalue->value.bytes.data, kvalue->value.bytes, count);
154 break;
155 case VIRTIO_SND_CTL_TYPE_IEC958:
156 memcpy(&uvalue->value.iec958, &kvalue->value.iec958,
157 sizeof(uvalue->value.iec958));
158 break;
159 }
160
161on_failure:
162 virtsnd_ctl_msg_unref(msg);
163
164 return rc;
165}
166
167/**
168 * virtsnd_kctl_put() - Write the value to the control.
169 * @kcontrol: ALSA control element.
170 * @uvalue: Element value.
171 *
172 * Context: Process context.
173 * Return: 0 on success, -errno on failure.
174 */
175static int virtsnd_kctl_put(struct snd_kcontrol *kcontrol,
176 struct snd_ctl_elem_value *uvalue)
177{
178 struct virtio_snd *snd = kcontrol->private_data;
179 struct virtio_snd_ctl_info *kinfo =
180 &snd->kctl_infos[kcontrol->private_value];
181 unsigned int type = le32_to_cpu(kinfo->type);
182 unsigned int count = le32_to_cpu(kinfo->count);
183 struct virtio_snd_msg *msg;
184 struct virtio_snd_ctl_hdr *hdr;
185 struct virtio_snd_ctl_value *kvalue;
186 size_t request_size = sizeof(*hdr) + sizeof(*kvalue);
187 size_t response_size = sizeof(struct virtio_snd_hdr);
188 unsigned int i;
189
190 msg = virtsnd_ctl_msg_alloc(request_size, response_size, GFP_KERNEL);
191 if (!msg)
192 return -ENOMEM;
193
194 hdr = virtsnd_ctl_msg_request(msg);
195 hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_WRITE);
196 hdr->control_id = cpu_to_le32(kcontrol->private_value);
197
198 kvalue = (void *)((u8 *)hdr + sizeof(*hdr));
199
200 switch (type) {
201 case VIRTIO_SND_CTL_TYPE_BOOLEAN:
202 case VIRTIO_SND_CTL_TYPE_INTEGER:
203 for (i = 0; i < count; ++i)
204 kvalue->value.integer[i] =
205 cpu_to_le32(uvalue->value.integer.value[i]);
206 break;
207 case VIRTIO_SND_CTL_TYPE_INTEGER64:
208 for (i = 0; i < count; ++i)
209 kvalue->value.integer64[i] =
210 cpu_to_le64(uvalue->value.integer64.value[i]);
211 break;
212 case VIRTIO_SND_CTL_TYPE_ENUMERATED:
213 for (i = 0; i < count; ++i)
214 kvalue->value.enumerated[i] =
215 cpu_to_le32(uvalue->value.enumerated.item[i]);
216 break;
217 case VIRTIO_SND_CTL_TYPE_BYTES:
218 memcpy(kvalue->value.bytes, uvalue->value.bytes.data, count);
219 break;
220 case VIRTIO_SND_CTL_TYPE_IEC958:
221 memcpy(&kvalue->value.iec958, &uvalue->value.iec958,
222 sizeof(kvalue->value.iec958));
223 break;
224 }
225
226 return virtsnd_ctl_msg_send_sync(snd, msg);
227}
228
229/**
230 * virtsnd_kctl_tlv_op() - Perform an operation on the control's metadata.
231 * @kcontrol: ALSA control element.
232 * @op_flag: Operation code (SNDRV_CTL_TLV_OP_XXX).
233 * @size: Size of the TLV data in bytes.
234 * @utlv: TLV data.
235 *
236 * Context: Process context.
237 * Return: 0 on success, -errno on failure.
238 */
239static int virtsnd_kctl_tlv_op(struct snd_kcontrol *kcontrol, int op_flag,
240 unsigned int size, unsigned int __user *utlv)
241{
242 struct virtio_snd *snd = kcontrol->private_data;
243 struct virtio_snd_msg *msg;
244 struct virtio_snd_ctl_hdr *hdr;
245 unsigned int *tlv;
246 struct scatterlist sg;
247 int rc;
248
249 msg = virtsnd_ctl_msg_alloc(request_size: sizeof(*hdr), response_size: sizeof(struct virtio_snd_hdr),
250 GFP_KERNEL);
251 if (!msg)
252 return -ENOMEM;
253
254 tlv = kzalloc(size, GFP_KERNEL);
255 if (!tlv) {
256 rc = -ENOMEM;
257 goto on_msg_unref;
258 }
259
260 sg_init_one(&sg, tlv, size);
261
262 hdr = virtsnd_ctl_msg_request(msg);
263 hdr->control_id = cpu_to_le32(kcontrol->private_value);
264
265 switch (op_flag) {
266 case SNDRV_CTL_TLV_OP_READ:
267 hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_TLV_READ);
268
269 rc = virtsnd_ctl_msg_send(snd, msg, NULL, in_sgs: &sg, nowait: false);
270 if (!rc) {
271 if (copy_to_user(to: utlv, from: tlv, n: size))
272 rc = -EFAULT;
273 }
274
275 break;
276 case SNDRV_CTL_TLV_OP_WRITE:
277 case SNDRV_CTL_TLV_OP_CMD:
278 if (op_flag == SNDRV_CTL_TLV_OP_WRITE)
279 hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_TLV_WRITE);
280 else
281 hdr->hdr.code =
282 cpu_to_le32(VIRTIO_SND_R_CTL_TLV_COMMAND);
283
284 if (copy_from_user(to: tlv, from: utlv, n: size)) {
285 rc = -EFAULT;
286 goto on_msg_unref;
287 } else {
288 rc = virtsnd_ctl_msg_send(snd, msg, out_sgs: &sg, NULL, nowait: false);
289 }
290
291 break;
292 default:
293 rc = -EINVAL;
294 /* We never get here - we listed all values for op_flag */
295 WARN_ON(1);
296 goto on_msg_unref;
297 }
298 kfree(objp: tlv);
299 return rc;
300
301on_msg_unref:
302 virtsnd_ctl_msg_unref(msg);
303 kfree(objp: tlv);
304
305 return rc;
306}
307
308/**
309 * virtsnd_kctl_get_enum_items() - Query items for the ENUMERATED element type.
310 * @snd: VirtIO sound device.
311 * @cid: Control element ID.
312 *
313 * This function is called during initial device initialization.
314 *
315 * Context: Any context that permits to sleep.
316 * Return: 0 on success, -errno on failure.
317 */
318static int virtsnd_kctl_get_enum_items(struct virtio_snd *snd, unsigned int cid)
319{
320 struct virtio_device *vdev = snd->vdev;
321 struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[cid];
322 struct virtio_kctl *kctl = &snd->kctls[cid];
323 struct virtio_snd_msg *msg;
324 struct virtio_snd_ctl_hdr *hdr;
325 unsigned int n = le32_to_cpu(kinfo->value.enumerated.items);
326 struct scatterlist sg;
327
328 msg = virtsnd_ctl_msg_alloc(request_size: sizeof(*hdr),
329 response_size: sizeof(struct virtio_snd_hdr), GFP_KERNEL);
330 if (!msg)
331 return -ENOMEM;
332
333 kctl->items = devm_kcalloc(dev: &vdev->dev, n, size: sizeof(*kctl->items),
334 GFP_KERNEL);
335 if (!kctl->items) {
336 virtsnd_ctl_msg_unref(msg);
337 return -ENOMEM;
338 }
339
340 sg_init_one(&sg, kctl->items, n * sizeof(*kctl->items));
341
342 hdr = virtsnd_ctl_msg_request(msg);
343 hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_ENUM_ITEMS);
344 hdr->control_id = cpu_to_le32(cid);
345
346 return virtsnd_ctl_msg_send(snd, msg, NULL, in_sgs: &sg, nowait: false);
347}
348
349/**
350 * virtsnd_kctl_parse_cfg() - Parse the control element configuration.
351 * @snd: VirtIO sound device.
352 *
353 * This function is called during initial device initialization.
354 *
355 * Context: Any context that permits to sleep.
356 * Return: 0 on success, -errno on failure.
357 */
358int virtsnd_kctl_parse_cfg(struct virtio_snd *snd)
359{
360 struct virtio_device *vdev = snd->vdev;
361 u32 i;
362 int rc;
363
364 virtio_cread_le(vdev, struct virtio_snd_config, controls,
365 &snd->nkctls);
366 if (!snd->nkctls)
367 return 0;
368
369 snd->kctl_infos = devm_kcalloc(dev: &vdev->dev, n: snd->nkctls,
370 size: sizeof(*snd->kctl_infos), GFP_KERNEL);
371 if (!snd->kctl_infos)
372 return -ENOMEM;
373
374 snd->kctls = devm_kcalloc(dev: &vdev->dev, n: snd->nkctls, size: sizeof(*snd->kctls),
375 GFP_KERNEL);
376 if (!snd->kctls)
377 return -ENOMEM;
378
379 rc = virtsnd_ctl_query_info(snd, command: VIRTIO_SND_R_CTL_INFO, start_id: 0, count: snd->nkctls,
380 size: sizeof(*snd->kctl_infos), info: snd->kctl_infos);
381 if (rc)
382 return rc;
383
384 for (i = 0; i < snd->nkctls; ++i) {
385 struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[i];
386 unsigned int type = le32_to_cpu(kinfo->type);
387
388 if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED) {
389 rc = virtsnd_kctl_get_enum_items(snd, cid: i);
390 if (rc)
391 return rc;
392 }
393 }
394
395 return 0;
396}
397
398/**
399 * virtsnd_kctl_build_devs() - Build ALSA control elements.
400 * @snd: VirtIO sound device.
401 *
402 * Context: Any context that permits to sleep.
403 * Return: 0 on success, -errno on failure.
404 */
405int virtsnd_kctl_build_devs(struct virtio_snd *snd)
406{
407 unsigned int cid;
408
409 for (cid = 0; cid < snd->nkctls; ++cid) {
410 struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[cid];
411 struct virtio_kctl *kctl = &snd->kctls[cid];
412 struct snd_kcontrol_new kctl_new;
413 unsigned int i;
414 int rc;
415
416 memset(&kctl_new, 0, sizeof(kctl_new));
417
418 kctl_new.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
419 kctl_new.name = kinfo->name;
420 kctl_new.index = le32_to_cpu(kinfo->index);
421
422 for (i = 0; i < ARRAY_SIZE(g_v2a_access_map); ++i)
423 if (le32_to_cpu(kinfo->access) & (1 << i))
424 kctl_new.access |= g_v2a_access_map[i];
425
426 if (kctl_new.access & (SNDRV_CTL_ELEM_ACCESS_TLV_READ |
427 SNDRV_CTL_ELEM_ACCESS_TLV_WRITE |
428 SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND)) {
429 kctl_new.access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
430 kctl_new.tlv.c = virtsnd_kctl_tlv_op;
431 }
432
433 kctl_new.info = virtsnd_kctl_info;
434 kctl_new.get = virtsnd_kctl_get;
435 kctl_new.put = virtsnd_kctl_put;
436 kctl_new.private_value = cid;
437
438 kctl->kctl = snd_ctl_new1(kcontrolnew: &kctl_new, private_data: snd);
439 if (!kctl->kctl)
440 return -ENOMEM;
441
442 rc = snd_ctl_add(card: snd->card, kcontrol: kctl->kctl);
443 if (rc)
444 return rc;
445 }
446
447 return 0;
448}
449
450/**
451 * virtsnd_kctl_event() - Handle the control element event notification.
452 * @snd: VirtIO sound device.
453 * @event: VirtIO sound event.
454 *
455 * Context: Interrupt context.
456 */
457void virtsnd_kctl_event(struct virtio_snd *snd, struct virtio_snd_event *event)
458{
459 struct virtio_snd_ctl_event *kevent =
460 (struct virtio_snd_ctl_event *)event;
461 struct virtio_kctl *kctl;
462 unsigned int cid = le16_to_cpu(kevent->control_id);
463 unsigned int mask = 0;
464 unsigned int i;
465
466 if (cid >= snd->nkctls)
467 return;
468
469 for (i = 0; i < ARRAY_SIZE(g_v2a_mask_map); ++i)
470 if (le16_to_cpu(kevent->mask) & (1 << i))
471 mask |= g_v2a_mask_map[i];
472
473
474 kctl = &snd->kctls[cid];
475
476 snd_ctl_notify(card: snd->card, mask, id: &kctl->kctl->id);
477}
478

source code of linux/sound/virtio/virtio_kctl.c