• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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. */
12 static 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. */
22 static 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. */
33 static 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  */
virtsnd_kctl_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)47 static 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  */
virtsnd_kctl_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uvalue)102 static 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 
161 on_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  */
virtsnd_kctl_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * uvalue)175 static 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  */
virtsnd_kctl_tlv_op(struct snd_kcontrol * kcontrol,int op_flag,unsigned int size,unsigned int __user * utlv)239 static 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(sizeof(*hdr), 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, &sg, false);
270 		if (!rc) {
271 			if (copy_to_user(utlv, tlv, 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(tlv, utlv, size)) {
285 			rc = -EFAULT;
286 			goto on_msg_unref;
287 		} else {
288 			rc = virtsnd_ctl_msg_send(snd, msg, &sg, NULL, 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(tlv);
299 	return rc;
300 
301 on_msg_unref:
302 	virtsnd_ctl_msg_unref(msg);
303 	kfree(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  */
virtsnd_kctl_get_enum_items(struct virtio_snd * snd,unsigned int cid)318 static 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(sizeof(*hdr),
329 				    sizeof(struct virtio_snd_hdr), GFP_KERNEL);
330 	if (!msg)
331 		return -ENOMEM;
332 
333 	kctl->items = devm_kcalloc(&vdev->dev, n, 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, &sg, 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  */
virtsnd_kctl_parse_cfg(struct virtio_snd * snd)358 int 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(&vdev->dev, snd->nkctls,
370 				       sizeof(*snd->kctl_infos), GFP_KERNEL);
371 	if (!snd->kctl_infos)
372 		return -ENOMEM;
373 
374 	snd->kctls = devm_kcalloc(&vdev->dev, snd->nkctls, sizeof(*snd->kctls),
375 				  GFP_KERNEL);
376 	if (!snd->kctls)
377 		return -ENOMEM;
378 
379 	rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_CTL_INFO, 0, snd->nkctls,
380 				    sizeof(*snd->kctl_infos), 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, 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  */
virtsnd_kctl_build_devs(struct virtio_snd * snd)405 int 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(&kctl_new, snd);
439 		if (!kctl->kctl)
440 			return -ENOMEM;
441 
442 		rc = snd_ctl_add(snd->card, 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  */
virtsnd_kctl_event(struct virtio_snd * snd,struct virtio_snd_event * event)457 void 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(snd->card, mask, &kctl->kctl->id);
477 }
478