Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/virtio/virtio_kctl.c
26378 views
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 = snd_kcontrol_chip(kcontrol);
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 = snd_kcontrol_chip(kcontrol);
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 = snd_kcontrol_chip(kcontrol);
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 = snd_kcontrol_chip(kcontrol);
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
*/
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
*/
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
*/
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
*/
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
479