Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: virtio: add support for audio controls

Implementation of support for audio controls in accordance with the
extension of the virtio sound device specification [1] planned for
virtio-v1.3-cs01.

The device can announce the VIRTIO_SND_F_CTLS feature. If the feature is
negotiated, then an additional field appears in the configuration space:

struct virtio_snd_config {
...
/* number of available control elements */
__le32 controls;
};

The driver can send the following requests to manage audio controls:

enum {
...
/* control element request types */
VIRTIO_SND_R_CTL_INFO = 0x0300,
VIRTIO_SND_R_CTL_ENUM_ITEMS,
VIRTIO_SND_R_CTL_READ,
VIRTIO_SND_R_CTL_WRITE,
VIRTIO_SND_R_CTL_TLV_READ,
VIRTIO_SND_R_CTL_TLV_WRITE,
VIRTIO_SND_R_CTL_TLV_COMMAND,
...
};

And the device can send the following audio control event notification:

enum {
...
/* control element event types */
VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200,
...
};

See additional details in [1].

[1] https://lists.oasis-open.org/archives/virtio-comment/202104/msg00013.html

Signed-off-by: Anton Yakovlev <anton.yakovlev@opensynergy.com>
Signed-off-by: Aiswarya Cyriac <aiswarya.cyriac@opensynergy.com>
Link: https://lore.kernel.org/r/20240115133654.576068-2-aiswarya.cyriac@opensynergy.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>

authored by

Anton Yakovlev and committed by
Takashi Iwai
d6568e3d a0978123

+664
+154
include/uapi/linux/virtio_snd.h
··· 8 8 #include <linux/virtio_types.h> 9 9 10 10 /******************************************************************************* 11 + * FEATURE BITS 12 + */ 13 + enum { 14 + /* device supports control elements */ 15 + VIRTIO_SND_F_CTLS = 0 16 + }; 17 + 18 + /******************************************************************************* 11 19 * CONFIGURATION SPACE 12 20 */ 13 21 struct virtio_snd_config { ··· 25 17 __le32 streams; 26 18 /* # of available channel maps */ 27 19 __le32 chmaps; 20 + /* # of available control elements */ 21 + __le32 controls; 28 22 }; 29 23 30 24 enum { ··· 65 55 /* channel map control request types */ 66 56 VIRTIO_SND_R_CHMAP_INFO = 0x0200, 67 57 58 + /* control element request types */ 59 + VIRTIO_SND_R_CTL_INFO = 0x0300, 60 + VIRTIO_SND_R_CTL_ENUM_ITEMS, 61 + VIRTIO_SND_R_CTL_READ, 62 + VIRTIO_SND_R_CTL_WRITE, 63 + VIRTIO_SND_R_CTL_TLV_READ, 64 + VIRTIO_SND_R_CTL_TLV_WRITE, 65 + VIRTIO_SND_R_CTL_TLV_COMMAND, 66 + 68 67 /* jack event types */ 69 68 VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000, 70 69 VIRTIO_SND_EVT_JACK_DISCONNECTED, ··· 81 62 /* PCM event types */ 82 63 VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100, 83 64 VIRTIO_SND_EVT_PCM_XRUN, 65 + 66 + /* control element event types */ 67 + VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200, 84 68 85 69 /* common status codes */ 86 70 VIRTIO_SND_S_OK = 0x8000, ··· 351 329 __u8 channels; 352 330 /* channel position values (VIRTIO_SND_CHMAP_XXX) */ 353 331 __u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE]; 332 + }; 333 + 334 + /******************************************************************************* 335 + * CONTROL ELEMENTS MESSAGES 336 + */ 337 + struct virtio_snd_ctl_hdr { 338 + /* VIRTIO_SND_R_CTL_XXX */ 339 + struct virtio_snd_hdr hdr; 340 + /* 0 ... virtio_snd_config::controls - 1 */ 341 + __le32 control_id; 342 + }; 343 + 344 + /* supported roles for control elements */ 345 + enum { 346 + VIRTIO_SND_CTL_ROLE_UNDEFINED = 0, 347 + VIRTIO_SND_CTL_ROLE_VOLUME, 348 + VIRTIO_SND_CTL_ROLE_MUTE, 349 + VIRTIO_SND_CTL_ROLE_GAIN 350 + }; 351 + 352 + /* supported value types for control elements */ 353 + enum { 354 + VIRTIO_SND_CTL_TYPE_BOOLEAN = 0, 355 + VIRTIO_SND_CTL_TYPE_INTEGER, 356 + VIRTIO_SND_CTL_TYPE_INTEGER64, 357 + VIRTIO_SND_CTL_TYPE_ENUMERATED, 358 + VIRTIO_SND_CTL_TYPE_BYTES, 359 + VIRTIO_SND_CTL_TYPE_IEC958 360 + }; 361 + 362 + /* supported access rights for control elements */ 363 + enum { 364 + VIRTIO_SND_CTL_ACCESS_READ = 0, 365 + VIRTIO_SND_CTL_ACCESS_WRITE, 366 + VIRTIO_SND_CTL_ACCESS_VOLATILE, 367 + VIRTIO_SND_CTL_ACCESS_INACTIVE, 368 + VIRTIO_SND_CTL_ACCESS_TLV_READ, 369 + VIRTIO_SND_CTL_ACCESS_TLV_WRITE, 370 + VIRTIO_SND_CTL_ACCESS_TLV_COMMAND 371 + }; 372 + 373 + struct virtio_snd_ctl_info { 374 + /* common header */ 375 + struct virtio_snd_info hdr; 376 + /* element role (VIRTIO_SND_CTL_ROLE_XXX) */ 377 + __le32 role; 378 + /* element value type (VIRTIO_SND_CTL_TYPE_XXX) */ 379 + __le32 type; 380 + /* element access right bit map (1 << VIRTIO_SND_CTL_ACCESS_XXX) */ 381 + __le32 access; 382 + /* # of members in the element value */ 383 + __le32 count; 384 + /* index for an element with a non-unique name */ 385 + __le32 index; 386 + /* name identifier string for the element */ 387 + __u8 name[44]; 388 + /* additional information about the element's value */ 389 + union { 390 + /* VIRTIO_SND_CTL_TYPE_INTEGER */ 391 + struct { 392 + /* minimum supported value */ 393 + __le32 min; 394 + /* maximum supported value */ 395 + __le32 max; 396 + /* fixed step size for value (0 = variable size) */ 397 + __le32 step; 398 + } integer; 399 + /* VIRTIO_SND_CTL_TYPE_INTEGER64 */ 400 + struct { 401 + /* minimum supported value */ 402 + __le64 min; 403 + /* maximum supported value */ 404 + __le64 max; 405 + /* fixed step size for value (0 = variable size) */ 406 + __le64 step; 407 + } integer64; 408 + /* VIRTIO_SND_CTL_TYPE_ENUMERATED */ 409 + struct { 410 + /* # of options supported for value */ 411 + __le32 items; 412 + } enumerated; 413 + } value; 414 + }; 415 + 416 + struct virtio_snd_ctl_enum_item { 417 + /* option name */ 418 + __u8 item[64]; 419 + }; 420 + 421 + struct virtio_snd_ctl_iec958 { 422 + /* AES/IEC958 channel status bits */ 423 + __u8 status[24]; 424 + /* AES/IEC958 subcode bits */ 425 + __u8 subcode[147]; 426 + /* nothing */ 427 + __u8 pad; 428 + /* AES/IEC958 subframe bits */ 429 + __u8 dig_subframe[4]; 430 + }; 431 + 432 + struct virtio_snd_ctl_value { 433 + union { 434 + /* VIRTIO_SND_CTL_TYPE_BOOLEAN|INTEGER value */ 435 + __le32 integer[128]; 436 + /* VIRTIO_SND_CTL_TYPE_INTEGER64 value */ 437 + __le64 integer64[64]; 438 + /* VIRTIO_SND_CTL_TYPE_ENUMERATED value (option indexes) */ 439 + __le32 enumerated[128]; 440 + /* VIRTIO_SND_CTL_TYPE_BYTES value */ 441 + __u8 bytes[512]; 442 + /* VIRTIO_SND_CTL_TYPE_IEC958 value */ 443 + struct virtio_snd_ctl_iec958 iec958; 444 + } value; 445 + }; 446 + 447 + /* supported event reason types */ 448 + enum { 449 + /* element's value has changed */ 450 + VIRTIO_SND_CTL_EVT_MASK_VALUE = 0, 451 + /* element's information has changed */ 452 + VIRTIO_SND_CTL_EVT_MASK_INFO, 453 + /* element's metadata has changed */ 454 + VIRTIO_SND_CTL_EVT_MASK_TLV 455 + }; 456 + 457 + struct virtio_snd_ctl_event { 458 + /* VIRTIO_SND_EVT_CTL_NOTIFY */ 459 + struct virtio_snd_hdr hdr; 460 + /* 0 ... virtio_snd_config::controls - 1 */ 461 + __le16 control_id; 462 + /* event reason bit map (1 << VIRTIO_SND_CTL_EVT_MASK_XXX) */ 463 + __le16 mask; 354 464 }; 355 465 356 466 #endif /* VIRTIO_SND_IF_H */
+1
sound/virtio/Makefile
··· 7 7 virtio_chmap.o \ 8 8 virtio_ctl_msg.o \ 9 9 virtio_jack.o \ 10 + virtio_kctl.o \ 10 11 virtio_pcm.o \ 11 12 virtio_pcm_msg.o \ 12 13 virtio_pcm_ops.o
+21
sound/virtio/virtio_card.c
··· 64 64 case VIRTIO_SND_EVT_PCM_XRUN: 65 65 virtsnd_pcm_event(snd, event); 66 66 break; 67 + case VIRTIO_SND_EVT_CTL_NOTIFY: 68 + virtsnd_kctl_event(snd, event); 69 + break; 67 70 } 68 71 } 69 72 ··· 236 233 if (rc) 237 234 return rc; 238 235 236 + if (virtio_has_feature(vdev, VIRTIO_SND_F_CTLS)) { 237 + rc = virtsnd_kctl_parse_cfg(snd); 238 + if (rc) 239 + return rc; 240 + } 241 + 239 242 if (snd->njacks) { 240 243 rc = virtsnd_jack_build_devs(snd); 241 244 if (rc) ··· 256 247 257 248 if (snd->nchmaps) { 258 249 rc = virtsnd_chmap_build_devs(snd); 250 + if (rc) 251 + return rc; 252 + } 253 + 254 + if (snd->nkctls) { 255 + rc = virtsnd_kctl_build_devs(snd); 259 256 if (rc) 260 257 return rc; 261 258 } ··· 432 417 { 0 }, 433 418 }; 434 419 420 + static unsigned int features[] = { 421 + VIRTIO_SND_F_CTLS 422 + }; 423 + 435 424 static struct virtio_driver virtsnd_driver = { 436 425 .driver.name = KBUILD_MODNAME, 437 426 .driver.owner = THIS_MODULE, 438 427 .id_table = id_table, 428 + .feature_table = features, 429 + .feature_table_size = ARRAY_SIZE(features), 439 430 .validate = virtsnd_validate, 440 431 .probe = virtsnd_probe, 441 432 .remove = virtsnd_remove,
+22
sound/virtio/virtio_card.h
··· 32 32 }; 33 33 34 34 /** 35 + * struct virtio_kctl - VirtIO control element. 36 + * @kctl: ALSA control element. 37 + * @items: Items for the ENUMERATED element type. 38 + */ 39 + struct virtio_kctl { 40 + struct snd_kcontrol *kctl; 41 + struct virtio_snd_ctl_enum_item *items; 42 + }; 43 + 44 + /** 35 45 * struct virtio_snd - VirtIO sound card device. 36 46 * @vdev: Underlying virtio device. 37 47 * @queues: Virtqueue wrappers. ··· 55 45 * @nsubstreams: Number of PCM substreams. 56 46 * @chmaps: VirtIO channel maps. 57 47 * @nchmaps: Number of channel maps. 48 + * @kctl_infos: VirtIO control element information. 49 + * @kctls: VirtIO control elements. 50 + * @nkctls: Number of control elements. 58 51 */ 59 52 struct virtio_snd { 60 53 struct virtio_device *vdev; ··· 72 59 u32 nsubstreams; 73 60 struct virtio_snd_chmap_info *chmaps; 74 61 u32 nchmaps; 62 + struct virtio_snd_ctl_info *kctl_infos; 63 + struct virtio_kctl *kctls; 64 + u32 nkctls; 75 65 }; 76 66 77 67 /* Message completion timeout in milliseconds (module parameter). */ ··· 123 107 int virtsnd_chmap_parse_cfg(struct virtio_snd *snd); 124 108 125 109 int virtsnd_chmap_build_devs(struct virtio_snd *snd); 110 + 111 + int virtsnd_kctl_parse_cfg(struct virtio_snd *snd); 112 + 113 + int virtsnd_kctl_build_devs(struct virtio_snd *snd); 114 + 115 + void virtsnd_kctl_event(struct virtio_snd *snd, struct virtio_snd_event *event); 126 116 127 117 #endif /* VIRTIO_SND_CARD_H */
+466
sound/virtio/virtio_kctl.c
··· 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 + */ 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 + */ 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 + */ 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 + */ 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 + virtsnd_ctl_msg_unref(msg); 257 + return -ENOMEM; 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 + else 287 + rc = virtsnd_ctl_msg_send(snd, msg, &sg, NULL, false); 288 + 289 + break; 290 + } 291 + 292 + kfree(tlv); 293 + 294 + return rc; 295 + } 296 + 297 + /** 298 + * virtsnd_kctl_get_enum_items() - Query items for the ENUMERATED element type. 299 + * @snd: VirtIO sound device. 300 + * @cid: Control element ID. 301 + * 302 + * This function is called during initial device initialization. 303 + * 304 + * Context: Any context that permits to sleep. 305 + * Return: 0 on success, -errno on failure. 306 + */ 307 + static int virtsnd_kctl_get_enum_items(struct virtio_snd *snd, unsigned int cid) 308 + { 309 + struct virtio_device *vdev = snd->vdev; 310 + struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[cid]; 311 + struct virtio_kctl *kctl = &snd->kctls[cid]; 312 + struct virtio_snd_msg *msg; 313 + struct virtio_snd_ctl_hdr *hdr; 314 + unsigned int n = le32_to_cpu(kinfo->value.enumerated.items); 315 + struct scatterlist sg; 316 + 317 + msg = virtsnd_ctl_msg_alloc(sizeof(*hdr), 318 + sizeof(struct virtio_snd_hdr), GFP_KERNEL); 319 + if (!msg) 320 + return -ENOMEM; 321 + 322 + kctl->items = devm_kcalloc(&vdev->dev, n, sizeof(*kctl->items), 323 + GFP_KERNEL); 324 + if (!kctl->items) { 325 + virtsnd_ctl_msg_unref(msg); 326 + return -ENOMEM; 327 + } 328 + 329 + sg_init_one(&sg, kctl->items, n * sizeof(*kctl->items)); 330 + 331 + hdr = virtsnd_ctl_msg_request(msg); 332 + hdr->hdr.code = cpu_to_le32(VIRTIO_SND_R_CTL_ENUM_ITEMS); 333 + hdr->control_id = cpu_to_le32(cid); 334 + 335 + return virtsnd_ctl_msg_send(snd, msg, NULL, &sg, false); 336 + } 337 + 338 + /** 339 + * virtsnd_kctl_parse_cfg() - Parse the control element configuration. 340 + * @snd: VirtIO sound device. 341 + * 342 + * This function is called during initial device initialization. 343 + * 344 + * Context: Any context that permits to sleep. 345 + * Return: 0 on success, -errno on failure. 346 + */ 347 + int virtsnd_kctl_parse_cfg(struct virtio_snd *snd) 348 + { 349 + struct virtio_device *vdev = snd->vdev; 350 + u32 i; 351 + int rc; 352 + 353 + virtio_cread_le(vdev, struct virtio_snd_config, controls, 354 + &snd->nkctls); 355 + if (!snd->nkctls) 356 + return 0; 357 + 358 + snd->kctl_infos = devm_kcalloc(&vdev->dev, snd->nkctls, 359 + sizeof(*snd->kctl_infos), GFP_KERNEL); 360 + if (!snd->kctl_infos) 361 + return -ENOMEM; 362 + 363 + snd->kctls = devm_kcalloc(&vdev->dev, snd->nkctls, sizeof(*snd->kctls), 364 + GFP_KERNEL); 365 + if (!snd->kctls) 366 + return -ENOMEM; 367 + 368 + rc = virtsnd_ctl_query_info(snd, VIRTIO_SND_R_CTL_INFO, 0, snd->nkctls, 369 + sizeof(*snd->kctl_infos), snd->kctl_infos); 370 + if (rc) 371 + return rc; 372 + 373 + for (i = 0; i < snd->nkctls; ++i) { 374 + struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[i]; 375 + unsigned int type = le32_to_cpu(kinfo->type); 376 + 377 + if (type == VIRTIO_SND_CTL_TYPE_ENUMERATED) { 378 + rc = virtsnd_kctl_get_enum_items(snd, i); 379 + if (rc) 380 + return rc; 381 + } 382 + } 383 + 384 + return 0; 385 + } 386 + 387 + /** 388 + * virtsnd_kctl_build_devs() - Build ALSA control elements. 389 + * @snd: VirtIO sound device. 390 + * 391 + * Context: Any context that permits to sleep. 392 + * Return: 0 on success, -errno on failure. 393 + */ 394 + int virtsnd_kctl_build_devs(struct virtio_snd *snd) 395 + { 396 + unsigned int cid; 397 + 398 + for (cid = 0; cid < snd->nkctls; ++cid) { 399 + struct virtio_snd_ctl_info *kinfo = &snd->kctl_infos[cid]; 400 + struct virtio_kctl *kctl = &snd->kctls[cid]; 401 + struct snd_kcontrol_new kctl_new; 402 + unsigned int i; 403 + int rc; 404 + 405 + memset(&kctl_new, 0, sizeof(kctl_new)); 406 + 407 + kctl_new.iface = SNDRV_CTL_ELEM_IFACE_MIXER; 408 + kctl_new.name = kinfo->name; 409 + kctl_new.index = le32_to_cpu(kinfo->index); 410 + 411 + for (i = 0; i < ARRAY_SIZE(g_v2a_access_map); ++i) 412 + if (le32_to_cpu(kinfo->access) & (1 << i)) 413 + kctl_new.access |= g_v2a_access_map[i]; 414 + 415 + if (kctl_new.access & (SNDRV_CTL_ELEM_ACCESS_TLV_READ | 416 + SNDRV_CTL_ELEM_ACCESS_TLV_WRITE | 417 + SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND)) { 418 + kctl_new.access |= SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; 419 + kctl_new.tlv.c = virtsnd_kctl_tlv_op; 420 + } 421 + 422 + kctl_new.info = virtsnd_kctl_info; 423 + kctl_new.get = virtsnd_kctl_get; 424 + kctl_new.put = virtsnd_kctl_put; 425 + kctl_new.private_value = cid; 426 + 427 + kctl->kctl = snd_ctl_new1(&kctl_new, snd); 428 + if (!kctl->kctl) 429 + return -ENOMEM; 430 + 431 + rc = snd_ctl_add(snd->card, kctl->kctl); 432 + if (rc) 433 + return rc; 434 + } 435 + 436 + return 0; 437 + } 438 + 439 + /** 440 + * virtsnd_kctl_event() - Handle the control element event notification. 441 + * @snd: VirtIO sound device. 442 + * @event: VirtIO sound event. 443 + * 444 + * Context: Interrupt context. 445 + */ 446 + void virtsnd_kctl_event(struct virtio_snd *snd, struct virtio_snd_event *event) 447 + { 448 + struct virtio_snd_ctl_event *kevent = 449 + (struct virtio_snd_ctl_event *)event; 450 + struct virtio_kctl *kctl; 451 + unsigned int cid = le16_to_cpu(kevent->control_id); 452 + unsigned int mask = 0; 453 + unsigned int i; 454 + 455 + if (cid >= snd->nkctls) 456 + return; 457 + 458 + for (i = 0; i < ARRAY_SIZE(g_v2a_mask_map); ++i) 459 + if (le16_to_cpu(kevent->mask) & (1 << i)) 460 + mask |= g_v2a_mask_map[i]; 461 + 462 + 463 + kctl = &snd->kctls[cid]; 464 + 465 + snd_ctl_notify(snd->card, mask, &kctl->kctl->id); 466 + }