[dm][virtio] update virtio dm

1. support RPMsg
2. support Sound
3. fixup virtio-blk free

Signed-off-by: GuEe-GUI <2991707448@qq.com>
This commit is contained in:
GuEe-GUI
2026-06-15 10:00:57 +08:00
committed by Rbb666
parent ed332e4aa9
commit bf0b9feabb
7 changed files with 2798 additions and 0 deletions
+12
View File
@@ -45,6 +45,12 @@ config RT_VIRTIO_RNG
depends on RT_HWCRYPTO_USING_RNG
default y
config RT_VIRTIO_RPMSG
bool "VirtIO Rpmsg"
depends on RT_USING_VIRTIO
depends on RT_USING_RPMSG
default y
config RT_VIRTIO_SCSI
bool "VirtIO SCSI"
depends on RT_USING_VIRTIO
@@ -92,6 +98,12 @@ config RT_VIRTIO_CRYPTO
depends on RT_HWCRYPTO_USING_RC4
default y
config RT_VIRTIO_SOUND
bool "VirtIO Sound"
depends on RT_USING_VIRTIO
depends on RT_USING_AUDIO
default y
config RT_VIRTIO_SCMI
bool "VirtIO SCMI"
depends on RT_USING_VIRTIO
+6
View File
@@ -28,6 +28,9 @@ if GetDepend(['RT_VIRTIO_CONSOLE']) or GetDepend(['RT_VIRTIO_RPROC_SERIAL']):
if GetDepend(['RT_VIRTIO_RNG']):
src += ['virtio-rng.c']
if GetDepend(['RT_VIRTIO_RPMSG']):
src += ['virtio-rpmsg.c']
if GetDepend(['RT_VIRTIO_SCSI']):
src += ['virtio-scsi.c']
@@ -43,6 +46,9 @@ if GetDepend(['RT_VIRTIO_INPUT']):
if GetDepend(['RT_VIRTIO_CRYPTO']):
src += ['virtio-crypto.c']
if GetDepend(['RT_VIRTIO_SOUND']):
src += ['virtio-sound.c']
if GetDepend(['RT_VIRTIO_SCMI']):
src += ['virtio-scmi.c']
+1
View File
@@ -257,6 +257,7 @@ static rt_err_t virtio_blk_probe(struct rt_virtio_device *vdev)
if ((vblk->vblk_id = rt_dm_ida_alloc(&virtio_blk_ida)) < 0)
{
rt_free(vblk);
return -RT_EFULL;
}
+460
View File
@@ -0,0 +1,460 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-25 GuEe-GUI the first version
*/
#include <rthw.h>
#include <rtthread.h>
#include <rtdevice.h>
#define DBG_TAG "virtio.dev.rpmsg"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
#include "virtio_config/virtio-rpmsg.h"
#define QUEUE_RX _queue_rx
#define QUEUE_TX _queue_tx
struct virtio_rpmsg_tx_buf
{
rt_uint8_t data[VIRTIO_RPMSG_MAX_BUF_SIZE];
rt_uint32_t idx;
};
struct virtio_rpmsg
{
struct rt_rpmsg_device parent;
struct rt_rpmsg_device *ns;
struct rt_virtio_device *vdev;
struct rt_virtqueue *vqs[2];
struct rt_spinlock tx_lock;
rt_bool_t supp_ns;
rt_uint8_t *tx_buffer;
struct rt_completion *tx_done;
};
#define raw_to_virtio_rpmsg(raw) (raw)->priv
static int _queue_rx, _queue_tx;
static rt_err_t virtio_rpmsg_create_endpoint(struct rt_rpmsg_device *rdev,
struct rt_rpmsg_endpoint *ept, struct rt_rpmsg_endpoint_info *info)
{
rt_err_t err = RT_EOK;
rt_bool_t is_remote = info->src == RT_RPMSG_ADDR_ANY;
struct rt_rpmsg_endpoint *target_ept;
struct virtio_rpmsg *vrpmsg = raw_to_virtio_rpmsg(rdev);
ept->sysdata = (void *)(rt_ubase_t)is_remote;
if (is_remote)
{
target_ept = rt_rpmsg_find_endpoint(rdev, info);
if (target_ept)
{
LOG_E("%s: endpoint (name: %s, src: %u, dst: %u) already exist",
rt_dm_dev_get_name(&vrpmsg->vdev->parent),
info->name, info->src, info->dst);
return -RT_EINVAL;
}
}
if (!is_remote && vrpmsg->supp_ns)
{
struct rt_rpmsg_ns_msg ns_msg;
rt_memset(&ns_msg, 0, sizeof(ns_msg));
if (info && info->name[0])
{
rt_strncpy(ns_msg.name, info->name, RT_RPMSG_NAME_SIZE);
}
else
{
rt_strncpy(ns_msg.name, rdev->id.name, RT_RPMSG_NAME_SIZE);
}
ns_msg.addr = rt_cpu_to_le32(ept->info.src);
ns_msg.flags = rt_cpu_to_le32(RT_RPMSG_NS_CREATE);
err = rt_rpmsg_sendto(ept, RT_RPMSG_NS_ADDR, &ns_msg, sizeof(ns_msg));
if (err)
{
LOG_E("%s: Notify remote error = %s",
rt_dm_dev_get_name(&vrpmsg->vdev->parent), rt_strerror(err));
}
}
return err;
}
static rt_err_t virtio_rpmsg_destroy_endpoint(struct rt_rpmsg_device *rdev,
struct rt_rpmsg_endpoint *ept)
{
rt_err_t err = RT_EOK;
rt_bool_t is_remote = !!ept->sysdata;
struct virtio_rpmsg *vrpmsg = raw_to_virtio_rpmsg(rdev);
if (!is_remote && vrpmsg->supp_ns)
{
struct rt_rpmsg_ns_msg ns_msg;
rt_memset(&ns_msg, 0, sizeof(ns_msg));
if (ept->info.name[0])
{
rt_strncpy(ns_msg.name, ept->info.name, RT_RPMSG_NAME_SIZE);
}
else
{
rt_strncpy(ns_msg.name, rdev->id.name, RT_RPMSG_NAME_SIZE);
}
ns_msg.addr = rt_cpu_to_le32(ept->info.src);
ns_msg.flags = rt_cpu_to_le32(RT_RPMSG_NS_DESTROY);
err = rt_rpmsg_sendto(ept, RT_RPMSG_NS_ADDR, &ns_msg, sizeof(ns_msg));
if (err)
{
LOG_E("%s: Notify remote error = %s",
rt_dm_dev_get_name(&vrpmsg->vdev->parent), rt_strerror(err));
}
}
return err;
}
static rt_err_t virtio_rpmsg_send(struct rt_rpmsg_device *rdev,
rt_uint32_t src, rt_uint32_t dst,
const void *data, rt_size_t len, rt_int32_t timeout)
{
rt_base_t level;
int idx;
struct rt_virtqueue *vq;
struct virtio_rpmsg_hdr *msg;
struct virtio_rpmsg_tx_buf *tx_buf;
struct virtio_rpmsg *vrpmsg = raw_to_virtio_rpmsg(rdev);
if (src == RT_RPMSG_ADDR_ANY || dst == RT_RPMSG_ADDR_ANY)
{
LOG_E("%s: Invalid addr(src: %u, dst: %u)",
rt_dm_dev_get_name(&vrpmsg->vdev->parent), src, dst);
return -RT_EINVAL;
}
if (len > VIRTIO_RPMSG_MAX_BUF_SIZE - sizeof(*msg))
{
LOG_E("%s: Data's len = %u > %u is too big",
rt_dm_dev_get_name(&vrpmsg->vdev->parent),
len, VIRTIO_RPMSG_MAX_BUF_SIZE - sizeof(*msg));
return -RT_EFULL;
}
vq = vrpmsg->vqs[QUEUE_TX];
rt_virtqueue_wait_prepare(vq, 1);
level = rt_spin_lock_irqsave(&vrpmsg->tx_lock);
idx = rt_virtqueue_next_buf_index(vq);
tx_buf = (void *)vrpmsg->tx_buffer + idx * sizeof(struct virtio_rpmsg_tx_buf);
tx_buf->idx = idx;
msg = (void *)tx_buf->data;
msg->src = rt_cpu_to_le32(src);
msg->dst = rt_cpu_to_le32(dst);
msg->reserved = 0;
msg->len = rt_cpu_to_le16(len);
msg->flags = 0;
LOG_D("%s: %cX-HDR(src: %u, dst: %u, len: %u, flags: %u, reserved: %u)",
rt_dm_dev_get_name(&vrpmsg->vdev->parent), 'T', src, dst, len, 0, 0);
rt_memcpy(msg->data, data, len);
rt_virtqueue_add_outbuf(vq, msg, sizeof(*msg) + len);
rt_virtqueue_kick(vq);
rt_spin_unlock_irqrestore(&vrpmsg->tx_lock, level);
if (timeout)
{
rt_completion_wait(&vrpmsg->tx_done[idx], timeout);
}
return RT_EOK;
}
static const struct rt_rpmsg_ops virtio_rpmsg_ops =
{
.create_endpoint = virtio_rpmsg_create_endpoint,
.destroy_endpoint = virtio_rpmsg_destroy_endpoint,
.send = virtio_rpmsg_send,
};
static void virtio_rpmsg_rx_done(struct rt_virtqueue *vq)
{
rt_size_t len, msg_len;
struct rt_rpmsg_device *rdev;
struct rt_rpmsg_endpoint *ept;
struct rt_rpmsg_endpoint_info info;
struct virtio_rpmsg_hdr *msg;
struct virtio_rpmsg *vrpmsg = vq->vdev->priv;
rdev = &vrpmsg->parent;
msg = rt_virtqueue_read_buf(vq, &len);
if (!msg)
{
LOG_D("%s: not used buffer", rt_dm_dev_get_name(&vrpmsg->vdev->parent));
return;
}
do {
msg_len = rt_le16_to_cpu(msg->len);
LOG_D("%s: %cX-HDR(src: %u, dst: %u, len: %u, flags: %u, reserved: %u)",
rt_dm_dev_get_name(&vrpmsg->vdev->parent), 'R',
rt_le32_to_cpu(msg->src),
rt_le32_to_cpu(msg->dst),
msg_len,
rt_le16_to_cpu(msg->flags),
rt_le32_to_cpu(msg->reserved));
info.src = rt_le32_to_cpu(msg->dst);
info.dst = RT_RPMSG_ADDR_ANY;
info.name[0] = '\0';
if (rt_le32_to_cpu(msg->dst) == RT_RPMSG_NS_ADDR && vrpmsg->ns)
{
ept = rt_rpmsg_find_endpoint(vrpmsg->ns, &info);
}
else
{
ept = rt_rpmsg_find_endpoint(rdev, &info);
}
if (ept && ept->rx_callback)
{
ept->rx_callback(rdev, rt_le32_to_cpu(msg->src), msg->data, msg_len);
}
rt_virtqueue_add_inbuf(vq, msg, VIRTIO_RPMSG_MAX_BUF_SIZE);
rt_virtqueue_kick(vq);
msg = rt_virtqueue_read_buf(vq, &len);
} while (msg);
}
static void virtio_rpmsg_tx_done(struct rt_virtqueue *vq)
{
rt_ubase_t level;
struct virtio_rpmsg_tx_buf *tx_buf;
struct virtio_rpmsg *vrpmsg = vq->vdev->priv;
level = rt_spin_lock_irqsave(&vrpmsg->tx_lock);
while ((tx_buf = rt_virtqueue_read_buf(vq, RT_NULL)))
{
rt_completion_done(&vrpmsg->tx_done[tx_buf->idx]);
}
rt_spin_unlock_irqrestore(&vrpmsg->tx_lock, level);
}
static rt_err_t virtio_rpmsg_vq_init(struct virtio_rpmsg *vrpmsg)
{
rt_err_t err;
rt_size_t vqs_nr = 2, qsize;
void *rx_buffer;
const char *names[RT_ARRAY_SIZE(vrpmsg->vqs)];
rt_virtqueue_callback cbs[RT_ARRAY_SIZE(vrpmsg->vqs)];
struct rt_virtio_device *vdev = vrpmsg->vdev;
struct rt_virtqueue *vq;
names[QUEUE_RX] = "rx";
names[QUEUE_TX] = "tx";
cbs[QUEUE_RX] = &virtio_rpmsg_rx_done;
cbs[QUEUE_TX] = &virtio_rpmsg_tx_done;
err = rt_virtio_virtqueue_install(vdev, vqs_nr, vrpmsg->vqs, names, cbs);
if (err)
{
return err;
}
qsize = rt_virtqueue_get_virtq_size(vrpmsg->vqs[QUEUE_TX]);
if (!(vrpmsg->tx_done = rt_malloc(sizeof(vrpmsg->tx_done[0]) * qsize)))
{
return -RT_ENOMEM;
}
for (int idx = 0; idx < qsize; ++idx)
{
rt_completion_init(&vrpmsg->tx_done[idx]);
}
vrpmsg->tx_buffer = rt_malloc(qsize * sizeof(struct virtio_rpmsg_tx_buf) +
rt_virtqueue_get_virtq_size(vrpmsg->vqs[QUEUE_RX]) * VIRTIO_RPMSG_MAX_BUF_SIZE);
if (!vrpmsg->tx_buffer)
{
return -RT_ENOMEM;
}
vq = vrpmsg->vqs[QUEUE_RX];
rx_buffer = vrpmsg->tx_buffer + qsize * sizeof(struct virtio_rpmsg_tx_buf);
for (int idx = 0; idx < qsize; ++idx, rx_buffer += VIRTIO_RPMSG_MAX_BUF_SIZE)
{
rt_virtqueue_add_inbuf(vq, rx_buffer, VIRTIO_RPMSG_MAX_BUF_SIZE);
rt_virtqueue_submit(vq);
}
rt_virtqueue_notify(vq);
return err;
}
static void virtio_rpmsg_vq_finit(struct virtio_rpmsg *vrpmsg)
{
if (vrpmsg->vqs[0])
{
rt_virtio_virtqueue_release(vrpmsg->vdev);
}
if (vrpmsg->tx_done)
{
rt_free(vrpmsg->tx_done);
}
if (vrpmsg->tx_buffer)
{
rt_free(vrpmsg->tx_buffer);
}
}
static rt_err_t virtio_rpmsg_probe(struct rt_virtio_device *vdev)
{
rt_err_t err = RT_EOK;
struct virtio_rpmsg *vrpmsg;
if (rt_rpmsg_mode() == RT_RPMSG_MODE_SLAVE)
{
_queue_rx = 0;
_queue_tx = 1;
}
else
{
_queue_tx = 0;
_queue_rx = 1;
}
vrpmsg = rt_calloc(1, sizeof(*vrpmsg));
if (!vrpmsg)
{
return -RT_ENOMEM;
}
vdev->priv = vrpmsg;
vrpmsg->vdev = vdev;
vdev->parent.user_data = vrpmsg;
if ((err = virtio_rpmsg_vq_init(vrpmsg)))
{
goto _fail;
}
rt_spin_lock_init(&vrpmsg->tx_lock);
rt_strncpy(vrpmsg->parent.id.name, "rpmsg-char", sizeof(vrpmsg->parent.id.name));
vrpmsg->parent.ops = &virtio_rpmsg_ops;
vrpmsg->parent.priv = vrpmsg;
if ((err = rt_rpmsg_device_register(&vrpmsg->parent)))
{
goto _fail;
}
/* Enable the name service */
if ((vrpmsg->supp_ns = rt_virtio_has_feature(vdev, VIRTIO_RPMSG_F_NS)))
{
vrpmsg->ns = rt_calloc(1, sizeof(*vrpmsg->ns));
if (!vrpmsg->ns)
{
goto _fail_ns;
}
rt_strncpy(vrpmsg->ns->id.name, "rpmsg-name-service", RT_RPMSG_NAME_SIZE);
vrpmsg->ns->ops = &virtio_rpmsg_ops;
vrpmsg->ns->priv = vrpmsg;
if ((err = rt_rpmsg_device_register(vrpmsg->ns)))
{
goto _fail_ns;
}
}
return RT_EOK;
_fail_ns:
rt_bus_remove_device(&vrpmsg->parent.parent);
_fail:
virtio_rpmsg_vq_finit(vrpmsg);
rt_free(vrpmsg);
return err;
}
static rt_err_t virtio_rpmsg_remove(struct rt_virtio_device *vdev)
{
struct virtio_rpmsg *vrpmsg = vdev->parent.user_data;
rt_bus_remove_device(&vrpmsg->parent.parent);
if (vrpmsg->ns)
{
rt_bus_remove_device(&vrpmsg->ns->parent);
}
virtio_rpmsg_vq_finit(vrpmsg);
rt_free(vrpmsg);
return RT_EOK;
}
static const struct rt_virtio_device_id virtio_rpmsg_ids[] =
{
{ VIRTIO_DEVICE_ID_RPMSG, VIRTIO_DEVICE_ANY_ID },
{ /* sentinel */ }
};
static struct rt_virtio_driver virtio_rpmsg_driver =
{
.ids = virtio_rpmsg_ids,
.features =
RT_BIT(VIRTIO_RPMSG_F_NS)
| RT_BIT(VIRTIO_F_ANY_LAYOUT),
.probe = virtio_rpmsg_probe,
.remove = virtio_rpmsg_remove,
};
RT_VIRTIO_DRIVER_EXPORT(virtio_rpmsg_driver);
File diff suppressed because it is too large Load Diff
+31
View File
@@ -0,0 +1,31 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-25 GuEe-GUI the first version
*/
#ifndef __VIRTIO_RPMSG_H__
#define __VIRTIO_RPMSG_H__
#include <drivers/core/dm.h>
#define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
#define VIRTIO_RPMSG_MAX_BUF_SIZE 512
#define VIRTIO_RPMSG_RESERVED_ADDRESSES 1024
rt_packed(struct virtio_rpmsg_hdr
{
rt_le32_t src;
rt_le32_t dst;
rt_le32_t reserved;
rt_le16_t len;
rt_le16_t flags;
rt_uint8_t data[];
});
#endif /* __VIRTIO_RPMSG_H__ */
+441
View File
@@ -0,0 +1,441 @@
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-25 GuEe-GUI the first version
*/
#ifndef __VIRTIO_SOUND_H__
#define __VIRTIO_SOUND_H__
#include <drivers/core/dm.h>
#define VIRTIO_SOUND_F_CTLS 1
struct virtio_snd_config
{
/* available physical jacks */
rt_le32_t jacks;
/* available PCM streams */
rt_le32_t streams;
/* available channel maps */
rt_le32_t chmaps;
/* available control elements if VIRTIO_SND_F_CTLS has been negotiated */
rt_le32_t controls;
};
/* supported dataflow directions */
enum
{
VIRTIO_SND_D_OUTPUT = 0,
VIRTIO_SND_D_INPUT
};
enum
{
/* jack control request types */
VIRTIO_SND_R_JACK_INFO = 1,
VIRTIO_SND_R_JACK_REMAP,
/* PCM control request types */
VIRTIO_SND_R_PCM_INFO = 0x0100,
VIRTIO_SND_R_PCM_SET_PARAMS,
VIRTIO_SND_R_PCM_PREPARE,
VIRTIO_SND_R_PCM_RELEASE,
VIRTIO_SND_R_PCM_START,
VIRTIO_SND_R_PCM_STOP,
/* channel map control request types */
VIRTIO_SND_R_CHMAP_INFO = 0x0200,
/* jack event types */
VIRTIO_SND_EVT_JACK_CONNECTED = 0x1000,
VIRTIO_SND_EVT_JACK_DISCONNECTED,
/* PCM event types */
VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED = 0x1100,
VIRTIO_SND_EVT_PCM_XRUN,
/* common status codes */
VIRTIO_SND_S_OK = 0x8000,
VIRTIO_SND_S_BAD_MSG,
VIRTIO_SND_S_NOT_SUPP,
VIRTIO_SND_S_IO_ERR
};
/* common header */
struct virtio_snd_hdr
{
rt_le32_t code;
};
/* event notification */
struct virtio_snd_event
{
/* VIRTIO_SND_EVT_XXX */
struct virtio_snd_hdr hdr;
/* optional event data */
rt_le32_t data;
};
/* common control request to query an item information */
struct virtio_snd_query_info
{
/* VIRTIO_SND_R_XXX_INFO */
struct virtio_snd_hdr hdr;
/* item start identifier */
rt_le32_t start_id;
/* item count to query */
rt_le32_t count;
/* item information size in bytes */
rt_le32_t size;
};
/* common item information header */
struct virtio_snd_info
{
/* function group node id (High Definition Audio Specification 7.1.2) */
rt_le32_t hda_fn_nid;
};
struct virtio_snd_jack_hdr
{
/* VIRTIO_SND_R_JACK_XXX */
struct virtio_snd_hdr hdr;
/* 0 ... virtio_snd_config::jacks - 1 */
rt_le32_t jack_id;
};
/* supported jack features */
enum
{
VIRTIO_SND_JACK_F_REMAP = 0
};
struct virtio_snd_jack_info
{
/* common header */
struct virtio_snd_info hdr;
/* supported feature bit map (1 << VIRTIO_SND_JACK_F_XXX) */
rt_le32_t features;
/* pin configuration (High Definition Audio Specification 7.3.3.31) */
rt_le32_t hda_reg_defconf;
/* pin capabilities (High Definition Audio Specification 7.3.4.9) */
rt_le32_t hda_reg_caps;
/* current jack connection status (0: disconnected, 1: connected) */
rt_uint8_t connected;
rt_uint8_t padding[7];
};
/* jack remapping control request */
struct virtio_snd_jack_remap
{
/* .code = VIRTIO_SND_R_JACK_REMAP */
struct virtio_snd_jack_hdr hdr;
/* selected association number */
rt_le32_t association;
/* selected sequence number */
rt_le32_t sequence;
};
struct virtio_snd_pcm_hdr
{
/* VIRTIO_SND_R_PCM_XXX */
struct virtio_snd_hdr hdr;
/* 0 ... virtio_snd_config::streams - 1 */
rt_le32_t stream_id;
};
/* supported PCM stream features */
enum
{
VIRTIO_SND_PCM_F_SHMEM_HOST = 0,
VIRTIO_SND_PCM_F_SHMEM_GUEST,
VIRTIO_SND_PCM_F_MSG_POLLING,
VIRTIO_SND_PCM_F_EVT_SHMEM_PERIODS,
VIRTIO_SND_PCM_F_EVT_XRUNS
};
/* supported PCM sample formats */
enum
{
/* analog formats (width / physical width) */
VIRTIO_SND_PCM_FMT_IMA_ADPCM = 0, /* 4 / 4 bits */
VIRTIO_SND_PCM_FMT_MU_LAW, /* 8 / 8 bits */
VIRTIO_SND_PCM_FMT_A_LAW, /* 8 / 8 bits */
VIRTIO_SND_PCM_FMT_S8, /* 8 / 8 bits */
VIRTIO_SND_PCM_FMT_U8, /* 8 / 8 bits */
VIRTIO_SND_PCM_FMT_S16, /* 16 / 16 bits */
VIRTIO_SND_PCM_FMT_U16, /* 16 / 16 bits */
VIRTIO_SND_PCM_FMT_S18_3, /* 18 / 24 bits */
VIRTIO_SND_PCM_FMT_U18_3, /* 18 / 24 bits */
VIRTIO_SND_PCM_FMT_S20_3, /* 20 / 24 bits */
VIRTIO_SND_PCM_FMT_U20_3, /* 20 / 24 bits */
VIRTIO_SND_PCM_FMT_S24_3, /* 24 / 24 bits */
VIRTIO_SND_PCM_FMT_U24_3, /* 24 / 24 bits */
VIRTIO_SND_PCM_FMT_S20, /* 20 / 32 bits */
VIRTIO_SND_PCM_FMT_U20, /* 20 / 32 bits */
VIRTIO_SND_PCM_FMT_S24, /* 24 / 32 bits */
VIRTIO_SND_PCM_FMT_U24, /* 24 / 32 bits */
VIRTIO_SND_PCM_FMT_S32, /* 32 / 32 bits */
VIRTIO_SND_PCM_FMT_U32, /* 32 / 32 bits */
VIRTIO_SND_PCM_FMT_FLOAT, /* 32 / 32 bits */
VIRTIO_SND_PCM_FMT_FLOAT64, /* 64 / 64 bits */
/* digital formats (width / physical width) */
VIRTIO_SND_PCM_FMT_DSD_U8, /* 8 / 8 bits */
VIRTIO_SND_PCM_FMT_DSD_U16, /* 16 / 16 bits */
VIRTIO_SND_PCM_FMT_DSD_U32, /* 32 / 32 bits */
VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME /* 32 / 32 bits */
};
/* supported PCM frame rates */
enum
{
VIRTIO_SND_PCM_RATE_5512 = 0,
VIRTIO_SND_PCM_RATE_8000,
VIRTIO_SND_PCM_RATE_11025,
VIRTIO_SND_PCM_RATE_16000,
VIRTIO_SND_PCM_RATE_22050,
VIRTIO_SND_PCM_RATE_32000,
VIRTIO_SND_PCM_RATE_44100,
VIRTIO_SND_PCM_RATE_48000,
VIRTIO_SND_PCM_RATE_64000,
VIRTIO_SND_PCM_RATE_88200,
VIRTIO_SND_PCM_RATE_96000,
VIRTIO_SND_PCM_RATE_176400,
VIRTIO_SND_PCM_RATE_192000,
VIRTIO_SND_PCM_RATE_384000
};
struct virtio_snd_pcm_info
{
/* common header */
struct virtio_snd_info hdr;
/* supported feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */
rt_le32_t features;
/* supported sample format bit map (1 << VIRTIO_SND_PCM_FMT_XXX) */
rt_le64_t formats;
/* supported frame rate bit map (1 << VIRTIO_SND_PCM_RATE_XXX) */
rt_le64_t rates;
/* dataflow direction (VIRTIO_SND_D_XXX) */
rt_uint8_t direction;
/* minimum # of supported channels */
rt_uint8_t channels_min;
/* maximum # of supported channels */
rt_uint8_t channels_max;
rt_uint8_t padding[5];
};
/* set PCM stream format */
struct virtio_snd_pcm_set_params
{
/* .code = VIRTIO_SND_R_PCM_SET_PARAMS */
struct virtio_snd_pcm_hdr hdr;
/* size of the hardware buffer */
rt_le32_t buffer_bytes;
/* size of the hardware period */
rt_le32_t period_bytes;
/* selected feature bit map (1 << VIRTIO_SND_PCM_F_XXX) */
rt_le32_t features;
/* selected # of channels */
rt_uint8_t channels;
/* selected sample format (VIRTIO_SND_PCM_FMT_XXX) */
rt_uint8_t format;
/* selected frame rate (VIRTIO_SND_PCM_RATE_XXX) */
rt_uint8_t rate;
rt_uint8_t padding;
};
/* I/O request header */
struct virtio_snd_pcm_xfer
{
/* 0 ... virtio_snd_config::streams - 1 */
rt_le32_t stream_id;
};
/* I/O request status */
struct virtio_snd_pcm_status
{
/* VIRTIO_SND_S_XXX */
rt_le32_t status;
/* current device latency */
rt_le32_t latency_bytes;
};
struct virtio_snd_chmap_hdr
{
/* VIRTIO_SND_R_CHMAP_XXX */
struct virtio_snd_hdr hdr;
/* 0 ... virtio_snd_config::chmaps - 1 */
rt_le32_t chmap_id;
};
/* standard channel position definition */
enum
{
VIRTIO_SND_CHMAP_NONE = 0, /* undefined */
VIRTIO_SND_CHMAP_NA, /* silent */
VIRTIO_SND_CHMAP_MONO, /* mono stream */
VIRTIO_SND_CHMAP_FL, /* front left */
VIRTIO_SND_CHMAP_FR, /* front right */
VIRTIO_SND_CHMAP_RL, /* rear left */
VIRTIO_SND_CHMAP_RR, /* rear right */
VIRTIO_SND_CHMAP_FC, /* front center */
VIRTIO_SND_CHMAP_LFE, /* low frequency (LFE) */
VIRTIO_SND_CHMAP_SL, /* side left */
VIRTIO_SND_CHMAP_SR, /* side right */
VIRTIO_SND_CHMAP_RC, /* rear center */
VIRTIO_SND_CHMAP_FLC, /* front left center */
VIRTIO_SND_CHMAP_FRC, /* front right center */
VIRTIO_SND_CHMAP_RLC, /* rear left center */
VIRTIO_SND_CHMAP_RRC, /* rear right center */
VIRTIO_SND_CHMAP_FLW, /* front left wide */
VIRTIO_SND_CHMAP_FRW, /* front right wide */
VIRTIO_SND_CHMAP_FLH, /* front left high */
VIRTIO_SND_CHMAP_FCH, /* front center high */
VIRTIO_SND_CHMAP_FRH, /* front right high */
VIRTIO_SND_CHMAP_TC, /* top center */
VIRTIO_SND_CHMAP_TFL, /* top front left */
VIRTIO_SND_CHMAP_TFR, /* top front right */
VIRTIO_SND_CHMAP_TFC, /* top front center */
VIRTIO_SND_CHMAP_TRL, /* top rear left */
VIRTIO_SND_CHMAP_TRR, /* top rear right */
VIRTIO_SND_CHMAP_TRC, /* top rear center */
VIRTIO_SND_CHMAP_TFLC, /* top front left center */
VIRTIO_SND_CHMAP_TFRC, /* top front right center */
VIRTIO_SND_CHMAP_TSL, /* top side left */
VIRTIO_SND_CHMAP_TSR, /* top side right */
VIRTIO_SND_CHMAP_LLFE, /* left LFE */
VIRTIO_SND_CHMAP_RLFE, /* right LFE */
VIRTIO_SND_CHMAP_BC, /* bottom center */
VIRTIO_SND_CHMAP_BLC, /* bottom left center */
VIRTIO_SND_CHMAP_BRC /* bottom right center */
};
/* maximum possible number of channels */
#define VIRTIO_SND_CHMAP_MAX_SIZE 18
struct virtio_snd_chmap_info
{
/* common header */
struct virtio_snd_info hdr;
/* dataflow direction (VIRTIO_SND_D_XXX) */
rt_uint8_t direction;
/* # of valid channel position values */
rt_uint8_t channels;
/* channel position values (VIRTIO_SND_CHMAP_XXX) */
rt_uint8_t positions[VIRTIO_SND_CHMAP_MAX_SIZE];
};
enum
{
VIRTIO_SND_CTL_ROLE_UNDEFINED = 0,
VIRTIO_SND_CTL_ROLE_VOLUME,
VIRTIO_SND_CTL_ROLE_MUTE,
VIRTIO_SND_CTL_ROLE_GAIN
};
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
};
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
{
struct virtio_snd_info hdr;
rt_le32_t role;
rt_le32_t type;
rt_le32_t access; /* 1 << VIRTIO_SND_CTL_ACCESS_XXX */
rt_le32_t count;
rt_le32_t index;
rt_uint8_t name[44];
union
{
struct
{
rt_le32_t min;
rt_le32_t max;
rt_le32_t step;
} integer;
struct
{
rt_le64_t min;
rt_le64_t max;
rt_le64_t step;
} integer64;
struct
{
rt_le32_t items;
} enumerated;
} value;
};
struct virtio_snd_ctl_enum_item
{
rt_uint8_t item[64];
};
struct virtio_snd_ctl_iec958
{
rt_uint8_t status[24]; /* AES/IEC958 channel status bits */
rt_uint8_t subcode[147]; /* AES/IEC958 subcode bits */
rt_uint8_t pad; /* nothing */
rt_uint8_t dig_subframe[4]; /* AES/IEC958 subframe bits */
};
struct virtio_snd_ctl_value
{
union
{
rt_le32_t integer[128];
rt_le64_t integer64[64];
rt_le32_t enumerated[128];
rt_uint8_t bytes[512];
struct virtio_snd_ctl_iec958 iec958;
} value;
};
struct virtio_snd_ctl_tlv
{
rt_le32_t type;
rt_le32_t length;
rt_le32_t value[];
};
enum
{
VIRTIO_SND_CTL_EVT_MASK_VALUE = 0,
VIRTIO_SND_CTL_EVT_MASK_INFO,
VIRTIO_SND_CTL_EVT_MASK_TLV
};
struct virtio_snd_ctl_event
{
struct virtio_snd_hdr hdr; /* .code = VIRTIO_SND_EVT_CTL_NOTIFY */
rt_le16_t control_id;
rt_le16_t mask; /* 1 << VIRTIO_SND_CTL_EVT_MASK_XXX */
};
#endif /* __VIRTIO_SOUND_H__ */