Commit d6568e3d authored by Anton Yakovlev's avatar Anton Yakovlev Committed by Takashi Iwai

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.htmlSigned-off-by: default avatarAnton Yakovlev <anton.yakovlev@opensynergy.com>
Signed-off-by: default avatarAiswarya Cyriac <aiswarya.cyriac@opensynergy.com>
Link: https://lore.kernel.org/r/20240115133654.576068-2-aiswarya.cyriac@opensynergy.comSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent a0978123
......@@ -7,6 +7,14 @@
#include <linux/virtio_types.h>
/*******************************************************************************
* FEATURE BITS
*/
enum {
/* device supports control elements */
VIRTIO_SND_F_CTLS = 0
};
/*******************************************************************************
* CONFIGURATION SPACE
*/
......@@ -17,6 +25,8 @@ struct virtio_snd_config {
__le32 streams;
/* # of available channel maps */
__le32 chmaps;
/* # of available control elements */
__le32 controls;
};
enum {
......@@ -55,6 +65,15 @@ enum {
/* channel map control request types */
VIRTIO_SND_R_CHMAP_INFO = 0x0200,
/* 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,
/* jack event types */
VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
VIRTIO_SND_EVT_JACK_DISCONNECTED,
......@@ -63,6 +82,9 @@ enum {
VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
VIRTIO_SND_EVT_PCM_XRUN,
/* control element event types */
VIRTIO_SND_EVT_CTL_NOTIFY = 0x1200,
/* common status codes */
VIRTIO_SND_S_OK = 0x8000,
VIRTIO_SND_S_BAD_MSG,
......@@ -331,4 +353,136 @@ struct virtio_snd_chmap_info {
__u8 positions[VIRTIO_SND_CHMAP_MAX_SIZE];
};
/*******************************************************************************
* CONTROL ELEMENTS MESSAGES
*/
struct virtio_snd_ctl_hdr {
/* VIRTIO_SND_R_CTL_XXX */
struct virtio_snd_hdr hdr;
/* 0 ... virtio_snd_config::controls - 1 */
__le32 control_id;
};
/* supported roles for control elements */
enum {
VIRTIO_SND_CTL_ROLE_UNDEFINED = 0,
VIRTIO_SND_CTL_ROLE_VOLUME,
VIRTIO_SND_CTL_ROLE_MUTE,
VIRTIO_SND_CTL_ROLE_GAIN
};
/* supported value types for control elements */
enum {
VIRTIO_SND_CTL_TYPE_BOOLEAN = 0,
VIRTIO_SND_CTL_TYPE_INTEGER,
VIRTIO_SND_CTL_TYPE_INTEGER64,
VIRTIO_SND_CTL_TYPE_ENUMERATED,
VIRTIO_SND_CTL_TYPE_BYTES,
VIRTIO_SND_CTL_TYPE_IEC958
};
/* supported access rights for control elements */
enum {
VIRTIO_SND_CTL_ACCESS_READ = 0,
VIRTIO_SND_CTL_ACCESS_WRITE,
VIRTIO_SND_CTL_ACCESS_VOLATILE,
VIRTIO_SND_CTL_ACCESS_INACTIVE,
VIRTIO_SND_CTL_ACCESS_TLV_READ,
VIRTIO_SND_CTL_ACCESS_TLV_WRITE,
VIRTIO_SND_CTL_ACCESS_TLV_COMMAND
};
struct virtio_snd_ctl_info {
/* common header */
struct virtio_snd_info hdr;
/* element role (VIRTIO_SND_CTL_ROLE_XXX) */
__le32 role;
/* element value type (VIRTIO_SND_CTL_TYPE_XXX) */
__le32 type;
/* element access right bit map (1 << VIRTIO_SND_CTL_ACCESS_XXX) */
__le32 access;
/* # of members in the element value */
__le32 count;
/* index for an element with a non-unique name */
__le32 index;
/* name identifier string for the element */
__u8 name[44];
/* additional information about the element's value */
union {
/* VIRTIO_SND_CTL_TYPE_INTEGER */
struct {
/* minimum supported value */
__le32 min;
/* maximum supported value */
__le32 max;
/* fixed step size for value (0 = variable size) */
__le32 step;
} integer;
/* VIRTIO_SND_CTL_TYPE_INTEGER64 */
struct {
/* minimum supported value */
__le64 min;
/* maximum supported value */
__le64 max;
/* fixed step size for value (0 = variable size) */
__le64 step;
} integer64;
/* VIRTIO_SND_CTL_TYPE_ENUMERATED */
struct {
/* # of options supported for value */
__le32 items;
} enumerated;
} value;
};
struct virtio_snd_ctl_enum_item {
/* option name */
__u8 item[64];
};
struct virtio_snd_ctl_iec958 {
/* AES/IEC958 channel status bits */
__u8 status[24];
/* AES/IEC958 subcode bits */
__u8 subcode[147];
/* nothing */
__u8 pad;
/* AES/IEC958 subframe bits */
__u8 dig_subframe[4];
};
struct virtio_snd_ctl_value {
union {
/* VIRTIO_SND_CTL_TYPE_BOOLEAN|INTEGER value */
__le32 integer[128];
/* VIRTIO_SND_CTL_TYPE_INTEGER64 value */
__le64 integer64[64];
/* VIRTIO_SND_CTL_TYPE_ENUMERATED value (option indexes) */
__le32 enumerated[128];
/* VIRTIO_SND_CTL_TYPE_BYTES value */
__u8 bytes[512];
/* VIRTIO_SND_CTL_TYPE_IEC958 value */
struct virtio_snd_ctl_iec958 iec958;
} value;
};
/* supported event reason types */
enum {
/* element's value has changed */
VIRTIO_SND_CTL_EVT_MASK_VALUE = 0,
/* element's information has changed */
VIRTIO_SND_CTL_EVT_MASK_INFO,
/* element's metadata has changed */
VIRTIO_SND_CTL_EVT_MASK_TLV
};
struct virtio_snd_ctl_event {
/* VIRTIO_SND_EVT_CTL_NOTIFY */
struct virtio_snd_hdr hdr;
/* 0 ... virtio_snd_config::controls - 1 */
__le16 control_id;
/* event reason bit map (1 << VIRTIO_SND_CTL_EVT_MASK_XXX) */
__le16 mask;
};
#endif /* VIRTIO_SND_IF_H */
......@@ -7,6 +7,7 @@ virtio_snd-objs := \
virtio_chmap.o \
virtio_ctl_msg.o \
virtio_jack.o \
virtio_kctl.o \
virtio_pcm.o \
virtio_pcm_msg.o \
virtio_pcm_ops.o
......
......@@ -64,6 +64,9 @@ static void virtsnd_event_dispatch(struct virtio_snd *snd,
case VIRTIO_SND_EVT_PCM_XRUN:
virtsnd_pcm_event(snd, event);
break;
case VIRTIO_SND_EVT_CTL_NOTIFY:
virtsnd_kctl_event(snd, event);
break;
}
}
......@@ -233,6 +236,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
if (rc)
return rc;
if (virtio_has_feature(vdev, VIRTIO_SND_F_CTLS)) {
rc = virtsnd_kctl_parse_cfg(snd);
if (rc)
return rc;
}
if (snd->njacks) {
rc = virtsnd_jack_build_devs(snd);
if (rc)
......@@ -251,6 +260,12 @@ static int virtsnd_build_devs(struct virtio_snd *snd)
return rc;
}
if (snd->nkctls) {
rc = virtsnd_kctl_build_devs(snd);
if (rc)
return rc;
}
return snd_card_register(snd->card);
}
......@@ -417,10 +432,16 @@ static const struct virtio_device_id id_table[] = {
{ 0 },
};
static unsigned int features[] = {
VIRTIO_SND_F_CTLS
};
static struct virtio_driver virtsnd_driver = {
.driver.name = KBUILD_MODNAME,
.driver.owner = THIS_MODULE,
.id_table = id_table,
.feature_table = features,
.feature_table_size = ARRAY_SIZE(features),
.validate = virtsnd_validate,
.probe = virtsnd_probe,
.remove = virtsnd_remove,
......
......@@ -31,6 +31,16 @@ struct virtio_snd_queue {
struct virtqueue *vqueue;
};
/**
* struct virtio_kctl - VirtIO control element.
* @kctl: ALSA control element.
* @items: Items for the ENUMERATED element type.
*/
struct virtio_kctl {
struct snd_kcontrol *kctl;
struct virtio_snd_ctl_enum_item *items;
};
/**
* struct virtio_snd - VirtIO sound card device.
* @vdev: Underlying virtio device.
......@@ -45,6 +55,9 @@ struct virtio_snd_queue {
* @nsubstreams: Number of PCM substreams.
* @chmaps: VirtIO channel maps.
* @nchmaps: Number of channel maps.
* @kctl_infos: VirtIO control element information.
* @kctls: VirtIO control elements.
* @nkctls: Number of control elements.
*/
struct virtio_snd {
struct virtio_device *vdev;
......@@ -59,6 +72,9 @@ struct virtio_snd {
u32 nsubstreams;
struct virtio_snd_chmap_info *chmaps;
u32 nchmaps;
struct virtio_snd_ctl_info *kctl_infos;
struct virtio_kctl *kctls;
u32 nkctls;
};
/* Message completion timeout in milliseconds (module parameter). */
......@@ -108,4 +124,10 @@ int virtsnd_chmap_parse_cfg(struct virtio_snd *snd);
int virtsnd_chmap_build_devs(struct virtio_snd *snd);
int virtsnd_kctl_parse_cfg(struct virtio_snd *snd);
int virtsnd_kctl_build_devs(struct virtio_snd *snd);
void virtsnd_kctl_event(struct virtio_snd *snd, struct virtio_snd_event *event);
#endif /* VIRTIO_SND_CARD_H */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment